diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-09-29 16:16:15 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-11-09 10:04:06 +0000 |
commit | a95a7417ad456115a1ef2da4bb8320531c0821f1 (patch) | |
tree | edcd59279e486d2fd4a8f88a7ed025bcf925c6e6 /chromium/weblayer | |
parent | 33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (diff) | |
download | qtwebengine-chromium-a95a7417ad456115a1ef2da4bb8320531c0821f1.tar.gz |
BASELINE: Update Chromium to 106.0.5249.126
Change-Id: Ib0bb21c437a7d1686e21c33f2d329f2ac425b7ab
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438936
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/weblayer')
118 files changed, 3161 insertions, 253 deletions
diff --git a/chromium/weblayer/API_OWNERS b/chromium/weblayer/API_OWNERS index 8098e861f7d..4357e6a00c9 100644 --- a/chromium/weblayer/API_OWNERS +++ b/chromium/weblayer/API_OWNERS @@ -3,5 +3,6 @@ # blundell@chromium.org boliu@chromium.org +cduvall@chromium.org jam@chromium.org sky@chromium.org diff --git a/chromium/weblayer/BUILD.gn b/chromium/weblayer/BUILD.gn index 97b2f3eef91..5de93877db5 100644 --- a/chromium/weblayer/BUILD.gn +++ b/chromium/weblayer/BUILD.gn @@ -293,6 +293,8 @@ source_set("weblayer_lib_base") { "browser/profile_disk_operations.h", "browser/profile_impl.cc", "browser/profile_impl.h", + "browser/reduce_accept_language_factory.cc", + "browser/reduce_accept_language_factory.h", "browser/signin_url_loader_throttle.cc", "browser/signin_url_loader_throttle.h", "browser/ssl_error_controller_client.cc", @@ -449,7 +451,6 @@ source_set("weblayer_lib_base") { "//components/language/core/browser", "//components/leveldb_proto", "//components/metrics", - "//components/metrics:content", "//components/net_log", "//components/network_time", "//components/no_state_prefetch/browser", @@ -470,6 +471,7 @@ source_set("weblayer_lib_base") { "//components/pref_registry:pref_registry", "//components/prefs", "//components/profile_metrics", + "//components/reduce_accept_language/browser", "//components/safe_browsing/content/browser", "//components/safe_browsing/content/browser:client_side_detection", "//components/safe_browsing/content/browser/web_ui", diff --git a/chromium/weblayer/app/content_main_delegate_impl.cc b/chromium/weblayer/app/content_main_delegate_impl.cc index cb033a0b45c..cfc13162d70 100644 --- a/chromium/weblayer/app/content_main_delegate_impl.cc +++ b/chromium/weblayer/app/content_main_delegate_impl.cc @@ -30,6 +30,7 @@ #include "content/public/common/url_constants.h" #include "media/base/media_switches.h" #include "services/network/public/cpp/features.h" +#include "third_party/abseil-cpp/absl/types/variant.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/web_runtime_features.h" #include "ui/base/resource/resource_bundle.h" @@ -153,11 +154,7 @@ ContentMainDelegateImpl::ContentMainDelegateImpl(MainParams params) ContentMainDelegateImpl::~ContentMainDelegateImpl() = default; -bool ContentMainDelegateImpl::BasicStartupComplete(int* exit_code) { - int dummy; - if (!exit_code) - exit_code = &dummy; - +absl::optional<int> ContentMainDelegateImpl::BasicStartupComplete() { // Disable features which are not currently supported in WebLayer. This allows // sites to do feature detection, and prevents crashes in some not fully // implemented features. @@ -232,14 +229,14 @@ bool ContentMainDelegateImpl::BasicStartupComplete(int* exit_code) { RegisterPathProvider(); - return false; + return absl::nullopt; } bool ContentMainDelegateImpl::ShouldCreateFeatureList(InvokedIn invoked_in) { #if BUILDFLAG(IS_ANDROID) // On android WebLayer is in charge of creating its own FeatureList in the // browser process. - return invoked_in == InvokedIn::kChildProcess; + return absl::holds_alternative<InvokedInChildProcess>(invoked_in); #else // TODO(weblayer-dev): Support feature lists on desktop. return true; @@ -298,9 +295,11 @@ void ContentMainDelegateImpl::PreSandboxStartup() { #endif } -void ContentMainDelegateImpl::PostEarlyInitialization(InvokedIn invoked_in) { - if (invoked_in != InvokedIn::kChildProcess) +absl::optional<int> ContentMainDelegateImpl::PostEarlyInitialization( + InvokedIn invoked_in) { + if (absl::holds_alternative<InvokedInBrowserProcess>(invoked_in)) browser_client_->CreateFeatureListAndFieldTrials(); + return absl::nullopt; } absl::variant<int, content::MainFunctionParams> diff --git a/chromium/weblayer/app/content_main_delegate_impl.h b/chromium/weblayer/app/content_main_delegate_impl.h index 151ecc647a5..9268e56e0f6 100644 --- a/chromium/weblayer/app/content_main_delegate_impl.h +++ b/chromium/weblayer/app/content_main_delegate_impl.h @@ -28,11 +28,11 @@ class ContentMainDelegateImpl : public content::ContentMainDelegate { ~ContentMainDelegateImpl() override; // ContentMainDelegate implementation: - bool BasicStartupComplete(int* exit_code) override; + absl::optional<int> BasicStartupComplete() override; bool ShouldCreateFeatureList(InvokedIn invoked_in) override; variations::VariationsIdsProvider* CreateVariationsIdsProvider() override; void PreSandboxStartup() override; - void PostEarlyInitialization(InvokedIn invoked_in) override; + absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override; absl::variant<int, content::MainFunctionParams> RunProcess( const std::string& process_type, content::MainFunctionParams main_function_params) override; diff --git a/chromium/weblayer/browser/DEPS b/chromium/weblayer/browser/DEPS index 46c1627bae1..14ac55d622e 100644 --- a/chromium/weblayer/browser/DEPS +++ b/chromium/weblayer/browser/DEPS @@ -60,6 +60,7 @@ include_rules = [ "+components/profile_metrics", "+components/no_state_prefetch/browser", "+components/no_state_prefetch/common", + "+components/reduce_accept_language/browser", "+components/resources/android", "+components/safe_browsing/android", "+components/safe_browsing/content/browser", diff --git a/chromium/weblayer/browser/ad_tagging_browsertest.cc b/chromium/weblayer/browser/ad_tagging_browsertest.cc index 3994d265b9e..2e4cbc84096 100644 --- a/chromium/weblayer/browser/ad_tagging_browsertest.cc +++ b/chromium/weblayer/browser/ad_tagging_browsertest.cc @@ -55,8 +55,8 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, subresource_filter::CreateSrcFrame(web_contents(), ad_url); // Verify that we are not evaluating subframe loads. - EXPECT_FALSE(observer.GetSubframeLoadPolicy(ad_url).has_value()); - EXPECT_FALSE(observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId())); + EXPECT_FALSE(observer.GetChildFrameLoadPolicy(ad_url).has_value()); + EXPECT_FALSE(observer.GetIsAdFrame(ad_frame->GetFrameTreeNodeId())); // Child frame created by ad script. content::RenderFrameHost* ad_frame_tagged_by_script = @@ -64,8 +64,8 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, web_contents(), GetURL("frame_factory.html?1")); // No frames should be detected by script heuristics. - EXPECT_FALSE(observer.GetIsAdSubframe( - ad_frame_tagged_by_script->GetFrameTreeNodeId())); + EXPECT_FALSE( + observer.GetIsAdFrame(ad_frame_tagged_by_script->GetFrameTreeNodeId())); } // TODO(crbug.com/1210190): This test is flaky. @@ -85,8 +85,8 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, subresource_filter::CreateSrcFrame(web_contents(), ad_url); // Verify that we are evaluating subframe loads. - EXPECT_TRUE(observer.GetSubframeLoadPolicy(ad_url).has_value()); - EXPECT_TRUE(observer.GetIsAdSubframe(ad_frame->GetFrameTreeNodeId())); + EXPECT_TRUE(observer.GetChildFrameLoadPolicy(ad_url).has_value()); + EXPECT_TRUE(observer.GetIsAdFrame(ad_frame->GetFrameTreeNodeId())); // Child frame created by ad script. content::RenderFrameHost* ad_frame_tagged_by_script = @@ -94,8 +94,8 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, web_contents(), GetURL("frame_factory.html?1")); // Frames should be detected by script heuristics. - EXPECT_TRUE(observer.GetIsAdSubframe( - ad_frame_tagged_by_script->GetFrameTreeNodeId())); + EXPECT_TRUE( + observer.GetIsAdFrame(ad_frame_tagged_by_script->GetFrameTreeNodeId())); } // TODO(crbug.com/1210190): This test is flaky. @@ -104,18 +104,18 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, DISABLED_FramesByURL) { // Main frame. NavigateAndWaitForCompletion(GetURL("frame_factory.html"), shell()); - EXPECT_FALSE(observer.GetIsAdSubframe( + EXPECT_FALSE(observer.GetIsAdFrame( web_contents()->GetPrimaryMainFrame()->GetFrameTreeNodeId())); // (1) Vanilla child. content::RenderFrameHost* vanilla_child = subresource_filter::CreateSrcFrame( web_contents(), GetURL("frame_factory.html?1")); - EXPECT_FALSE(observer.GetIsAdSubframe(vanilla_child->GetFrameTreeNodeId())); + EXPECT_FALSE(observer.GetIsAdFrame(vanilla_child->GetFrameTreeNodeId())); // (2) Ad child. content::RenderFrameHost* ad_child = subresource_filter::CreateSrcFrame( web_contents(), GetURL("frame_factory.html?2&ad=true")); - EXPECT_TRUE(observer.GetIsAdSubframe(ad_child->GetFrameTreeNodeId())); + EXPECT_TRUE(observer.GetIsAdFrame(ad_child->GetFrameTreeNodeId())); EXPECT_TRUE(subresource_filter::EvidenceForFrameComprises( ad_child, /*parent_is_ad=*/false, blink::mojom::FilterListResult::kMatchedBlockingRule, @@ -124,7 +124,7 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, DISABLED_FramesByURL) { // (3) Ad child of 2. content::RenderFrameHost* ad_child_2 = subresource_filter::CreateSrcFrame( ad_child, GetURL("frame_factory.html?sub=1&3&ad=true")); - EXPECT_TRUE(observer.GetIsAdSubframe(ad_child_2->GetFrameTreeNodeId())); + EXPECT_TRUE(observer.GetIsAdFrame(ad_child_2->GetFrameTreeNodeId())); EXPECT_TRUE(subresource_filter::EvidenceForFrameComprises( ad_child_2, /*parent_is_ad=*/true, blink::mojom::FilterListResult::kMatchedBlockingRule, @@ -134,7 +134,7 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, DISABLED_FramesByURL) { content::RenderFrameHost* vanilla_child_2 = subresource_filter::CreateSrcFrame(ad_child, GetURL("frame_factory.html?4")); - EXPECT_TRUE(observer.GetIsAdSubframe(vanilla_child_2->GetFrameTreeNodeId())); + EXPECT_TRUE(observer.GetIsAdFrame(vanilla_child_2->GetFrameTreeNodeId())); EXPECT_TRUE(subresource_filter::EvidenceForFrameComprises( vanilla_child_2, /*parent_is_ad=*/true, blink::mojom::FilterListResult::kMatchedNoRules, @@ -148,7 +148,7 @@ IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, DISABLED_FramesByURL) { content::RenderFrameHost* vanilla_child_3 = subresource_filter::CreateSrcFrame(vanilla_child, GetURL("frame_factory.html?5")); - EXPECT_FALSE(observer.GetIsAdSubframe(vanilla_child_3->GetFrameTreeNodeId())); + EXPECT_FALSE(observer.GetIsAdFrame(vanilla_child_3->GetFrameTreeNodeId())); } } // namespace weblayer diff --git a/chromium/weblayer/browser/android/javatests/BUILD.gn b/chromium/weblayer/browser/android/javatests/BUILD.gn index f41e1b58f1b..3f575f96faa 100644 --- a/chromium/weblayer/browser/android/javatests/BUILD.gn +++ b/chromium/weblayer/browser/android/javatests/BUILD.gn @@ -352,7 +352,6 @@ instrumentation_test_runner("weblayer_bundle_test") { "fr-CA", ] android_test_apk = ":weblayer_bundle_test_apk" - android_test_apk_name = "WebLayerBundleTest" additional_apks = [ "//net/android:net_test_support_apk" ] data = [ "//weblayer/test/data/" ] never_incremental = true diff --git a/chromium/weblayer/browser/android/javatests/skew/expectations.txt b/chromium/weblayer/browser/android/javatests/skew/expectations.txt index 3afaaf290cc..5c69edd9c55 100644 --- a/chromium/weblayer/browser/android/javatests/skew/expectations.txt +++ b/chromium/weblayer/browser/android/javatests/skew/expectations.txt @@ -11,6 +11,10 @@ # results: [ Skip ] # conflicts_allowed: True +# Test is flaky, with the particular flake signaled in the bug below but the underlying cause likely +# being crbug.com/1277901. +crbug.com/1329813 [ all ] org.chromium.weblayer.test.ExternalNavigationTest#testNonHandledExternalIntentWithFallbackUrlThatLaunchesIntentAfterRedirectBlocksFallbackIntent [ Skip ] + # No real changes to weblayer APIs, changes should only affect chrome-internal behavior around # navigation which the test depends on. crbug.com/1196803 [ client_lte_91 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoBlockedWhenBackgroundLaunchesAllowedAndUserForbids [ Skip ] diff --git a/chromium/weblayer/browser/android/javatests/weblayer_instrumentation_test_versions.py b/chromium/weblayer/browser/android/javatests/weblayer_instrumentation_test_versions.py index f9ecc347772..704bdb8ef90 100755 --- a/chromium/weblayer/browser/android/javatests/weblayer_instrumentation_test_versions.py +++ b/chromium/weblayer/browser/android/javatests/weblayer_instrumentation_test_versions.py @@ -185,9 +185,6 @@ def main(): '--test-apk', os.path.join(args.client_outdir, 'apks/WebLayerInstrumentationTest.apk'), - '--test-jar', - os.path.join(args.client_outdir, - 'test.lib.java/WebLayerInstrumentationTest.jar'), '--apk-under-test', os.path.join(args.client_outdir, 'apks/WebLayerShellSystemWebView.apk'), '--use-webview-provider', diff --git a/chromium/weblayer/browser/android/metrics/metrics_browsertest.cc b/chromium/weblayer/browser/android/metrics/metrics_browsertest.cc index cdbde5aa596..16f50c9c21c 100644 --- a/chromium/weblayer/browser/android/metrics/metrics_browsertest.cc +++ b/chromium/weblayer/browser/android/metrics/metrics_browsertest.cc @@ -11,6 +11,7 @@ #include "components/metrics/metrics_log_uploader.h" #include "components/metrics/metrics_service.h" #include "components/metrics/metrics_switches.h" +#include "components/metrics/stability_metrics_helper.h" #include "content/public/test/browser_test_utils.h" #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h" #include "weblayer/browser/android/metrics/metrics_test_helper.h" @@ -147,6 +148,7 @@ IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, PageLoadsEnableMultipleUploads) { } IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, NavigationIncrementsPageLoadCount) { + base::HistogramTester histogram_tester; ASSERT_TRUE(embedded_test_server()->Start()); metrics::ChromeUserMetricsExtension log = WaitForNextMetricsLog(); // The initial log should not have a page load count (because nothing was @@ -155,6 +157,8 @@ IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, NavigationIncrementsPageLoadCount) { const metrics::SystemProfileProto& system_profile = log.system_profile(); ASSERT_TRUE(system_profile.has_stability()); EXPECT_EQ(0, system_profile.stability().page_load_count()); + histogram_tester.ExpectBucketCount( + "Stability.Counts2", metrics::StabilityEventType::kPageLoad, 0); } // Loading a page should increment the page load count. @@ -165,6 +169,8 @@ IN_PROC_BROWSER_TEST_F(MetricsBrowserTest, NavigationIncrementsPageLoadCount) { const metrics::SystemProfileProto& system_profile = log.system_profile(); ASSERT_TRUE(system_profile.has_stability()); EXPECT_EQ(1, system_profile.stability().page_load_count()); + histogram_tester.ExpectBucketCount( + "Stability.Counts2", metrics::StabilityEventType::kPageLoad, 1); } } diff --git a/chromium/weblayer/browser/autofill_client_impl.cc b/chromium/weblayer/browser/autofill_client_impl.cc index 2d870b5716c..6c20c132d82 100644 --- a/chromium/weblayer/browser/autofill_client_impl.cc +++ b/chromium/weblayer/browser/autofill_client_impl.cc @@ -237,6 +237,20 @@ void AutofillClientImpl::ScanCreditCard(CreditCardScanCallback callback) { NOTREACHED(); } +bool AutofillClientImpl::IsTouchToFillCreditCardSupported() { + return false; +} + +bool AutofillClientImpl::ShowTouchToFillCreditCard( + base::WeakPtr<autofill::TouchToFillDelegate> delegate) { + NOTREACHED(); + return false; +} + +void AutofillClientImpl::HideTouchToFillCreditCard() { + NOTREACHED(); +} + void AutofillClientImpl::ShowAutofillPopup( const autofill::AutofillClient::PopupOpenArgs& open_args, base::WeakPtr<autofill::AutofillPopupDelegate> delegate) { diff --git a/chromium/weblayer/browser/autofill_client_impl.h b/chromium/weblayer/browser/autofill_client_impl.h index 6cc60bc6b81..b4b70fc9a41 100644 --- a/chromium/weblayer/browser/autofill_client_impl.h +++ b/chromium/weblayer/browser/autofill_client_impl.h @@ -109,6 +109,10 @@ class AutofillClientImpl AddressProfileSavePromptCallback callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(CreditCardScanCallback callback) override; + bool IsTouchToFillCreditCardSupported() override; + bool ShowTouchToFillCreditCard( + base::WeakPtr<autofill::TouchToFillDelegate> delegate) override; + void HideTouchToFillCreditCard() override; void ShowAutofillPopup( const autofill::AutofillClient::PopupOpenArgs& open_args, base::WeakPtr<autofill::AutofillPopupDelegate> delegate) override; diff --git a/chromium/weblayer/browser/bluetooth/weblayer_bluetooth_delegate_impl_client.cc b/chromium/weblayer/browser/bluetooth/weblayer_bluetooth_delegate_impl_client.cc index 9b3137904f6..7a0e6d2e03b 100644 --- a/chromium/weblayer/browser/bluetooth/weblayer_bluetooth_delegate_impl_client.cc +++ b/chromium/weblayer/browser/bluetooth/weblayer_bluetooth_delegate_impl_client.cc @@ -59,25 +59,16 @@ WebLayerBluetoothDelegateImplClient::ShowBluetoothScanningPrompt( #endif } -void WebLayerBluetoothDelegateImplClient::ShowBluetoothDeviceCredentialsDialog( +void WebLayerBluetoothDelegateImplClient::ShowBluetoothDevicePairDialog( content::RenderFrameHost* frame, const std::u16string& device_identifier, - content::BluetoothDelegate::CredentialsCallback callback) { + content::BluetoothDelegate::PairPromptCallback callback, + content::BluetoothDelegate::PairingKind, + const absl::optional<std::u16string>& pin) { // Web Bluetooth is not supported for desktop in WebLayer and Android already // bonds on demand, so this should not be called on any platform. - std::move(callback).Run( - content::BluetoothDelegate::DeviceCredentialsPromptResult::kCancelled, - /*result=*/std::u16string()); + std::move(callback).Run(content::BluetoothDelegate::PairPromptResult( + content::BluetoothDelegate::PairPromptStatus::kCancelled)); NOTREACHED(); } - -void WebLayerBluetoothDelegateImplClient::ShowBluetoothDevicePairConfirmDialog( - content::RenderFrameHost* frame, - const std::u16string& device_identifier, - content::BluetoothDelegate::PairConfirmCallback callback) { - // Web Bluetooth is not supported for desktop in WebLayer and Android already - // bonds on demand, so this should not be called on any platform. - NOTREACHED(); -} - } // namespace weblayer diff --git a/chromium/weblayer/browser/bluetooth/weblayer_bluetooth_delegate_impl_client.h b/chromium/weblayer/browser/bluetooth/weblayer_bluetooth_delegate_impl_client.h index 9eb8028100a..403c9577e23 100644 --- a/chromium/weblayer/browser/bluetooth/weblayer_bluetooth_delegate_impl_client.h +++ b/chromium/weblayer/browser/bluetooth/weblayer_bluetooth_delegate_impl_client.h @@ -43,14 +43,13 @@ class WebLayerBluetoothDelegateImplClient content::RenderFrameHost* frame, const content::BluetoothScanningPrompt::EventHandler& event_handler) override; - void ShowBluetoothDeviceCredentialsDialog( - content::RenderFrameHost* frame, - const std::u16string& device_identifier, - content::BluetoothDelegate::CredentialsCallback callback) override; - void ShowBluetoothDevicePairConfirmDialog( + + void ShowBluetoothDevicePairDialog( content::RenderFrameHost* frame, const std::u16string& device_identifier, - content::BluetoothDelegate::PairConfirmCallback callback) override; + content::BluetoothDelegate::PairPromptCallback callback, + content::BluetoothDelegate::PairingKind, + const absl::optional<std::u16string>& pin) override; }; } // namespace weblayer diff --git a/chromium/weblayer/browser/browser_context_impl.cc b/chromium/weblayer/browser/browser_context_impl.cc index 6d4bfe5e783..09095cf6e9b 100644 --- a/chromium/weblayer/browser/browser_context_impl.cc +++ b/chromium/weblayer/browser/browser_context_impl.cc @@ -23,6 +23,7 @@ #include "components/prefs/json_pref_store.h" #include "components/prefs/pref_service.h" #include "components/prefs/pref_service_factory.h" +#include "components/reduce_accept_language/browser/reduce_accept_language_service.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h" #include "components/site_isolation/pref_names.h" @@ -47,6 +48,7 @@ #include "weblayer/browser/client_hints_factory.h" #include "weblayer/browser/heavy_ad_service_factory.h" #include "weblayer/browser/permissions/permission_manager_factory.h" +#include "weblayer/browser/reduce_accept_language_factory.h" #include "weblayer/browser/stateful_ssl_host_state_delegate_factory.h" #include "weblayer/public/common/switches.h" @@ -220,6 +222,11 @@ BrowserContextImpl::GetBrowsingDataRemoverDelegate() { return BrowsingDataRemoverDelegateFactory::GetForBrowserContext(this); } +content::ReduceAcceptLanguageControllerDelegate* +BrowserContextImpl::GetReduceAcceptLanguageControllerDelegate() { + return ReduceAcceptLanguageFactory::GetForBrowserContext(this); +} + download::InProgressDownloadManager* BrowserContextImpl::RetriveInProgressDownloadManager() { // Override this to provide a connection to the wake lock service. diff --git a/chromium/weblayer/browser/browser_context_impl.h b/chromium/weblayer/browser/browser_context_impl.h index b2fb37566ae..47169d7325e 100644 --- a/chromium/weblayer/browser/browser_context_impl.h +++ b/chromium/weblayer/browser/browser_context_impl.h @@ -65,6 +65,8 @@ class BrowserContextImpl : public content::BrowserContext { download::InProgressDownloadManager* RetriveInProgressDownloadManager() override; content::ContentIndexProvider* GetContentIndexProvider() override; + content::ReduceAcceptLanguageControllerDelegate* + GetReduceAcceptLanguageControllerDelegate() override; ProfileImpl* profile_impl() const { return profile_impl_; } diff --git a/chromium/weblayer/browser/browser_controls_container_view.cc b/chromium/weblayer/browser/browser_controls_container_view.cc index 13ce69ecca9..96a7e5b8126 100644 --- a/chromium/weblayer/browser/browser_controls_container_view.cc +++ b/chromium/weblayer/browser/browser_controls_container_view.cc @@ -36,7 +36,7 @@ BrowserControlsContainerView::BrowserControlsContainerView( is_top_(is_top) { DCHECK(content_view_render_view_); if (!is_top_) { - content_view_render_view_->SetHeightChangedListener( + content_view_render_view_->SetContentHeightChangedListener( base::BindRepeating(&BrowserControlsContainerView::ContentHeightChanged, base::Unretained(this))); } @@ -44,7 +44,7 @@ BrowserControlsContainerView::BrowserControlsContainerView( BrowserControlsContainerView::~BrowserControlsContainerView() { if (!is_top_) { - content_view_render_view_->SetHeightChangedListener( + content_view_render_view_->SetContentHeightChangedListener( base::RepeatingClosure()); } } @@ -75,7 +75,8 @@ int BrowserControlsContainerView::GetContentHeightDelta() { if (is_top_) return web_contents()->GetNativeView()->GetLayer()->position().y(); - return content_view_render_view_->height() - controls_layer_->position().y(); + return content_view_render_view_->content_height() - + controls_layer_->position().y(); } bool BrowserControlsContainerView::IsFullyVisible() const { @@ -175,8 +176,8 @@ void BrowserControlsContainerView::DoSetBottomControlsOffset() { if (!controls_layer_) return; controls_layer_->SetPosition( - gfx::PointF(0, content_view_render_view_->height() - GetControlsHeight() + - GetControlsOffset())); + gfx::PointF(0, content_view_render_view_->content_height() - + GetControlsHeight() + GetControlsOffset())); } static jlong diff --git a/chromium/weblayer/browser/browser_controls_navigation_state_handler.cc b/chromium/weblayer/browser/browser_controls_navigation_state_handler.cc index afe0790a91a..77eb49759ae 100644 --- a/chromium/weblayer/browser/browser_controls_navigation_state_handler.cc +++ b/chromium/weblayer/browser/browser_controls_navigation_state_handler.cc @@ -74,9 +74,7 @@ void BrowserControlsNavigationStateHandler::DidFinishNavigation( void BrowserControlsNavigationStateHandler::DidFinishLoad( content::RenderFrameHost* render_frame_host, const GURL& validated_url) { - const bool is_main_frame = - render_frame_host->GetMainFrame() == render_frame_host; - if (is_main_frame) + if (render_frame_host->IsInPrimaryMainFrame()) ScheduleStopDelayedForceShow(); } @@ -84,12 +82,8 @@ void BrowserControlsNavigationStateHandler::DidFailLoad( content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code) { - const bool is_main_frame = - render_frame_host->GetMainFrame() == render_frame_host; - if (is_main_frame) + if (render_frame_host->IsInPrimaryMainFrame()) { ScheduleStopDelayedForceShow(); - if (render_frame_host->IsActive() && - (render_frame_host == web_contents()->GetPrimaryMainFrame())) { UpdateState(); } } diff --git a/chromium/weblayer/browser/browser_controls_navigation_state_handler_browsertest.cc b/chromium/weblayer/browser/browser_controls_navigation_state_handler_browsertest.cc new file mode 100644 index 00000000000..10ba23562e8 --- /dev/null +++ b/chromium/weblayer/browser/browser_controls_navigation_state_handler_browsertest.cc @@ -0,0 +1,80 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/browser/web_contents.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "weblayer/browser/browser_controls_navigation_state_handler.h" +#include "weblayer/browser/browser_controls_navigation_state_handler_delegate.h" +#include "weblayer/browser/tab_impl.h" +#include "weblayer/shell/browser/shell.h" +#include "weblayer/test/weblayer_browser_test.h" +#include "weblayer/test/weblayer_browser_test_utils.h" + +namespace weblayer { + +class BrowserConrolsNavigationStateHandlerBrowserTest + : public WebLayerBrowserTest { + public: + BrowserConrolsNavigationStateHandlerBrowserTest() = default; + ~BrowserConrolsNavigationStateHandlerBrowserTest() override = default; + + // WebLayerBrowserTest: + void SetUpOnMainThread() override { + WebLayerBrowserTest::SetUpOnMainThread(); + ASSERT_TRUE(embedded_test_server()->Start()); + } + + content::WebContents* web_contents() { + return static_cast<TabImpl*>(shell()->tab())->web_contents(); + } + + private: +}; + +class TestBrowserControlsNavigationStateHandlerDelegate + : public BrowserControlsNavigationStateHandlerDelegate { + public: + // BrowserControlsNavigationStateHandlerDelegate: + void OnBrowserControlsStateStateChanged( + ControlsVisibilityReason reason, + cc::BrowserControlsState state) override { + state_ = state; + if (quit_callback_) + std::move(quit_callback_).Run(); + } + void OnUpdateBrowserControlsStateBecauseOfProcessSwitch( + bool did_commit) override {} + + void WaitForStateChanged() { + base::RunLoop run_loop; + quit_callback_ = run_loop.QuitClosure(); + run_loop.Run(); + } + + cc::BrowserControlsState state() { return state_; } + + private: + base::OnceClosure quit_callback_; + cc::BrowserControlsState state_ = cc::BrowserControlsState::kBoth; +}; + +// Tests that BrowserConrolsNavigationStateHandler informs that the status is +// updated according to navigation progress. +IN_PROC_BROWSER_TEST_F(BrowserConrolsNavigationStateHandlerBrowserTest, Basic) { + TestBrowserControlsNavigationStateHandlerDelegate test_delegate; + BrowserControlsNavigationStateHandler + browser_controls_navigation_state_handler(web_contents(), &test_delegate); + GURL test_url(embedded_test_server()->GetURL("/simple_page.html")); + NavigateAndWaitForStart(test_url, shell()->tab()); + // `test_delegate` should get the status is updated to `kShown` on + // DidStartNavigation(); + EXPECT_EQ(test_delegate.state(), cc::BrowserControlsState::kShown); + test_delegate.WaitForStateChanged(); + // `test_delegate` should get the status is updated to `kBoth` on + // DidFinishLoad(); + EXPECT_EQ(web_contents()->GetLastCommittedURL(), test_url); + EXPECT_EQ(test_delegate.state(), cc::BrowserControlsState::kBoth); +} + +} // namespace weblayer diff --git a/chromium/weblayer/browser/client_hints_factory.cc b/chromium/weblayer/browser/client_hints_factory.cc index d65a8d2c554..7a16852e2ef 100644 --- a/chromium/weblayer/browser/client_hints_factory.cc +++ b/chromium/weblayer/browser/client_hints_factory.cc @@ -32,6 +32,7 @@ ClientHintsFactory::ClientHintsFactory() "ClientHints", BrowserContextDependencyManager::GetInstance()) { DependsOn(HostContentSettingsMapFactory::GetInstance()); + DependsOn(CookieSettingsFactory::GetInstance()); } ClientHintsFactory::~ClientHintsFactory() = default; diff --git a/chromium/weblayer/browser/content_browser_client_impl.cc b/chromium/weblayer/browser/content_browser_client_impl.cc index 214354fffe0..2f24cb0e0db 100644 --- a/chromium/weblayer/browser/content_browser_client_impl.cc +++ b/chromium/weblayer/browser/content_browser_client_impl.cc @@ -259,7 +259,7 @@ void AllowEmptyOriginIdCB(base::OnceCallback<void(bool)> callback) { void CreateMediaDrmStorage( content::RenderFrameHost* render_frame_host, mojo::PendingReceiver<::media::mojom::MediaDrmStorage> receiver) { - DCHECK(render_frame_host); + CHECK(render_frame_host); if (render_frame_host->GetLastCommittedOrigin().opaque()) { DVLOG(1) << __func__ << ": Unique origin."; @@ -269,7 +269,7 @@ void CreateMediaDrmStorage( // The object will be deleted on connection error, or when the frame navigates // away. new cdm::MediaDrmStorageImpl( - render_frame_host, base::BindRepeating(&CreateOriginId), + *render_frame_host, base::BindRepeating(&CreateOriginId), base::BindRepeating(&AllowEmptyOriginIdCB), std::move(receiver)); } #endif // BUILDFLAG(IS_ANDROID) @@ -336,6 +336,7 @@ content::AllowServiceWorkerResult ContentBrowserClientImpl::AllowServiceWorker( const absl::optional<url::Origin>& top_frame_origin, const GURL& script_url, content::BrowserContext* context) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return embedder_support::AllowServiceWorker( scope, site_for_cookies, top_frame_origin, CookieSettingsFactory::GetForBrowserContext(context).get(), @@ -875,23 +876,26 @@ void ContentBrowserClientImpl:: // TODO(https://crbug.com/1265864): Move the registry logic below to a // dedicated file to ensure security review coverage. // TODO(lingqi): Swap the parameters so that lambda functions are not needed. - associated_registry.AddInterface(base::BindRepeating( - [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver<autofill::mojom::AutofillDriver> - receiver) { - autofill::ContentAutofillDriverFactory::BindAutofillDriver( - std::move(receiver), render_frame_host); - }, - &render_frame_host)); - associated_registry.AddInterface(base::BindRepeating( - [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver<autofill::mojom::PasswordManagerDriver> - receiver) { - PasswordManagerDriverFactory::BindPasswordManagerDriver( - std::move(receiver), render_frame_host); - }, - &render_frame_host)); - associated_registry.AddInterface(base::BindRepeating( + associated_registry.AddInterface<autofill::mojom::AutofillDriver>( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver<autofill::mojom::AutofillDriver> + receiver) { + autofill::ContentAutofillDriverFactory::BindAutofillDriver( + std::move(receiver), render_frame_host); + }, + &render_frame_host)); + associated_registry.AddInterface<autofill::mojom::PasswordManagerDriver>( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver< + autofill::mojom::PasswordManagerDriver> receiver) { + PasswordManagerDriverFactory::BindPasswordManagerDriver( + std::move(receiver), render_frame_host); + }, + &render_frame_host)); + associated_registry.AddInterface< + content_capture::mojom::ContentCaptureReceiver>(base::BindRepeating( [](content::RenderFrameHost* render_frame_host, mojo::PendingAssociatedReceiver< content_capture::mojom::ContentCaptureReceiver> receiver) { @@ -899,15 +903,17 @@ void ContentBrowserClientImpl:: std::move(receiver), render_frame_host); }, &render_frame_host)); - associated_registry.AddInterface(base::BindRepeating( - [](content::RenderFrameHost* render_frame_host, - mojo::PendingAssociatedReceiver< - page_load_metrics::mojom::PageLoadMetrics> receiver) { - page_load_metrics::MetricsWebContentsObserver::BindPageLoadMetrics( - std::move(receiver), render_frame_host); - }, - &render_frame_host)); - associated_registry.AddInterface(base::BindRepeating( + associated_registry.AddInterface<page_load_metrics::mojom::PageLoadMetrics>( + base::BindRepeating( + [](content::RenderFrameHost* render_frame_host, + mojo::PendingAssociatedReceiver< + page_load_metrics::mojom::PageLoadMetrics> receiver) { + page_load_metrics::MetricsWebContentsObserver::BindPageLoadMetrics( + std::move(receiver), render_frame_host); + }, + &render_frame_host)); + associated_registry.AddInterface< + security_interstitials::mojom::InterstitialCommands>(base::BindRepeating( [](content::RenderFrameHost* render_frame_host, mojo::PendingAssociatedReceiver< security_interstitials::mojom::InterstitialCommands> receiver) { @@ -915,7 +921,8 @@ void ContentBrowserClientImpl:: BindInterstitialCommands(std::move(receiver), render_frame_host); }, &render_frame_host)); - associated_registry.AddInterface(base::BindRepeating( + associated_registry.AddInterface< + subresource_filter::mojom::SubresourceFilterHost>(base::BindRepeating( [](content::RenderFrameHost* render_frame_host, mojo::PendingAssociatedReceiver< subresource_filter::mojom::SubresourceFilterHost> receiver) { @@ -938,8 +945,9 @@ void ContentBrowserClientImpl::ExposeInterfacesToRenderer( mojo::MakeSelfOwnedReceiver(std::make_unique<SpellCheckHostImpl>(), std::move(receiver)); }; - registry->AddInterface(base::BindRepeating(create_spellcheck_host), - content::GetUIThreadTaskRunner({})); + registry->AddInterface<spellcheck::mojom::SpellCheckHost>( + base::BindRepeating(create_spellcheck_host), + content::GetUIThreadTaskRunner({})); if (base::FeatureList::IsEnabled(features::kWebLayerSafeBrowsing) && IsSafebrowsingSupported()) { diff --git a/chromium/weblayer/browser/content_view_render_view.cc b/chromium/weblayer/browser/content_view_render_view.cc index b6e60b8f939..6453be9bf27 100644 --- a/chromium/weblayer/browser/content_view_render_view.cc +++ b/chromium/weblayer/browser/content_view_render_view.cc @@ -46,13 +46,13 @@ ContentViewRenderView::ContentViewRenderView(JNIEnv* env, } ContentViewRenderView::~ContentViewRenderView() { - DCHECK(height_changed_listener_.is_null()); + DCHECK(content_height_changed_listener_.is_null()); } -void ContentViewRenderView::SetHeightChangedListener( +void ContentViewRenderView::SetContentHeightChangedListener( base::RepeatingClosure callback) { - DCHECK(height_changed_listener_.is_null() || callback.is_null()); - height_changed_listener_ = std::move(callback); + DCHECK(content_height_changed_listener_.is_null() || callback.is_null()); + content_height_changed_listener_ = std::move(callback); } // static @@ -91,14 +91,21 @@ void ContentViewRenderView::SetCurrentWebContents( root_container_layer_->AddChild(web_contents_layer_); } +void ContentViewRenderView::OnViewportSizeChanged(JNIEnv* env, + jint width, + jint height) { + bool content_height_changed = content_height_ != height; + content_height_ = height; + if (content_height_changed && !content_height_changed_listener_.is_null()) + content_height_changed_listener_.Run(); +} + void ContentViewRenderView::OnPhysicalBackingSizeChanged( JNIEnv* env, const JavaParamRef<jobject>& jweb_contents, jint width, jint height, jboolean for_config_change) { - bool height_changed = height_ != height; - height_ = height; content::WebContents* web_contents = content::WebContents::FromJavaWebContents(jweb_contents); gfx::Size size(width, height); @@ -115,9 +122,6 @@ void ContentViewRenderView::OnPhysicalBackingSizeChanged( override_deadline = base::TimeDelta(); web_contents->GetNativeView()->OnPhysicalBackingSizeChanged( size, override_deadline); - - if (height_changed && !height_changed_listener_.is_null()) - height_changed_listener_.Run(); } void ContentViewRenderView::SurfaceCreated(JNIEnv* env) { diff --git a/chromium/weblayer/browser/content_view_render_view.h b/chromium/weblayer/browser/content_view_render_view.h index f9c9fdd2668..988e557b56d 100644 --- a/chromium/weblayer/browser/content_view_render_view.h +++ b/chromium/weblayer/browser/content_view_render_view.h @@ -40,9 +40,9 @@ class ContentViewRenderView : public content::CompositorClient { return root_container_layer_; } - // Height, in pixels. - int height() const { return height_; } - void SetHeightChangedListener(base::RepeatingClosure callback); + // Content Height, in pixels. + int content_height() const { return content_height_; } + void SetContentHeightChangedListener(base::RepeatingClosure callback); // Methods called from Java via JNI ----------------------------------------- void Destroy(JNIEnv* env); @@ -55,6 +55,7 @@ class ContentViewRenderView : public content::CompositorClient { jint width, jint height, jboolean for_config_change); + void OnViewportSizeChanged(JNIEnv* env, jint width, jint height); void SurfaceCreated(JNIEnv* env); void SurfaceDestroyed(JNIEnv* env, jboolean cache_back_buffer); void SurfaceChanged(JNIEnv* env, @@ -94,8 +95,8 @@ class ContentViewRenderView : public content::CompositorClient { scoped_refptr<cc::Layer> root_container_layer_; scoped_refptr<cc::Layer> web_contents_layer_; - base::RepeatingClosure height_changed_listener_; - int height_ = 0; + base::RepeatingClosure content_height_changed_listener_; + int content_height_ = 0; }; } // namespace weblayer diff --git a/chromium/weblayer/browser/download_manager_delegate_impl.cc b/chromium/weblayer/browser/download_manager_delegate_impl.cc index ff8e7a70a88..2b4926ba8d5 100644 --- a/chromium/weblayer/browser/download_manager_delegate_impl.cc +++ b/chromium/weblayer/browser/download_manager_delegate_impl.cc @@ -91,8 +91,7 @@ bool DownloadManagerDelegateImpl::DetermineDownloadTarget( download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, download::DownloadItem::MixedContentStatus::UNKNOWN, item->GetForcedFilePath(), base::FilePath(), - std::string() /*mime_type*/, absl::nullopt /*download_schedule*/, - download::DOWNLOAD_INTERRUPT_REASON_NONE); + std::string() /*mime_type*/, download::DOWNLOAD_INTERRUPT_REASON_NONE); return true; } @@ -264,7 +263,6 @@ void DownloadManagerDelegateImpl::OnDownloadPathGenerated( download::DownloadItem::MixedContentStatus::UNKNOWN, suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload")), base::FilePath(), std::string() /*mime_type*/, - absl::nullopt /*download_schedule*/, download::DOWNLOAD_INTERRUPT_REASON_NONE); } diff --git a/chromium/weblayer/browser/feature_list_creator.cc b/chromium/weblayer/browser/feature_list_creator.cc index 70304626019..592ff38a895 100644 --- a/chromium/weblayer/browser/feature_list_creator.cc +++ b/chromium/weblayer/browser/feature_list_creator.cc @@ -11,6 +11,7 @@ #include "components/prefs/pref_service.h" #include "components/variations/service/variations_service.h" #include "components/variations/variations_crash_keys.h" +#include "components/variations/variations_switches.h" #include "content/public/browser/network_service_instance.h" #include "content/public/common/content_switch_dependent_feature_overrides.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -106,10 +107,13 @@ void FeatureListCreator::SetUpFieldTrials() { std::vector<std::string> variation_ids; auto feature_list = std::make_unique<base::FeatureList>(); + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); variations_service_->SetUpFieldTrials( variation_ids, - content::GetSwitchDependentFeatureOverrides( - *base::CommandLine::ForCurrentProcess()), + command_line->GetSwitchValueASCII( + variations::switches::kForceVariationIds), + content::GetSwitchDependentFeatureOverrides(*command_line), std::move(feature_list), &weblayer_field_trials_); variations::InitCrashKeys(); #else diff --git a/chromium/weblayer/browser/java/BUILD.gn b/chromium/weblayer/browser/java/BUILD.gn index b4a9e6834e6..812e3ad73d9 100644 --- a/chromium/weblayer/browser/java/BUILD.gn +++ b/chromium/weblayer/browser/java/BUILD.gn @@ -408,10 +408,7 @@ android_library("test_java") { annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] } -android_library("junit_test_support") { - # Platform checks are broken for Robolectric. See https://crbug.com/1071638. - bypass_platform_checks = true - testonly = true +robolectric_library("junit_test_support") { deps = [ ":java", "//components/payments/content/android:java", @@ -421,7 +418,6 @@ android_library("junit_test_support") { "//content/public/android:content_java", "//mojo/public/java:bindings_java", "//mojo/public/java:system_java", - "//third_party/android_deps:robolectric_all_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/blink/public/mojom:android_mojo_bindings_java", "//third_party/mockito:mockito_java", @@ -433,9 +429,7 @@ android_library("junit_test_support") { sources = [ "org/chromium/weblayer_private/payments/test_support/WebLayerPaymentRequestBuilder.java" ] } -junit_binary("weblayer_junit_tests") { - # Platform checks are broken for Robolectric. See https://crbug.com/1071638. - bypass_platform_checks = true +robolectric_binary("weblayer_junit_tests") { testonly = true sources = [ "org/chromium/weblayer_private/payments/WebLayerPaymentRequestServiceTest.java" ] resources_package = "org.chromium.weblayer_private.test" diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java index 4927ae672df..ba72036cd82 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ActionModeCallback.java @@ -7,10 +7,12 @@ package org.chromium.weblayer_private; import android.app.SearchManager; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Rect; import android.os.RemoteException; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import androidx.annotation.Nullable; @@ -26,7 +28,7 @@ import org.chromium.weblayer_private.interfaces.ObjectWrapper; /** * A class that handles selection action mode for WebLayer. */ -public final class ActionModeCallback implements ActionMode.Callback { +public final class ActionModeCallback extends ActionMode.Callback2 { private final ActionModeCallbackHelper mHelper; // Can be null during init. private @Nullable ITabClient mTabClient; @@ -79,8 +81,7 @@ public final class ActionModeCallback implements ActionMode.Callback { private boolean isWebSearchAvailable() { Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); intent.putExtra(SearchManager.EXTRA_NEW_SEARCH, true); - return !PackageManagerUtils.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY) - .isEmpty(); + return PackageManagerUtils.canResolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); } @Override @@ -109,4 +110,9 @@ public final class ActionModeCallback implements ActionMode.Callback { public final void onDestroyActionMode(ActionMode mode) { mHelper.onDestroyActionMode(); } + + @Override + public void onGetContentRect(ActionMode mode, View view, Rect outRect) { + mHelper.onGetContentRect(mode, view, outRect); + } } diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ArCoreVersionUtils.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ArCoreVersionUtils.java index 365bcbf3efb..bdad3ff26c0 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ArCoreVersionUtils.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ArCoreVersionUtils.java @@ -15,9 +15,9 @@ import org.chromium.base.annotations.JNINamespace; @JNINamespace("weblayer") class ArCoreVersionUtils { - // Corresponds to V1.22. Must be updated if the arcore version in + // Corresponds to V1.32. Must be updated if the arcore version in // //third_party/arcore-android-sdk-client is rolled. - private static final int MIN_APK_VERSION = 202940000; + private static final int MIN_APK_VERSION = 221020000; private static final String AR_CORE_PACKAGE = "com.google.ar.core"; private static final String METADATA_KEY_MIN_APK_VERSION = "com.google.ar.core.min_apk_version"; diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java index 8e0b222270b..f959495156c 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java @@ -7,15 +7,18 @@ package org.chromium.weblayer_private; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; +import android.os.Build; import android.os.Bundle; import android.os.RemoteException; import android.provider.Settings; import android.text.TextUtils; +import android.view.SurfaceControlViewHost; import android.view.View; import android.webkit.ValueCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.fragment.app.FragmentManager; import org.chromium.base.ObserverList; @@ -460,7 +463,7 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan } @Override - public List getTabs() { + public List<TabImpl> getTabs() { StrictModeWorkaround.apply(); return Arrays.asList(BrowserImplJni.get().getTabs(mNativeBrowser)); } @@ -472,6 +475,17 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan } @Override + public int[] getTabIds() { + StrictModeWorkaround.apply(); + List<TabImpl> tabs = getTabs(); + int[] ids = new int[tabs.size()]; + for(int i = 0; i < tabs.size(); i++) { + ids[i] = tabs.get(i).getId(); + } + return ids; + } + + @Override public void setClient(IBrowserClient client) { // This function is called from the client once everything has been setup (meaning all the // client classes have been created and AIDL interfaces established in both directions). @@ -728,6 +742,15 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan } } + @RequiresApi(Build.VERSION_CODES.R) + @Override + public void setSurfaceControlViewHost(IObjectWrapper wrappedHost) { + // TODO(rayankans): Handle fallback for older devices. + SurfaceControlViewHost host = + ObjectWrapper.unwrap(wrappedHost, SurfaceControlViewHost.class); + host.setView(mViewController.getView(), 0, 0); + } + @NativeMethods interface Natives { long createBrowser(long profile, BrowserImpl caller); diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java index f3eb434b15f..b1df391d46c 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java @@ -4,6 +4,7 @@ package org.chromium.weblayer_private; +import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.os.RemoteException; @@ -188,8 +189,16 @@ public final class BrowserViewController }); mContentViewRenderView.addView(mBottomSheetContainer); + Activity activity = ContextUtils.activityFromContext(context); + if (activity == null) { + // TODO(rayankans): Remove assumptions about Activity from BottomSheetController. + mBottomSheetController = null; + mPwaBottomSheetController = null; + mBottomSheetObserver = null; + return; + } mBottomSheetController = BottomSheetControllerFactory.createBottomSheetController( - () -> mScrim, (v) -> {}, ContextUtils.activityFromContext(context).getWindow(), + () -> mScrim, (v) -> {}, activity.getWindow(), KeyboardVisibilityDelegate.getInstance(), () -> mBottomSheetContainer, () -> mContentViewRenderView.getHeight()); BottomSheetControllerFactory.attach(mWindowAndroid, mBottomSheetController); @@ -235,9 +244,11 @@ public final class BrowserViewController } public void destroy() { - BottomSheetControllerFactory.detach(mBottomSheetController); - mBottomSheetController.removeObserver(mBottomSheetObserver); - PwaBottomSheetControllerFactory.detach(mPwaBottomSheetController); + if (mBottomSheetController != null) { + BottomSheetControllerFactory.detach(mBottomSheetController); + mBottomSheetController.removeObserver(mBottomSheetObserver); + PwaBottomSheetControllerFactory.detach(mPwaBottomSheetController); + } mWindowAndroid.setModalDialogManager(null); setActiveTab(null); if (mOnscreenContentProvider != null) mOnscreenContentProvider.destroy(); diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java index dce3faddc7c..f8b8f686bac 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ContentViewRenderView.java @@ -872,7 +872,11 @@ public class ContentViewRenderView @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { + if (mWebContents == null) return; updateWebContentsSize(); + Size viewportSize = getViewportSize(); + ContentViewRenderViewJni.get().onViewportSizeChanged( + mNativeContentViewRenderView, viewportSize.getWidth(), viewportSize.getHeight()); } /** @@ -1093,6 +1097,7 @@ public class ContentViewRenderView void setCurrentWebContents(long nativeContentViewRenderView, WebContents webContents); void onPhysicalBackingSizeChanged(long nativeContentViewRenderView, WebContents webContents, int width, int height, boolean forConfigChange); + void onViewportSizeChanged(long nativeContentViewRenderView, int width, int height); void surfaceCreated(long nativeContentViewRenderView); void surfaceDestroyed(long nativeContentViewRenderView, boolean cacheBackBuffer); void surfaceChanged(long nativeContentViewRenderView, boolean canBeUsedWithSurfaceControl, diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java index 5b76ecfde73..3085b7ae541 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java @@ -6,12 +6,14 @@ package org.chromium.weblayer_private; import android.content.Context; import android.content.Intent; +import android.content.pm.ResolveInfo; import android.os.RemoteException; import androidx.annotation.Nullable; import org.chromium.base.Callback; import org.chromium.base.Function; +import org.chromium.base.supplier.Supplier; import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.components.external_intents.ExternalNavigationDelegate; import org.chromium.components.external_intents.ExternalNavigationParams; @@ -23,6 +25,8 @@ import org.chromium.url.Origin; import org.chromium.weblayer_private.interfaces.APICallException; import org.chromium.weblayer_private.interfaces.ExternalIntentInIncognitoUserDecision; +import java.util.List; + /** * WebLayer's implementation of the {@link ExternalNavigationDelegate}. */ @@ -149,8 +153,8 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat public void maybeSetPendingIncognitoUrl(Intent intent) {} @Override - public boolean maybeLaunchInstantApp( - GURL url, GURL referrerUrl, boolean isIncomingRedirect, boolean isSerpReferrer) { + public boolean maybeLaunchInstantApp(GURL url, GURL referrerUrl, boolean isIncomingRedirect, + boolean isSerpReferrer, Supplier<List<ResolveInfo>> resolveInfoSupplier) { return false; } @@ -176,7 +180,8 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat } @Override - public boolean isIntentForTrustedCallingApp(Intent intent) { + public boolean isIntentForTrustedCallingApp( + Intent intent, Supplier<List<ResolveInfo>> resolveInfoSupplier) { return false; } @@ -204,7 +209,8 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat } @Override - public boolean maybeSetTargetPackage(Intent intent) { + public boolean maybeSetTargetPackage( + Intent intent, Supplier<List<ResolveInfo>> resolveInfoSupplier) { return false; } diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/FragmentHostingRemoteFragmentImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FragmentHostingRemoteFragmentImpl.java index 13f836ffae0..6ac7dc5563e 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/FragmentHostingRemoteFragmentImpl.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/FragmentHostingRemoteFragmentImpl.java @@ -167,7 +167,9 @@ public abstract class FragmentHostingRemoteFragmentImpl extends RemoteFragmentIm // within an AppCompatActivity, it will be from the embedder's ClassLoader, so in WebLayer's // ClassLoader the initialization hasn't occurred. Creating an AppCompatDelegate manually // here will perform the necessary initialization. - AppCompatDelegate.create(getActivity(), null); + if (getActivity() != null) { + AppCompatDelegate.create(getActivity(), null); + } } @Override diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java index e4353bc7620..dfe72d7e1fb 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java @@ -8,7 +8,6 @@ import android.app.Activity; import android.os.SystemClock; import org.chromium.base.ContextUtils; -import org.chromium.components.external_intents.AuthenticatorNavigationInterceptor; import org.chromium.components.external_intents.ExternalNavigationHandler; import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingAsyncActionType; import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult; @@ -91,11 +90,6 @@ public class InterceptNavigationDelegateClientImpl implements InterceptNavigatio } @Override - public AuthenticatorNavigationInterceptor createAuthenticatorNavigationInterceptor() { - return null; - } - - @Override public boolean isIncognito() { return mTab.getProfile().isIncognito(); } diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java index 5ae639acb1a..d303483b863 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java @@ -274,6 +274,8 @@ public final class ProfileImpl long toMillis, @NonNull IObjectWrapper completionCallback) { StrictModeWorkaround.apply(); checkNotDestroyed(); + // `toMillis` should be greater than `fromMillis` + assert fromMillis < toMillis; // Handle ContentCapture data clearing. PlatformContentCaptureController controller = PlatformContentCaptureController.getInstance(); diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java index 3723120fcf2..5373cad57a7 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java @@ -227,6 +227,7 @@ public final class TabImpl extends ITab.Stub { @Override protected void onVerticalScrollDirectionChanged( boolean directionUp, float currentScrollRatio) { + super.onVerticalScrollDirectionChanged(directionUp, currentScrollRatio); try { mClient.onScrollNotification(directionUp ? ScrollNotificationType.DIRECTION_CHANGED_UP @@ -275,11 +276,17 @@ public final class TabImpl extends ITab.Stub { mWebContentsObserver = new WebContentsObserver() { @Override - public void didStartNavigation(NavigationHandle navigationHandle) { - if (navigationHandle.isInPrimaryMainFrame() && !navigationHandle.isSameDocument()) { + public void didStartNavigationInPrimaryMainFrame(NavigationHandle navigationHandle) { + if (!navigationHandle.isSameDocument()) { hideFindInPageUiAndNotifyClient(); } } + + @Override + public void didStartNavigationNoop(NavigationHandle navigationHandle) { + if (!navigationHandle.isInPrimaryMainFrame()) return; + } + @Override public void viewportFitChanged(@WebContentsObserver.ViewportFitType int value) { ensureDisplayCutoutController(); diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebContentsGestureStateTracker.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebContentsGestureStateTracker.java index eb9ca9b1ddd..0a1312404bd 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebContentsGestureStateTracker.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebContentsGestureStateTracker.java @@ -64,7 +64,8 @@ public final class WebContentsGestureStateTracker { mGestureListener = new GestureStateListener() { @Override - public void onFlingStartGesture(int scrollOffsetY, int scrollExtentY) { + public void onFlingStartGesture( + int scrollOffsetY, int scrollExtentY, boolean isDirectionUp) { onScrollingStateChanged(); } @@ -74,7 +75,8 @@ public final class WebContentsGestureStateTracker { } @Override - public void onScrollStarted(int scrollOffsetY, int scrollExtentY) { + public void onScrollStarted( + int scrollOffsetY, int scrollExtentY, boolean isDirectionUp) { onScrollingStateChanged(); } diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java index b5d8ae6e804..175d9108b82 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java @@ -78,27 +78,27 @@ public final class WebLayerNotificationWrapperBuilder extends NotificationWrappe * resources. This is useful when {@link Icon} is not available. */ private int getFallbackAndroidResource(int appResourceId) { - if (appResourceId == R.drawable.ic_play_arrow_white_36dp) { + if (appResourceId == R.drawable.ic_play_arrow_white_24dp) { return android.R.drawable.ic_media_play; } - if (appResourceId == R.drawable.ic_pause_white_36dp) { + if (appResourceId == R.drawable.ic_pause_white_24dp) { return android.R.drawable.ic_media_pause; } - if (appResourceId == R.drawable.ic_stop_white_36dp) { + if (appResourceId == R.drawable.ic_stop_white_24dp) { // There's no ic_media_stop. This standin is at least a square. In practice this // shouldn't ever come up as stop is only used in (Chrome) cast notifications. return android.R.drawable.checkbox_off_background; } - if (appResourceId == R.drawable.ic_skip_previous_white_36dp) { + if (appResourceId == R.drawable.ic_skip_previous_white_24dp) { return android.R.drawable.ic_media_previous; } - if (appResourceId == R.drawable.ic_skip_next_white_36dp) { + if (appResourceId == R.drawable.ic_skip_next_white_24dp) { return android.R.drawable.ic_media_next; } - if (appResourceId == R.drawable.ic_fast_forward_white_36dp) { + if (appResourceId == R.drawable.ic_fast_forward_white_24dp) { return android.R.drawable.ic_media_ff; } - if (appResourceId == R.drawable.ic_fast_rewind_white_36dp) { + if (appResourceId == R.drawable.ic_fast_rewind_white_24dp) { return android.R.drawable.ic_media_rew; } if (appResourceId == R.drawable.audio_playing) { diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl index ece38bee852..7bd4e537b15 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IBrowser.aidl @@ -55,4 +55,10 @@ interface IBrowser { // Added in 91. void setChangeVisibilityOnNextDetach(in boolean changeVisibility) = 18; + + // Added in 105. + void setSurfaceControlViewHost(in IObjectWrapper host) = 19; + + // Added in 105 + int[] getTabIds() = 20; } diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py index 8fa31a20902..e507cad300d 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py @@ -72,6 +72,10 @@ class AidlFile: def _CompareApiDumpForFiles(input_api, output_api, aidl_files): if len(aidl_files) == 0: return [] + # These tests fail to run on Windows (devil_chromium needs some non-standard + # Windows modules) and given the Android dependencies this is reasonable. + if input_api.is_windows: + return [] repo_root = input_api.change.RepositoryRoot() build_android_dir = os.path.join(repo_root, 'build', 'android') @@ -81,7 +85,14 @@ def _CompareApiDumpForFiles(input_api, output_api, aidl_files): from devil.android.sdk import build_tools devil_chromium.Initialize() - aidl_tool_path = build_tools.GetPath('aidl') + try: + aidl_tool_path = build_tools.GetPath('aidl') + except Exception as e: + if input_api.no_diffs: + # If we are running presubmits with --all or --files and the 'aidl' tool + # cannot be found then that probably means that target_os = 'android' is + # missing from .gclient and the failure is not interesting. + return [] if not os.path.exists(aidl_tool_path): return [output_api.PresubmitError( 'Android sdk does not contain aidl command ' + aidl_tool_path)] diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java index 23f8f61a4f2..106483b7538 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java @@ -9,8 +9,6 @@ import androidx.annotation.Nullable; import org.chromium.components.payments.BrowserPaymentRequest; import org.chromium.components.payments.JourneyLogger; import org.chromium.components.payments.PaymentApp; -import org.chromium.components.payments.PaymentAppFactoryDelegate; -import org.chromium.components.payments.PaymentAppService; import org.chromium.components.payments.PaymentAppType; import org.chromium.components.payments.PaymentRequestService; import org.chromium.components.payments.PaymentRequestService.Delegate; @@ -107,13 +105,6 @@ public class WebLayerPaymentRequestService implements BrowserPaymentRequest { // Implements BrowserPaymentRequest: @Override - public void addPaymentAppFactories( - PaymentAppService service, PaymentAppFactoryDelegate delegate) { - // There's no WebLayer specific factories. - } - - // Implements BrowserPaymentRequest: - @Override @Nullable public String showOrSkipAppSelector(boolean isShowWaitingForUpdatedDetails, PaymentItem total, boolean shouldSkipAppSelector) { diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java index b24a6fe6ba7..efc62c056e3 100644 --- a/chromium/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java +++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java @@ -5,7 +5,7 @@ package org.chromium.weblayer_private.settings; import android.app.Activity; -import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; import androidx.annotation.Nullable; import androidx.preference.Preference; @@ -47,7 +47,7 @@ public class WebLayerSiteSettingsDelegate } @Override - public void getFaviconImageForURL(GURL faviconUrl, Callback<Bitmap> callback) { + public void getFaviconImageForURL(GURL faviconUrl, Callback<Drawable> callback) { // We don't currently support favicons on WebLayer. callback.onResult(null); } @@ -137,4 +137,15 @@ public class WebLayerSiteSettingsDelegate @Override public void dismissPrivacySandboxSnackbar() {} + + @Override + public boolean canLaunchClearBrowsingDataDialog() { + return false; + } + + @Override + public void launchClearBrowsingDataDialog(Activity currentActivity) {} + + @Override + public void onDestroyView() {} } diff --git a/chromium/weblayer/browser/overlay_popup_ad_intervention_browsertest.cc b/chromium/weblayer/browser/overlay_popup_ad_intervention_browsertest.cc index 0424fe82790..4455d2bacbe 100644 --- a/chromium/weblayer/browser/overlay_popup_ad_intervention_browsertest.cc +++ b/chromium/weblayer/browser/overlay_popup_ad_intervention_browsertest.cc @@ -134,8 +134,9 @@ class OverlayPopupAdViolationBrowserTestWithoutEnforcement base::test::ScopedFeatureList feature_list_; }; +// TODO(https://crbug.com/1344280): Test is flaky. IN_PROC_BROWSER_TEST_F(OverlayPopupAdViolationBrowserTestWithoutEnforcement, - OverlayPopupAd_NoAdInterventionTriggered) { + DISABLED_OverlayPopupAd_NoAdInterventionTriggered) { base::HistogramTester histogram_tester; GURL url = embedded_test_server()->GetURL( diff --git a/chromium/weblayer/browser/page_load_metrics_browsertest.cc b/chromium/weblayer/browser/page_load_metrics_browsertest.cc index f6f7dc153fc..060d0a3c796 100644 --- a/chromium/weblayer/browser/page_load_metrics_browsertest.cc +++ b/chromium/weblayer/browser/page_load_metrics_browsertest.cc @@ -26,10 +26,22 @@ class PageLoadMetricsObserver // page_load_metrics::PageLoadMetricsObserver implementation: - // TODO(https://crbug.com/1317494): Audit and use appropriate policy. ObservePolicy OnFencedFramesStart( content::NavigationHandle* navigation_handle, const GURL& currently_committed_url) override { + // This class is only interested in events for outer-most frame that are + // forwarded by PageLoadTracker. So, this class doesn't need observer-level + // forwarding. + return STOP_OBSERVING; + } + + PageLoadMetricsObserver::ObservePolicy OnPrerenderStart( + content::NavigationHandle* navigation_handle, + const GURL& currently_committed_url) override { + // Currently, prerendering is not enabled for WebLayer. + // + // TODO(https://crbug.com/1267224): If support prerendering, add callbacks + // and tests. return STOP_OBSERVING; } diff --git a/chromium/weblayer/browser/page_load_metrics_observer_impl.cc b/chromium/weblayer/browser/page_load_metrics_observer_impl.cc index fdaeaf80c79..48216ab3f8a 100644 --- a/chromium/weblayer/browser/page_load_metrics_observer_impl.cc +++ b/chromium/weblayer/browser/page_load_metrics_observer_impl.cc @@ -18,11 +18,24 @@ namespace weblayer { -// TODO(https://crbug.com/1317494): Audit and use appropriate policy. page_load_metrics::PageLoadMetricsObserver::ObservePolicy PageLoadMetricsObserverImpl::OnFencedFramesStart( content::NavigationHandle* navigation_handle, const GURL& currently_committed_url) { + // This class is only interested in events for outer-most frame that are + // forwarded by PageLoadTracker. So, this class doesn't need observer-level + // forwarding. + return STOP_OBSERVING; +} + +page_load_metrics::PageLoadMetricsObserver::ObservePolicy +PageLoadMetricsObserverImpl::OnPrerenderStart( + content::NavigationHandle* navigation_handle, + const GURL& currently_committed_url) { + // Currently, prerendering is not enabled for WebLayer. + // + // TODO(https://crbug.com/1267224): If support prerendering, add callbacks, + // e.g. notification of activation_start. return STOP_OBSERVING; } diff --git a/chromium/weblayer/browser/page_load_metrics_observer_impl.h b/chromium/weblayer/browser/page_load_metrics_observer_impl.h index c6d94133cd9..b23b030462d 100644 --- a/chromium/weblayer/browser/page_load_metrics_observer_impl.h +++ b/chromium/weblayer/browser/page_load_metrics_observer_impl.h @@ -19,6 +19,8 @@ class PageLoadMetricsObserverImpl ObservePolicy OnFencedFramesStart( content::NavigationHandle* navigation_handle, const GURL& currently_committed_url) override; + ObservePolicy OnPrerenderStart(content::NavigationHandle* navigation_handle, + const GURL& currently_committed_url) override; ObservePolicy FlushMetricsOnAppEnterBackground( const page_load_metrics::mojom::PageLoadTiming& timing) override; ObservePolicy OnHidden( diff --git a/chromium/weblayer/browser/password_manager_driver_factory.cc b/chromium/weblayer/browser/password_manager_driver_factory.cc index 814beb62e2b..e74439062f5 100644 --- a/chromium/weblayer/browser/password_manager_driver_factory.cc +++ b/chromium/weblayer/browser/password_manager_driver_factory.cc @@ -37,8 +37,7 @@ class PasswordManagerDriverFactory::PasswordManagerDriver void PasswordFormsParsed( const std::vector<autofill::FormData>& raw_forms_data) override {} void PasswordFormsRendered( - const std::vector<autofill::FormData>& raw_visible_forms_data, - bool did_stop_loading) override {} + const std::vector<autofill::FormData>& raw_visible_forms_data) override {} void PasswordFormSubmitted(const autofill::FormData& raw_form_data) override { } void InformAboutUserInput(const autofill::FormData& raw_form_data) override { @@ -105,6 +104,9 @@ void PasswordManagerDriverFactory::BindPasswordManagerDriver( mojo::PendingAssociatedReceiver<autofill::mojom::PasswordManagerDriver> pending_receiver, content::RenderFrameHost* render_frame_host) { + // TODO(https://crbug.com/1233858): Similarly to the + // ContentPasswordManagerDriver implementation. Do not bind the interface when + // the RenderFrameHost is in an anonymous iframe. content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); if (!web_contents) diff --git a/chromium/weblayer/browser/permissions/permission_manager_factory.cc b/chromium/weblayer/browser/permissions/permission_manager_factory.cc index ef813c2e918..b13d7428e87 100644 --- a/chromium/weblayer/browser/permissions/permission_manager_factory.cc +++ b/chromium/weblayer/browser/permissions/permission_manager_factory.cc @@ -126,7 +126,7 @@ permissions::PermissionManager::PermissionContextMap CreatePermissionContexts( continue; #endif ContentSettingsType content_settings_type = - permissions::PermissionUtil::PermissionTypeToContentSetting(type); + permissions::PermissionUtil::PermissionTypeToContentSettingType(type); if (permission_contexts.find(content_settings_type) == permission_contexts.end()) { permission_contexts[content_settings_type] = diff --git a/chromium/weblayer/browser/permissions/weblayer_permissions_client.cc b/chromium/weblayer/browser/permissions/weblayer_permissions_client.cc index e0993278a5f..6cd171c316a 100644 --- a/chromium/weblayer/browser/permissions/weblayer_permissions_client.cc +++ b/chromium/weblayer/browser/permissions/weblayer_permissions_client.cc @@ -12,7 +12,6 @@ #include "weblayer/browser/cookie_settings_factory.h" #include "weblayer/browser/host_content_settings_map_factory.h" #include "weblayer/browser/permissions/permission_decision_auto_blocker_factory.h" -#include "weblayer/browser/permissions/permission_manager_factory.h" #include "weblayer/browser/subresource_filter_profile_context_factory.h" #if BUILDFLAG(IS_ANDROID) @@ -63,11 +62,6 @@ WebLayerPermissionsClient::GetPermissionActionsHistory( return nullptr; } -permissions::PermissionManager* WebLayerPermissionsClient::GetPermissionManager( - content::BrowserContext* browser_context) { - return PermissionManagerFactory::GetForBrowserContext(browser_context); -} - permissions::ObjectPermissionContextBase* WebLayerPermissionsClient::GetChooserContext( content::BrowserContext* browser_context, diff --git a/chromium/weblayer/browser/permissions/weblayer_permissions_client.h b/chromium/weblayer/browser/permissions/weblayer_permissions_client.h index a193c0ea981..a772aeb35f4 100644 --- a/chromium/weblayer/browser/permissions/weblayer_permissions_client.h +++ b/chromium/weblayer/browser/permissions/weblayer_permissions_client.h @@ -30,8 +30,6 @@ class WebLayerPermissionsClient : public permissions::PermissionsClient { content::BrowserContext* browser_context) override; permissions::PermissionDecisionAutoBlocker* GetPermissionDecisionAutoBlocker( content::BrowserContext* browser_context) override; - permissions::PermissionManager* GetPermissionManager( - content::BrowserContext* browser_context) override; permissions::ObjectPermissionContextBase* GetChooserContext( content::BrowserContext* browser_context, ContentSettingsType type) override; diff --git a/chromium/weblayer/browser/profile_impl.cc b/chromium/weblayer/browser/profile_impl.cc index 8748a5f3f3c..aa6e5cccdaf 100644 --- a/chromium/weblayer/browser/profile_impl.cc +++ b/chromium/weblayer/browser/profile_impl.cc @@ -304,6 +304,8 @@ void ProfileImpl::ClearBrowsingData( content::BrowsingDataRemover::DATA_TYPE_ATTRIBUTION_REPORTING; remove_mask |= content::BrowsingDataRemover::DATA_TYPE_AGGREGATION_SERVICE; + remove_mask |= content::BrowsingDataRemover:: + DATA_TYPE_PRIVATE_AGGREGATION_INTERNAL; break; case BrowsingDataType::CACHE: remove_mask |= content::BrowsingDataRemover::DATA_TYPE_CACHE; diff --git a/chromium/weblayer/browser/reduce_accept_language_factory.cc b/chromium/weblayer/browser/reduce_accept_language_factory.cc new file mode 100644 index 00000000000..aa524437203 --- /dev/null +++ b/chromium/weblayer/browser/reduce_accept_language_factory.cc @@ -0,0 +1,50 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "weblayer/browser/reduce_accept_language_factory.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/reduce_accept_language/browser/reduce_accept_language_service.h" +#include "weblayer/browser/browser_context_impl.h" +#include "weblayer/browser/host_content_settings_map_factory.h" + +namespace weblayer { + +// static +reduce_accept_language::ReduceAcceptLanguageService* +ReduceAcceptLanguageFactory::GetForBrowserContext( + content::BrowserContext* context) { + return static_cast<reduce_accept_language::ReduceAcceptLanguageService*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +ReduceAcceptLanguageFactory* ReduceAcceptLanguageFactory::GetInstance() { + static base::NoDestructor<ReduceAcceptLanguageFactory> instance; + return instance.get(); +} + +ReduceAcceptLanguageFactory::ReduceAcceptLanguageFactory() + : BrowserContextKeyedServiceFactory( + "ReduceAcceptLanguage", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(HostContentSettingsMapFactory::GetInstance()); +} + +ReduceAcceptLanguageFactory::~ReduceAcceptLanguageFactory() = default; + +KeyedService* ReduceAcceptLanguageFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new reduce_accept_language::ReduceAcceptLanguageService( + HostContentSettingsMapFactory::GetForBrowserContext(context), + static_cast<BrowserContextImpl*>(context)->pref_service(), + context->IsOffTheRecord()); +} + +content::BrowserContext* ReduceAcceptLanguageFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return context; +} + +} // namespace weblayer
\ No newline at end of file diff --git a/chromium/weblayer/browser/reduce_accept_language_factory.h b/chromium/weblayer/browser/reduce_accept_language_factory.h new file mode 100644 index 00000000000..1c8f51f622f --- /dev/null +++ b/chromium/weblayer/browser/reduce_accept_language_factory.h @@ -0,0 +1,42 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBLAYER_BROWSER_REDUCE_ACCEPT_LANGUAGE_FACTORY_H_ +#define WEBLAYER_BROWSER_REDUCE_ACCEPT_LANGUAGE_FACTORY_H_ + +#include "base/no_destructor.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "components/reduce_accept_language/browser/reduce_accept_language_service.h" +#include "content/public/browser/reduce_accept_language_controller_delegate.h" + +namespace weblayer { + +class ReduceAcceptLanguageFactory : public BrowserContextKeyedServiceFactory { + public: + static reduce_accept_language::ReduceAcceptLanguageService* + GetForBrowserContext(content::BrowserContext* context); + + static ReduceAcceptLanguageFactory* GetInstance(); + + // Non-copyable, non-moveable. + ReduceAcceptLanguageFactory(const ReduceAcceptLanguageFactory&) = delete; + ReduceAcceptLanguageFactory& operator=(const ReduceAcceptLanguageFactory&) = + delete; + + private: + friend base::NoDestructor<ReduceAcceptLanguageFactory>; + + ReduceAcceptLanguageFactory(); + ~ReduceAcceptLanguageFactory() override; + + // BrowserContextKeyedServiceFactory methods: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; +}; + +} // namespace weblayer + +#endif // WEBLAYER_BROWSER_REDUCE_ACCEPT_LANGUAGE_FACTORY_H_ diff --git a/chromium/weblayer/browser/reduce_accept_language_service_browsertest.cc b/chromium/weblayer/browser/reduce_accept_language_service_browsertest.cc new file mode 100644 index 00000000000..06084022de4 --- /dev/null +++ b/chromium/weblayer/browser/reduce_accept_language_service_browsertest.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/language/core/browser/language_prefs.h" +#include "components/language/core/browser/pref_names.h" +#include "components/prefs/pref_service.h" +#include "components/reduce_accept_language/browser/reduce_accept_language_service.h" +#include "components/reduce_accept_language/browser/reduce_accept_language_service_test_util.h" +#include "url/gurl.h" +#include "url/origin.h" +#include "weblayer/browser/browser_context_impl.h" +#include "weblayer/browser/host_content_settings_map_factory.h" +#include "weblayer/browser/reduce_accept_language_factory.h" +#include "weblayer/browser/tab_impl.h" +#include "weblayer/shell/browser/shell.h" +#include "weblayer/test/weblayer_browser_test.h" +#include "weblayer/test/weblayer_browser_test_utils.h" + +using reduce_accept_language::test::ReduceAcceptLanguageServiceTester; + +namespace weblayer { + +class ReduceAcceptLanguageServiceTest : public WebLayerBrowserTest { + public: + void SetUpOnMainThread() override { + WebLayerBrowserTest::SetUpOnMainThread(); + service_tester_ = std::make_unique<ReduceAcceptLanguageServiceTester>( + settings_map(), service(), prefs()); + language::LanguagePrefs(prefs()).SetUserSelectedLanguagesList( + {"en", "ja", "it"}); + } + + content::WebContents* web_contents() { + return static_cast<TabImpl*>(shell()->tab())->web_contents(); + } + + HostContentSettingsMap* settings_map() { + return HostContentSettingsMapFactory::GetForBrowserContext( + web_contents()->GetBrowserContext()); + } + + PrefService* prefs() { + return static_cast<BrowserContextImpl*>(web_contents()->GetBrowserContext()) + ->pref_service(); + } + + reduce_accept_language::ReduceAcceptLanguageService* service() { + return ReduceAcceptLanguageFactory::GetForBrowserContext( + web_contents()->GetBrowserContext()); + } + + ReduceAcceptLanguageServiceTester* tester() { return service_tester_.get(); } + + private: + std::unique_ptr<ReduceAcceptLanguageServiceTester> service_tester_; +}; + +IN_PROC_BROWSER_TEST_F(ReduceAcceptLanguageServiceTest, GetAcceptLanguageList) { + tester()->VerifyFetchAcceptLanguageList({"en", "ja", "it"}); + reduce_accept_language::ReduceAcceptLanguageService incognito_service( + settings_map(), prefs(), true); + // Verify incognito mode only has first accept language. + EXPECT_EQ(std::vector<std::string>{"en"}, + incognito_service.GetUserAcceptLanguages()); +} + +IN_PROC_BROWSER_TEST_F(ReduceAcceptLanguageServiceTest, PersistLanguageFail) { + tester()->VerifyPersistFail(GURL("ws://example.com/"), "Zh-CN"); +} + +IN_PROC_BROWSER_TEST_F(ReduceAcceptLanguageServiceTest, + PersistLanguageSuccessJavaScriptNotEnabled) { + tester()->VerifyPersistSuccessOnJavaScriptDisable( + GURL("https://example.com/"), "Zh-CN"); +} + +IN_PROC_BROWSER_TEST_F(ReduceAcceptLanguageServiceTest, + PersistLanguageSuccess) { + tester()->VerifyPersistSuccess(GURL("https://example.com/"), "Zh-CN"); +} + +IN_PROC_BROWSER_TEST_F(ReduceAcceptLanguageServiceTest, + PersistLanguageMultipleHosts) { + tester()->VerifyPersistMultipleHostsSuccess( + {GURL("https://example1.com/"), GURL("https://example2.com/"), + GURL("http://example.com/")}, + {"en-US", "es-MX", "zh-CN"}); +} + +} // namespace weblayer
\ No newline at end of file diff --git a/chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc b/chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc index df3e9e863eb..3f27d417f9f 100644 --- a/chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc +++ b/chromium/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc @@ -320,15 +320,18 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, DoesNotShowInterstitial_Safe) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_SAFE, false); } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, ShowsInterstitial_Malware) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, + DISABLED_ShowsInterstitial_Malware) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_URL_MALWARE, true); } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, ShowsInterstitial_Phishing) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, + DISABLED_ShowsInterstitial_Phishing) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_URL_PHISHING, true); } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, CheckNavigationErrorType) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, + DISABLED_CheckNavigationErrorType) { auto threat_types = { safe_browsing::SB_THREAT_TYPE_URL_PHISHING, safe_browsing::SB_THREAT_TYPE_URL_MALWARE, @@ -347,16 +350,20 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, CheckNavigationErrorType) { } } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, ShowsInterstitial_Unwanted) { +// Tests below are disabled due to failures on Android. +// See crbug.com/1340200. +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, + DISABLED_ShowsInterstitial_Unwanted) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_URL_UNWANTED, true); } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, ShowsInterstitial_Billing) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, + DISABLED_ShowsInterstitial_Billing) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_BILLING, true); } IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, - ShowsInterstitial_Malware_Subresource) { + DISABLED_ShowsInterstitial_Malware_Subresource) { NavigateWithSubResourceAndThreatType( safe_browsing::SB_THREAT_TYPE_URL_MALWARE, true); } diff --git a/chromium/weblayer/browser/safe_browsing/weblayer_client_side_detection_host_delegate.cc b/chromium/weblayer/browser/safe_browsing/weblayer_client_side_detection_host_delegate.cc index abb4b8adf4d..82036c1a9ae 100644 --- a/chromium/weblayer/browser/safe_browsing/weblayer_client_side_detection_host_delegate.cc +++ b/chromium/weblayer/browser/safe_browsing/weblayer_client_side_detection_host_delegate.cc @@ -12,6 +12,7 @@ #include "weblayer/browser/browser_process.h" #include "weblayer/browser/safe_browsing/client_side_detection_service_factory.h" #include "weblayer/browser/safe_browsing/safe_browsing_service.h" +#include "weblayer/browser/verdict_cache_manager_factory.h" namespace weblayer { @@ -48,10 +49,11 @@ WebLayerClientSideDetectionHostDelegate::GetSafeBrowsingUIManager() { return sb_service->GetSafeBrowsingUIManager(); } -safe_browsing::ClientSideDetectionService* +base::WeakPtr<safe_browsing::ClientSideDetectionService> WebLayerClientSideDetectionHostDelegate::GetClientSideDetectionService() { return ClientSideDetectionServiceFactory::GetForBrowserContext( - web_contents_->GetBrowserContext()); + web_contents_->GetBrowserContext()) + ->GetWeakPtr(); } void WebLayerClientSideDetectionHostDelegate::AddReferrerChain( @@ -59,4 +61,10 @@ void WebLayerClientSideDetectionHostDelegate::AddReferrerChain( GURL current_url, const content::GlobalRenderFrameHostId& current_outermost_main_frame_id) {} +raw_ptr<safe_browsing::VerdictCacheManager> +WebLayerClientSideDetectionHostDelegate::GetCacheManager() { + return VerdictCacheManagerFactory::GetForBrowserContext( + web_contents_->GetBrowserContext()); +} + } // namespace weblayer diff --git a/chromium/weblayer/browser/safe_browsing/weblayer_client_side_detection_host_delegate.h b/chromium/weblayer/browser/safe_browsing/weblayer_client_side_detection_host_delegate.h index 9bcb2db091b..96f0c962743 100644 --- a/chromium/weblayer/browser/safe_browsing/weblayer_client_side_detection_host_delegate.h +++ b/chromium/weblayer/browser/safe_browsing/weblayer_client_side_detection_host_delegate.h @@ -36,12 +36,13 @@ class WebLayerClientSideDetectionHostDelegate GetSafeBrowsingDBManager() override; scoped_refptr<safe_browsing::BaseUIManager> GetSafeBrowsingUIManager() override; - safe_browsing::ClientSideDetectionService* GetClientSideDetectionService() - override; + base::WeakPtr<safe_browsing::ClientSideDetectionService> + GetClientSideDetectionService() override; void AddReferrerChain(safe_browsing::ClientPhishingRequest* verdict, GURL current_url, const content::GlobalRenderFrameHostId& current_outermost_main_frame_id) override; + raw_ptr<safe_browsing::VerdictCacheManager> GetCacheManager() override; private: raw_ptr<content::WebContents> web_contents_; diff --git a/chromium/weblayer/browser/site_isolation_browsertest.cc b/chromium/weblayer/browser/site_isolation_browsertest.cc index d88b2f5bc22..e7fd7e8b0b8 100644 --- a/chromium/weblayer/browser/site_isolation_browsertest.cc +++ b/chromium/weblayer/browser/site_isolation_browsertest.cc @@ -47,10 +47,10 @@ class SiteIsolationBrowserTest : public WebLayerBrowserTest { std::vector<std::string> GetSavedIsolatedSites() { PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile()->GetBrowserContext()); - auto* list = - prefs->GetList(site_isolation::prefs::kUserTriggeredIsolatedOrigins); + const auto& list = prefs->GetValueList( + site_isolation::prefs::kUserTriggeredIsolatedOrigins); std::vector<std::string> sites; - for (const base::Value& value : list->GetListDeprecated()) + for (const base::Value& value : list) sites.push_back(value.GetString()); return sites; } diff --git a/chromium/weblayer/browser/ssl_error_controller_client.cc b/chromium/weblayer/browser/ssl_error_controller_client.cc index 9e38dbcfc79..a3ac87401da 100644 --- a/chromium/weblayer/browser/ssl_error_controller_client.cc +++ b/chromium/weblayer/browser/ssl_error_controller_client.cc @@ -49,7 +49,8 @@ void SSLErrorControllerClient::GoBack() { void SSLErrorControllerClient::Proceed() { web_contents_->GetBrowserContext()->GetSSLHostStateDelegate()->AllowCert( - request_url_.host(), *ssl_info_.cert.get(), cert_error_, web_contents_); + request_url_.host(), *ssl_info_.cert.get(), cert_error_, + web_contents_->GetPrimaryMainFrame()->GetStoragePartition()); Reload(); } diff --git a/chromium/weblayer/browser/tab_impl.cc b/chromium/weblayer/browser/tab_impl.cc index 30a1743caab..bfa7537d8d0 100644 --- a/chromium/weblayer/browser/tab_impl.cc +++ b/chromium/weblayer/browser/tab_impl.cc @@ -32,7 +32,6 @@ #include "components/js_injection/browser/js_communication_host.h" #include "components/js_injection/browser/web_message_host.h" #include "components/js_injection/browser/web_message_host_factory.h" -#include "components/metrics/content/content_stability_metrics_provider.h" #include "components/permissions/permission_manager.h" #include "components/permissions/permission_request_manager.h" #include "components/permissions/permission_result.h" @@ -388,8 +387,6 @@ TabImpl::TabImpl(ProfileImpl* profile, InitializePageLoadMetricsForWebContents(web_contents_.get()); ukm::InitializeSourceUrlRecorderForWebContents(web_contents_.get()); - metrics::ContentStabilityMetricsProvider::SetupWebContentsObserver( - web_contents_.get()); #if BUILDFLAG(IS_ANDROID) javascript_dialogs::TabModalDialogManager::CreateForWebContents( diff --git a/chromium/weblayer/browser/translate_client_impl.cc b/chromium/weblayer/browser/translate_client_impl.cc index 99c1b298b9e..625007dbf7c 100644 --- a/chromium/weblayer/browser/translate_client_impl.cc +++ b/chromium/weblayer/browser/translate_client_impl.cc @@ -86,8 +86,7 @@ bool TranslateClientImpl::ShowTranslateUI( translate::TranslateInfoBarDelegate::Create( step != translate::TRANSLATE_STEP_BEFORE_TRANSLATE, translate_manager_->GetWeakPtr(), - infobars::ContentInfoBarManager::FromWebContents(web_contents()), - web_contents()->GetBrowserContext()->IsOffTheRecord(), step, + infobars::ContentInfoBarManager::FromWebContents(web_contents()), step, source_language, target_language, error_type, triggered_from_menu); return true; #else diff --git a/chromium/weblayer/browser/url_bar/page_info_browsertest.cc b/chromium/weblayer/browser/url_bar/page_info_browsertest.cc index b5e8fd718b6..ab6368a24ce 100644 --- a/chromium/weblayer/browser/url_bar/page_info_browsertest.cc +++ b/chromium/weblayer/browser/url_bar/page_info_browsertest.cc @@ -8,6 +8,8 @@ #include "components/content_settings/core/common/content_settings.h" #include "components/page_info/android/page_info_client.h" #include "components/page_info/page_info_delegate.h" +#include "third_party/blink/public/common/permissions/permission_utils.h" +#include "url/origin.h" #include "weblayer/browser/tab_impl.h" #include "weblayer/browser/url_bar/page_info_delegate_impl.h" #include "weblayer/public/navigation_controller.h" @@ -70,7 +72,7 @@ IN_PROC_BROWSER_TEST_F(PageInfoBrowserTest, ContentSettings) { EXPECT_TRUE(page_info_delegate->GetContentSettings()); } -IN_PROC_BROWSER_TEST_F(PageInfoBrowserTest, PermissionStatus) { +IN_PROC_BROWSER_TEST_F(PageInfoBrowserTest, PermissionResult) { std::unique_ptr<PageInfoDelegate> page_info_delegate = page_info::GetPageInfoClient()->CreatePageInfoDelegate(GetWebContents()); ASSERT_TRUE(page_info_delegate); @@ -83,7 +85,8 @@ IN_PROC_BROWSER_TEST_F(PageInfoBrowserTest, PermissionStatus) { // Check that |page_info_delegate| returns expected ContentSettingsType. EXPECT_EQ(page_info_delegate - ->GetPermissionStatus(ContentSettingsType::NOTIFICATIONS, url) + ->GetPermissionResult(blink::PermissionType::NOTIFICATIONS, + url::Origin::Create(url)) .content_setting, CONTENT_SETTING_BLOCK); } diff --git a/chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc b/chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc index 49d1050401e..687a31d1181 100644 --- a/chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc +++ b/chromium/weblayer/browser/url_bar/page_info_delegate_impl.cc @@ -5,16 +5,17 @@ #include "weblayer/browser/url_bar/page_info_delegate_impl.h" #include "build/build_config.h" -#include "components/permissions/permission_manager.h" #include "components/security_interstitials/content/stateful_ssl_host_state_delegate.h" #include "components/security_state/content/content_utils.h" #include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h" #include "components/subresource_filter/content/browser/subresource_filter_profile_context.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/permission_controller.h" +#include "content/public/browser/permission_result.h" +#include "url/origin.h" #include "weblayer/browser/host_content_settings_map_factory.h" #include "weblayer/browser/page_specific_content_settings_delegate.h" #include "weblayer/browser/permissions/permission_decision_auto_blocker_factory.h" -#include "weblayer/browser/permissions/permission_manager_factory.h" #include "weblayer/browser/stateful_ssl_host_state_delegate_factory.h" #include "weblayer/browser/subresource_filter_profile_context_factory.h" @@ -55,11 +56,14 @@ std::u16string PageInfoDelegateImpl::GetWarningDetailText() { } #endif -permissions::PermissionResult PageInfoDelegateImpl::GetPermissionStatus( - ContentSettingsType type, - const GURL& site_url) { - return PermissionManagerFactory::GetForBrowserContext(GetBrowserContext()) - ->GetPermissionStatusForDisplayOnSettingsUI(type, site_url); +permissions::PermissionResult PageInfoDelegateImpl::GetPermissionResult( + blink::PermissionType permission, + const url::Origin& origin) { + content::PermissionResult permission_result = + GetBrowserContext() + ->GetPermissionController() + ->GetPermissionResultForOriginWithoutContext(permission, origin); + return permissions::PermissionUtil::ToPermissionResult(permission_result); } #if !BUILDFLAG(IS_ANDROID) @@ -74,6 +78,11 @@ void PageInfoDelegateImpl::ShowSiteSettings(const GURL& site_url) { NOTREACHED(); } +void PageInfoDelegateImpl::ShowCookiesSettings() { + // Used for desktop only. Doesn't need implementation for WebLayer. + NOTREACHED(); +} + void PageInfoDelegateImpl::OpenCookiesDialog() { // Used for desktop only. Doesn't need implementation for WebLayer. NOTREACHED(); diff --git a/chromium/weblayer/browser/url_bar/page_info_delegate_impl.h b/chromium/weblayer/browser/url_bar/page_info_delegate_impl.h index 384cf99c85f..1d666633a8a 100644 --- a/chromium/weblayer/browser/url_bar/page_info_delegate_impl.h +++ b/chromium/weblayer/browser/url_bar/page_info_delegate_impl.h @@ -32,13 +32,14 @@ class PageInfoDelegateImpl : public PageInfoDelegate { void OnUserActionOnPasswordUi(safe_browsing::WarningAction action) override; std::u16string GetWarningDetailText() override; #endif - permissions::PermissionResult GetPermissionStatus( - ContentSettingsType type, - const GURL& site_url) override; + permissions::PermissionResult GetPermissionResult( + blink::PermissionType permission, + const url::Origin& origin) override; #if !BUILDFLAG(IS_ANDROID) bool CreateInfoBarDelegate() override; void ShowSiteSettings(const GURL& site_url) override; + void ShowCookiesSettings() override; void OpenCookiesDialog() override; void OpenCertificateDialog(net::X509Certificate* certificate) override; void OpenConnectionHelpCenterPage(const ui::Event& event) override; diff --git a/chromium/weblayer/browser/webapps/webapk_install_scheduler.cc b/chromium/weblayer/browser/webapps/webapk_install_scheduler.cc index fe275568059..72e6a9ae40d 100644 --- a/chromium/weblayer/browser/webapps/webapk_install_scheduler.cc +++ b/chromium/weblayer/browser/webapps/webapk_install_scheduler.cc @@ -91,10 +91,10 @@ void WebApkInstallScheduler::OnGotIconMurmur2HashesBuildProto( } webapps::BuildProto( - *shortcut_info_.get(), std::string() /* primary_icon_data */, - is_primary_icon_maskable_, std::string() /* splash_icon_data */, - "" /* package_name */, "" /* version */, std::move(*hashes), - false /* is_manifest_stale */, + *shortcut_info_.get(), shortcut_info_->manifest_id, + std::string() /* primary_icon_data */, is_primary_icon_maskable_, + std::string() /* splash_icon_data */, "" /* package_name */, + "" /* version */, std::move(*hashes), false /* is_manifest_stale */, false /* is_app_identity_update_supported */, base::BindOnce(&WebApkInstallScheduler::ScheduleWithChrome, weak_ptr_factory_.GetWeakPtr())); @@ -123,4 +123,4 @@ bool WebApkInstallScheduler::IsInstallServiceAvailable() { return WebApkInstallSchedulerBridge::IsInstallServiceAvailable(); } -} // namespace weblayer
\ No newline at end of file +} // namespace weblayer diff --git a/chromium/weblayer/browser/webapps/webapk_install_scheduler_browsertest.cc b/chromium/weblayer/browser/webapps/webapk_install_scheduler_browsertest.cc index 6f563ebbb8e..fc4d1c84d62 100644 --- a/chromium/weblayer/browser/webapps/webapk_install_scheduler_browsertest.cc +++ b/chromium/weblayer/browser/webapps/webapk_install_scheduler_browsertest.cc @@ -5,6 +5,7 @@ #include "weblayer/browser/webapps/webapk_install_scheduler.h" #include "base/files/file_path.h" +#include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "components/webapps/browser/android/shortcut_info.h" #include "components/webapps/browser/android/webapk/webapk_types.h" @@ -173,7 +174,7 @@ class WebApkInstallSchedulerTest : public WebLayerBrowserTest { } private: - content::WebContents* web_contents_; + raw_ptr<content::WebContents> web_contents_; net::EmbeddedTestServer test_server_; diff --git a/chromium/weblayer/browser/webui/net_export_ui.cc b/chromium/weblayer/browser/webui/net_export_ui.cc index 1ad56cabbfe..f2de43b5d9b 100644 --- a/chromium/weblayer/browser/webui/net_export_ui.cc +++ b/chromium/weblayer/browser/webui/net_export_ui.cc @@ -45,26 +45,26 @@ class NetExportMessageHandler // content::WebUIMessageHandler implementation. void RegisterMessages() override { - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( net_log::kEnableNotifyUIWithStateHandler, base::BindRepeating(&NetExportMessageHandler::OnEnableNotifyUIWithState, base::Unretained(this))); - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( net_log::kStartNetLogHandler, base::BindRepeating(&NetExportMessageHandler::OnStartNetLog, base::Unretained(this))); - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( net_log::kStopNetLogHandler, base::BindRepeating(&NetExportMessageHandler::OnStopNetLog, base::Unretained(this))); - web_ui()->RegisterDeprecatedMessageCallback( + web_ui()->RegisterMessageCallback( net_log::kSendNetLogHandler, base::BindRepeating(&NetExportMessageHandler::OnSendNetLog, base::Unretained(this))); } // Messages - void OnEnableNotifyUIWithState(const base::ListValue* list) { + void OnEnableNotifyUIWithState(const base::Value::List& list) { AllowJavascript(); if (!state_observation_manager_.IsObserving()) { state_observation_manager_.Observe(file_writer_.get()); @@ -72,9 +72,7 @@ class NetExportMessageHandler NotifyUIWithState(file_writer_->GetState()); } - void OnStartNetLog(const base::ListValue* list) { - base::Value::ConstListView params = list->GetListDeprecated(); - + void OnStartNetLog(const base::Value::List& params) { // Determine the capture mode. if (!params.empty() && params[0].is_string()) { capture_mode_ = net_log::NetExportFileWriter::CaptureModeFromString( @@ -88,16 +86,18 @@ class NetExportMessageHandler StartNetLog(base::FilePath()); } - void OnStopNetLog(const base::ListValue* list) { file_writer_->StopNetLog(); } + void OnStopNetLog(const base::Value::List& list) { + file_writer_->StopNetLog(); + } - void OnSendNetLog(const base::ListValue* list) { + void OnSendNetLog(const base::Value::List& list) { file_writer_->GetFilePathToCompletedLog( base::BindOnce(&NetExportMessageHandler::SendEmail)); } // net_log::NetExportFileWriter::StateObserver implementation. - void OnNewState(const base::DictionaryValue& state) override { - NotifyUIWithState(state.CreateDeepCopy()); + void OnNewState(const base::Value::Dict& state) override { + NotifyUIWithState(state); } private: @@ -133,8 +133,8 @@ class NetExportMessageHandler // Fires net-log-info-changed event to update the JavaScript UI in the // renderer. - void NotifyUIWithState(std::unique_ptr<base::DictionaryValue> state) { - FireWebUIListener(net_log::kNetLogInfoChangedEvent, *state); + void NotifyUIWithState(const base::Value::Dict& state) { + FireWebUIListener(net_log::kNetLogInfoChangedEvent, state); } // Cached pointer to SystemNetworkContextManager's NetExportFileWriter. diff --git a/chromium/weblayer/grit_strings_allowlist.txt b/chromium/weblayer/grit_strings_allowlist.txt index 3b4dfe4f3a5..f1a512e9e02 100644 --- a/chromium/weblayer/grit_strings_allowlist.txt +++ b/chromium/weblayer/grit_strings_allowlist.txt @@ -269,8 +269,8 @@ IDS_SITE_SETTINGS_TYPE_USB_DEVICES IDS_SITE_SETTINGS_TYPE_USB_DEVICES_MID_SENTENCE IDS_SITE_SETTINGS_TYPE_VR IDS_SITE_SETTINGS_TYPE_VR_MID_SENTENCE -IDS_SITE_SETTINGS_TYPE_WINDOW_PLACEMENT -IDS_SITE_SETTINGS_TYPE_WINDOW_PLACEMENT_MID_SENTENCE +IDS_SITE_SETTINGS_TYPE_WINDOW_MANAGEMENT +IDS_SITE_SETTINGS_TYPE_WINDOW_MANAGEMENT_MID_SENTENCE IDS_SMS_INFOBAR_BUTTON_OK IDS_SMS_INFOBAR_STATUS_SMS_RECEIVED IDS_SMS_INFOBAR_TITLE diff --git a/chromium/weblayer/public/java/BUILD.gn b/chromium/weblayer/public/java/BUILD.gn index b5805258831..db36f15aa6c 100644 --- a/chromium/weblayer/public/java/BUILD.gn +++ b/chromium/weblayer/public/java/BUILD.gn @@ -173,3 +173,77 @@ process_version("client_version") { output = _version_constants_java_file sources = [ "//chrome/VERSION" ] } + +android_aidl("browserfragment_aidl") { + import_include = [ "." ] + sources = [ + "org/chromium/browserfragment/interfaces/IBooleanCallback.aidl", + "org/chromium/browserfragment/interfaces/IBrowserFragmentDelegate.aidl", + "org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl", + "org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl", + "org/chromium/browserfragment/interfaces/IBrowserSandboxService.aidl", + "org/chromium/browserfragment/interfaces/IFragmentParams.aidl", + "org/chromium/browserfragment/interfaces/IStringCallback.aidl", + "org/chromium/browserfragment/interfaces/ITabCallback.aidl", + "org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl", + "org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl", + "org/chromium/browserfragment/interfaces/ITabParams.aidl", + "org/chromium/browserfragment/interfaces/ITabProxy.aidl", + "org/chromium/browserfragment/interfaces/IWebMessageCallback.aidl", + "org/chromium/browserfragment/interfaces/IWebMessageReplyProxy.aidl", + ] +} + +android_library("browserfragment_interfaces_java") { + deps = [ "//base:base_java" ] + srcjar_deps = [ ":browserfragment_aidl" ] +} + +android_library("browserfragment_java") { + sources = [ + "org/chromium/browserfragment/Browser.java", + "org/chromium/browserfragment/BrowserFragment.java", + "org/chromium/browserfragment/FragmentParams.java", + "org/chromium/browserfragment/Tab.java", + "org/chromium/browserfragment/TabManager.java", + "org/chromium/browserfragment/TabNavigationController.java", + "org/chromium/browserfragment/TabObserver.java", + "org/chromium/browserfragment/TabObserverDelegate.java", + "org/chromium/browserfragment/WebMessageCallback.java", + "org/chromium/browserfragment/WebMessageReplyProxy.java", + ] + + resources_package = "org.chromium.browserfragment" + deps = [ + ":browserfragment_interfaces_java", + "//base:base_java", + "//third_party/android_deps:com_google_guava_guava_android_java", + "//third_party/android_deps:com_google_guava_listenablefuture_java", + "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_appcompat_appcompat_java", + "//third_party/androidx:androidx_concurrent_concurrent_futures_java", + "//third_party/androidx:androidx_fragment_fragment_java", + "//third_party/androidx:androidx_lifecycle_lifecycle_viewmodel_java", + ] + + proguard_configs = [ "proguard.flags" ] +} + +android_library("browserfragment_sandbox_java") { + sources = [ + # Additional weblayer public files that are for the sandbox. + "org/chromium/weblayer/BrowserFragmentDelegate.java", + "org/chromium/weblayer/BrowserFragmentTabDelegate.java", + "org/chromium/weblayer/BrowserSandboxService.java", + "org/chromium/weblayer/TabNavigationControllerProxy.java", + "org/chromium/weblayer/TabParams.java", + "org/chromium/weblayer/TabProxy.java", + "org/chromium/weblayer/WebMessageReplyProxyProxy.java", + ] + resources_package = "org.chromium.weblayer" + deps = [ + ":browserfragment_interfaces_java", + ":java", + "//third_party/androidx:androidx_annotation_annotation_java", + ] +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/Browser.java b/chromium/weblayer/public/java/org/chromium/browserfragment/Browser.java new file mode 100644 index 00000000000..6b570c4b63d --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/Browser.java @@ -0,0 +1,138 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.concurrent.futures.CallbackToFutureAdapter; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +import org.chromium.browserfragment.interfaces.IBrowserSandboxCallback; +import org.chromium.browserfragment.interfaces.IBrowserSandboxService; + +/** + * Handle to the Browsing Sandbox. Must be created asynchronously. + */ +public class Browser { + // Use another APK as a placeholder for an actual sandbox, since they are conceptually the + // same thing. + private static final String BROWSER_SANDBOX_PACKAGE = "org.chromium.browserfragment.sandbox"; + + private static final String BROWSER_SANDBOX_ACTION = + "org.chromium.weblayer.intent.action.BROWSERSANDBOX"; + + private static final String DEFAULT_PROFILE_NAME = "DefaultProfile"; + + private static Browser sInstance; + + private IBrowserSandboxService mBrowserSandboxService; + + private static class ConnectionSetup implements ServiceConnection { + private CallbackToFutureAdapter.Completer<Browser> mCompleter; + private IBrowserSandboxService mBrowserSandboxService; + private Context mContext; + + private final IBrowserSandboxCallback mBrowserSandboxCallback = + new IBrowserSandboxCallback.Stub() { + @Override + public void onBrowserProcessInitialized() { + sInstance = new Browser(mBrowserSandboxService); + mCompleter.set(sInstance); + mCompleter = null; + } + }; + + ConnectionSetup(Context context, CallbackToFutureAdapter.Completer<Browser> completer) { + mContext = context; + mCompleter = completer; + } + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + mBrowserSandboxService = IBrowserSandboxService.Stub.asInterface(service); + try { + mBrowserSandboxService.initializeBrowserProcess(mBrowserSandboxCallback); + } catch (RemoteException e) { + mCompleter.setException(e); + mCompleter = null; + } + } + + // TODO(rayankans): Actually handle failure / disconnection events. + @Override + public void onServiceDisconnected(ComponentName name) {} + } + + private Browser(IBrowserSandboxService service) { + mBrowserSandboxService = service; + } + + /** + * Asynchronously creates a handle to the browsing sandbox after initializing the + * browser process. + * @param context The application context. + */ + @NonNull + public static ListenableFuture<Browser> create(@NonNull Context context) { + if (sInstance != null) { + return Futures.immediateFuture(sInstance); + } + return CallbackToFutureAdapter.getFuture(completer -> { + ConnectionSetup connectionSetup = new ConnectionSetup(context, completer); + + Intent intent = new Intent(BROWSER_SANDBOX_ACTION); + intent.setPackage(BROWSER_SANDBOX_PACKAGE); + + context.bindService(intent, connectionSetup, Context.BIND_AUTO_CREATE); + + // Debug string. + return "Browser Sandbox Future"; + }); + } + + /** + * Creates a new BrowserFragment for displaying web content. + */ + @Nullable + public BrowserFragment createFragment() { + FragmentParams params = + (new FragmentParams.Builder()).setProfileName(DEFAULT_PROFILE_NAME).build(); + return createFragment(params); + } + + /** + * Creates a new BrowserFragment for displaying web content. + */ + @Nullable + public BrowserFragment createFragment(FragmentParams params) { + try { + BrowserFragment fragment = new BrowserFragment(); + fragment.initialize( + this, mBrowserSandboxService.createFragmentDelegate(params.getParcelable())); + return fragment; + } catch (RemoteException e) { + return null; + } + } + + /** + * Enables or disables DevTools remote debugging. + */ + public void setRemoteDebuggingEnabled(boolean enabled) { + try { + mBrowserSandboxService.setRemoteDebuggingEnabled(enabled); + } catch (RemoteException e) { + } + } +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/BrowserFragment.java b/chromium/weblayer/public/java/org/chromium/browserfragment/BrowserFragment.java new file mode 100644 index 00000000000..a8f7b8c8265 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/BrowserFragment.java @@ -0,0 +1,300 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import android.content.Context; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.view.LayoutInflater; +import android.view.SurfaceControlViewHost.SurfacePackage; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.concurrent.futures.CallbackToFutureAdapter; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; + +import com.google.common.util.concurrent.ListenableFuture; + +import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegate; +import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegateClient; + +/** + * Fragment for rendering web content. + * This is created through `Browser`, since the browsing sandbox must be initialized to render web + * content. + */ +public class BrowserFragment extends Fragment { + private SurfaceView mSurfaceView; + private Browser mBrowser; + private IBrowserFragmentDelegate mDelegate; + private final TabObserverDelegate mTabObserverDelegate = new TabObserverDelegate(); + private ListenableFuture<TabManager> mFutureTabManager; + private CallbackToFutureAdapter.Completer<TabManager> mTabManagerCompleter; + private Bundle mInstanceState = new Bundle(); + + private final IBrowserFragmentDelegateClient mClient = + new IBrowserFragmentDelegateClient.Stub() { + @Override + public void onSurfacePackageReady(SurfacePackage surfacePackage) { + SurfaceView surfaceView = (SurfaceView) BrowserFragment.super.getView(); + surfaceView.setChildSurfacePackage(surfacePackage); + } + + @Override + public void onStarted(Bundle instanceState) { + mInstanceState = instanceState; + mTabManagerCompleter.set(new TabManager(mDelegate)); + } + }; + + private SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(SurfaceHolder holder) { + IBinder hostToken = ((SurfaceView) getView()).getHostToken(); + assert hostToken != null; + try { + mDelegate.attachViewHierarchy(hostToken); + } catch (RemoteException e) { + } + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + resizeSurfaceView(width, height); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) {} + }; + + /** + * This constructor is for the system FragmentManager only. Please use + * {@link Browser#createFragment}. + */ + public BrowserFragment() { + mFutureTabManager = CallbackToFutureAdapter.getFuture(completer -> { + mTabManagerCompleter = completer; + // Debug string. + return "TabManager Future"; + }); + } + + void initialize(Browser browser, IBrowserFragmentDelegate delegate) throws RemoteException { + mBrowser = browser; + mDelegate = delegate; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + BrowserViewModel model = getViewModel(); + if (model.hasSavedState()) { + // Load from view model. + assert mBrowser == null; + + mBrowser = model.mBrowser; + mDelegate = model.mDelegate; + } else { + // Save to View model. + assert mBrowser != null; + + model.mBrowser = mBrowser; + model.mDelegate = mDelegate; + } + + AppCompatDelegate.create(getActivity(), null); + + try { + mDelegate.setClient(mClient); + mDelegate.setTabObserverDelegate(mTabObserverDelegate); + mDelegate.onAttach(); + } catch (RemoteException e) { + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + try { + mDelegate.onCreate(savedInstanceState); + } catch (RemoteException e) { + } + } + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return new BrowserSurfaceView(getActivity(), mSurfaceHolderCallback); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + // We intentionally do not forward the onDestroy call here to avoid destroying/recreating + // the WebLayer implementations every time. + // onDestroy is called once the ViewModel is cleared because that guarantees that the + // Fragment will no longer be used. + } + + @Override + public void onDetach() { + super.onDetach(); + try { + mDelegate.onDetach(); + } catch (RemoteException e) { + } + } + + @Override + public void onStart() { + super.onStart(); + try { + mDelegate.onStart(); + } catch (RemoteException e) { + } + } + + @Override + public void onStop() { + super.onStop(); + try { + mDelegate.onStop(); + } catch (RemoteException e) { + } + } + + @Override + public void onResume() { + super.onResume(); + try { + mDelegate.onResume(); + } catch (RemoteException e) { + } + } + + @Override + public void onPause() { + super.onPause(); + try { + mDelegate.onPause(); + } catch (RemoteException e) { + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putAll(mInstanceState); + } + + public Browser getBrowser() { + return mBrowser; + } + + private void resizeSurfaceView(int width, int height) { + try { + mDelegate.resizeView(width, height); + } catch (RemoteException e) { + } + } + + /** + * Returns a ListenableFuture to the TabManager, which becomes available after the + * BrowserFragments onStart method finished. + */ + @NonNull + public ListenableFuture<TabManager> getTabManager() { + return mFutureTabManager; + } + + /** + * Register a tab observer and returns if successful. + * + * @param tabObserver The TabObserver. + * + * @return true if observer was added to the list of observers. + */ + public boolean registerTabObserver(@NonNull TabObserver tabObserver) { + return mTabObserverDelegate.registerObserver(tabObserver); + } + + /** + * Unregister a tab observer and returns if successful. + * + * @param tabObserver The TabObserver to remove. + * + * @return true if observer was removed from the list of observers. + */ + public boolean unregisterTabObserver(@NonNull TabObserver tabObserver) { + return mTabObserverDelegate.unregisterObserver(tabObserver); + } + + private BrowserViewModel getViewModel() { + return new ViewModelProvider(this).get(BrowserViewModel.class); + } + + /** + * A custom SurfaceView that registers a SurfaceHolder.Callback. + */ + private class BrowserSurfaceView extends SurfaceView { + private SurfaceHolder.Callback mSurfaceHolderCallback; + + BrowserSurfaceView(Context context, SurfaceHolder.Callback surfaceHolderCallback) { + super(context); + mSurfaceHolderCallback = surfaceHolderCallback; + setZOrderOnTop(true); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + getHolder().addCallback(mSurfaceHolderCallback); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + getHolder().removeCallback(mSurfaceHolderCallback); + } + } + + /** + * This class is an implementation detail and not intended for public use. It may change at any + * time in incompatible ways, including being removed. + * <p> + * This class stores BrowserFragment specific state to a ViewModel so that it can reused if a + * new Fragment is created that should share the same state. + */ + public static final class BrowserViewModel extends ViewModel { + @Nullable + private Browser mBrowser; + @Nullable + private IBrowserFragmentDelegate mDelegate; + + boolean hasSavedState() { + return mBrowser != null; + } + + @Override + public void onCleared() { + if (mDelegate != null) { + try { + mDelegate.onDestroy(); + } catch (RemoteException e) { + } + } + } + } +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/FragmentParams.java b/chromium/weblayer/public/java/org/chromium/browserfragment/FragmentParams.java new file mode 100644 index 00000000000..9907fd87099 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/FragmentParams.java @@ -0,0 +1,79 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.chromium.browserfragment.interfaces.IFragmentParams; + +/** + * Parameters for {@link Browser#createBrowserFragment}. + */ +public class FragmentParams { + @Nullable + private String mProfileName; + + @Nullable + private String mPersistenceId; + + private boolean mIsIncognito; + + IFragmentParams getParcelable() { + IFragmentParams params = new IFragmentParams(); + params.profileName = mProfileName; + params.persistenceId = mPersistenceId; + params.isIncognito = mIsIncognito; + return params; + } + + /** + * A Builder class to help create FragmentParams. + */ + public static final class Builder { + private FragmentParams mParams = new FragmentParams(); + + public FragmentParams build() { + return mParams; + } + + /** + * Sets the name of the profile. Null or empty string implicitly creates an incognito + * profile. If {@code profile} must only contain alphanumeric and underscore characters + * since it will be used as a directory name in the file system. + * + * @param name The name of the profile. + */ + @NonNull + public Builder setProfileName(@Nullable String profileName) { + mParams.mProfileName = profileName; + return this; + } + + /** + * Sets the persistence id, which uniquely identifies the Browser for saving the set of tabs + * and navigations. A value of null does not save/restore any state. A non-null value + * results in asynchronously restoring the tabs and navigations. Supplying a non-null value + * means the Browser initially has no tabs (until restore is complete). + * + * @param persistenceId The id for persistence. + */ + @NonNull + public Builder setPersistenceId(@Nullable String persistenceId) { + mParams.mPersistenceId = persistenceId; + return this; + } + + /** + * Sets whether the profile is incognito. + * @param incognito Whether the profile should be incognito. + */ + @NonNull + public Builder setIsIncognito(boolean isIncognito) { + mParams.mIsIncognito = isIncognito; + return this; + } + } +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/Tab.java b/chromium/weblayer/public/java/org/chromium/browserfragment/Tab.java new file mode 100644 index 00000000000..c37ed22fadb --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/Tab.java @@ -0,0 +1,153 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.concurrent.futures.CallbackToFutureAdapter; + +import com.google.common.util.concurrent.ListenableFuture; + +import org.chromium.browserfragment.interfaces.IStringCallback; +import org.chromium.browserfragment.interfaces.ITabParams; +import org.chromium.browserfragment.interfaces.ITabProxy; +import org.chromium.browserfragment.interfaces.IWebMessageCallback; +import org.chromium.browserfragment.interfaces.IWebMessageReplyProxy; + +import java.util.List; + +/** + * Tab controls the tab content and state. + */ +public class Tab { + private ITabProxy mTabProxy; + private TabNavigationController mTabNavigationController; + + private String mGuid; + + Tab(@NonNull ITabParams tabParams) { + assert tabParams.tabProxy != null; + assert tabParams.tabGuid != null; + assert tabParams.navigationControllerProxy != null; + + mTabProxy = tabParams.tabProxy; + mGuid = tabParams.tabGuid; + mTabNavigationController = new TabNavigationController(tabParams.navigationControllerProxy); + } + + public String getGuid() { + return mGuid; + } + + /** + * Sets this Tab to active. + */ + public void setActive() { + try { + mTabProxy.setActive(); + } catch (RemoteException e) { + } + } + + /* + * Closes this Tab. + */ + public void close() { + try { + mTabProxy.close(); + } catch (RemoteException e) { + } + } + + public ListenableFuture<String> executeScript( + @NonNull String script, boolean useSeparateIsolate) { + return CallbackToFutureAdapter.getFuture(completer -> { + try { + mTabProxy.executeScript(script, useSeparateIsolate, new IStringCallback.Stub() { + @Override + public void onResult(String result) { + completer.set(result); + } + }); + } catch (RemoteException e) { + completer.setException(e); + } + + return "Tab.executeScript Future"; + }); + } + + /** + * Returns the navigation controller for this Tab. + * + * @return The TabNavigationController. + */ + @NonNull + public TabNavigationController getNavigationController() { + return mTabNavigationController; + } + + /** + * Adds a WebMessageCallback and injects a JavaScript object into each frame that the + * WebMessageCallback will listen on. + * + * The injected JavaScript object will be named {@code jsObjectName} in the global scope. This + * will inject the JavaScript object in any frame whose origin matches {@code + * allowedOriginRules} for every navigation after this call, and the JavaScript object will be + * available immediately when the page begins to load. + */ + public void registerWebMessageCallback( + WebMessageCallback callback, String jsObjectName, List<String> allowedOrigins) { + try { + mTabProxy.registerWebMessageCallback(new IWebMessageCallback.Stub() { + @Override + public void onWebMessageReceived( + IWebMessageReplyProxy iReplyProxy, String message) { + callback.onWebMessageReceived(new WebMessageReplyProxy(iReplyProxy), message); + } + + @Override + public void onWebMessageReplyProxyClosed(IWebMessageReplyProxy iReplyProxy) { + callback.onWebMessageReplyProxyClosed(new WebMessageReplyProxy(iReplyProxy)); + } + + @Override + public void onWebMessageReplyProxyActiveStateChanged( + IWebMessageReplyProxy iReplyProxy) { + callback.onWebMessageReplyProxyActiveStateChanged( + new WebMessageReplyProxy(iReplyProxy)); + } + }, jsObjectName, allowedOrigins); + } catch (RemoteException e) { + } + } + + /** + * Removes the JavaScript object previously registered by way of registerWebMessageCallback. + * This impacts future navigations (not any already loaded navigations). + * + * @param jsObjectName Name of the JavaScript object. + */ + public void unregisterWebMessageCallback(String jsObjectName) { + try { + mTabProxy.unregisterWebMessageCallback(jsObjectName); + } catch (RemoteException e) { + } + } + + @Override + public int hashCode() { + return mGuid.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof Tab) { + return this == obj || mGuid.equals(((Tab) obj).getGuid()); + } + return false; + } +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/TabManager.java b/chromium/weblayer/public/java/org/chromium/browserfragment/TabManager.java new file mode 100644 index 00000000000..5765e5c3723 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/TabManager.java @@ -0,0 +1,120 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.concurrent.futures.CallbackToFutureAdapter; + +import com.google.common.util.concurrent.ListenableFuture; + +import org.chromium.browserfragment.interfaces.IBooleanCallback; +import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegate; +import org.chromium.browserfragment.interfaces.ITabCallback; +import org.chromium.browserfragment.interfaces.ITabParams; + +/** + * Class for interaction with Browser Tabs. + * Calls into BrowserFragmentDelegate which runs on the Binder thread, and requires + * finished initialization from onCreate on UIThread. + * Access only via ListenableFuture through BrowserFragment. + */ +public class TabManager { + private IBrowserFragmentDelegate mDelegate; + + private final class RequestNavigationCallback extends IBooleanCallback.Stub { + private CallbackToFutureAdapter.Completer<Boolean> mCompleter; + + RequestNavigationCallback(CallbackToFutureAdapter.Completer<Boolean> completer) { + mCompleter = completer; + } + + @Override + public void onResult(boolean didNavigate) { + mCompleter.set(didNavigate); + } + } + + private final class TabCallback extends ITabCallback.Stub { + private CallbackToFutureAdapter.Completer<Tab> mCompleter; + + TabCallback(CallbackToFutureAdapter.Completer<Tab> completer) { + mCompleter = completer; + } + + @Override + public void onResult(@Nullable ITabParams tabParams) { + if (tabParams != null) { + mCompleter.set(new Tab(tabParams)); + return; + } + mCompleter.set(null); + } + }; + + TabManager(IBrowserFragmentDelegate delegate) { + mDelegate = delegate; + } + + /** + * Returns a ListenableFuture for the currently active Tab; The tab can be null if no Tab is + * active. + * + * @return ListenableFuture for the active Tab. + */ + @NonNull + public ListenableFuture<Tab> getActiveTab() { + return CallbackToFutureAdapter.getFuture(completer -> { + try { + mDelegate.getActiveTab(new TabCallback(completer)); + } catch (RemoteException e) { + completer.setException(e); + } + // Debug string. + return "Active Tab Future"; + }); + } + + /** + * Creates a new Tab and returns it in a ListenableFuture. + * + * @return ListenableFuture for the new Tab. + */ + @NonNull + public ListenableFuture<Tab> createTab() { + return CallbackToFutureAdapter.getFuture(completer -> { + try { + mDelegate.createTab(new TabCallback(completer)); + } catch (RemoteException e) { + completer.setException(e); + } + // Debug string. + return "Create Tab Future"; + }); + } + + /** + * Tries to navigate back inside the Browser session and returns a Future with a Boolean + * which is true if the back navigation was successful. + * + * Only recommended to use if no switching of Tabs is used. + * + * Navigates back inside the currently active tab if possible. If that is not possible, + * checks if any Tab was added to the BrowserFragment before the currently active Tab, + * if so, the currently active Tab is closed and this Tab is set to active. + * + * @return ListenableFuture with a Boolean stating if back navigation was successful. + */ + @NonNull + public ListenableFuture<Boolean> tryNavigateBack() { + return CallbackToFutureAdapter.getFuture(completer -> { + mDelegate.tryNavigateBack(new RequestNavigationCallback(completer)); + // Debug string. + return "Did navigate back Future"; + }); + } +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/TabNavigationController.java b/chromium/weblayer/public/java/org/chromium/browserfragment/TabNavigationController.java new file mode 100644 index 00000000000..3e48e55690e --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/TabNavigationController.java @@ -0,0 +1,103 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.concurrent.futures.CallbackToFutureAdapter; + +import com.google.common.util.concurrent.ListenableFuture; + +import org.chromium.browserfragment.interfaces.IBooleanCallback; +import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy; + +/** + * TabNavigationController controls the navigation in a Tab. + */ +public class TabNavigationController { + private final ITabNavigationControllerProxy mTabNavigationControllerProxy; + + private final class RequestNavigationCallback extends IBooleanCallback.Stub { + private CallbackToFutureAdapter.Completer<Boolean> mCompleter; + + RequestNavigationCallback(CallbackToFutureAdapter.Completer<Boolean> completer) { + mCompleter = completer; + } + + @Override + public void onResult(boolean possible) { + mCompleter.set(possible); + } + }; + + TabNavigationController(ITabNavigationControllerProxy tabNavigationControllerProxy) { + mTabNavigationControllerProxy = tabNavigationControllerProxy; + } + + /** + * Navigates this Tab to the given URI. + * + * @param uri The destination URI. + */ + public void navigate(@NonNull String uri) { + try { + mTabNavigationControllerProxy.navigate(uri); + } catch (RemoteException e) { + } + } + + /** + * Navigates to the previous navigation. + */ + public void goBack() { + try { + mTabNavigationControllerProxy.goBack(); + } catch (RemoteException e) { + } + } + + /** + * Navigates to the next navigation. + */ + public void goForward() { + try { + mTabNavigationControllerProxy.goForward(); + } catch (RemoteException e) { + } + } + + /** + * Returns true if there is a navigation before the current one. + * + * @return ListenableFuture with a Boolean stating if there is a navigation before the current + * one. + */ + @NonNull + public ListenableFuture<Boolean> canGoBack() { + return CallbackToFutureAdapter.getFuture(completer -> { + mTabNavigationControllerProxy.canGoBack(new RequestNavigationCallback(completer)); + + // Debug string. + return "Can navigate back Future"; + }); + } + + /** + * Returns true if there is a navigation after the current one. + * + * @return ListenableFuture with a Boolean stating if there is a navigation after the current + * one. + */ + @NonNull + public ListenableFuture<Boolean> canGoForward() { + return CallbackToFutureAdapter.getFuture(completer -> { + mTabNavigationControllerProxy.canGoForward(new RequestNavigationCallback(completer)); + + // Debug string. + return "Can navigate forward Future"; + }); + } +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/TabObserver.java b/chromium/weblayer/public/java/org/chromium/browserfragment/TabObserver.java new file mode 100644 index 00000000000..11584a7a5ab --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/TabObserver.java @@ -0,0 +1,43 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * An interface for observing changes to the set of tabs in a BrowserFragment. + */ +public abstract class TabObserver { + /** + * The active tab has changed. + * + * @param activeTab The newly active tab, null if no tab is active. + */ + public void onActiveTabChanged(@Nullable Tab activeTab) {} + + /** + * A tab was added to the BrowserFragment. + * + * @param tab The tab that was added. + */ + public void onTabAdded(@NonNull Tab tab) {} + + /** + * A tab was removed from the BrowserFragment. + * + * WARNING: this is *not* called when the BrowserFragment is destroyed. See {@link + * #onWillDestroyBrowserAndAllTabs} for more. + * + * @param tab The tab that was removed. + */ + public void onTabRemoved(@NonNull Tab tab) {} + + /** + * Called when the BrowserFragment is about to be destroyed. After this + * call the BrowserFragment with all Tabs are destroyed and can not be used. + */ + public void onWillDestroyBrowserAndAllTabs() {} +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/TabObserverDelegate.java b/chromium/weblayer/public/java/org/chromium/browserfragment/TabObserverDelegate.java new file mode 100644 index 00000000000..7614f960401 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/TabObserverDelegate.java @@ -0,0 +1,84 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import android.os.Handler; +import android.os.Looper; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.chromium.base.ObserverList; +import org.chromium.browserfragment.interfaces.ITabObserverDelegate; +import org.chromium.browserfragment.interfaces.ITabParams; + +/** + * TabObserverDelegate notifies TabObservers of Tab-events in weblayer. + */ +class TabObserverDelegate extends ITabObserverDelegate.Stub { + private final Handler mHandler = new Handler(Looper.getMainLooper()); + + private ObserverList<TabObserver> mTabObservers = new ObserverList<TabObserver>(); + + /** + * Register a TabObserver. + * + * @return true if the observer was added to the list of observers. + */ + boolean registerObserver(TabObserver tabObserver) { + return mTabObservers.addObserver(tabObserver); + } + + /** + * Unregister a TabObserver. + * + * @return true if the observer was removed from the list of observers. + */ + boolean unregisterObserver(TabObserver tabObserver) { + return mTabObservers.removeObserver(tabObserver); + } + + @Override + public void notifyActiveTabChanged(@Nullable ITabParams tabParams) { + mHandler.post(() -> { + Tab tab = null; + if (tabParams != null) { + tab = new Tab(tabParams); + } + for (TabObserver observer : mTabObservers) { + observer.onActiveTabChanged(tab); + } + }); + } + + @Override + public void notifyTabAdded(@NonNull ITabParams tabParams) { + mHandler.post(() -> { + Tab tab = new Tab(tabParams); + for (TabObserver observer : mTabObservers) { + observer.onTabAdded(tab); + } + }); + } + + @Override + public void notifyTabRemoved(@NonNull ITabParams tabParams) { + mHandler.post(() -> { + Tab tab = new Tab(tabParams); + for (TabObserver observer : mTabObservers) { + observer.onTabRemoved(tab); + } + }); + } + + @Override + public void notifyWillDestroyBrowserAndAllTabs() { + mHandler.post(() -> { + for (TabObserver observer : mTabObservers) { + observer.onWillDestroyBrowserAndAllTabs(); + } + }); + } +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/WebMessageCallback.java b/chromium/weblayer/public/java/org/chromium/browserfragment/WebMessageCallback.java new file mode 100644 index 00000000000..8b3d382173f --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/WebMessageCallback.java @@ -0,0 +1,45 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +/** + * An interface to receive message events from a JavaScript object of a Tab. + * + * This callback, the name of the JavaScript object, as well as the origins that are + * targeted are set via {@link Tab#registerWebMessageCallback}. + */ +public abstract class WebMessageCallback { + /** + * A WebMessage was received. + * + * <b>WARNING</b>: It is possible to receive messages from an inactive page. This happens if a + * message it sent around the same time the page is put in the back forward cache. As a result + * of this, it is possible for this method to be called with a new proxy that is inactive. + * + * @param replyProxy An object that may be used to post a message back to the page. + * @param message The message from the page. + */ + public void onWebMessageReceived(WebMessageReplyProxy replyProxy, String message) {} + + /** + * {@link WebMessageReplyProxy} was closed. + * + * This typically happens when navigating to another page. If the page goes into the back + * forward cache, then message channels are left open (and this is not called). In that case + * this method will be called either when the page is evicted from the cache or when the user + * goes back to it and then navigates away and it doesn't go into the back forward cache again. + * + * @param replyProxy The proxy that has been closed. + */ + public void onWebMessageReplyProxyClosed(WebMessageReplyProxy replyProxy) {} + + /** + * The active state of the reply proxy has changed. + * If a channel is active it is not closed and not in the back forward cache. + * + * @param proxy The proxy that changed state. + */ + public void onWebMessageReplyProxyActiveStateChanged(WebMessageReplyProxy proxy) {} +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/WebMessageReplyProxy.java b/chromium/weblayer/public/java/org/chromium/browserfragment/WebMessageReplyProxy.java new file mode 100644 index 00000000000..06e9b421e11 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/WebMessageReplyProxy.java @@ -0,0 +1,33 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment; + +import android.os.RemoteException; + +import org.chromium.browserfragment.interfaces.IWebMessageReplyProxy; + +/** + * Used to post a message to a page. WebMessageReplyProxy is created when a page posts a message to + * the JavaScript object that was created by way of {@link Tab#registerWebMessageCallback}. + */ +public class WebMessageReplyProxy { + private final IWebMessageReplyProxy mWebMessageReplyProxy; + + WebMessageReplyProxy(IWebMessageReplyProxy webMessageReplyProxy) { + mWebMessageReplyProxy = webMessageReplyProxy; + } + + /** + * Post a message back to the JavaScript object. + * + * @param message The message to post. + */ + public void postMessage(String message) { + try { + mWebMessageReplyProxy.postMessage(message); + } catch (RemoteException e) { + } + }; +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBooleanCallback.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBooleanCallback.aidl new file mode 100644 index 00000000000..c1401fdeedc --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBooleanCallback.aidl @@ -0,0 +1,9 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +oneway interface IBooleanCallback { + void onResult(in boolean result) = 1; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegate.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegate.aidl new file mode 100644 index 00000000000..a3fbccd81c0 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegate.aidl @@ -0,0 +1,35 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import android.os.Bundle; +import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegateClient; +import org.chromium.browserfragment.interfaces.IBooleanCallback; +import org.chromium.browserfragment.interfaces.ITabObserverDelegate; +import org.chromium.browserfragment.interfaces.ITabProxy; +import org.chromium.browserfragment.interfaces.ITabCallback; + +oneway interface IBrowserFragmentDelegate { + void setClient(in IBrowserFragmentDelegateClient client) = 1; + + void attachViewHierarchy(in IBinder hostToken) = 2; + void resizeView(in int width, in int height) = 3; + + // Fragment events. + void onCreate(in Bundle savedInstanceState) = 4; + void onAttach() = 5; + void onDestroy() = 6; + void onDetach() = 7; + void onStart() = 8; + void onStop() = 9; + void onResume() = 10; + void onPause() = 11; + + // Tab operations. + void getActiveTab(ITabCallback callback) = 14; + void setTabObserverDelegate(ITabObserverDelegate tabObserverDelegate) = 15; + void tryNavigateBack(IBooleanCallback callback) = 17; + void createTab(ITabCallback callback) = 18; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl new file mode 100644 index 00000000000..36afb8d2ce6 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl @@ -0,0 +1,12 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import android.view.SurfaceControlViewHost.SurfacePackage; + +oneway interface IBrowserFragmentDelegateClient { + void onSurfacePackageReady(in SurfacePackage surfacePackage) = 1; + void onStarted(in Bundle instanceState) = 2; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl new file mode 100644 index 00000000000..74a696c14e4 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl @@ -0,0 +1,11 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import android.view.SurfaceControlViewHost.SurfacePackage; + +oneway interface IBrowserSandboxCallback { + void onBrowserProcessInitialized() = 1; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxService.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxService.aidl new file mode 100644 index 00000000000..7731a820df8 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IBrowserSandboxService.aidl @@ -0,0 +1,17 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegate; +import org.chromium.browserfragment.interfaces.IBrowserSandboxCallback; +import org.chromium.browserfragment.interfaces.IFragmentParams; + +interface IBrowserSandboxService { + void initializeBrowserProcess(in IBrowserSandboxCallback callback) = 1; + + IBrowserFragmentDelegate createFragmentDelegate(in IFragmentParams params) = 2; + + void setRemoteDebuggingEnabled(in boolean enabled) = 3; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IFragmentParams.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IFragmentParams.aidl new file mode 100644 index 00000000000..bb5f1669a5f --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IFragmentParams.aidl @@ -0,0 +1,11 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +parcelable IFragmentParams { + String profileName; + String persistenceId; + boolean isIncognito; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IStringCallback.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IStringCallback.aidl new file mode 100644 index 00000000000..d34d38f704b --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IStringCallback.aidl @@ -0,0 +1,9 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +oneway interface IStringCallback { + void onResult(in String result) = 1; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabCallback.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabCallback.aidl new file mode 100644 index 00000000000..ee74c6fa74b --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabCallback.aidl @@ -0,0 +1,11 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import org.chromium.browserfragment.interfaces.ITabParams; + +oneway interface ITabCallback { + void onResult(in ITabParams tabParams) = 1; +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl new file mode 100644 index 00000000000..f79ba9ef32d --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl @@ -0,0 +1,16 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import org.chromium.browserfragment.interfaces.IBooleanCallback; + +oneway interface ITabNavigationControllerProxy { + void navigate(in String uri) = 1; + void goBack() = 2; + void goForward() = 3; + void canGoBack(IBooleanCallback callback) = 4; + void canGoForward(IBooleanCallback callback) = 5; + +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl new file mode 100644 index 00000000000..2a9e9aaa4cf --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl @@ -0,0 +1,14 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import org.chromium.browserfragment.interfaces.ITabParams; + +oneway interface ITabObserverDelegate { + void notifyActiveTabChanged(in ITabParams tabParams) = 1; + void notifyTabAdded(in ITabParams tabParams) = 2; + void notifyTabRemoved(in ITabParams tabParams) = 3; + void notifyWillDestroyBrowserAndAllTabs() = 4; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabParams.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabParams.aidl new file mode 100644 index 00000000000..8e78cbcea6d --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabParams.aidl @@ -0,0 +1,14 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import org.chromium.browserfragment.interfaces.ITabProxy; +import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy; + +parcelable ITabParams { + ITabProxy tabProxy; + String tabGuid; + ITabNavigationControllerProxy navigationControllerProxy; +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabProxy.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabProxy.aidl new file mode 100644 index 00000000000..03bc1c5f8c7 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/ITabProxy.aidl @@ -0,0 +1,19 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import org.chromium.browserfragment.interfaces.IStringCallback; +import org.chromium.browserfragment.interfaces.IWebMessageCallback; + +import java.util.List; + +oneway interface ITabProxy { + void setActive() = 1; + void close() = 2; + void executeScript(in String script, in boolean useSeparateIsolate, in IStringCallback callback) = 3; + + void registerWebMessageCallback(in IWebMessageCallback callback, in String jsObjectName, in List<String> allowedOrigins) = 4; + void unregisterWebMessageCallback(in String jsObjectName) = 5; +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IWebMessageCallback.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IWebMessageCallback.aidl new file mode 100644 index 00000000000..0ca7a61a1e2 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IWebMessageCallback.aidl @@ -0,0 +1,13 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +import org.chromium.browserfragment.interfaces.IWebMessageReplyProxy; + +oneway interface IWebMessageCallback { + void onWebMessageReceived(IWebMessageReplyProxy replyProxy, String message) = 1; + void onWebMessageReplyProxyClosed(IWebMessageReplyProxy replyProxy) = 2; + void onWebMessageReplyProxyActiveStateChanged(IWebMessageReplyProxy proxy) = 3; +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IWebMessageReplyProxy.aidl b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IWebMessageReplyProxy.aidl new file mode 100644 index 00000000000..f945f5f15e9 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/IWebMessageReplyProxy.aidl @@ -0,0 +1,9 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.interfaces; + +oneway interface IWebMessageReplyProxy { + void postMessage(String message) = 1; +} diff --git a/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/OWNERS b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/OWNERS new file mode 100644 index 00000000000..8f094e0099e --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/browserfragment/interfaces/OWNERS @@ -0,0 +1,2 @@ +per-file *.aidl=set noparent +per-file *.aidl=file://ipc/SECURITY_OWNERS diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/Browser.java b/chromium/weblayer/public/java/org/chromium/weblayer/Browser.java index 10a8f86ea39..51d985203aa 100644 --- a/chromium/weblayer/public/java/org/chromium/weblayer/Browser.java +++ b/chromium/weblayer/public/java/org/chromium/weblayer/Browser.java @@ -5,6 +5,7 @@ package org.chromium.weblayer; import android.os.RemoteException; +import android.view.SurfaceControlViewHost; import android.view.View; import android.webkit.ValueCallback; @@ -90,10 +91,14 @@ public class Browser { mBrowserRestoreCallbacks = null; } - Browser(IBrowser impl, Fragment fragment) { + // Constructor for browserfragment to inject the {@code tabListCallback} on startup. + Browser(IBrowser impl, Fragment fragment, @Nullable TabListCallback tabListCallback) { mImpl = impl; mFragment = fragment; mTabListCallbacks = new ObserverList<TabListCallback>(); + if (tabListCallback != null) { + mTabListCallbacks.addObserver(tabListCallback); + } mBrowserControlsOffsetCallbacks = new ObserverList<BrowserControlsOffsetCallback>(); mBrowserRestoreCallbacks = new ObserverList<BrowserRestoreCallback>(); @@ -105,6 +110,10 @@ public class Browser { } } + Browser(IBrowser impl, Fragment fragment) { + this(impl, fragment, null); + } + /** * Changes the fragment. During configuration changes the fragment may change. */ @@ -236,6 +245,21 @@ public class Browser { } /** + * Returns a List of Tabs as saved in the native Browser. + * + * @return The Tabs. + */ + @NonNull + private int[] getTabIds() { + ThreadCheck.ensureOnUiThread(); + try { + return mImpl.getTabIds(); + } catch (RemoteException e) { + throw new APICallException(e); + } + } + + /** * Disposes a Tab. If {@link tab} is the active Tab, no Tab is made active. After this call * {@link tab} should not be used. * @@ -260,6 +284,47 @@ public class Browser { } /** + * Navigates to the previous navigation across all tabs according to tabs in native Browser. + */ + void tryNavigateBack(@NonNull Callback<Boolean> callback) { + Tab activeTab = getActiveTab(); + if (activeTab == null) { + callback.onResult(false); + return; + } + if (activeTab.dismissTransientUi()) { + callback.onResult(true); + return; + } + NavigationController controller = activeTab.getNavigationController(); + if (controller.canGoBack()) { + controller.goBack(); + callback.onResult(true); + return; + } + int[] tabIds = getTabIds(); + if (tabIds.length > 1) { + Tab previousTab = null; + int activeTabId = activeTab.getId(); + int prevId = -1; + for (int id : tabIds) { + if (id == activeTabId) { + previousTab = Tab.getTabById(prevId); + break; + } + prevId = id; + } + if (previousTab != null) { + activeTab.dispatchBeforeUnloadAndClose(); + setActiveTab(previousTab); + callback.onResult(true); + return; + } + } + callback.onResult(false); + } + + /** * Adds a TabListCallback. * * @param callback The TabListCallback. @@ -591,6 +656,25 @@ public class Browser { } } + /** + * Attaches the top-level view to the SurfaceControlViewHost. + * @param host The SurfaceControlViewHost created from the host app's SurfaceView. + * + * @since 105 + */ + void setSurfaceControlViewHost(SurfaceControlViewHost host) { + ThreadCheck.ensureOnUiThread(); + + if (WebLayer.getSupportedMajorVersionInternal() < 105) { + throw new UnsupportedOperationException(); + } + try { + mImpl.setSurfaceControlViewHost(ObjectWrapper.wrap(host)); + } catch (RemoteException e) { + throw new APICallException(e); + } + } + private final class BrowserClientImpl extends IBrowserClient.Stub { @Override public void onActiveTabChanged(int activeTabId) { diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragment.java b/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragment.java index a120cc2429d..bfb6a447c5e 100644 --- a/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragment.java +++ b/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragment.java @@ -46,6 +46,8 @@ public final class BrowserFragment extends RemoteFragment { // Nonnull between onCreate() and onDestroy(). private Browser mBrowser; + private boolean mIgnoreViewModel; + /** * This constructor is for the system FragmentManager only. Please use * {@link WebLayer#createBrowserFragment}. @@ -74,7 +76,7 @@ public final class BrowserFragment extends RemoteFragment { throw new RuntimeException("BrowserFragment was created without arguments."); } // If there is saved state, then it should be used and this method should not be called. - assert !(new ViewModelProvider(this)).get(BrowserViewModel.class).hasSavedState(); + assert !getViewModel().hasSavedState(); try { mWebLayer = WebLayer.loadSync(appContext); } catch (Exception e) { @@ -96,30 +98,53 @@ public final class BrowserFragment extends RemoteFragment { @Override public void onAttach(Context context) { ThreadCheck.ensureOnUiThread(); - BrowserViewModel browserViewModel = new ViewModelProvider(this).get(BrowserViewModel.class); + BrowserViewModel browserViewModel = getViewModel(); if (browserViewModel.hasSavedState()) { configureFromViewModel(browserViewModel); } super.onAttach(context); } + // Method for browserfragment to inject the {@code tabListCallback} on startup of the weblayer + // browser. + void onCreate(Bundle savedInstanceState, @Nullable TabListCallback tabListCallback) { + onCreateInternal(savedInstanceState, tabListCallback); + + // Set |mForwardCreateDestroyEvents| to true so subsequent `onCreate` calls from the host + // process don't recreate the internal objects. + mForwardCreateDestroyEvents = false; + } + @Override public void onCreate(Bundle savedInstanceState) { + onCreateInternal(savedInstanceState, null); + } + + private void onCreateInternal( + Bundle savedInstanceState, @Nullable TabListCallback tabListCallback) { super.onCreate(savedInstanceState); if (mBrowser != null) { // If mBrowser is non-null, it means mBrowser came from a ViewModel. return; } try { - mBrowser = new Browser(mImpl.getBrowser(), this); + mBrowser = new Browser(mImpl.getBrowser(), this, tabListCallback); } catch (RemoteException e) { throw new APICallException(e); } if (useViewModel()) { - saveToViewModel(new ViewModelProvider(this).get(BrowserViewModel.class)); + saveToViewModel(getViewModel()); } } + void onDestroy(boolean force) { + if (force) { + mForwardCreateDestroyEvents = true; + } + + onDestroy(); + } + @Override @SuppressWarnings("ReferenceEquality") public void onDestroy() { @@ -163,10 +188,23 @@ public final class BrowserFragment extends RemoteFragment { } private boolean useViewModel() { + if (mIgnoreViewModel) { + return false; + } Bundle args = getArguments(); return args == null ? false : args.getBoolean(BrowserFragmentArgs.USE_VIEW_MODEL, false); } + private BrowserViewModel getViewModel() { + return mIgnoreViewModel ? new BrowserViewModel() + : new ViewModelProvider(this).get(BrowserViewModel.class); + } + + // TODO(rayankans): Remove ViewModel from this class. + void ignoreViewModel() { + mIgnoreViewModel = true; + } + /** * This class is an implementation detail and not intended for public use. It may change at any * time in incompatible ways, including being removed. diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragmentDelegate.java b/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragmentDelegate.java new file mode 100644 index 00000000000..8d36ec11e18 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragmentDelegate.java @@ -0,0 +1,189 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.weblayer; + +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.view.SurfaceControlViewHost; +import android.view.WindowManager; + +import org.chromium.browserfragment.interfaces.IBooleanCallback; +import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegate; +import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegateClient; +import org.chromium.browserfragment.interfaces.IFragmentParams; +import org.chromium.browserfragment.interfaces.ITabCallback; +import org.chromium.browserfragment.interfaces.ITabObserverDelegate; +import org.chromium.browserfragment.interfaces.ITabParams; + +/** + * This class acts as a proxy between the embedding app's BrowserFragment and + * the WebLayer implementation. + */ +class BrowserFragmentDelegate extends IBrowserFragmentDelegate.Stub { + private final Handler mHandler = new Handler(Looper.getMainLooper()); + + private Context mContext; + private WebLayer mWebLayer; + + // TODO(rayankans): Create an event handler instead of using the weblayer fragment directly. + private BrowserFragment mFragment; + + private BrowserFragmentTabDelegate mTabDelegate; + + private IBrowserFragmentDelegateClient mClient; + private SurfaceControlViewHost mSurfaceControlViewHost; + + BrowserFragmentDelegate(Context context, WebLayer webLayer, IFragmentParams params) { + mContext = context; + mWebLayer = webLayer; + mTabDelegate = new BrowserFragmentTabDelegate(); + + BrowserFragmentCreateParams createParams = (new BrowserFragmentCreateParams.Builder()) + .setProfileName(params.profileName) + .setPersistenceId(params.persistenceId) + .setIsIncognito(params.isIncognito) + .build(); + mHandler.post(() -> { + mFragment = (BrowserFragment) WebLayer.createBrowserFragmentWithParams(createParams); + mFragment.ignoreViewModel(); + }); + } + + @Override + public void setClient(IBrowserFragmentDelegateClient client) { + mClient = client; + } + + @Override + public void attachViewHierarchy(IBinder hostToken) { + mHandler.post(() -> attachViewHierarchyOnUi(hostToken)); + } + + private void attachViewHierarchyOnUi(IBinder hostToken) { + WindowManager window = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + + assert mSurfaceControlViewHost == null; + mSurfaceControlViewHost = + new SurfaceControlViewHost(mContext, window.getDefaultDisplay(), hostToken); + + mFragment.getBrowser().setSurfaceControlViewHost(mSurfaceControlViewHost); + try { + mClient.onSurfacePackageReady(mSurfaceControlViewHost.getSurfacePackage()); + } catch (RemoteException e) { + } + } + + @Override + public void resizeView(int width, int height) { + mHandler.post(() -> { + if (mSurfaceControlViewHost != null) { + mSurfaceControlViewHost.relayout(width, height); + } + }); + } + + @Override + public void getActiveTab(ITabCallback tabCallback) { + mHandler.post(() -> { + Tab activeTab = mFragment.getBrowser().getActiveTab(); + try { + if (activeTab != null) { + ITabParams tabParams = TabParams.buildParcelable(activeTab); + tabCallback.onResult(tabParams); + } else { + tabCallback.onResult(null); + } + } catch (RemoteException e) { + } + }); + } + + @Override + public void onAttach() { + mHandler.post(() -> mFragment.onAttach(mContext)); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + mHandler.post(() -> mFragment.onCreate(savedInstanceState, mTabDelegate)); + } + + @Override + public void onDestroy() { + mHandler.post(() -> mFragment.onDestroy(/* force= */ true)); + } + + @Override + public void onDetach() { + mHandler.post(() -> { + mFragment.onDetach(); + mSurfaceControlViewHost.release(); + mSurfaceControlViewHost = null; + }); + } + + @Override + public void onStart() { + mHandler.post(() -> { + mFragment.onStart(); + + // Retrieve the instance state. + Bundle instanceState = new Bundle(); + mFragment.onSaveInstanceState(instanceState); + + try { + mClient.onStarted(instanceState); + } catch (RemoteException e) { + } + }); + } + + @Override + public void onStop() { + mHandler.post(() -> mFragment.onStop()); + } + + @Override + public void onResume() { + mHandler.post(() -> mFragment.onResume()); + } + + @Override + public void onPause() { + mHandler.post(() -> mFragment.onPause()); + } + + @Override + public void setTabObserverDelegate(ITabObserverDelegate tabObserverDelegate) { + mTabDelegate.setObserver(tabObserverDelegate); + } + + @Override + public void tryNavigateBack(IBooleanCallback callback) { + mHandler.post(() -> { + mFragment.getBrowser().tryNavigateBack(didNavigate -> { + try { + callback.onResult(didNavigate); + } catch (RemoteException e) { + } + }); + }); + } + + @Override + public void createTab(ITabCallback callback) { + mHandler.post(() -> { + Tab newTab = mFragment.getBrowser().createTab(); + try { + callback.onResult(TabParams.buildParcelable(newTab)); + } catch (RemoteException e) { + } + }); + } +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragmentTabDelegate.java b/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragmentTabDelegate.java new file mode 100644 index 00000000000..dd937f06efe --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/weblayer/BrowserFragmentTabDelegate.java @@ -0,0 +1,86 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.weblayer; + +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.chromium.browserfragment.interfaces.ITabObserverDelegate; +import org.chromium.browserfragment.interfaces.ITabParams; + +/** + * This class acts as a proxy between the Tab events happening in + * weblayer and the TabManager in browserfragment. + */ +class BrowserFragmentTabDelegate extends TabListCallback { + private ITabObserverDelegate mTabObserver; + + private final NewTabCallback mNewTabCallback = new NewTabCallback() { + @Override + public void onNewTab(@NonNull Tab tab, @NewTabType int type) { + // Set foreground tabs and tabs in new windows by default to active. + switch (type) { + case NewTabType.FOREGROUND_TAB: + case NewTabType.NEW_WINDOW: + tab.getBrowser().setActiveTab(tab); + break; + } + } + }; + + void setObserver(ITabObserverDelegate observer) { + mTabObserver = observer; + } + + @Override + public void onActiveTabChanged(@Nullable Tab tab) { + maybeRunOnTabObserver(observer -> { + ITabParams tabParams = null; + if (tab != null) { + tabParams = TabParams.buildParcelable(tab); + } + observer.notifyActiveTabChanged(tabParams); + }); + } + + @Override + public void onTabAdded(@NonNull Tab tab) { + // This is a requirement to open new tabs. + tab.setNewTabCallback(mNewTabCallback); + + maybeRunOnTabObserver(observer -> { + ITabParams tabParams = TabParams.buildParcelable(tab); + observer.notifyTabAdded(tabParams); + }); + } + + @Override + public void onTabRemoved(@NonNull Tab tab) { + maybeRunOnTabObserver(observer -> { + ITabParams tabParams = TabParams.buildParcelable(tab); + observer.notifyTabRemoved(tabParams); + }); + } + + @Override + public void onWillDestroyBrowserAndAllTabs() { + maybeRunOnTabObserver(observer -> observer.notifyWillDestroyBrowserAndAllTabs()); + } + + private interface OnTabObserverCallback { + void run(ITabObserverDelegate tabObserver) throws RemoteException; + } + + private void maybeRunOnTabObserver(OnTabObserverCallback callback) { + if (mTabObserver != null) { + try { + callback.run(mTabObserver); + } catch (RemoteException e) { + } + } + } +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/BrowserSandboxService.java b/chromium/weblayer/public/java/org/chromium/weblayer/BrowserSandboxService.java new file mode 100644 index 00000000000..25a64ea3509 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/weblayer/BrowserSandboxService.java @@ -0,0 +1,64 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.weblayer; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; + +import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegate; +import org.chromium.browserfragment.interfaces.IBrowserSandboxCallback; +import org.chromium.browserfragment.interfaces.IBrowserSandboxService; +import org.chromium.browserfragment.interfaces.IFragmentParams; + +/** + * Service running the browser process for a BrowserFragment outside of the hosting + * application's process. + */ +public class BrowserSandboxService extends Service { + private final Context mContext = this; + + private final IBrowserSandboxService.Stub mBinder = new IBrowserSandboxService.Stub() { + private WebLayer mWebLayer; + + @Override + public void initializeBrowserProcess(IBrowserSandboxCallback callback) { + new Handler(Looper.getMainLooper()).post(() -> { + WebLayer.loadAsync(mContext, (webLayer) -> onWebLayerReady(webLayer, callback)); + }); + } + + private void onWebLayerReady(WebLayer webLayer, IBrowserSandboxCallback callback) { + mWebLayer = webLayer; + try { + callback.onBrowserProcessInitialized(); + } catch (RemoteException e) { + } + } + + @Override + public IBrowserFragmentDelegate createFragmentDelegate(IFragmentParams params) { + assert mWebLayer != null; + + return new BrowserFragmentDelegate(mContext, mWebLayer, params); + } + + @Override + public void setRemoteDebuggingEnabled(boolean enabled) { + assert mWebLayer != null; + mWebLayer.setRemoteDebuggingEnabled(enabled); + } + + }; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } +} diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/RemoteFragment.java b/chromium/weblayer/public/java/org/chromium/weblayer/RemoteFragment.java index eb89893dbb4..948a4287d5b 100644 --- a/chromium/weblayer/public/java/org/chromium/weblayer/RemoteFragment.java +++ b/chromium/weblayer/public/java/org/chromium/weblayer/RemoteFragment.java @@ -68,6 +68,11 @@ abstract class RemoteFragment extends Fragment { // Whetner saveToViewModel() was called. In other words, state was saved to ViewModelImpl. private boolean mSavedStateToViewModel; + // Whether to forward the onCreate and onDestroy events to the remote fragment. + // TODO(rayankans): Remove this hack once BrowserFragmentDelegate is merged with + // BrowserFragment. + protected boolean mForwardCreateDestroyEvents = true; + private static final class IRemoteFragmentClientImpl extends IRemoteFragmentClient.Stub { private RemoteFragment mRemoteFragment; // Used to track when destroy is being called because a ViewModel is being destroyed. When @@ -339,6 +344,9 @@ abstract class RemoteFragment extends Fragment { super.onCreate(savedInstanceState); return; } + if (!mForwardCreateDestroyEvents) { + return; + } try { mRemoteFragment.handleOnCreate(ObjectWrapper.wrap(savedInstanceState)); } catch (RemoteException e) { @@ -447,6 +455,11 @@ abstract class RemoteFragment extends Fragment { return; } ThreadCheck.ensureOnUiThread(); + + if (!mForwardCreateDestroyEvents) { + return; + } + try { mRemoteFragment.handleOnDestroy(); // The other side does the clean up automatically in handleOnDestroy() @@ -471,7 +484,11 @@ abstract class RemoteFragment extends Fragment { } private void superOnCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + // TODO(rayankans): Remove calls into the base Fragment class. + try { + super.onCreate(savedInstanceState); + } catch (NullPointerException e) { + } } private void superOnAttach(Context context) { diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/Tab.java b/chromium/weblayer/public/java/org/chromium/weblayer/Tab.java index c3d37fd73bf..ac81926e330 100644 --- a/chromium/weblayer/public/java/org/chromium/weblayer/Tab.java +++ b/chromium/weblayer/public/java/org/chromium/weblayer/Tab.java @@ -57,6 +57,8 @@ public class Tab { private @Nullable ActionModeCallback mActionModeCallback; // Id from the remote side. private final int mId; + // Guid from the remote side. + private final String mGuid; // Constructor for test mocking. protected Tab() { @@ -67,6 +69,7 @@ public class Tab { mCallbacks = null; mScrollOffsetCallbacks = null; mId = 0; + mGuid = ""; } Tab(ITab impl, Browser browser) { @@ -74,6 +77,7 @@ public class Tab { mBrowser = browser; try { mId = impl.getId(); + mGuid = impl.getGuid(); mImpl.setClient(new TabClientImpl()); } catch (RemoteException e) { throw new APICallException(e); @@ -308,7 +312,6 @@ public class Tab { @NonNull public NavigationController getNavigationController() { - ThreadCheck.ensureOnUiThread(); throwIfDestroyed(); return mNavigationController; } @@ -414,13 +417,7 @@ public class Tab { */ @NonNull public String getGuid() { - ThreadCheck.ensureOnUiThread(); - throwIfDestroyed(); - try { - return mImpl.getGuid(); - } catch (RemoteException e) { - throw new APICallException(e); - } + return mGuid; } /** diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java b/chromium/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java new file mode 100644 index 00000000000..fd2407e7c7e --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/weblayer/TabNavigationControllerProxy.java @@ -0,0 +1,62 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.weblayer; + +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; + +import org.chromium.browserfragment.interfaces.IBooleanCallback; +import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy; + +class TabNavigationControllerProxy extends ITabNavigationControllerProxy.Stub { + private final Handler mHandler = new Handler(Looper.getMainLooper()); + + private final NavigationController mNavigationController; + + TabNavigationControllerProxy(NavigationController navigationController) { + mNavigationController = navigationController; + } + + @Override + public void navigate(String uri) { + mHandler.post(() -> { + NavigateParams.Builder navigateParamsBuilder = + new NavigateParams.Builder().disableIntentProcessing(); + mNavigationController.navigate(Uri.parse(uri), navigateParamsBuilder.build()); + }); + } + + @Override + public void goBack() { + mHandler.post(() -> { mNavigationController.goBack(); }); + } + + @Override + public void goForward() { + mHandler.post(() -> { mNavigationController.goForward(); }); + } + + @Override + public void canGoBack(IBooleanCallback callback) { + mHandler.post(() -> { + try { + callback.onResult(mNavigationController.canGoBack()); + } catch (RemoteException e) { + } + }); + } + + @Override + public void canGoForward(IBooleanCallback callback) { + mHandler.post(() -> { + try { + callback.onResult(mNavigationController.canGoForward()); + } catch (RemoteException e) { + } + }); + } +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/TabParams.java b/chromium/weblayer/public/java/org/chromium/weblayer/TabParams.java new file mode 100644 index 00000000000..a647844d660 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/weblayer/TabParams.java @@ -0,0 +1,24 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.weblayer; + +import androidx.annotation.NonNull; + +import org.chromium.browserfragment.interfaces.ITabParams; + +/** + * Parameters for {@link Tab}. + */ +class TabParams { + static ITabParams buildParcelable(@NonNull Tab tab) { + ITabParams parcel = new ITabParams(); + parcel.tabProxy = new TabProxy(tab); + parcel.tabGuid = tab.getGuid(); + parcel.navigationControllerProxy = + new TabNavigationControllerProxy(tab.getNavigationController()); + + return parcel; + } +}
\ No newline at end of file diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/TabProxy.java b/chromium/weblayer/public/java/org/chromium/weblayer/TabProxy.java new file mode 100644 index 00000000000..ea78b72e446 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/weblayer/TabProxy.java @@ -0,0 +1,119 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.weblayer; + +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; + +import org.chromium.browserfragment.interfaces.IStringCallback; +import org.chromium.browserfragment.interfaces.ITabProxy; +import org.chromium.browserfragment.interfaces.IWebMessageCallback; + +import java.util.List; + +/** + * This class acts as a proxy between a Tab object in the embedding app + * and the Tab implementation in WebLayer. + */ +class TabProxy extends ITabProxy.Stub { + private final Handler mHandler = new Handler(Looper.getMainLooper()); + + private int mTabId; + private String mGuid; + + TabProxy(Tab tab) { + mTabId = tab.getId(); + mGuid = tab.getGuid(); + } + + void invalidate() { + mTabId = -1; + mGuid = null; + } + + boolean isValid() { + return mGuid != null; + } + + private Tab getTab() { + Tab tab = Tab.getTabById(mTabId); + if (tab == null) { + // TODO(swestphal): Raise exception. + } + return tab; + } + + @Override + public void setActive() { + mHandler.post(() -> { + Tab tab = getTab(); + tab.getBrowser().setActiveTab(tab); + }); + } + + @Override + public void close() { + mHandler.post(() -> { + getTab().dispatchBeforeUnloadAndClose(); + invalidate(); + }); + } + + @Override + public void executeScript(String script, boolean useSeparateIsolate, IStringCallback callback) { + mHandler.post(() -> { + // TODO(rayankans): Verify the tab's origin is 1P. + getTab().executeScript(script, useSeparateIsolate, (String result) -> { + try { + callback.onResult(result); + } catch (RemoteException e) { + } + }); + }); + } + + @Override + public void registerWebMessageCallback( + IWebMessageCallback callback, String jsObjectName, List<String> allowedOrigins) { + mHandler.post(() -> { + getTab().registerWebMessageCallback(new WebMessageCallback() { + @Override + public void onWebMessageReceived( + WebMessageReplyProxy replyProxy, WebMessage message) { + try { + callback.onWebMessageReceived( + new WebMessageReplyProxyProxy(replyProxy), message.getContents()); + } catch (RemoteException e) { + } + } + + @Override + public void onWebMessageReplyProxyClosed(WebMessageReplyProxy replyProxy) { + try { + callback.onWebMessageReplyProxyClosed( + new WebMessageReplyProxyProxy(replyProxy)); + } catch (RemoteException e) { + } + } + + @Override + public void onWebMessageReplyProxyActiveStateChanged( + WebMessageReplyProxy replyProxy) { + try { + callback.onWebMessageReplyProxyActiveStateChanged( + new WebMessageReplyProxyProxy(replyProxy)); + } catch (RemoteException e) { + } + } + }, jsObjectName, allowedOrigins); + }); + } + + @Override + public void unregisterWebMessageCallback(String jsObjectName) { + mHandler.post(() -> { getTab().unregisterWebMessageCallback(jsObjectName); }); + } +} diff --git a/chromium/weblayer/public/java/org/chromium/weblayer/WebMessageReplyProxyProxy.java b/chromium/weblayer/public/java/org/chromium/weblayer/WebMessageReplyProxyProxy.java new file mode 100644 index 00000000000..1ad7c1f9a32 --- /dev/null +++ b/chromium/weblayer/public/java/org/chromium/weblayer/WebMessageReplyProxyProxy.java @@ -0,0 +1,29 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.weblayer; + +import android.os.Handler; +import android.os.Looper; + +import org.chromium.browserfragment.interfaces.IWebMessageReplyProxy; + +/** + * This class act as a proxy between browserfragment and the {@link WebMessageReplyProxy} in + * weblayer. + */ +class WebMessageReplyProxyProxy extends IWebMessageReplyProxy.Stub { + private Handler mHandler = new Handler(Looper.getMainLooper()); + + private final WebMessageReplyProxy mWebMessageReplyProxy; + + WebMessageReplyProxyProxy(WebMessageReplyProxy webMessageReplyProxy) { + mWebMessageReplyProxy = webMessageReplyProxy; + } + + @Override + public void postMessage(String message) { + mHandler.post(() -> { mWebMessageReplyProxy.postMessage(new WebMessage(message)); }); + } +} diff --git a/chromium/weblayer/renderer/content_renderer_client_impl.cc b/chromium/weblayer/renderer/content_renderer_client_impl.cc index 5046b828aaf..65149ff6f72 100644 --- a/chromium/weblayer/renderer/content_renderer_client_impl.cc +++ b/chromium/weblayer/renderer/content_renderer_client_impl.cc @@ -172,7 +172,8 @@ void ContentRendererClientImpl::RenderFrameCreated( } } -void ContentRendererClientImpl::WebViewCreated(blink::WebView* web_view) { +void ContentRendererClientImpl::WebViewCreated(blink::WebView* web_view, + bool was_created_by_renderer) { new prerender::NoStatePrefetchClient(web_view); } diff --git a/chromium/weblayer/renderer/content_renderer_client_impl.h b/chromium/weblayer/renderer/content_renderer_client_impl.h index c5318ec73e4..d4ed15bf2cb 100644 --- a/chromium/weblayer/renderer/content_renderer_client_impl.h +++ b/chromium/weblayer/renderer/content_renderer_client_impl.h @@ -36,7 +36,8 @@ class ContentRendererClientImpl : public content::ContentRendererClient { // content::ContentRendererClient: void RenderThreadStarted() override; void RenderFrameCreated(content::RenderFrame* render_frame) override; - void WebViewCreated(blink::WebView* web_view) override; + void WebViewCreated(blink::WebView* web_view, + bool was_created_by_renderer) override; SkBitmap* GetSadPluginBitmap() override; SkBitmap* GetSadWebViewBitmap() override; void PrepareErrorPage(content::RenderFrame* render_frame, diff --git a/chromium/weblayer/renderer/error_page_helper.cc b/chromium/weblayer/renderer/error_page_helper.cc index 6eb924db516..dc8b9454555 100644 --- a/chromium/weblayer/renderer/error_page_helper.cc +++ b/chromium/weblayer/renderer/error_page_helper.cc @@ -57,9 +57,9 @@ void ErrorPageHelper::DisableErrorPageHelperForNextError() { ErrorPageHelper::ErrorPageHelper(content::RenderFrame* render_frame) : RenderFrameObserver(render_frame), RenderFrameObserverTracker<ErrorPageHelper>(render_frame) { - render_frame->GetAssociatedInterfaceRegistry()->AddInterface( - base::BindRepeating(&ErrorPageHelper::BindErrorPageHelper, - weak_factory_.GetWeakPtr())); + render_frame->GetAssociatedInterfaceRegistry() + ->AddInterface<mojom::ErrorPageHelper>(base::BindRepeating( + &ErrorPageHelper::BindErrorPageHelper, weak_factory_.GetWeakPtr())); } ErrorPageHelper::~ErrorPageHelper() = default; diff --git a/chromium/weblayer/renderer/weblayer_render_thread_observer.cc b/chromium/weblayer/renderer/weblayer_render_thread_observer.cc index 913c304be54..3d8a589d31a 100644 --- a/chromium/weblayer/renderer/weblayer_render_thread_observer.cc +++ b/chromium/weblayer/renderer/weblayer_render_thread_observer.cc @@ -14,7 +14,8 @@ WebLayerRenderThreadObserver::~WebLayerRenderThreadObserver() = default; void WebLayerRenderThreadObserver::RegisterMojoInterfaces( blink::AssociatedInterfaceRegistry* associated_interfaces) { - associated_interfaces->AddInterface(base::BindRepeating( + associated_interfaces->AddInterface< + mojom::RendererConfiguration>(base::BindRepeating( &WebLayerRenderThreadObserver::OnRendererConfigurationAssociatedRequest, base::Unretained(this))); } diff --git a/chromium/weblayer/shell/android/BUILD.gn b/chromium/weblayer/shell/android/BUILD.gn index 74362f16869..de9a8db0e75 100644 --- a/chromium/weblayer/shell/android/BUILD.gn +++ b/chromium/weblayer/shell/android/BUILD.gn @@ -106,6 +106,26 @@ weblayer_shell_apk_helper("weblayer_shell_system_webview") { apk_name = "WebLayerShellSystemWebView" } +generate_wrapper("run_browserfragment_shell") { + testonly = true + wrapper_script = "$root_out_dir/bin/run_browserfragment_shell" + executable = "//weblayer/tools/run_weblayer_shell.py" + executable_args = [ + "--shell-apk-path", + "@WrappedPath(apks/BFShell.apk)", + "--support-apk-path", + "@WrappedPath(apks/BFSandbox.apk)", + "--support-apk-path", + "@WrappedPath(apks/WebLayerSupport.apk)", + ] + + deps = [ + ":browser_sandbox_apk", + ":browserfragment_shell_apk", + ":weblayer_support_apk", + ] +} + generate_wrapper("run_weblayer_shell") { testonly = true wrapper_script = "$root_out_dir/bin/run_weblayer_shell" @@ -304,3 +324,82 @@ script_test("weblayer_shell_wpt") { "//third_party/blink/tools:wpt_tests_android_isolate", ] } + +# TODO(rayankans): Update `run_weblayer_shell` to also deploy the browserfragment shell with a +# browser sandbox APK. + +browserfragment_shell_manifest = + "$target_gen_dir/browserfragment_shell_manifest/AndroidManifest.xml" + +jinja_template("browserfragment_shell_manifest") { + input = "browserfragment_shell_apk/AndroidManifest.xml" + output = browserfragment_shell_manifest +} + +android_resources("browserfragment_shell_resources") { + sources = [ + "browserfragment_shell_apk/res/layout/main.xml", + "browserfragment_shell_apk/res/values/styles.xml", + ] +} + +android_library("browserfragment_shell_java") { + testonly = true + resources_package = "org.chromium.browserfragment.shell" + + sources = [ "browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java" ] + + deps = [ + ":browserfragment_shell_resources", + "//base:base_java", + "//third_party/android_deps:com_google_guava_guava_android_java", + "//third_party/androidx:androidx_appcompat_appcompat_java", + "//third_party/androidx:androidx_fragment_fragment_java", + "//weblayer/public/java:browserfragment_java", + ] +} + +android_apk("browserfragment_shell_apk") { + testonly = true + + # Test runner does not support having "additional apks" that are incremental. + never_incremental = true + + deps = [ + ":browserfragment_shell_java", + ":browserfragment_shell_manifest", + ] + + apk_name = "BFShell" + android_manifest = browserfragment_shell_manifest + min_sdk_version = default_min_sdk_version + target_sdk_version = 28 + android_manifest_dep = ":browserfragment_shell_manifest" +} + +browser_sandbox_manifest = + "$target_gen_dir/browser_sandbox_manifest/AndroidManifest.xml" + +jinja_template("browser_sandbox_manifest") { + input = "browser_sandbox_apk/AndroidManifest.xml" + output = browser_sandbox_manifest +} + +android_apk("browser_sandbox_apk") { + testonly = true + + # Test runner does not support having "additional apks" that are incremental. + never_incremental = true + + deps = [ + ":browser_sandbox_manifest", + "//weblayer/public/java:browserfragment_sandbox_java", + ] + + apk_name = "BFSandbox" + android_manifest = browser_sandbox_manifest + min_sdk_version = default_min_sdk_version + target_sdk_version = 28 + android_manifest_dep = ":browser_sandbox_manifest" + shared_resources = true +} diff --git a/chromium/weblayer/shell/android/browser_sandbox_apk/AndroidManifest.xml b/chromium/weblayer/shell/android/browser_sandbox_apk/AndroidManifest.xml new file mode 100644 index 00000000000..f258fe5d3dd --- /dev/null +++ b/chromium/weblayer/shell/android/browser_sandbox_apk/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Copyright 2022 The Chromium Authors. All rights reserved. + + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.chromium.browserfragment.sandbox"> + + <application android:label="BF sandbox"> + + <service android:name="org.chromium.weblayer.BrowserSandboxService" + android:exported="true" > + <intent-filter> + <action android:name="org.chromium.weblayer.intent.action.BROWSERSANDBOX" /> + </intent-filter> + </service> + + <!-- TODO(rayankans): Make this a template. --> + <meta-data android:name="org.chromium.weblayer.WebLayerPackage" + android:value="org.chromium.weblayer.support"/> + + </application> +</manifest> diff --git a/chromium/weblayer/shell/android/browserfragment_shell_apk/AndroidManifest.xml b/chromium/weblayer/shell/android/browserfragment_shell_apk/AndroidManifest.xml new file mode 100644 index 00000000000..fee9e739e42 --- /dev/null +++ b/chromium/weblayer/shell/android/browserfragment_shell_apk/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Copyright 2022 The Chromium Authors. All rights reserved. + + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="org.chromium.browserfragment.shell"> + + <application android:label="BF shell" + android:supportsRtl="true"> + <activity android:name="BrowserFragmentShellActivity" + android:launchMode="singleTask" + android:theme="@style/ShellTheme" + android:windowSoftInputMode="adjustResize" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/chromium/weblayer/shell/android/browserfragment_shell_apk/res/layout/main.xml b/chromium/weblayer/shell/android/browserfragment_shell_apk/res/layout/main.xml new file mode 100644 index 00000000000..7361030f06f --- /dev/null +++ b/chromium/weblayer/shell/android/browserfragment_shell_apk/res/layout/main.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2022 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <Button + android:id="@+id/create_tab" + android:text="Create and Preload Tab" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + <Button + android:id="@+id/navigate_tab" + android:text="Open Tab" + android:enabled="false" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </LinearLayout> + <androidx.fragment.app.FragmentContainerView + android:id="@+id/fragment_container_view" + android:layout_width="match_parent" + android:layout_height="match_parent" /> +</LinearLayout> + diff --git a/chromium/weblayer/shell/android/browserfragment_shell_apk/res/values/styles.xml b/chromium/weblayer/shell/android/browserfragment_shell_apk/res/values/styles.xml new file mode 100644 index 00000000000..1577b6d4ad8 --- /dev/null +++ b/chromium/weblayer/shell/android/browserfragment_shell_apk/res/values/styles.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources xmlns:tools="http://schemas.android.com/tools"> + <style name="ShellTheme" parent="Theme.AppCompat.DayNight.NoActionBar"/> +</resources>
\ No newline at end of file diff --git a/chromium/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java b/chromium/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java new file mode 100644 index 00000000000..30b89504e89 --- /dev/null +++ b/chromium/weblayer/shell/android/browserfragment_shell_apk/src/org/chromium/browserfragment/shell/BrowserFragmentShellActivity.java @@ -0,0 +1,200 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.browserfragment.shell; + +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; + +import com.google.common.util.concurrent.AsyncFunction; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +import org.chromium.base.Log; +import org.chromium.browserfragment.Browser; +import org.chromium.browserfragment.BrowserFragment; +import org.chromium.browserfragment.FragmentParams; +import org.chromium.browserfragment.Tab; +import org.chromium.browserfragment.TabManager; +import org.chromium.browserfragment.TabObserver; +import org.chromium.browserfragment.WebMessageCallback; +import org.chromium.browserfragment.WebMessageReplyProxy; + +import java.util.Arrays; +import java.util.List; + +/** + * Activity for managing the Demo Shell. + */ +public class BrowserFragmentShellActivity extends AppCompatActivity { + private static final String TAG = "BrowserFragmentShell"; + + private static final String BROWSER_FRAGMENT_TAG = "BROWSER_FRAGMENT_TAG"; + + private Context mContext; + + private TabManager mTabManager; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.main); + + mContext = getApplicationContext(); + + ListenableFuture<Browser> browserFuture = Browser.create(mContext); + Futures.addCallback(browserFuture, new FutureCallback<Browser>() { + @Override + public void onSuccess(Browser browser) { + onBrowserReady(browser, savedInstanceState); + } + + @Override + public void onFailure(Throwable thrown) {} + }, mContext.getMainExecutor()); + + final Button createTabButton = findViewById(R.id.create_tab); + final Button navigateButton = findViewById(R.id.navigate_tab); + + createTabButton.setOnClickListener((View v) -> { + if (mTabManager != null) { + ListenableFuture<Tab> newTabFuture = mTabManager.createTab(); + Futures.addCallback(newTabFuture, new FutureCallback<Tab>() { + @Override + public void onSuccess(Tab newTab) { + navigateButton.setEnabled(true); + newTab.getNavigationController().navigate("https://google.com"); + // TODO(swestphal): Call this in a Tab-loaded-callback instead. + navigateButton.setOnClickListener((View v) -> { + navigateButton.setEnabled(false); + newTab.setActive(); + }); + } + @Override + public void onFailure(Throwable thrown) {} + }, mContext.getMainExecutor()); + } + }); + } + + private void onBrowserReady(Browser browser, Bundle savedInstanceState) { + browser.setRemoteDebuggingEnabled(true); + + BrowserFragment fragment = getOrCreateBrowserFragment(browser, savedInstanceState); + + fragment.registerTabObserver(new TabObserver() { + @Override + public void onActiveTabChanged(@Nullable Tab activeTab) { + Log.i(TAG, "received 'onActiveTabChanged'-event"); + } + + @Override + public void onTabAdded(@NonNull Tab tab) { + Log.i(TAG, "received 'onTabAdded'-event"); + } + + @Override + public void onTabRemoved(@NonNull Tab tab) { + Log.i(TAG, "received 'onTabRemoved'-event"); + } + + @Override + public void onWillDestroyBrowserAndAllTabs() { + Log.i(TAG, "received 'onWillDestroyBrowserAndAllTabs'-event"); + } + }); + ListenableFuture<TabManager> tabManagerFuture = fragment.getTabManager(); + AsyncFunction<TabManager, Tab> getActiveTabTask = tabManager -> { + mTabManager = tabManager; + return tabManager.getActiveTab(); + }; + ListenableFuture<Tab> activeTabFuture = Futures.transformAsync( + tabManagerFuture, getActiveTabTask, mContext.getMainExecutor()); + + Futures.addCallback(activeTabFuture, new FutureCallback<Tab>() { + @Override + public void onSuccess(Tab activeTab) { + if (savedInstanceState == null) { + // TODO(rayankans): Expose Tab URL to avoid relying on |savedInstanceState|. + activeTab.getNavigationController().navigate("https://google.com"); + + activeTab.registerWebMessageCallback(new WebMessageCallback() { + @Override + public void onWebMessageReceived( + WebMessageReplyProxy replyProxy, String message) { + Log.i(TAG, "received WebMessage: " + message); + replyProxy.postMessage("Bouncing answer from browser: " + message); + } + + @Override + public void onWebMessageReplyProxyClosed(WebMessageReplyProxy replyProxy) {} + + @Override + public void onWebMessageReplyProxyActiveStateChanged( + WebMessageReplyProxy proxy) {} + }, "x", Arrays.asList("*")); + } + } + @Override + public void onFailure(Throwable thrown) {} + }, mContext.getMainExecutor()); + } + + private BrowserFragment getOrCreateBrowserFragment(Browser browser, Bundle savedInstanceState) { + FragmentManager fragmentManager = getSupportFragmentManager(); + if (savedInstanceState != null) { + List<Fragment> fragments = fragmentManager.getFragments(); + if (fragments.size() > 1) { + throw new IllegalStateException("More than one fragment added, shouldn't happen"); + } + if (fragments.size() == 1) { + return (BrowserFragment) fragments.get(0); + } + } + + FragmentParams params = + (new FragmentParams.Builder()).setProfileName("DefaultProfile").build(); + BrowserFragment fragment = browser.createFragment(params); + + fragmentManager.beginTransaction() + .setReorderingAllowed(true) + .add(R.id.fragment_container_view, fragment, BROWSER_FRAGMENT_TAG) + .commit(); + + return fragment; + } + + @Override + public void onBackPressed() { + BrowserFragment fragment = (BrowserFragment) getSupportFragmentManager().findFragmentByTag( + BROWSER_FRAGMENT_TAG); + if (fragment == null) { + super.onBackPressed(); + return; + } + ListenableFuture<Boolean> tryNavigateBackFuture = mTabManager.tryNavigateBack(); + Futures.addCallback(tryNavigateBackFuture, new FutureCallback<Boolean>() { + @Override + public void onSuccess(Boolean didNavigate) { + if (!didNavigate) { + BrowserFragmentShellActivity.super.onBackPressed(); + } + } + @Override + public void onFailure(Throwable thrown) { + BrowserFragmentShellActivity.super.onBackPressed(); + } + }, mContext.getMainExecutor()); + } +} diff --git a/chromium/weblayer/shell/android/shell_apk/DEPS b/chromium/weblayer/shell/android/shell_apk/DEPS index 941c524071c..976d31890b3 100644 --- a/chromium/weblayer/shell/android/shell_apk/DEPS +++ b/chromium/weblayer/shell/android/shell_apk/DEPS @@ -6,5 +6,6 @@ include_rules = [ # possible, as it can be confusing since the ClassLoader of the client will be # different from the implementation. Only simple utility classes are allowed. "+base/android/java/src/org/chromium/base/IntentUtils.java", + "+base/android/java/src/org/chromium/base/Log.java", "+base/android/java/src/org/chromium/base/compat/ApiHelperForR.java", ] diff --git a/chromium/weblayer/test/BUILD.gn b/chromium/weblayer/test/BUILD.gn index 8f8ca44d65d..03c93c2856e 100644 --- a/chromium/weblayer/test/BUILD.gn +++ b/chromium/weblayer/test/BUILD.gn @@ -116,6 +116,7 @@ test("weblayer_browsertests") { "//components/favicon/content", "//components/heavy_ad_intervention", "//components/infobars/content", + "//components/language/core/browser", "//components/network_session_configurator/common", "//components/network_time", "//components/no_state_prefetch/browser", @@ -126,6 +127,8 @@ test("weblayer_browsertests") { "//components/permissions", "//components/permissions:test_support", "//components/prefs", + "//components/reduce_accept_language/browser:browser", + "//components/reduce_accept_language/browser:test_support", "//components/security_interstitials/content:security_interstitial_page", "//components/sessions:test_support", "//components/signin/core/browser", @@ -183,6 +186,7 @@ test("weblayer_browsertests") { "../browser/popup_blocker_browsertest.cc", "../browser/prefetch_browsertest.cc", "../browser/profile_browsertest.cc", + "../browser/reduce_accept_language_service_browsertest.cc", "../browser/site_isolation_browsertest.cc", "../browser/ssl_browsertest.cc", "../browser/subresource_filter_browsertest.cc", @@ -217,6 +221,7 @@ test("weblayer_browsertests") { "../browser/android/metrics/metrics_test_helper.h", "../browser/android/metrics/ukm_browsertest.cc", "../browser/autofill_browsertest.cc", + "../browser/browser_controls_navigation_state_handler_browsertest.cc", "../browser/safe_browsing/client_side_detection_service_browsertest.cc", "../browser/safe_browsing/client_side_detection_service_factory_browsertest.cc", "../browser/safe_browsing/safe_browsing_browsertest.cc", diff --git a/chromium/weblayer/tools/run_weblayer_shell.py b/chromium/weblayer/tools/run_weblayer_shell.py index 41391b2152b..05fc96a0eaf 100755 --- a/chromium/weblayer/tools/run_weblayer_shell.py +++ b/chromium/weblayer/tools/run_weblayer_shell.py @@ -73,6 +73,12 @@ def main(): 'launch'] launch_cmd.extend(args.remaining_args) subprocess.call(launch_cmd) + elif (os.path.basename(args.shell_apk_path) == "BFShell.apk"): + launch_cmd = [os.path.join(os.path.dirname(args.shell_apk_path), + os.pardir, 'bin', 'browserfragment_shell_apk'), + 'launch'] + launch_cmd.extend(args.remaining_args) + subprocess.call(launch_cmd) else: device.adb.Shell('monkey -p org.chromium.weblayer.shell 1') |