diff --git a/.gn b/.gn index 5356717..5a11496 100644 --- a/.gn +++ b/.gn
@@ -82,6 +82,12 @@ "//v8:cppgc_base", # 1 error "//v8:v8_internal_headers", # 11 errors "//v8:v8_libplatform", # 2 errors + + # After making partition_alloc a standalone library, remove partition_alloc + # target from the skip list, because partition_aloc will depend on its own + # base. + # partition alloc standalone library bug is https://crbug.com/1151236. + "//base/allocator/partition_allocator:partition_alloc", # 292 errors ] # These are the list of GN files that run exec_script. This whitelist exists
diff --git a/DEPS b/DEPS index 9904bed..df91280 100644 --- a/DEPS +++ b/DEPS
@@ -253,7 +253,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'ae5984082b5e7aa4e7c4c8f9201f83bca067f66e', + 'skia_revision': '371b3a68b254b89536efbf3a059fa128a4aa5156', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -261,7 +261,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'cbbf5b5dafeda4191b0f41914127b4ccf14d7a5b', + 'angle_revision': '45543295b75842b499c137a9ed3a727e818ef185', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -328,7 +328,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '393848420284a7c004748a4ec078c51605337cbd', + 'devtools_frontend_revision': '23ad1b50d79b1545d2b68b2157536e796de89716', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -724,16 +724,16 @@ Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248', 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + '326bd0e693eef75d6b10294e6acbfd3bfed3636b', + 'url': Var('chromium_git') + '/website.git' + '@' + '9e03811dcd09e0b382264f94108f4b3840cd7fbd', }, 'src/ios/third_party/earl_grey2/src': { - 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '0c6bc2b507d0efe5091094099086de7b9035e924', + 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'aaf6cd0daad5e447754d89141fb75a2a0c4cee9a', 'condition': 'checkout_ios', }, 'src/ios/third_party/edo/src': { - 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + 'f7dea1a5bdc745493aeffece692a4883e85c0e78', + 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '727e556705278598fce683522beedbb9946bfda0', 'condition': 'checkout_ios', }, @@ -1814,7 +1814,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ca7a17a9c855382eae3465f5a846679c5273d47d', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0a380bc2473917740e92bdd1e1fb56eb57873c9d', 'condition': 'checkout_src_internal', },
diff --git a/ash/ambient/test/test_ambient_client.h b/ash/ambient/test/test_ambient_client.h index 9056168..8e81885 100644 --- a/ash/ambient/test/test_ambient_client.h +++ b/ash/ambient/test/test_ambient_client.h
@@ -28,6 +28,7 @@ // AmbientClient: bool IsAmbientModeAllowed() override; + void SetAmbientModeAllowedForTesting(bool allowed) override {} void RequestAccessToken(GetAccessTokenCallback callback) override; void DownloadImage(const std::string& url, ash::ImageDownloader::DownloadCallback callback) override;
diff --git a/ash/components/arc/compat_mode/compat_mode_button_controller.cc b/ash/components/arc/compat_mode/compat_mode_button_controller.cc index 5a456cf..418e0e8a 100644 --- a/ash/components/arc/compat_mode/compat_mode_button_controller.cc +++ b/ash/components/arc/compat_mode/compat_mode_button_controller.cc
@@ -168,6 +168,8 @@ frame_view->GetHeaderView()->GetFrameHeader()->GetCenterButton(); if (!compat_mode_button || !compat_mode_button->GetEnabled()) return; + if (resize_toggle_menu_ && resize_toggle_menu_->IsBubbleShown()) + return; resize_toggle_menu_.reset(); resize_toggle_menu_ = std::make_unique<ResizeToggleMenu>(frame_view->frame(), pref_delegate);
diff --git a/ash/components/arc/compat_mode/resize_toggle_menu.cc b/ash/components/arc/compat_mode/resize_toggle_menu.cc index 1d7fa04..ad0153c 100644 --- a/ash/components/arc/compat_mode/resize_toggle_menu.cc +++ b/ash/components/arc/compat_mode/resize_toggle_menu.cc
@@ -49,8 +49,14 @@ frame->SetCornerRadius(corner_radius_); } + base::WeakPtr<RoundedCornerBubbleDialogDelegateView> GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + private: const int corner_radius_; + base::WeakPtrFactory<RoundedCornerBubbleDialogDelegateView> weak_factory_{ + this}; }; } // namespace @@ -230,6 +236,7 @@ auto delegate_view = std::make_unique<RoundedCornerBubbleDialogDelegateView>(kCornerRadius); + bubble_view_ = delegate_view->GetWeakPtr(); // Setup delegate. delegate_view->SetArrow(views::BubbleBorder::Arrow::TOP_CENTER); @@ -301,6 +308,10 @@ FROM_HERE, auto_close_closure_.callback(), kAutoCloseDelay); } +bool ResizeToggleMenu::IsBubbleShown() const { + return bubble_view_ && bubble_view_->GetWidget(); +} + void ResizeToggleMenu::CloseBubble() { if (!bubble_widget_ || bubble_widget_->IsClosed()) return;
diff --git a/ash/components/arc/compat_mode/resize_toggle_menu.h b/ash/components/arc/compat_mode/resize_toggle_menu.h index b3eb77b..76b4bea5 100644 --- a/ash/components/arc/compat_mode/resize_toggle_menu.h +++ b/ash/components/arc/compat_mode/resize_toggle_menu.h
@@ -79,6 +79,8 @@ intptr_t old) override; void OnWindowDestroying(aura::Window* window) override; + bool IsBubbleShown() const; + private: friend class ResizeToggleMenuTest; @@ -88,6 +90,8 @@ gfx::Rect GetAnchorRect() const; + base::WeakPtr<views::BubbleDialogDelegateView> bubble_view_; + std::unique_ptr<views::BubbleDialogDelegateView> MakeBubbleDelegateView( views::Widget* parent, gfx::Rect anchor_rect, @@ -106,8 +110,9 @@ base::CancelableOnceClosure auto_close_closure_; - // Store only for testing. views::Widget* bubble_widget_{nullptr}; + + // Store only for testing. MenuButtonView* phone_button_{nullptr}; MenuButtonView* tablet_button_{nullptr}; MenuButtonView* resizable_button_{nullptr};
diff --git a/ash/components/arc/compat_mode/resize_toggle_menu_unittest.cc b/ash/components/arc/compat_mode/resize_toggle_menu_unittest.cc index 69ca134..f380049 100644 --- a/ash/components/arc/compat_mode/resize_toggle_menu_unittest.cc +++ b/ash/components/arc/compat_mode/resize_toggle_menu_unittest.cc
@@ -61,7 +61,10 @@ SyncResizeLockPropertyWithMojoState(widget()); } + void CloseBubble() { resize_toggle_menu_->CloseBubble(); } + views::Widget* widget() { return widget_.get(); } + ResizeToggleMenu* resize_toggle_menu() { return resize_toggle_menu_.get(); } private: views::Button* GetButtonByCommandId(ResizeCompatMode command_id) { @@ -265,4 +268,13 @@ widget()->SetFullscreen(false); } +// Test that IsBubbleOpen returns the correct state of the bubble +TEST_F(ResizeToggleMenuTest, TestIsBubbleShown) { + EXPECT_TRUE(IsMenuRunning()); + EXPECT_TRUE(resize_toggle_menu()->IsBubbleShown()); + CloseBubble(); + RunPendingMessages(); + EXPECT_FALSE(resize_toggle_menu()->IsBubbleShown()); +} + } // namespace arc
diff --git a/ash/components/cryptohome/OWNERS b/ash/components/cryptohome/OWNERS index e1627725..911c45d4 100644 --- a/ash/components/cryptohome/OWNERS +++ b/ash/components/cryptohome/OWNERS
@@ -1 +1,2 @@ +antrim@chromium.org hashimoto@chromium.org
diff --git a/ash/display/overscan_calibrator.cc b/ash/display/overscan_calibrator.cc index afb834e6..9b0a377 100644 --- a/ash/display/overscan_calibrator.cc +++ b/ash/display/overscan_calibrator.cc
@@ -63,7 +63,7 @@ gfx::Transform move_transform; move_transform.Translate(x_offset, y_offset); rotate_transform.ConcatTransform(move_transform); - base_path.transform(SkMatrix(rotate_transform.matrix()), &path); + base_path.transform(rotate_transform.matrix().asM33(), &path); canvas->DrawPath(path, content_flags); canvas->DrawPath(path, border_flags);
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc index 7d60498e..99b7af0 100644 --- a/ash/drag_drop/drag_drop_controller_unittest.cc +++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -137,12 +137,6 @@ void OnDragExited() override { num_drag_exits_++; } - DragOperation OnPerformDrop(const ui::DropTargetEvent& event) override { - DragOperation output_drag_op = DragOperation::kNone; - PerformDrop(event, output_drag_op); - return output_drag_op; - } - DropCallback GetDropCallback(const ui::DropTargetEvent& event) override { return base::BindOnce(&DragTestView::PerformDrop, base::Unretained(this)); } @@ -310,15 +304,6 @@ State::kDragUpdateInvoked == state_); state_ = State::kDragExitInvoked; } - DragOperation OnPerformDrop( - const ui::DropTargetEvent& event, - std::unique_ptr<ui::OSExchangeData> data) override { - DragOperation output_drag_op = DragOperation::kNone; - PerformDrop(std::move(data), output_drag_op); - - return output_drag_op; - } - DropCallback GetDropCallback(const ui::DropTargetEvent& event) override { return base::BindOnce(&EventTargetTestDelegate::PerformDrop, base::Unretained(this));
diff --git a/ash/drag_drop/drag_drop_unittest.cc b/ash/drag_drop/drag_drop_unittest.cc index 043feea..53d042e 100644 --- a/ash/drag_drop/drag_drop_unittest.cc +++ b/ash/drag_drop/drag_drop_unittest.cc
@@ -63,13 +63,6 @@ int OnDragUpdated(const ui::DropTargetEvent& event) override { return ui::DragDropTypes::DRAG_MOVE; } - ui::mojom::DragOperation OnPerformDrop( - const ui::DropTargetEvent& event) override { - ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone; - PerformDrop(event, output_drag_op); - return output_drag_op; - } - DropCallback GetDropCallback(const ui::DropTargetEvent& event) override { return base::BindOnce(&TargetView::PerformDrop, base::Unretained(this)); }
diff --git a/ash/fast_ink/view_tree_host_root_view.cc b/ash/fast_ink/view_tree_host_root_view.cc index b787339..d8714ba 100644 --- a/ash/fast_ink/view_tree_host_root_view.cc +++ b/ash/fast_ink/view_tree_host_root_view.cc
@@ -344,7 +344,7 @@ int stride = resource->gpu_memory_buffer->stride(0); std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(info, data, stride); - canvas->setMatrix(static_cast<SkMatrix>(rotate_transform_.matrix())); + canvas->setMatrix(rotate_transform_.matrix().asM33()); display_item_list->Raster(canvas.get()); {
diff --git a/ash/public/cpp/ambient/ambient_client.h b/ash/public/cpp/ambient/ambient_client.h index ba5cd368..afce249 100644 --- a/ash/public/cpp/ambient/ambient_client.h +++ b/ash/public/cpp/ambient/ambient_client.h
@@ -41,6 +41,8 @@ // Return whether the ambient mode is allowed for the user. virtual bool IsAmbientModeAllowed() = 0; + virtual void SetAmbientModeAllowedForTesting(bool allowed) = 0; + // Return the gaia and access token associated with the active user's profile. virtual void RequestAccessToken(GetAccessTokenCallback callback) = 0;
diff --git a/ash/webui/personalization_app/personalization_app_ui.cc b/ash/webui/personalization_app/personalization_app_ui.cc index a3776d8..934e52f 100644 --- a/ash/webui/personalization_app/personalization_app_ui.cc +++ b/ash/webui/personalization_app/personalization_app_ui.cc
@@ -5,6 +5,7 @@ #include "ash/webui/personalization_app/personalization_app_ui.h" #include "ash/constants/ash_features.h" +#include "ash/public/cpp/ambient/ambient_client.h" #include "ash/webui/grit/ash_personalization_app_resources.h" #include "ash/webui/grit/ash_personalization_app_resources_map.h" #include "ash/webui/personalization_app/personalization_app_ambient_provider.h" @@ -33,6 +34,11 @@ return GURL(kGooglePhotosURL); } +bool IsAmbientModeAllowed() { + return ash::AmbientClient::Get() && + ash::AmbientClient::Get()->IsAmbientModeAllowed(); +} + void AddResources(content::WebUIDataSource* source) { source->AddResourcePath("", IDR_ASH_PERSONALIZATION_APP_TRUSTED_INDEX_HTML); source->AddResourcePaths(base::make_span( @@ -192,6 +198,8 @@ source->AddBoolean("isDarkLightModeEnabled", features::IsDarkLightModeEnabled()); + + source->AddBoolean("isAmbientModeAllowed", IsAmbientModeAllowed()); } } // namespace
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_main_element.html b/ash/webui/personalization_app/resources/trusted/personalization_main_element.html index 9a7d01a..9a60406 100644 --- a/ash/webui/personalization_app/resources/trusted/personalization_main_element.html +++ b/ash/webui/personalization_app/resources/trusted/personalization_main_element.html
@@ -62,13 +62,16 @@ <personalization-theme></personalization-theme> </template> </wallpaper-preview> - <ambient-preview main-page> - <div id="ambientLabel"> - <p>$i18n{screensaverLabel}</p> - <cr-button id="ambientSubpageLink" on-click="onClickAmbientSubpageLink_"> - <iron-icon icon="cr:chevron-right" aria-hidden="true"></iron-icon> - </cr-button> - </div> - </ambient-preview> + <template is="dom-if" if="[[isAmbientModeAllowed_()]]"> + <ambient-preview main-page> + <div id="ambientLabel"> + <p>$i18n{screensaverLabel}</p> + <cr-button id="ambientSubpageLink" + on-click="onClickAmbientSubpageLink_"> + <iron-icon icon="cr:chevron-right" aria-hidden="true"></iron-icon> + </cr-button> + </div> + </ambient-preview> + </template> </div> </div>
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts b/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts index e039007d..1a4a898 100644 --- a/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts +++ b/ash/webui/personalization_app/resources/trusted/personalization_main_element.ts
@@ -9,7 +9,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {Paths, PersonalizationRouter} from './personalization_router_element.js'; +import {isAmbientModeAllowed, Paths, PersonalizationRouter} from './personalization_router_element.js'; import {WithPersonalizationStore} from './personalization_store.js'; export class PersonalizationMain extends WithPersonalizationStore { @@ -34,6 +34,10 @@ return loadTimeData.getBoolean('isDarkLightModeEnabled'); } + private isAmbientModeAllowed_(): boolean { + return isAmbientModeAllowed(); + } + private onClickUserSubpageLink_() { PersonalizationRouter.instance().goToRoute(Paths.User); }
diff --git a/ash/webui/personalization_app/resources/trusted/personalization_router_element.ts b/ash/webui/personalization_app/resources/trusted/personalization_router_element.ts index 011852f..a4a4522 100644 --- a/ash/webui/personalization_app/resources/trusted/personalization_router_element.ts +++ b/ash/webui/personalization_app/resources/trusted/personalization_router_element.ts
@@ -29,6 +29,10 @@ return loadTimeData.getBoolean('isPersonalizationHubEnabled'); } +export function isAmbientModeAllowed(): boolean { + return loadTimeData.getBoolean('isAmbientModeAllowed'); +} + export class PersonalizationRouter extends PolymerElement { static get is() { return 'personalization-router'; @@ -42,6 +46,7 @@ return { path_: { type: String, + observer: 'onPathChanged_', }, query_: { @@ -119,11 +124,19 @@ } private shouldShowRootPage_(path: string|null): boolean { - return isPersonalizationHubEnabled() && path === Paths.Root; + if (!isPersonalizationHubEnabled()) { + return false; + } + + // If the ambient mode is not allowed, will not show Ambient/AmbientAlbums + // subpages. + return (path === Paths.Root) || + (!!path && path.startsWith(Paths.Ambient) && !isAmbientModeAllowed()); } private shouldShowAmbientSubpage_(path: string|null): boolean { - return isPersonalizationHubEnabled() && !!path?.startsWith(Paths.Ambient); + return isPersonalizationHubEnabled() && !!path?.startsWith(Paths.Ambient) && + isAmbientModeAllowed(); } private shouldShowUserSubpage_(path: string|null): boolean { @@ -137,6 +150,18 @@ private shouldShowBreadcrumb_(path: string|null): boolean { return path !== Paths.Root; } + + /** + * When navigating to Ambient/AmbientAlbums subpages, but the ambient mode is + * not allowed, will not show Ambient/AmbientAlbums subpages. Reset path to + * root in this case. + */ + private onPathChanged_(path: string|null) { + if (!!path && path.startsWith(Paths.Ambient) && !isAmbientModeAllowed()) { + // Reset the path to root. + this.setProperties({path_: Paths.Root, queryParams_: {}}); + } + } } customElements.define(PersonalizationRouter.is, PersonalizationRouter);
diff --git a/ash/webui/personalization_app/test/personalization_app_browsertest.js b/ash/webui/personalization_app/test/personalization_app_browsertest.js index caef8d9..83221918 100644 --- a/ash/webui/personalization_app/test/personalization_app_browsertest.js +++ b/ash/webui/personalization_app/test/personalization_app_browsertest.js
@@ -9,6 +9,7 @@ GEN('#include "ash/webui/personalization_app/test/personalization_app_browsertest_fixture.h"'); GEN('#include "ash/constants/ash_features.h"'); +GEN('#include "ash/public/cpp/ambient/ambient_client.h"'); GEN('#include "chromeos/constants/chromeos_features.h"'); GEN('#include "content/public/test/browser_test.h"'); @@ -91,29 +92,8 @@ const wallpaperPreview = document.querySelector('personalization-router') .shadowRoot.querySelector('personalization-main') .shadowRoot.querySelector('wallpaper-preview'); - const ambientPreview = document.querySelector('personalization-router') - .shadowRoot.querySelector('personalization-main') - .shadowRoot.querySelector('ambient-preview'); assertTrue(!!userPreview); assertTrue(!!wallpaperPreview); - assertTrue(!!ambientPreview); - testDone(); -}); - -TEST_F('PersonalizationAppBrowserTest', 'ShowsAmbientPreview', () => { - const preview = document.querySelector('personalization-router') - .shadowRoot.querySelector('personalization-main') - .shadowRoot.querySelector('ambient-preview'); - assertTrue(!!preview); - testDone(); -}); - -TEST_F('PersonalizationAppBrowserTest', 'ShowsAmbientSubpageLink', () => { - const ambientSubpageLink = - document.querySelector('personalization-router') - .shadowRoot.querySelector('personalization-main') - .shadowRoot.querySelector('#ambientSubpageLink'); - assertTrue(!!ambientSubpageLink); testDone(); }); @@ -146,6 +126,74 @@ testDone(); }); +class PersonalizationAppAmbientModeAllowedBrowserTest extends + PersonalizationAppBrowserTest { + /** @override */ + get testGenPreamble() { + return () => { + GEN('ash::AmbientClient::Get()->SetAmbientModeAllowedForTesting(true);'); + }; + } +} + +this[PersonalizationAppAmbientModeAllowedBrowserTest.name] = + PersonalizationAppAmbientModeAllowedBrowserTest; + +TEST_F( + 'PersonalizationAppAmbientModeAllowedBrowserTest', 'ShowsAmbientPreview', + () => { + const preview = document.querySelector('personalization-router') + .shadowRoot.querySelector('personalization-main') + .shadowRoot.querySelector('ambient-preview'); + assertTrue(!!preview); + testDone(); + }); + +TEST_F( + 'PersonalizationAppAmbientModeAllowedBrowserTest', + 'ShowsAmbientSubpageLink', () => { + const ambientSubpageLink = + document.querySelector('personalization-router') + .shadowRoot.querySelector('personalization-main') + .shadowRoot.querySelector('#ambientSubpageLink'); + assertTrue(!!ambientSubpageLink); + testDone(); + }); + +class PersonalizationAppAmbientModeDisllowedBrowserTest extends + PersonalizationAppBrowserTest { + /** @override */ + get testGenPreamble() { + return () => { + GEN('ash::AmbientClient::Get()->SetAmbientModeAllowedForTesting(false);'); + }; + } +} + +this[PersonalizationAppAmbientModeDisllowedBrowserTest.name] = + PersonalizationAppAmbientModeDisllowedBrowserTest; + +TEST_F( + 'PersonalizationAppAmbientModeDisllowedBrowserTest', + 'NotShowAmbientPreview', () => { + const preview = document.querySelector('personalization-router') + .shadowRoot.querySelector('personalization-main') + .shadowRoot.querySelector('ambient-preview'); + assertFalse(!!preview); + testDone(); + }); + +TEST_F( + 'PersonalizationAppAmbientModeDisllowedBrowserTest', + 'NotShowAmbientSubpageLink', () => { + const ambientSubpageLink = + document.querySelector('personalization-router') + .shadowRoot.querySelector('personalization-main') + .shadowRoot.querySelector('#ambientSubpageLink'); + assertFalse(!!ambientSubpageLink); + testDone(); + }); + class WallpaperSubpageBrowserTest extends PersonalizationAppBrowserTest { /** @override */ get browsePreload() {
diff --git a/ash/webui/shimless_rma/resources/onboarding_update_page.html b/ash/webui/shimless_rma/resources/onboarding_update_page.html index cd6b793..9ae97d7 100644 --- a/ash/webui/shimless_rma/resources/onboarding_update_page.html +++ b/ash/webui/shimless_rma/resources/onboarding_update_page.html
@@ -2,38 +2,45 @@ #performUpdateButton { border-color: var(--google-blue-600); } -</style> + #updateStatusDiv { + align-items: center; + display: flex; + } +</style> <base-page> <div slot="left-pane"> <h1>[[i18n('osUpdateTitleText')]]</h1> - <div hidden$="[[isCompliant_]]" class="instructions"> - <div inner-h-t-m-l="[[verificationFailedMessage_]]"></div> - <div>[[i18n('osUpdateUnqualifiedComponentsBottomText')]]</div> + <div id="updateInstructionsDiv" hidden$="[[updateInProgress_]]"> + <div hidden$="[[isCompliant_]]" class="instructions"> + <div inner-h-t-m-l="[[verificationFailedMessage_]]"></div> + <div>[[i18n('osUpdateUnqualifiedComponentsBottomText')]]</div> + </div> + <div hidden$="[[!isCompliant_]]" class="instructions"> + [[i18n('osUpdateOutOfDateDescriptionText')]] + </div> + <div id="versionInfo"> + <iron-icon id="updateIcon" class="small-icon" icon="shimless-icon:info"> + </iron-icon> + <span class="instructions">[[currentVersionText_]]</span> + </div> + <p id="networkUnavailable" hidden$="[[networkAvailable]]"> + [[i18n('onboardingUpdateConnectToInternet')]] + </p> + <cr-button id="performUpdateButton" disabled="[[allButtonsDisabled]]" + on-click="onUpdateButtonClicked_"> + [[updateVersionButtonLabel_]] + <iron-icon id="restartIcon" icon="shimless-icon:update" + class="small-icon"> + </iron-icon> + </cr-button> </div> - <div hidden$="[[!isCompliant_]]" class="instructions"> - [[i18n('osUpdateOutOfDateDescriptionText')]] - </div> - <div id="versionInfo"> - <iron-icon id="updateIcon" class="small-icon" icon="shimless-icon:info"> - </iron-icon> - <span class="instructions">[[currentVersionText_]]</span> - </div> - <div id="progressMessage"> - <paper-spinner-lite hidden$="[[!updateInProgress_]]" active> + <div id="updateStatusDiv" class="instructions" + hidden$="[[!updateInProgress_]]"> + <paper-spinner-lite class="small-spinner" active> </paper-spinner-lite> - <div class="instructions">[[updateProgressMessage_]]</div> + <span>[[i18n('updatingOsVersionText')]]</span> </div> - <p id="networkUnavailable" hidden$="[[networkAvailable]]"> - [[i18n('onboardingUpdateConnectToInternet')]] - </p> - <cr-button id="performUpdateButton" disabled="[[allButtonsDisabled]]" - on-click="onUpdateButtonClicked_"> - [[updateVersionButtonLabel_]] - <iron-icon id="restartIcon" icon="shimless-icon:update" - class="small-icon"> - </iron-icon> - </cr-button> </div> <div slot="right-pane"> <div class="illustration-wrapper">
diff --git a/ash/webui/shimless_rma/resources/onboarding_update_page.js b/ash/webui/shimless_rma/resources/onboarding_update_page.js index 1fc815cf..e6538a6 100644 --- a/ash/webui/shimless_rma/resources/onboarding_update_page.js +++ b/ash/webui/shimless_rma/resources/onboarding_update_page.js
@@ -77,12 +77,6 @@ value: '', }, - /** @protected */ - updateProgressMessage_: { - type: String, - value: '', - }, - /** * TODO(joonbug): populate this and make private. */ @@ -179,7 +173,6 @@ this.updateInProgress_ = true; this.shimlessRmaService_.updateOs().then((res) => { if (!res.updateStarted) { - this.updateProgressMessage_ = this.i18n('osUpdateFailedToStartText'); this.updateInProgress_ = false; } }); @@ -200,15 +193,13 @@ if (!this.updateInProgress_) { return; } + if (operation === OsUpdateOperation.kIdle || operation === OsUpdateOperation.kReportingErrorEvent || operation === OsUpdateOperation.kNeedPermissionToUpdate || operation === OsUpdateOperation.kDisabled) { this.updateInProgress_ = false; } - this.updateProgressMessage_ = this.i18n( - 'onboardingUpdateProgress', this.i18n(operationNameKeys[operation]), - Math.round(progress * 100)); } /**
diff --git a/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html b/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html index 346cb75..03a47b36 100644 --- a/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html +++ b/ash/webui/shimless_rma/resources/shimless_rma_shared_css.html
@@ -41,6 +41,12 @@ width: 286px; } + .small-spinner { + height: 20px; + padding-inline-end: 8px; + width: 20px; + } + h1 { color: var(--shimless-title-text-color); font-family: var(--shimless-title-font-family);
diff --git a/ash/webui/shimless_rma/shimless_rma.cc b/ash/webui/shimless_rma/shimless_rma.cc index 141897f1..8559b1ca 100644 --- a/ash/webui/shimless_rma/shimless_rma.cc +++ b/ash/webui/shimless_rma/shimless_rma.cc
@@ -130,6 +130,7 @@ IDS_SHIMLESS_RMA_CURRENT_VERSION_UP_TO_DATE}, {"updateVersionRestartLabel", IDS_SHIMLESS_RMA_UPDATE_VERSION_AND_RESTART}, + {"updatingOsVersionText", IDS_SHIMLESS_RMA_UPDATING_OS_VERSION}, // Choose WP disable method page {"chooseWpDisableMethodPageTitleText", IDS_SHIMLESS_RMA_CHOOSE_WP_DISABLE_METHOD_PAGE_TITLE},
diff --git a/base/BUILD.gn b/base/BUILD.gn index 4b4eb780..46d1d5c 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -117,22 +117,6 @@ ] } -config("memory_tagging") { - if (current_cpu == "arm64" && is_clang && - (is_linux || is_chromeos || is_android || is_fuchsia)) { - # base/ has access to the MTE intrinsics because it needs to use them, - # but they're not backwards compatible. Use base::CPU::has_mte() - # beforehand to confirm or use indirect functions (ifuncs) to select - # an MTE-specific implementation at dynamic link-time. - cflags = [ - "-Xclang", - "-target-feature", - "-Xclang", - "+mte", - ] - } -} - config("base_implementation") { defines = [ "BASE_IMPLEMENTATION" ] configs = [ "//build/config/compiler:wexit_time_destructors" ] @@ -1418,7 +1402,6 @@ configs += [ ":base_implementation", - ":memory_tagging", "//build/config:precompiled_headers", "//build/config/compiler:wglobal_constructors", ] @@ -1502,10 +1485,14 @@ sources += [ "allocator/allocator_shim.cc", "allocator/allocator_shim.h", - "allocator/allocator_shim_default_dispatch_to_partition_alloc.cc", - "allocator/allocator_shim_default_dispatch_to_partition_alloc.h", "allocator/allocator_shim_internals.h", ] + if (use_partition_alloc) { + sources += [ + "allocator/allocator_shim_default_dispatch_to_partition_alloc.cc", + "allocator/allocator_shim_default_dispatch_to_partition_alloc.h", + ] + } if (is_android) { sources += [ "allocator/allocator_shim_override_cpp_symbols.h", @@ -2002,127 +1989,14 @@ "allocator/partition_alloc_features.h", "allocator/partition_alloc_support.cc", "allocator/partition_alloc_support.h", - "allocator/partition_allocator/address_pool_manager.cc", - "allocator/partition_allocator/address_pool_manager.h", - "allocator/partition_allocator/address_pool_manager_bitmap.cc", - "allocator/partition_allocator/address_pool_manager_bitmap.h", - "allocator/partition_allocator/address_pool_manager_types.h", - "allocator/partition_allocator/address_space_randomization.cc", - "allocator/partition_allocator/address_space_randomization.h", - "allocator/partition_allocator/address_space_stats.h", - "allocator/partition_allocator/allocation_guard.cc", - "allocator/partition_allocator/allocation_guard.h", - "allocator/partition_allocator/dangling_raw_ptr_checks.cc", - "allocator/partition_allocator/dangling_raw_ptr_checks.h", - "allocator/partition_allocator/extended_api.cc", - "allocator/partition_allocator/extended_api.h", - "allocator/partition_allocator/memory_reclaimer.cc", - "allocator/partition_allocator/memory_reclaimer.h", - "allocator/partition_allocator/oom.cc", - "allocator/partition_allocator/oom.h", - "allocator/partition_allocator/oom_callback.cc", - "allocator/partition_allocator/oom_callback.h", - "allocator/partition_allocator/page_allocator.cc", - "allocator/partition_allocator/page_allocator.h", - "allocator/partition_allocator/page_allocator_constants.h", - "allocator/partition_allocator/page_allocator_internal.h", - "allocator/partition_allocator/partition_address_space.cc", - "allocator/partition_allocator/partition_address_space.h", - "allocator/partition_allocator/partition_alloc-inl.h", - "allocator/partition_allocator/partition_alloc.cc", - "allocator/partition_allocator/partition_alloc.h", - "allocator/partition_allocator/partition_alloc_check.h", - "allocator/partition_allocator/partition_alloc_config.h", - "allocator/partition_allocator/partition_alloc_constants.h", - "allocator/partition_allocator/partition_alloc_forward.h", - "allocator/partition_allocator/partition_alloc_hooks.cc", - "allocator/partition_allocator/partition_alloc_hooks.h", - "allocator/partition_allocator/partition_alloc_notreached.h", - "allocator/partition_allocator/partition_bucket.cc", - "allocator/partition_allocator/partition_bucket.h", - "allocator/partition_allocator/partition_bucket_lookup.h", - "allocator/partition_allocator/partition_cookie.h", - "allocator/partition_allocator/partition_direct_map_extent.h", - "allocator/partition_allocator/partition_freelist_entry.h", - "allocator/partition_allocator/partition_lock.h", - "allocator/partition_allocator/partition_oom.cc", - "allocator/partition_allocator/partition_oom.h", - "allocator/partition_allocator/partition_page.cc", - "allocator/partition_allocator/partition_page.h", - "allocator/partition_allocator/partition_ref_count.h", - "allocator/partition_allocator/partition_root.cc", - "allocator/partition_allocator/partition_root.h", - "allocator/partition_allocator/partition_stats.cc", - "allocator/partition_allocator/partition_stats.h", - "allocator/partition_allocator/partition_tag.h", - "allocator/partition_allocator/partition_tag_bitmap.h", - "allocator/partition_allocator/partition_tls.h", - "allocator/partition_allocator/random.cc", - "allocator/partition_allocator/random.h", - "allocator/partition_allocator/reservation_offset_table.cc", - "allocator/partition_allocator/reservation_offset_table.h", - "allocator/partition_allocator/spinning_mutex.cc", - "allocator/partition_allocator/spinning_mutex.h", - "allocator/partition_allocator/starscan/logging.h", - "allocator/partition_allocator/starscan/metadata_allocator.cc", - "allocator/partition_allocator/starscan/metadata_allocator.h", - "allocator/partition_allocator/starscan/pcscan.cc", - "allocator/partition_allocator/starscan/pcscan.h", - "allocator/partition_allocator/starscan/pcscan_internal.cc", - "allocator/partition_allocator/starscan/pcscan_internal.h", - "allocator/partition_allocator/starscan/pcscan_scheduling.cc", - "allocator/partition_allocator/starscan/pcscan_scheduling.h", - "allocator/partition_allocator/starscan/raceful_worklist.h", - "allocator/partition_allocator/starscan/scan_loop.h", - "allocator/partition_allocator/starscan/snapshot.cc", - "allocator/partition_allocator/starscan/snapshot.h", - "allocator/partition_allocator/starscan/stack/stack.cc", - "allocator/partition_allocator/starscan/stack/stack.h", - "allocator/partition_allocator/starscan/starscan_fwd.h", - "allocator/partition_allocator/starscan/state_bitmap.h", - "allocator/partition_allocator/starscan/stats_collector.cc", - "allocator/partition_allocator/starscan/stats_collector.h", - "allocator/partition_allocator/starscan/stats_reporter.h", - "allocator/partition_allocator/starscan/write_protector.cc", - "allocator/partition_allocator/starscan/write_protector.h", - "allocator/partition_allocator/tagging.cc", - "allocator/partition_allocator/tagging.h", - "allocator/partition_allocator/thread_cache.cc", - "allocator/partition_allocator/thread_cache.h", - "allocator/partition_allocator/yield_processor.h", ] - if (is_win) { - sources += [ - "allocator/partition_allocator/page_allocator_internals_win.h", - "allocator/partition_allocator/partition_tls_win.cc", - ] - } else if (is_posix) { - sources += [ - "allocator/partition_allocator/page_allocator_internals_posix.cc", - "allocator/partition_allocator/page_allocator_internals_posix.h", - ] - } else if (is_fuchsia) { - sources += [ - "allocator/partition_allocator/page_allocator_internals_fuchsia.h", - ] - } - - if (current_cpu == "x64") { - defines += [ "PA_PCSCAN_STACK_SUPPORTED" ] - sources += [ "allocator/partition_allocator/starscan/stack/asm/x64/push_registers_asm.cc" ] - } else if (current_cpu == "x86") { - defines += [ "PA_PCSCAN_STACK_SUPPORTED" ] - sources += [ "allocator/partition_allocator/starscan/stack/asm/x86/push_registers_asm.cc" ] - } else if (current_cpu == "arm") { - defines += [ "PA_PCSCAN_STACK_SUPPORTED" ] - sources += [ "allocator/partition_allocator/starscan/stack/asm/arm/push_registers_asm.cc" ] - } else if (current_cpu == "arm64") { - defines += [ "PA_PCSCAN_STACK_SUPPORTED" ] - sources += [ "allocator/partition_allocator/starscan/stack/asm/arm64/push_registers_asm.cc" ] - } else { - # To support a trampoline for another arch, please refer to v8/src/heap/base. - } } + + # Need this to pass gn check, because gn check doesn't see + # BUILDFLAG(USE_PARTITION_ALLOC). A linker will remove all + # partition_alloc code if use_partition_alloc = false because no code uses + # partition_alloc. + public_deps += [ "allocator/partition_allocator:partition_alloc" ] } # Windows. @@ -3934,8 +3808,6 @@ ] deps += [ "//build/rust:cxx_cppdeps" ] } - - configs += [ ":memory_tagging" ] } action("build_date") {
diff --git a/base/allocator/partition_allocator/BUILD.gn b/base/allocator/partition_allocator/BUILD.gn new file mode 100644 index 0000000..cc5bf37 --- /dev/null +++ b/base/allocator/partition_allocator/BUILD.gn
@@ -0,0 +1,206 @@ +# 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. + +import("//base/allocator/allocator.gni") + +# Add partition_alloc.gni and import it for partition_alloc configs. + +config("partition_alloc_implementation") { + # After introducing partition_alloc_export, replace BASE_IMPLEMENTATION with + # PARTITION_ALLOC_IMPLEMENTATION. + defines = [ "BASE_IMPLEMENTATION" ] +} + +config("memory_tagging") { + if (current_cpu == "arm64" && is_clang && + (is_linux || is_chromeos || is_android || is_fuchsia)) { + # base/ has access to the MTE intrinsics because it needs to use them, + # but they're not backwards compatible. Use base::CPU::has_mte() + # beforehand to confirm or use indirect functions (ifuncs) to select + # an MTE-specific implementation at dynamic link-time. + cflags = [ + "-Xclang", + "-target-feature", + "-Xclang", + "+mte", + ] + } +} + +if (is_fuchsia) { + config("fuchsia_sync_lib") { + libs = [ + "sync", # Used by spinning_mutex.h. + ] + } +} + +# TODO(crbug.com/1151236): Add component("base") for partition_alloc +# base, and make partition_alloc standalone library depend on it. + +# TODO(crbug.com/1151236): Add component("partition_alloc") to build +# partition_alloc as a standalone_library. +source_set("partition_alloc") { + sources = [ + "address_pool_manager.cc", + "address_pool_manager.h", + "address_pool_manager_bitmap.cc", + "address_pool_manager_bitmap.h", + "address_pool_manager_types.h", + "address_space_randomization.cc", + "address_space_randomization.h", + "address_space_stats.h", + "allocation_guard.cc", + "allocation_guard.h", + "dangling_raw_ptr_checks.cc", + "dangling_raw_ptr_checks.h", + "extended_api.cc", + "extended_api.h", + "memory_reclaimer.cc", + "memory_reclaimer.h", + "oom.cc", + "oom.h", + "oom_callback.cc", + "oom_callback.h", + "page_allocator.cc", + "page_allocator.h", + "page_allocator_constants.h", + "page_allocator_internal.h", + "partition_address_space.cc", + "partition_address_space.h", + "partition_alloc-inl.h", + "partition_alloc.cc", + "partition_alloc.h", + "partition_alloc_check.h", + "partition_alloc_config.h", + "partition_alloc_constants.h", + "partition_alloc_forward.h", + "partition_alloc_hooks.cc", + "partition_alloc_hooks.h", + "partition_alloc_notreached.h", + "partition_bucket.cc", + "partition_bucket.h", + "partition_bucket_lookup.h", + "partition_cookie.h", + "partition_direct_map_extent.h", + "partition_freelist_entry.h", + "partition_lock.h", + "partition_oom.cc", + "partition_oom.h", + "partition_page.cc", + "partition_page.h", + "partition_ref_count.h", + "partition_root.cc", + "partition_root.h", + "partition_stats.cc", + "partition_stats.h", + "partition_tag.h", + "partition_tag_bitmap.h", + "partition_tls.h", + "random.cc", + "random.h", + "reservation_offset_table.cc", + "reservation_offset_table.h", + "spinning_mutex.cc", + "spinning_mutex.h", + "starscan/logging.h", + "starscan/metadata_allocator.cc", + "starscan/metadata_allocator.h", + "starscan/pcscan.cc", + "starscan/pcscan.h", + "starscan/pcscan_internal.cc", + "starscan/pcscan_internal.h", + "starscan/pcscan_scheduling.cc", + "starscan/pcscan_scheduling.h", + "starscan/raceful_worklist.h", + "starscan/scan_loop.h", + "starscan/snapshot.cc", + "starscan/snapshot.h", + "starscan/stack/stack.cc", + "starscan/stack/stack.h", + "starscan/starscan_fwd.h", + "starscan/state_bitmap.h", + "starscan/stats_collector.cc", + "starscan/stats_collector.h", + "starscan/stats_reporter.h", + "starscan/write_protector.cc", + "starscan/write_protector.h", + "tagging.cc", + "tagging.h", + "thread_cache.cc", + "thread_cache.h", + "yield_processor.h", + ] + defines = [] + if (is_win) { + sources += [ + "page_allocator_internals_win.h", + "partition_tls_win.cc", + ] + } else if (is_posix) { + sources += [ + "page_allocator_internals_posix.cc", + "page_allocator_internals_posix.h", + ] + } else if (is_fuchsia) { + sources += [ "page_allocator_internals_fuchsia.h" ] + } + if (current_cpu == "x64") { + defines += [ "PA_PCSCAN_STACK_SUPPORTED" ] + sources += [ "starscan/stack/asm/x64/push_registers_asm.cc" ] + } else if (current_cpu == "x86") { + defines += [ "PA_PCSCAN_STACK_SUPPORTED" ] + sources += [ "starscan/stack/asm/x86/push_registers_asm.cc" ] + } else if (current_cpu == "arm") { + defines += [ "PA_PCSCAN_STACK_SUPPORTED" ] + sources += [ "starscan/stack/asm/arm/push_registers_asm.cc" ] + } else if (current_cpu == "arm64") { + defines += [ "PA_PCSCAN_STACK_SUPPORTED" ] + sources += [ "starscan/stack/asm/arm64/push_registers_asm.cc" ] + } else { + # To support a trampoline for another arch, please refer to v8/src/heap/base. + } + public_deps = [ + "//base:debugging_buildflags", + "//base:logging_buildflags", + "//base:synchronization_buildflags", + "//base:tracing_buildflags", + "//base/allocator:buildflags", + "//build:branding_buildflags", + "//build:chromecast_buildflags", + "//build:chromeos_buildflags", + "//build/config/compiler:compiler_buildflags", + ] + deps = [] + configs += [ + ":partition_alloc_implementation", + ":memory_tagging", + ] + public_configs = [] + if (is_android) { + # tagging.cc requires __arm_mte_set_* functions. + deps += [ "//third_party/android_ndk:cpu_features" ] + } + if (is_fuchsia) { + public_deps += [ + "//third_party/fuchsia-sdk/sdk/pkg/fit", + "//third_party/fuchsia-sdk/sdk/pkg/sync", + "//third_party/fuchsia-sdk/sdk/pkg/zx", + ] + + # Needed for users of spinning_mutex.h, which for performance reasons, + # contains inlined calls to `libsync` inside the header file. + # It appends an entry to the "libs" section of the dependent target. + public_configs += [ ":fuchsia_sync_lib" ] + } + + frameworks = [] + if (is_mac) { + # SecTaskGetCodeSignStatus needs: + frameworks += [ "Security.framework" ] + } +} +# TODO(crbug.com/1151236): After making partition_alloc a standalone library, +# move test code here. i.e. test("partition_alloc_tests") { ... } and +# test("partition_alloc_perftests").
diff --git a/base/allocator/partition_allocator/allocation_guard.h b/base/allocator/partition_allocator/allocation_guard.h index c05f5974..ebbe83bf 100644 --- a/base/allocator/partition_allocator/allocation_guard.h +++ b/base/allocator/partition_allocator/allocation_guard.h
@@ -6,6 +6,7 @@ #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_ALLOCATION_GUARD_H_ #include "base/allocator/partition_allocator/partition_alloc_config.h" +#include "base/base_export.h" #include "build/build_config.h" namespace partition_alloc { @@ -13,14 +14,14 @@ #if defined(PA_HAS_ALLOCATION_GUARD) // Disallow allocations in the scope. Does not nest. -class ScopedDisallowAllocations { +class BASE_EXPORT ScopedDisallowAllocations { public: ScopedDisallowAllocations(); ~ScopedDisallowAllocations(); }; // Disallow allocations in the scope. Does not nest. -class ScopedAllowAllocations { +class BASE_EXPORT ScopedAllowAllocations { public: ScopedAllowAllocations(); ~ScopedAllowAllocations();
diff --git a/base/allocator/partition_allocator/partition_alloc_check.h b/base/allocator/partition_allocator/partition_alloc_check.h index a4aef54..b60d978 100644 --- a/base/allocator/partition_allocator/partition_alloc_check.h +++ b/base/allocator/partition_allocator/partition_alloc_check.h
@@ -12,6 +12,7 @@ #include "base/check.h" #include "base/debug/alias.h" #include "base/immediate_crash.h" +#include "build/build_config.h" #define PA_STRINGIFY_IMPL(s) #s #define PA_STRINGIFY(s) PA_STRINGIFY_IMPL(s) @@ -96,10 +97,19 @@ #endif +// alignas(16) DebugKv causes breakpad_unittests and sandbox_linux_unittests +// failures on android-marshmallow-x86-rel because of SIGSEGV. +#if BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_X86_FAMILY) && \ + defined(ARCH_CPU_32_BITS) +#define PA_DEBUGKV_ALIGN alignas(8) +#else +#define PA_DEBUGKV_ALIGN alignas(16) +#endif + namespace partition_alloc::internal { // Used for PA_DEBUG_DATA_ON_STACK, below. -struct alignas(16) DebugKv { +struct PA_DEBUGKV_ALIGN DebugKv { // 16 bytes object aligned on 16 bytes, to make it easier to see in crash // reports. char k[8] = {}; // Not necessarily 0-terminated.
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc index 163cad5..22edeec 100644 --- a/base/trace_event/malloc_dump_provider.cc +++ b/base/trace_event/malloc_dump_provider.cc
@@ -100,7 +100,9 @@ if (pmd) { MemoryAllocatorDump* win_heap_dump = pmd->CreateAllocatorDump("malloc/win_heap"); - win_heap_dump->AddScalar("size", "bytes", main_heap_info.allocated_size); + win_heap_dump->AddScalar(MemoryAllocatorDump::kNameSize, + MemoryAllocatorDump::kUnitsBytes, + main_heap_info.allocated_size); } } } @@ -146,6 +148,134 @@ } #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) +#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(IS_APPLE) +void ReportAppleAllocStats(size_t* total_virtual_size, + size_t* resident_size, + size_t* allocated_objects_size) { + malloc_statistics_t stats = {0}; + malloc_zone_statistics(nullptr, &stats); + *total_virtual_size += stats.size_allocated; + *allocated_objects_size += stats.size_in_use; + + // Resident size is approximated pretty well by stats.max_size_in_use. + // However, on macOS, freed blocks are both resident and reusable, which is + // semantically equivalent to deallocated. The implementation of libmalloc + // will also only hold a fixed number of freed regions before actually + // starting to deallocate them, so stats.max_size_in_use is also not + // representative of the peak size. As a result, stats.max_size_in_use is + // typically somewhere between actually resident [non-reusable] pages, and + // peak size. This is not very useful, so we just use stats.size_in_use for + // resident_size, even though it's an underestimate and fails to account for + // fragmentation. See + // https://bugs.chromium.org/p/chromium/issues/detail?id=695263#c1. + *resident_size += stats.size_in_use; +} +#endif + +#if (BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(IS_ANDROID)) || \ + (!BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && !BUILDFLAG(IS_WIN) && \ + !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_FUCHSIA)) +void ReportMallinfoStats(ProcessMemoryDump* pmd, + size_t* total_virtual_size, + size_t* resident_size, + size_t* allocated_objects_size, + size_t* allocated_objects_count) { +#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) +#if __GLIBC_PREREQ(2, 33) +#define MALLINFO2_FOUND_IN_LIBC + struct mallinfo2 info = mallinfo2(); +#endif +#endif // defined(__GLIBC__) && defined(__GLIBC_PREREQ) +#if !defined(MALLINFO2_FOUND_IN_LIBC) + struct mallinfo info = mallinfo(); +#endif +#undef MALLINFO2_FOUND_IN_LIBC + // In case of Android's jemalloc |arena| is 0 and the outer pages size is + // reported by |hblkhd|. In case of dlmalloc the total is given by + // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF. + *total_virtual_size += info.arena + info.hblkhd; + *resident_size += info.uordblks; + + // Total allocated space is given by |uordblks|. + *allocated_objects_size += info.uordblks; + + if (pmd) { + MemoryAllocatorDump* sys_alloc_dump = + pmd->CreateAllocatorDump("malloc/sys_malloc"); + sys_alloc_dump->AddScalar(MemoryAllocatorDump::kNameSize, + MemoryAllocatorDump::kUnitsBytes, info.uordblks); + } +} +#endif + +#if BUILDFLAG(USE_PARTITION_ALLOC) +void ReportPartitionAllocThreadCacheStats(ProcessMemoryDump* pmd, + MemoryAllocatorDump* dump, + const ThreadCacheStats& stats, + const std::string& metrics_suffix, + bool detailed) { + dump->AddScalar("alloc_count", MemoryAllocatorDump::kTypeScalar, + stats.alloc_count); + dump->AddScalar("alloc_hits", MemoryAllocatorDump::kTypeScalar, + stats.alloc_hits); + dump->AddScalar("alloc_misses", MemoryAllocatorDump::kTypeScalar, + stats.alloc_misses); + + dump->AddScalar("alloc_miss_empty", MemoryAllocatorDump::kTypeScalar, + stats.alloc_miss_empty); + dump->AddScalar("alloc_miss_too_large", MemoryAllocatorDump::kTypeScalar, + stats.alloc_miss_too_large); + + dump->AddScalar("cache_fill_count", MemoryAllocatorDump::kTypeScalar, + stats.cache_fill_count); + dump->AddScalar("cache_fill_hits", MemoryAllocatorDump::kTypeScalar, + stats.cache_fill_hits); + dump->AddScalar("cache_fill_misses", MemoryAllocatorDump::kTypeScalar, + stats.cache_fill_misses); + + dump->AddScalar("batch_fill_count", MemoryAllocatorDump::kTypeScalar, + stats.batch_fill_count); + + dump->AddScalar(MemoryAllocatorDump::kNameSize, + MemoryAllocatorDump::kUnitsBytes, stats.bucket_total_memory); + dump->AddScalar("metadata_overhead", MemoryAllocatorDump::kUnitsBytes, + stats.metadata_overhead); + + if (stats.alloc_count) { + int hit_rate_percent = + static_cast<int>((100 * stats.alloc_hits) / stats.alloc_count); + base::UmaHistogramPercentage( + "Memory.PartitionAlloc.ThreadCache.HitRate" + metrics_suffix, + hit_rate_percent); + int batch_fill_rate_percent = + static_cast<int>((100 * stats.batch_fill_count) / stats.alloc_count); + base::UmaHistogramPercentage( + "Memory.PartitionAlloc.ThreadCache.BatchFillRate" + metrics_suffix, + batch_fill_rate_percent); + +#if defined(PA_THREAD_CACHE_ALLOC_STATS) + if (detailed) { + base::internal::BucketIndexLookup lookup{}; + std::string name = dump->absolute_name(); + for (size_t i = 0; i < kNumBuckets; i++) { + size_t bucket_size = lookup.bucket_sizes()[i]; + if (bucket_size == kInvalidBucketSize) + continue; + // Covers all normal buckets, that is up to ~1MiB, so 7 digits. + std::string dump_name = + base::StringPrintf("%s/buckets_alloc/%07d", name.c_str(), + static_cast<int>(bucket_size)); + auto* buckets_alloc_dump = pmd->CreateAllocatorDump(dump_name); + buckets_alloc_dump->AddScalar("count", + MemoryAllocatorDump::kUnitsObjects, + stats.allocs_per_bucket_[i]); + } + } +#endif // defined(PA_THREAD_CACHE_ALLOC_STATS) + } +} +#endif // BUILDFLAG(USE_PARTITION_ALLOC) + } // namespace // static @@ -166,16 +296,17 @@ ProcessMemoryDump* pmd) { { base::AutoLock auto_lock(emit_metrics_on_memory_dump_lock_); - if (!emit_metrics_on_memory_dump_) + if (!emit_metrics_on_memory_dump_) { return true; + } } size_t total_virtual_size = 0; size_t resident_size = 0; size_t allocated_objects_size = 0; size_t allocated_objects_count = 0; -#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) uint64_t syscall_count = 0; +#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) uint64_t pa_only_resident_size; uint64_t pa_only_allocated_objects_size; #endif @@ -188,32 +319,20 @@ pa_only_resident_size = resident_size; pa_only_allocated_objects_size = allocated_objects_size; - // Even when PartitionAlloc is used, WinHeap is still used as well, report - // its statistics. -#if OS_WIN + // Even when PartitionAlloc is used, WinHeap / System malloc is still used as + // well, report its statistics. +#if BUILDFLAG(IS_ANDROID) + ReportMallinfoStats(pmd, &total_virtual_size, &resident_size, + &allocated_objects_size, &allocated_objects_count); +#elif BUILDFLAG(IS_WIN) ReportWinHeapStats(args.level_of_detail, pmd, &total_virtual_size, &resident_size, &allocated_objects_size, &allocated_objects_count); -#endif - // TODO(keishi): Add glibc malloc on Android -#elif BUILDFLAG(IS_APPLE) - malloc_statistics_t stats = {0}; - malloc_zone_statistics(nullptr, &stats); - total_virtual_size = stats.size_allocated; - allocated_objects_size = stats.size_in_use; +#endif // BUILDFLAG(IS_ANDROID), BUILDFLAG(IS_WIN) - // Resident size is approximated pretty well by stats.max_size_in_use. - // However, on macOS, freed blocks are both resident and reusable, which is - // semantically equivalent to deallocated. The implementation of libmalloc - // will also only hold a fixed number of freed regions before actually - // starting to deallocate them, so stats.max_size_in_use is also not - // representative of the peak size. As a result, stats.max_size_in_use is - // typically somewhere between actually resident [non-reusable] pages, and - // peak size. This is not very useful, so we just use stats.size_in_use for - // resident_size, even though it's an underestimate and fails to account for - // fragmentation. See - // https://bugs.chromium.org/p/chromium/issues/detail?id=695263#c1. - resident_size = stats.size_in_use; +#elif BUILDFLAG(IS_APPLE) + ReportAppleAllocStats(&total_virtual_size, &resident_size, + &allocated_objects_size); #elif BUILDFLAG(IS_WIN) ReportWinHeapStats(args.level_of_detail, nullptr, &total_virtual_size, &resident_size, &allocated_objects_size, @@ -221,24 +340,8 @@ #elif BUILDFLAG(IS_FUCHSIA) // TODO(fuchsia): Port, see https://crbug.com/706592. #else -#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) -#if __GLIBC_PREREQ(2, 33) -#define MALLINFO2_FOUND_IN_LIBC - struct mallinfo2 info = mallinfo2(); -#endif -#endif // defined(__GLIBC__) && defined(__GLIBC_PREREQ) -#if !defined(MALLINFO2_FOUND_IN_LIBC) - struct mallinfo info = mallinfo(); -#endif -#undef MALLINFO2_FOUND_IN_LIBC - // In case of Android's jemalloc |arena| is 0 and the outer pages size is - // reported by |hblkhd|. In case of dlmalloc the total is given by - // |arena| + |hblkhd|. For more details see link: http://goo.gl/fMR8lF. - total_virtual_size = info.arena + info.hblkhd; - resident_size = info.uordblks; - - // Total allocated space is given by |uordblks|. - allocated_objects_size = info.uordblks; + ReportMallinfoStats(/*pmd=*/nullptr, &total_virtual_size, &resident_size, + &allocated_objects_size, &allocated_objects_count); #endif MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc"); @@ -287,29 +390,24 @@ MemoryAllocatorDump::kUnitsBytes, waste); } + ReportSyscallCount(syscall_count, outer_dump); + + return true; +} + +void MallocDumpProvider::ReportSyscallCount(uint64_t syscall_count, + MemoryAllocatorDump* malloc_dump) { #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) uint64_t new_syscalls = syscall_count - last_syscall_count_; base::TimeDelta time_since_last_dump = base::TimeTicks::Now() - last_memory_dump_time_; uint64_t syscalls_per_minute = static_cast<uint64_t>( (60 * new_syscalls) / time_since_last_dump.InSecondsF()); - outer_dump->AddScalar("syscalls_per_minute", "count", syscalls_per_minute); + malloc_dump->AddScalar("syscalls_per_minute", "count", syscalls_per_minute); last_memory_dump_time_ = base::TimeTicks::Now(); last_syscall_count_ = syscall_count; #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) - - return true; -} - -void MallocDumpProvider::EnableMetrics() { - base::AutoLock auto_lock(emit_metrics_on_memory_dump_lock_); - emit_metrics_on_memory_dump_ = true; -} - -void MallocDumpProvider::DisableMetrics() { - base::AutoLock auto_lock(emit_metrics_on_memory_dump_lock_); - emit_metrics_on_memory_dump_ = false; } #if BUILDFLAG(USE_PARTITION_ALLOC) @@ -342,26 +440,34 @@ size_t fragmentation = total_committed_bytes == 0 ? 0 : 100 * wasted / total_committed_bytes; - allocator_dump->AddScalar("size", "bytes", + allocator_dump->AddScalar(MemoryAllocatorDump::kNameSize, + MemoryAllocatorDump::kUnitsBytes, memory_stats->total_resident_bytes); - allocator_dump->AddScalar("allocated_objects_size", "bytes", + allocator_dump->AddScalar("allocated_objects_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->total_active_bytes); - allocator_dump->AddScalar("virtual_size", "bytes", + allocator_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes, memory_stats->total_mmapped_bytes); - allocator_dump->AddScalar("virtual_committed_size", "bytes", + allocator_dump->AddScalar("virtual_committed_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->total_committed_bytes); - allocator_dump->AddScalar("max_committed_size", "bytes", + allocator_dump->AddScalar("max_committed_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->max_committed_bytes); - allocator_dump->AddScalar("allocated_size", "bytes", + allocator_dump->AddScalar("allocated_size", MemoryAllocatorDump::kUnitsBytes, memory_stats->total_allocated_bytes); - allocator_dump->AddScalar("max_allocated_size", "bytes", + allocator_dump->AddScalar("max_allocated_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->max_allocated_bytes); - allocator_dump->AddScalar("decommittable_size", "bytes", + allocator_dump->AddScalar("decommittable_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->total_decommittable_bytes); - allocator_dump->AddScalar("discardable_size", "bytes", + allocator_dump->AddScalar("discardable_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->total_discardable_bytes); #if BUILDFLAG(USE_BACKUP_REF_PTR) - allocator_dump->AddScalar("brp_quarantined_size", "bytes", + allocator_dump->AddScalar("brp_quarantined_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->total_brp_quarantined_bytes); allocator_dump->AddScalar("brp_quarantined_count", "count", memory_stats->total_brp_quarantined_count); @@ -371,7 +477,7 @@ allocator_dump->AddScalar("syscall_total_time_ms", "ms", memory_stats->syscall_total_time_ns / 1e6); allocator_dump->AddScalar("fragmentation", "percent", fragmentation); - allocator_dump->AddScalar("wasted", "bytes", wasted); + allocator_dump->AddScalar("wasted", MemoryAllocatorDump::kUnitsBytes, wasted); if (memory_stats->has_thread_cache) { const auto& thread_cache_stats = memory_stats->current_thread_cache_stats; @@ -405,81 +511,37 @@ MemoryAllocatorDump* allocator_dump = memory_dump_->CreateAllocatorDump(dump_name); - allocator_dump->AddScalar("size", "bytes", memory_stats->resident_bytes); - allocator_dump->AddScalar("allocated_objects_size", "bytes", + allocator_dump->AddScalar(MemoryAllocatorDump::kNameSize, + MemoryAllocatorDump::kUnitsBytes, + memory_stats->resident_bytes); + allocator_dump->AddScalar("allocated_objects_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->active_bytes); - allocator_dump->AddScalar("slot_size", "bytes", + allocator_dump->AddScalar("slot_size", MemoryAllocatorDump::kUnitsBytes, memory_stats->bucket_slot_size); - allocator_dump->AddScalar("decommittable_size", "bytes", + allocator_dump->AddScalar("decommittable_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->decommittable_bytes); - allocator_dump->AddScalar("discardable_size", "bytes", + allocator_dump->AddScalar("discardable_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->discardable_bytes); // TODO(bartekn): Rename the scalar names. - allocator_dump->AddScalar("total_slot_span_size", "bytes", + allocator_dump->AddScalar("total_slot_span_size", + MemoryAllocatorDump::kUnitsBytes, memory_stats->allocated_slot_span_size); - allocator_dump->AddScalar("active_slot_spans", "objects", + allocator_dump->AddScalar("active_slot_spans", + MemoryAllocatorDump::kUnitsObjects, memory_stats->num_active_slot_spans); - allocator_dump->AddScalar("full_slot_spans", "objects", + allocator_dump->AddScalar("full_slot_spans", + MemoryAllocatorDump::kUnitsObjects, memory_stats->num_full_slot_spans); - allocator_dump->AddScalar("empty_slot_spans", "objects", + allocator_dump->AddScalar("empty_slot_spans", + MemoryAllocatorDump::kUnitsObjects, memory_stats->num_empty_slot_spans); - allocator_dump->AddScalar("decommitted_slot_spans", "objects", + allocator_dump->AddScalar("decommitted_slot_spans", + MemoryAllocatorDump::kUnitsObjects, memory_stats->num_decommitted_slot_spans); } - -void ReportPartitionAllocThreadCacheStats(ProcessMemoryDump* pmd, - MemoryAllocatorDump* dump, - const ThreadCacheStats& stats, - const std::string& metrics_suffix, - bool detailed) { - dump->AddScalar("alloc_count", "scalar", stats.alloc_count); - dump->AddScalar("alloc_hits", "scalar", stats.alloc_hits); - dump->AddScalar("alloc_misses", "scalar", stats.alloc_misses); - - dump->AddScalar("alloc_miss_empty", "scalar", stats.alloc_miss_empty); - dump->AddScalar("alloc_miss_too_large", "scalar", stats.alloc_miss_too_large); - - dump->AddScalar("cache_fill_count", "scalar", stats.cache_fill_count); - dump->AddScalar("cache_fill_hits", "scalar", stats.cache_fill_hits); - dump->AddScalar("cache_fill_misses", "scalar", stats.cache_fill_misses); - - dump->AddScalar("batch_fill_count", "scalar", stats.batch_fill_count); - - dump->AddScalar("size", "bytes", stats.bucket_total_memory); - dump->AddScalar("metadata_overhead", "bytes", stats.metadata_overhead); - - if (stats.alloc_count) { - int hit_rate_percent = - static_cast<int>((100 * stats.alloc_hits) / stats.alloc_count); - base::UmaHistogramPercentage( - "Memory.PartitionAlloc.ThreadCache.HitRate" + metrics_suffix, - hit_rate_percent); - int batch_fill_rate_percent = - static_cast<int>((100 * stats.batch_fill_count) / stats.alloc_count); - base::UmaHistogramPercentage( - "Memory.PartitionAlloc.ThreadCache.BatchFillRate" + metrics_suffix, - batch_fill_rate_percent); - -#if defined(PA_THREAD_CACHE_ALLOC_STATS) - if (detailed) { - base::internal::BucketIndexLookup lookup{}; - std::string name = dump->absolute_name(); - for (size_t i = 0; i < kNumBuckets; i++) { - size_t bucket_size = lookup.bucket_sizes()[i]; - if (bucket_size == kInvalidBucketSize) - continue; - // Covers all normal buckets, that is up to ~1MiB, so 7 digits. - std::string dump_name = - base::StringPrintf("%s/buckets_alloc/%07d", name.c_str(), - static_cast<int>(bucket_size)); - auto* buckets_alloc_dump = pmd->CreateAllocatorDump(dump_name); - buckets_alloc_dump->AddScalar("count", "objects", - stats.allocs_per_bucket_[i]); - } - } -#endif // defined(PA_THREAD_CACHE_ALLOC_STATS) - } -} #endif // BUILDFLAG(USE_PARTITION_ALLOC) } // namespace trace_event
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h index ca6c0c6..2f1625a 100644 --- a/base/trace_event/malloc_dump_provider.h +++ b/base/trace_event/malloc_dump_provider.h
@@ -25,6 +25,8 @@ namespace base { namespace trace_event { +class MemoryAllocatorDump; + // Dump provider which collects process-wide memory stats. class BASE_EXPORT MallocDumpProvider : public MemoryDumpProvider { public: @@ -41,18 +43,15 @@ bool OnMemoryDump(const MemoryDumpArgs& args, ProcessMemoryDump* pmd) override; - // Used by out-of-process heap-profiling. When malloc is profiled by an - // external process, that process will be responsible for emitting metrics on - // behalf of this one. Thus, MallocDumpProvider should not do anything. - void EnableMetrics(); - void DisableMetrics(); - private: friend struct DefaultSingletonTraits<MallocDumpProvider>; MallocDumpProvider(); ~MallocDumpProvider() override; + void ReportSyscallCount(uint64_t syscall_count, + MemoryAllocatorDump* malloc_dump); + bool emit_metrics_on_memory_dump_ GUARDED_BY(emit_metrics_on_memory_dump_lock_) = true; base::Lock emit_metrics_on_memory_dump_lock_; @@ -105,14 +104,6 @@ bool detailed_; }; -class MemoryAllocatorDump; - -BASE_EXPORT void ReportPartitionAllocThreadCacheStats( - ProcessMemoryDump* pmd, - MemoryAllocatorDump* dump, - const ThreadCacheStats& stats, - const std::string& metrics_suffix, - bool detailed); #endif // BUILDFLAG(USE_PARTITION_ALLOC) } // namespace trace_event
diff --git a/base/trace_event/memory_infra_background_allowlist.cc b/base/trace_event/memory_infra_background_allowlist.cc index 35d3410..f8a9e79a 100644 --- a/base/trace_event/memory_infra_background_allowlist.cc +++ b/base/trace_event/memory_infra_background_allowlist.cc
@@ -156,6 +156,7 @@ "malloc/partitions/original", "malloc/partitions/nonscannable", "malloc/partitions/nonquarantinable", + "malloc/sys_malloc", "malloc/win_heap", #endif "media/webmediaplayer/audio/player_0x?",
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 3dca68a4..f9c9e8e1 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -7.20220324.3.1 +7.20220325.0.1
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc index b1bb5c7..51336ef 100644 --- a/cc/layers/render_surface_impl.cc +++ b/cc/layers/render_surface_impl.cc
@@ -85,8 +85,8 @@ gfx::Rect surface_content_rect = content_rect(); const FilterOperations& filters = Filters(); if (!filters.IsEmpty()) { - surface_content_rect = filters.MapRect(surface_content_rect, - SkMatrix(SurfaceScale().matrix())); + surface_content_rect = + filters.MapRect(surface_content_rect, SurfaceScale().matrix().asM33()); } gfx::RectF drawable_content_rect = MathUtil::MapClippedRect( draw_transform(), gfx::RectF(surface_content_rect)); @@ -221,8 +221,8 @@ const gfx::Transform& target_to_surface) { gfx::Rect clip_in_surface_space = MathUtil::ProjectEnclosingClippedRect(target_to_surface, clip_rect()); - gfx::Rect expanded_clip_in_surface_space = Filters().MapRect( - clip_in_surface_space, SkMatrix(SurfaceScale().matrix())); + gfx::Rect expanded_clip_in_surface_space = + Filters().MapRect(clip_in_surface_space, SurfaceScale().matrix().asM33()); gfx::Rect expanded_clip_in_target_space = MathUtil::MapEnclosingClippedRect( draw_transform(), expanded_clip_in_surface_space); return expanded_clip_in_target_space;
diff --git a/cc/paint/display_item_list_unittest.cc b/cc/paint/display_item_list_unittest.cc index d198ccf..3246ef6 100644 --- a/cc/paint/display_item_list_unittest.cc +++ b/cc/paint/display_item_list_unittest.cc
@@ -334,7 +334,7 @@ SkRect::MakeLTRB(0.f + first_offset.x(), 0.f + first_offset.y(), 60.f + first_offset.x(), 60.f + first_offset.y()), red_paint); - expected_canvas.setMatrix(SkMatrix(transform.matrix())); + expected_canvas.setMatrix(transform.matrix().asM33()); expected_canvas.drawRect( SkRect::MakeLTRB(50.f + second_offset.x(), 50.f + second_offset.y(), 75.f + second_offset.x(), 75.f + second_offset.y()),
diff --git a/cc/trees/clip_expander.cc b/cc/trees/clip_expander.cc index 7fb0fa3..ee3b25603 100644 --- a/cc/trees/clip_expander.cc +++ b/cc/trees/clip_expander.cc
@@ -28,7 +28,7 @@ filter_draw_transform.Scale(effect_node->surface_contents_scale.x(), effect_node->surface_contents_scale.y()); return effect_node->filters.MapRect(rect, - SkMatrix(filter_draw_transform.matrix())); + filter_draw_transform.matrix().asM33()); } gfx::Rect ClipExpander::MapRectReverse( @@ -40,7 +40,7 @@ filter_draw_transform.Scale(effect_node->surface_contents_scale.x(), effect_node->surface_contents_scale.y()); return effect_node->filters.MapRectReverse( - rect, SkMatrix(filter_draw_transform.matrix())); + rect, filter_draw_transform.matrix().asM33()); } } // namespace cc
diff --git a/cc/trees/damage_tracker.cc b/cc/trees/damage_tracker.cc index 3101aa1..b3f0da73 100644 --- a/cc/trees/damage_tracker.cc +++ b/cc/trees/damage_tracker.cc
@@ -216,7 +216,7 @@ bool is_rect_valid = damage_for_this_update_.GetAsRect(&damage_rect); if (is_rect_valid && !damage_rect.IsEmpty()) { damage_rect = render_surface->Filters().MapRect( - damage_rect, SkMatrix(render_surface->SurfaceScale().matrix())); + damage_rect, render_surface->SurfaceScale().matrix().asM33()); damage_for_this_update_ = DamageAccumulator(); damage_for_this_update_.Union(damage_rect); }
diff --git a/cc/trees/property_tree_builder_unittest.cc b/cc/trees/property_tree_builder_unittest.cc index 33535565..ee8c82f9 100644 --- a/cc/trees/property_tree_builder_unittest.cc +++ b/cc/trees/property_tree_builder_unittest.cc
@@ -357,9 +357,8 @@ gfx::Transform vertical_flip; vertical_flip.Scale(1, -1); - sk_sp<PaintFilter> flip_filter = - sk_make_sp<MatrixPaintFilter>(SkMatrix(vertical_flip.matrix()), - PaintFlags::FilterQuality::kLow, nullptr); + sk_sp<PaintFilter> flip_filter = sk_make_sp<MatrixPaintFilter>( + vertical_flip.matrix().asM33(), PaintFlags::FilterQuality::kLow, nullptr); FilterOperations reflection_filter; reflection_filter.Append( FilterOperation::CreateReferenceFilter(sk_make_sp<XfermodePaintFilter>( @@ -418,9 +417,8 @@ gfx::Transform vertical_flip; vertical_flip.Scale(1, -1); - sk_sp<PaintFilter> flip_filter = - sk_make_sp<MatrixPaintFilter>(SkMatrix(vertical_flip.matrix()), - PaintFlags::FilterQuality::kLow, nullptr); + sk_sp<PaintFilter> flip_filter = sk_make_sp<MatrixPaintFilter>( + vertical_flip.matrix().asM33(), PaintFlags::FilterQuality::kLow, nullptr); FilterOperations reflection_filter; reflection_filter.Append( FilterOperation::CreateReferenceFilter(sk_make_sp<XfermodePaintFilter>(
diff --git a/chrome/VERSION b/chrome/VERSION index 5366000..5eaf009 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=102 MINOR=0 -BUILD=4963 +BUILD=4964 PATCH=0
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/attribution_reporting/AttributionProviderIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/attribution_reporting/AttributionProviderIntegrationTest.java index 5e734d3..37dad2f0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/attribution_reporting/AttributionProviderIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/attribution_reporting/AttributionProviderIntegrationTest.java
@@ -48,8 +48,9 @@ // enable-experimental-web-platform-features turns on the overall ConversionMeasurement Blink // feature. // conversions-debug-mode will send reports with no delay or noise. -@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, - "enable-experimental-web-platform-features", "conversions-debug-mode"}) +@CommandLineFlags. +Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "enable-experimental-web-platform-features", + "enable-blink-test-features", "conversions-debug-mode"}) @Features.EnableFeatures(ChromeFeatureList.APP_TO_WEB_ATTRIBUTION) public class AttributionProviderIntegrationTest { private static final String EVENT_ID = "12345";
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 5e1a2930..eb055e9 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-101.0.4951.7_rc-r1-merged.afdo.bz2 +chromeos-chrome-amd64-101.0.4951.10_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 2467744..53191e2d 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -4553,6 +4553,8 @@ "apps/app_discovery_service/app_discovery_util.h", "apps/app_discovery_service/app_fetcher_manager.cc", "apps/app_discovery_service/app_fetcher_manager.h", + "apps/app_discovery_service/game_extras.cc", + "apps/app_discovery_service/game_extras.h", "apps/app_discovery_service/play_extras.cc", "apps/app_discovery_service/play_extras.h", "apps/app_discovery_service/recommended_arc_app_fetcher.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 6acb90e..02143169 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -7141,6 +7141,16 @@ "disable-dialog-for-testing/true/show-sample-data/true," "EnableFetchingAccountCapabilities")}, + {"privacy-sandbox-ads-apis", + flag_descriptions::kPrivacySandboxAdsAPIsOverrideName, + flag_descriptions::kPrivacySandboxAdsAPIsOverrideDescription, kOsAll, + // Use a command-line parameter instead of a FEATURE_VALUE_TYPE to enable + // multiple related features when they are available. + SINGLE_VALUE_TYPE_AND_VALUE(switches::kEnableFeatures, + "PrivacySandboxAdsAPIsOverride" + "Fledge,BrowsingTopics,ConversionMeasurement" + "OverridePrivacySandboxSettingsLocalTesting")}, + {"animated-image-resume", flag_descriptions::kAnimatedImageResumeName, flag_descriptions::kAnimatedImageResumeDescription, kOsAll, FEATURE_VALUE_TYPE(features::kAnimatedImageResume)},
diff --git a/chrome/browser/apps/app_discovery_service/game_extras.cc b/chrome/browser/apps/app_discovery_service/game_extras.cc new file mode 100644 index 0000000..72cc5cec --- /dev/null +++ b/chrome/browser/apps/app_discovery_service/game_extras.cc
@@ -0,0 +1,53 @@ +// 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 "chrome/browser/apps/app_discovery_service/game_extras.h" + +namespace apps { +namespace { + +using Source = GameExtras::Source; + +} // namespace + +GameExtras::GameExtras( + const std::string& id, + const std::u16string& title, + Source source, + const absl::optional<std::vector<std::u16string>>& platforms, + const GURL& icon_url) + : id_(id), + title_(title), + source_(source), + platforms_(platforms), + icon_url_(icon_url) {} + +GameExtras::~GameExtras() = default; + +const std::string& GameExtras::GetId() const { + return id_; +} + +const std::u16string& GameExtras::GetTitle() const { + return title_; +} + +Source GameExtras::GetSource() const { + return source_; +} + +const absl::optional<std::vector<std::u16string>>& GameExtras::GetPlatforms() + const { + return platforms_; +} + +const GURL& GameExtras::GetIconUrl() const { + return icon_url_; +} + +GameExtras* GameExtras::AsGameExtras() { + return this; +} + +} // namespace apps
diff --git a/chrome/browser/apps/app_discovery_service/game_extras.h b/chrome/browser/apps/app_discovery_service/game_extras.h new file mode 100644 index 0000000..8f48010 --- /dev/null +++ b/chrome/browser/apps/app_discovery_service/game_extras.h
@@ -0,0 +1,54 @@ +// 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 CHROME_BROWSER_APPS_APP_DISCOVERY_SERVICE_GAME_EXTRAS_H_ +#define CHROME_BROWSER_APPS_APP_DISCOVERY_SERVICE_GAME_EXTRAS_H_ + +#include <string> +#include <vector> + +#include "chrome/browser/apps/app_discovery_service/result.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "url/gurl.h" + +namespace apps { + +class GameExtras : public SourceExtras { + public: + // Which cloud gaming source a result comes from. These values are persisted + // to logs. Entries should not be renumbered or reused. + enum class Source { + // TODO(crbug.com/1305880): Replace with real source. + kTemporarySource = 1, + }; + + GameExtras(const std::string& id, + const std::u16string& title, + Source source, + const absl::optional<std::vector<std::u16string>>& platforms, + const GURL& icon_url); + GameExtras(const GameExtras&) = delete; + GameExtras& operator=(const GameExtras&) = delete; + ~GameExtras() override; + + const std::string& GetId() const; + const std::u16string& GetTitle() const; + Source GetSource() const; + const absl::optional<std::vector<std::u16string>>& GetPlatforms() const; + const GURL& GetIconUrl() const; + + // Result::SourceExtras: + GameExtras* AsGameExtras() override; + + private: + std::string id_; + std::u16string title_; + Source source_; + absl::optional<std::vector<std::u16string>> platforms_; + GURL icon_url_; +}; + +} // namespace apps + +#endif // CHROME_BROWSER_APPS_APP_DISCOVERY_SERVICE_GAME_EXTRAS_H_
diff --git a/chrome/browser/apps/app_discovery_service/play_extras.h b/chrome/browser/apps/app_discovery_service/play_extras.h index 4efa24d..02fde68 100644 --- a/chrome/browser/apps/app_discovery_service/play_extras.h +++ b/chrome/browser/apps/app_discovery_service/play_extras.h
@@ -14,16 +14,16 @@ class PlayExtras : public SourceExtras { public: - explicit PlayExtras(const std::string& package_name, - const GURL& icon_url, - const std::u16string& category, - const std::u16string& description, - const std::u16string& content_rating, - const GURL& content_rating_icon_url, - const bool in_app_purchases, - const bool previously_installed, - const bool contains_ads, - const bool optimized_for_chrome); + PlayExtras(const std::string& package_name, + const GURL& icon_url, + const std::u16string& category, + const std::u16string& description, + const std::u16string& content_rating, + const GURL& content_rating_icon_url, + const bool in_app_purchases, + const bool previously_installed, + const bool contains_ads, + const bool optimized_for_chrome); PlayExtras(const PlayExtras&) = delete; PlayExtras& operator=(const PlayExtras&) = delete; ~PlayExtras() override;
diff --git a/chrome/browser/apps/app_discovery_service/result.cc b/chrome/browser/apps/app_discovery_service/result.cc index 8007569..906f69d 100644 --- a/chrome/browser/apps/app_discovery_service/result.cc +++ b/chrome/browser/apps/app_discovery_service/result.cc
@@ -8,6 +8,10 @@ namespace apps { +GameExtras* SourceExtras::AsGameExtras() { + return nullptr; +} + PlayExtras* SourceExtras::AsPlayExtras() { return nullptr; }
diff --git a/chrome/browser/apps/app_discovery_service/result.h b/chrome/browser/apps/app_discovery_service/result.h index d2d2666b..e8152c4 100644 --- a/chrome/browser/apps/app_discovery_service/result.h +++ b/chrome/browser/apps/app_discovery_service/result.h
@@ -11,6 +11,7 @@ namespace apps { enum class AppSource; +class GameExtras; class PlayExtras; // Can be overridden by Sources that have unique fields. @@ -23,6 +24,7 @@ // virtual FooExtras* AsFooExtras { return nullptr; } // Safe downcasts: + virtual GameExtras* AsGameExtras(); virtual PlayExtras* AsPlayExtras(); };
diff --git a/chrome/browser/apps/app_service/publishers/app_publisher.h b/chrome/browser/apps/app_service/publishers/app_publisher.h index 09b5041..c1ddcbc 100644 --- a/chrome/browser/apps/app_service/publishers/app_publisher.h +++ b/chrome/browser/apps/app_service/publishers/app_publisher.h
@@ -79,6 +79,10 @@ virtual void LaunchAppWithParams(AppLaunchParams&& params, LaunchCallback callback) = 0; + virtual void LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) {} + protected: #if !BUILDFLAG(IS_CHROMEOS_LACROS) // Publish one `app` to AppServiceProxy. Should be called whenever the app
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps.cc b/chrome/browser/apps/app_service/publishers/arc_apps.cc index 0bd2106..c0e93a2 100644 --- a/chrome/browser/apps/app_service/publishers/arc_apps.cc +++ b/chrome/browser/apps/app_service/publishers/arc_apps.cc
@@ -704,6 +704,12 @@ std::move(callback).Run(LaunchResult()); } +void ArcApps::LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) { + arc::ExecuteArcShortcutCommand(profile_, app_id, shortcut_id, display_id); +} + void ArcApps::Connect( mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote, apps::mojom::ConnectOptionsPtr opts) {
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps.h b/chrome/browser/apps/app_service/publishers/arc_apps.h index 90537c5e..0fb9ee5 100644 --- a/chrome/browser/apps/app_service/publishers/arc_apps.h +++ b/chrome/browser/apps/app_service/publishers/arc_apps.h
@@ -101,6 +101,9 @@ apps::LoadIconCallback callback) override; void LaunchAppWithParams(AppLaunchParams&& params, LaunchCallback callback) override; + void LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) override; // apps::mojom::Publisher overrides. void Connect(mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote,
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps.cc b/chrome/browser/apps/app_service/publishers/crostini_apps.cc index 4847ff96..3afe733 100644 --- a/chrome/browser/apps/app_service/publishers/crostini_apps.cc +++ b/chrome/browser/apps/app_service/publishers/crostini_apps.cc
@@ -139,6 +139,15 @@ std::move(callback).Run(LaunchResult()); } +void CrostiniApps::LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) { + if (app_id == crostini::kCrostiniTerminalSystemAppId) { + crostini::ExecuteTerminalMenuShortcutCommand(profile_, shortcut_id, + display_id); + } +} + void CrostiniApps::Connect( mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote, apps::mojom::ConnectOptionsPtr opts) {
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps.h b/chrome/browser/apps/app_service/publishers/crostini_apps.h index 0451f6a..54a1b9a 100644 --- a/chrome/browser/apps/app_service/publishers/crostini_apps.h +++ b/chrome/browser/apps/app_service/publishers/crostini_apps.h
@@ -64,6 +64,9 @@ apps::LoadIconCallback callback) override; void LaunchAppWithParams(AppLaunchParams&& params, LaunchCallback callback) override; + void LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) override; // apps::mojom::Publisher overrides. void Connect(mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote,
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc index b87ef68..5dfad40 100644 --- a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc +++ b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
@@ -814,6 +814,7 @@ app->show_in_launcher = false; app->show_in_search = false; app->show_in_shelf = false; + app->handles_intents = false; } if (disable_for_lacros) app->show_in_management = false; @@ -862,6 +863,7 @@ app->show_in_launcher = apps::mojom::OptionalBool::kFalse; app->show_in_search = apps::mojom::OptionalBool::kFalse; app->show_in_shelf = apps::mojom::OptionalBool::kFalse; + app->handles_intents = apps::mojom::OptionalBool::kFalse; } if (disable_for_lacros) app->show_in_management = apps::mojom::OptionalBool::kFalse;
diff --git a/chrome/browser/apps/app_service/publishers/publisher_unittest.cc b/chrome/browser/apps/app_service/publishers/publisher_unittest.cc index 3823dd7..a6d8384 100644 --- a/chrome/browser/apps/app_service/publishers/publisher_unittest.cc +++ b/chrome/browser/apps/app_service/publishers/publisher_unittest.cc
@@ -9,6 +9,7 @@ #include "base/memory/raw_ptr.h" #include "base/test/scoped_feature_list.h" #include "base/time/time.h" +#include "base/values.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" @@ -70,7 +71,9 @@ base::DictionaryValue value; value.SetStringKey("name", name); value.SetStringKey("version", version); - value.SetStringPath("app.launch.web_url", url); + base::ListValue scripts; + scripts.Append("script.js"); + value.SetPath("app.background.scripts", std::move(scripts)); scoped_refptr<extensions::Extension> app = extensions::Extension::Create( base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value, extensions::Extension::WAS_INSTALLED_BY_DEFAULT, id, &err); @@ -593,6 +596,29 @@ /*has_badge=*/true, /*paused=*/true, WindowMode::kBrowser); } +// Check that when Lacros is primary, the app is disabled by policy and does +// not handle intents. +TEST_F(StandaloneBrowserPublisherTest, ExtensionAppsDisabledByPolicy) { + // Install a "web store" app. + scoped_refptr<extensions::Extension> store = + MakeExtensionApp("webstore", "0.0", "http://google.com", + std::string(extensions::kWebStoreAppId)); + service_->AddExtension(store.get()); + + AppServiceTest app_service_test; + app_service_test.SetUp(profile()); + VerifyApp(AppType::kChromeApp, store->id(), store->name(), + Readiness::kDisabledByPolicy, InstallReason::kDefault, + InstallSource::kChromeWebStore, {}, base::Time(), base::Time(), + apps::Permissions(), + /*is_platform_app=*/true, /*recommendable=*/true, + /*searchable=*/true, + /*show_in_launcher=*/false, /*show_in_shelf=*/false, + /*show_in_search=*/false, /*show_in_management=*/false, + /*handles_intents=*/false, /*allow_uninstall=*/true, + /*has_badge=*/false, /*paused=*/false); +} + // This framework conveniently sets up everything but borealis. using NonBorealisPublisherTest = StandaloneBrowserPublisherTest; @@ -632,7 +658,7 @@ VerifyApp(AppType::kChromeApp, store->id(), store->name(), Readiness::kReady, InstallReason::kDefault, InstallSource::kChromeWebStore, {}, base::Time(), base::Time(), apps::Permissions(), - /*is_platform_app=*/false, /*recommendable=*/true, + /*is_platform_app=*/true, /*recommendable=*/true, /*searchable=*/true, /*show_in_launcher=*/true, /*show_in_shelf=*/true, /*show_in_search=*/true, /*show_in_management=*/true, @@ -646,7 +672,7 @@ VerifyApp(AppType::kChromeApp, store->id(), store->name(), Readiness::kUninstalledByUser, InstallReason::kDefault, InstallSource::kChromeWebStore, {}, base::Time(), base::Time(), - apps::Permissions(), /*is_platform_app=*/false, + apps::Permissions(), /*is_platform_app=*/true, /*recommendable=*/true, /*searchable=*/true, /*show_in_launcher=*/true, /*show_in_shelf=*/true, @@ -659,7 +685,7 @@ VerifyApp(AppType::kChromeApp, store->id(), store->name(), Readiness::kReady, InstallReason::kDefault, InstallSource::kChromeWebStore, {}, base::Time(), base::Time(), apps::Permissions(), - /*is_platform_app=*/false, /*recommendable=*/true, + /*is_platform_app=*/true, /*recommendable=*/true, /*searchable=*/true, /*show_in_launcher=*/true, /*show_in_shelf=*/true, /*show_in_search=*/true, /*show_in_management=*/true, @@ -672,7 +698,7 @@ VerifyApp(AppType::kChromeApp, store->id(), store->name(), Readiness::kReady, InstallReason::kDefault, InstallSource::kChromeWebStore, {}, kLastLaunchTime, base::Time(), apps::Permissions(), - /*is_platform_app=*/false); + /*is_platform_app=*/true); } TEST_F(PublisherTest, WebAppsOnApps) {
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc index f41ecda..62fa613 100644 --- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc +++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
@@ -101,6 +101,17 @@ apps::LaunchResultToMojomLaunchResultCallback(std::move(callback))); } +void WebAppsCrosapi::LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) { + if (!LogIfNotConnected(FROM_HERE)) { + return; + } + + controller_->ExecuteContextMenuCommand(app_id, shortcut_id, + base::DoNothing()); +} + void WebAppsCrosapi::Connect( mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote, apps::mojom::ConnectOptionsPtr opts) {
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h index 866a519..b16db45 100644 --- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h +++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h
@@ -72,6 +72,9 @@ apps::LoadIconCallback callback) override; void LaunchAppWithParams(AppLaunchParams&& params, LaunchCallback callback) override; + void LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) override; // apps::PublisherBase overrides. void Connect(mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote,
diff --git a/chrome/browser/ash/borealis/borealis_features.cc b/chrome/browser/ash/borealis/borealis_features.cc index d31bcae..c2dbcf1 100644 --- a/chrome/browser/ash/borealis/borealis_features.cc +++ b/chrome/browser/ash/borealis/borealis_features.cc
@@ -224,7 +224,8 @@ std::string board = GetBoardName(); TokenAuthority auth = GetAuthorityForToken(board, hash_of_current_token); if (auth == TokenAuthority::kRejected) { - LOG(WARNING) << "Incorrect token for board=" << board; + LOG(WARNING) << "Incorrect token hash '" << hash_of_current_token + << "' for board=" << board; return AllowStatus::kIncorrectToken; } else if (auth == TokenAuthority::kAllowedOverridesHardwareChecks) { return AllowStatus::kAllowed;
diff --git a/chrome/browser/ash/input_method/assistive_suggester.cc b/chrome/browser/ash/input_method/assistive_suggester.cc index 31e5e87..05513866 100644 --- a/chrome/browser/ash/input_method/assistive_suggester.cc +++ b/chrome/browser/ash/input_method/assistive_suggester.cc
@@ -1,7 +1,6 @@ // Copyright 2019 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 "chrome/browser/ash/input_method/assistive_suggester.h" #include "ash/constants/ash_features.h" @@ -430,7 +429,8 @@ bool AssistiveSuggester::OnSurroundingTextChanged(const std::u16string& text, int cursor_pos, int anchor_pos) { - if (context_id_ == -1) + RecordAssistiveMatchMetrics(text, cursor_pos, anchor_pos); + if (!IsAssistiveFeatureEnabled() || context_id_ == -1) return false; if (IsMultiWordSuggestEnabled()) {
diff --git a/chrome/browser/ash/input_method/assistive_suggester.h b/chrome/browser/ash/input_method/assistive_suggester.h index 94ea7f05..a5c65f41 100644 --- a/chrome/browser/ash/input_method/assistive_suggester.h +++ b/chrome/browser/ash/input_method/assistive_suggester.h
@@ -58,12 +58,6 @@ // Called when a text field loses focus, and suggester stops working. void OnBlur(); - // Checks the text before cursor, emits metric if any assistive prefix is - // matched. - void RecordAssistiveMatchMetrics(const std::u16string& text, - int cursor_pos, - int anchor_pos); - // Called when a surrounding text is changed. // Returns true if it changes the surrounding text, e.g. a suggestion is // generated or dismissed. @@ -106,6 +100,12 @@ bool IsExpandedMultiWordSuggestEnabled(); + // Checks the text before cursor, emits metric if any assistive prefix is + // matched. + void RecordAssistiveMatchMetrics(const std::u16string& text, + int cursor_pos, + int anchor_pos); + void RecordAssistiveMatchMetricsForAction(AssistiveType action); // Only the first applicable reason in DisabledReason enum is returned.
diff --git a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc index 0d32351..7befd13 100644 --- a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc +++ b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
@@ -30,7 +30,6 @@ using ime::TextSuggestionMode; using ime::TextSuggestionType; -const char kEmojiData[] = "happy,😀;😃;😄"; const char kUsEnglishEngineId[] = "xkb:us::eng"; const char kSpainSpanishEngineId[] = "xkb:es::spa"; @@ -454,6 +453,39 @@ histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Match", 0); } +TEST_F(AssistiveSuggesterMultiWordTest, OnSuggestionExistShowSuggestion) { + std::vector<TextSuggestion> suggestions = { + TextSuggestion{.mode = TextSuggestionMode::kPrediction, + .type = TextSuggestionType::kMultiWord, + .text = "hello there"}}; + + assistive_suggester_->OnActivate(kUsEnglishEngineId); + assistive_suggester_->OnFocus(5); + assistive_suggester_->OnSurroundingTextChanged(u"", 0, 0); + assistive_suggester_->OnExternalSuggestionsUpdated(suggestions); + + EXPECT_TRUE(suggestion_handler_->GetShowingSuggestion()); + EXPECT_EQ(suggestion_handler_->GetSuggestionText(), u"hello there"); +} + +TEST_F(AssistiveSuggesterMultiWordTest, OnDisabledFlagShouldNotShowSuggestion) { + feature_list_.Reset(); + feature_list_.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kAssistMultiWord}); + std::vector<TextSuggestion> suggestions = { + TextSuggestion{.mode = TextSuggestionMode::kPrediction, + .type = TextSuggestionType::kMultiWord, + .text = "hello there"}}; + + assistive_suggester_->OnActivate(kUsEnglishEngineId); + assistive_suggester_->OnFocus(5); + assistive_suggester_->OnSurroundingTextChanged(u"", 0, 0); + assistive_suggester_->OnExternalSuggestionsUpdated(suggestions); + + EXPECT_FALSE(suggestion_handler_->GetShowingSuggestion()); +} + TEST_F(AssistiveSuggesterMultiWordTest, MatchMetricRecordedWhenOneOrMoreSuggestions) { std::vector<TextSuggestion> suggestions = { @@ -672,6 +704,7 @@ } void SetUp() override { + const char kEmojiData[] = "arrow,←;↑;→"; suggestion_handler_ = std::make_unique<FakeSuggestionHandler>(); assistive_suggester_ = std::make_unique<AssistiveSuggester>( suggestion_handler_.get(), profile_.get(), @@ -704,11 +737,25 @@ chrome_keyboard_controller_client_; }; +TEST_F(AssistiveSuggesterEmojiTest, ShouldNotSuggestWhenEmojiDisabled) { + profile_->GetPrefs()->SetBoolean(prefs::kEmojiSuggestionEnterpriseAllowed, + false); + profile_->GetPrefs()->SetBoolean(prefs::kEmojiSuggestionEnabled, false); + + assistive_suggester_->OnActivate(kUsEnglishEngineId); + assistive_suggester_->OnFocus(5); + + EXPECT_FALSE(assistive_suggester_->OnSurroundingTextChanged(u"arrow ", 6, 6)); + EXPECT_FALSE(suggestion_handler_->GetShowingSuggestion()); +} + TEST_F(AssistiveSuggesterEmojiTest, ShouldReturnPrefixBasedEmojiSuggestions) { assistive_suggester_->OnActivate(kUsEnglishEngineId); assistive_suggester_->OnFocus(5); - EXPECT_TRUE(assistive_suggester_->OnSurroundingTextChanged(u"happy ", 6, 6)); + EXPECT_TRUE(assistive_suggester_->OnSurroundingTextChanged(u"arrow ", 6, 6)); + EXPECT_TRUE(suggestion_handler_->GetShowingSuggestion()); + EXPECT_EQ(suggestion_handler_->GetSuggestionText(), u"←"); } } // namespace input_method
diff --git a/chrome/browser/ash/input_method/fake_suggestion_handler.cc b/chrome/browser/ash/input_method/fake_suggestion_handler.cc index 6082bcb..15bb8844 100644 --- a/chrome/browser/ash/input_method/fake_suggestion_handler.cc +++ b/chrome/browser/ash/input_method/fake_suggestion_handler.cc
@@ -67,7 +67,19 @@ int context_id, const AssistiveWindowProperties& assistive_window, std::string* error) { - return false; + if (assistive_window.candidates.empty()) { + return true; + } + + if (assistive_window.visible) { + showing_suggestion_ = true; + // TODO(b/225988020): Expand this class to allow for multiple suggestion + // candidates. Currently only saves the first one. + suggestion_text_ = assistive_window.candidates.front(); + } else { + showing_suggestion_ = false; + } + return true; } void FakeSuggestionHandler::Announce(const std::u16string& message) {
diff --git a/chrome/browser/ash/input_method/native_input_method_engine.cc b/chrome/browser/ash/input_method/native_input_method_engine.cc index 6342c0a..85108a9 100644 --- a/chrome/browser/ash/input_method/native_input_method_engine.cc +++ b/chrome/browser/ash/input_method/native_input_method_engine.cc
@@ -190,9 +190,11 @@ } } -mojom::AutocorrectMode AutocorrectFlagsToMojoType(int flags) { - if ((flags & ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF) || - (flags & ui::TEXT_INPUT_FLAG_SPELLCHECK_OFF)) { +mojom::AutocorrectMode AutocorrectFlagsToMojoType(int flags, + bool is_normal_screen) { + if (((flags & ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF) || + (flags & ui::TEXT_INPUT_FLAG_SPELLCHECK_OFF)) || + !is_normal_screen) { return mojom::AutocorrectMode::kDisabled; } return mojom::AutocorrectMode::kEnabled; @@ -771,11 +773,15 @@ OverrideXkbLayoutIfNeeded(InputMethodManager::Get()->GetImeKeyboard(), settings); + const bool is_normal_screen = + InputMethodManager::Get()->GetActiveIMEState()->GetUIStyle() == + InputMethodManager::UIStyle::kNormal; auto input_field_info = mojom::InputFieldInfo::New( TextInputTypeToMojoType(context.type), - AutocorrectFlagsToMojoType(context.flags), - context.should_do_learning ? mojom::PersonalizationMode::kEnabled - : mojom::PersonalizationMode::kDisabled); + AutocorrectFlagsToMojoType(context.flags, is_normal_screen), + context.should_do_learning && is_normal_screen + ? mojom::PersonalizationMode::kEnabled + : mojom::PersonalizationMode::kDisabled); auto on_focus_callback = base::BindOnce( &NativeInputMethodEngine::ImeObserver::ActivateTextClient, weak_ptr_factory_.GetWeakPtr(), text_client_->context_id); @@ -950,12 +956,7 @@ .anchor_pos = anchor_pos, .offset_pos = offset_pos}; - assistive_suggester_->RecordAssistiveMatchMetrics(text, cursor_pos, - anchor_pos); - if (assistive_suggester_->IsAssistiveFeatureEnabled()) { - assistive_suggester_->OnSurroundingTextChanged(text, cursor_pos, - anchor_pos); - } + assistive_suggester_->OnSurroundingTextChanged(text, cursor_pos, anchor_pos); autocorrect_manager_->OnSurroundingTextChanged(text, cursor_pos, anchor_pos); if (grammar_manager_->IsOnDeviceGrammarEnabled()) { grammar_manager_->OnSurroundingTextChanged(text, cursor_pos, anchor_pos);
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc b/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc index c2bb549..00a17487 100644 --- a/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc +++ b/chrome/browser/ash/input_method/native_input_method_engine_unittest.cc
@@ -501,6 +501,57 @@ InputMethodManager::Shutdown(); } +TEST_F(NativeInputMethodEngineTest, + DisablesAutocorrectAndLearningAtLockScreen) { + TestingProfile testing_profile; + SetInputMethodOptions(testing_profile, /*autocorrect_enabled=*/true, + /*predictive_writing_enabled=*/false); + + testing::StrictMock<MockInputMethod> mock_input_method; + InputMethodManager::Initialize( + new TestInputMethodManager(&mock_input_method)); + InputMethodManager::Get()->GetActiveIMEState()->SetUIStyle( + InputMethodManager::UIStyle::kLock); + NativeInputMethodEngine engine; + engine.Initialize(std::make_unique<StubInputMethodEngineObserver>(), + /*extension_id=*/"", &testing_profile); + + { + testing::InSequence seq; + EXPECT_CALL(mock_input_method, + OnFocus(MojoEq(ime::mojom::InputFieldInfo( + ime::mojom::InputFieldType::kText, + ime::mojom::AutocorrectMode::kDisabled, + ime::mojom::PersonalizationMode::kDisabled)), + _, _)) + .WillOnce( + ::testing::Invoke([](ime::mojom::InputFieldInfoPtr info, + ime::mojom::InputMethodSettingsPtr settings, + base::OnceCallback<void(bool)> callback) { + EXPECT_EQ(*settings, + *ime::mojom::InputMethodSettings::NewLatinSettings( + ime::mojom::LatinSettings::New( + /*autocorrect=*/true, + /*predictive_writing=*/false))); + std::move(callback).Run(true); + })); + EXPECT_CALL(mock_input_method, OnSurroundingTextChanged(_, _, _)); + } + + ui::IMEEngineHandlerInterface::InputContext input_context( + ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT, + ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE, + /*should_do_learning=*/true); + engine.Enable(kEngineIdUs); + engine.FlushForTesting(); // ensure input_method connected. + engine.FocusIn(input_context); + engine.FlushForTesting(); + + InputMethodManager::Get()->GetActiveIMEState()->SetUIStyle( + InputMethodManager::UIStyle::kNormal); + InputMethodManager::Shutdown(); +} + TEST_F(NativeInputMethodEngineTest, FocusUpdatesXkbLayout) { TestingProfile testing_profile; SetPinyinLayoutPrefs(testing_profile, "Colemak");
diff --git a/chrome/browser/ash/login/screens/marketing_opt_in_screen_browsertest.cc b/chrome/browser/ash/login/screens/marketing_opt_in_screen_browsertest.cc index 53aedf6..33120a3 100644 --- a/chrome/browser/ash/login/screens/marketing_opt_in_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/marketing_opt_in_screen_browsertest.cc
@@ -194,7 +194,9 @@ GetScreen()->set_ingore_pref_sync_for_testing(true); OobeBaseTest::SetUpOnMainThread(); - LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true; + auto* wizard_context = LoginDisplayHost::default_host()->GetWizardContext(); + wizard_context->is_branded_build = true; + wizard_context->defer_oobe_flow_finished_for_tests = true; } MarketingOptInScreen* MarketingOptInScreenTest::GetScreen() {
diff --git a/chrome/browser/attribution_reporting/chrome_attribution_browsertest.cc b/chrome/browser/attribution_reporting/chrome_attribution_browsertest.cc index ff32757..ff067163 100644 --- a/chrome/browser/attribution_reporting/chrome_attribution_browsertest.cc +++ b/chrome/browser/attribution_reporting/chrome_attribution_browsertest.cc
@@ -31,6 +31,7 @@ // Sets up the blink runtime feature for ConversionMeasurement. command_line->AppendSwitch( switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitch(switches::kEnableBlinkTestFeatures); } void SetUpOnMainThread() override {
diff --git a/chrome/browser/attribution_reporting/conversions_usage_restriction_trial_browsertest.cc b/chrome/browser/attribution_reporting/conversions_usage_restriction_trial_browsertest.cc deleted file mode 100644 index 6bd281e1..0000000 --- a/chrome/browser/attribution_reporting/conversions_usage_restriction_trial_browsertest.cc +++ /dev/null
@@ -1,118 +0,0 @@ -// Copyright 2020 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 <memory> - -#include "base/bind.h" -#include "base/strings/strcat.h" -#include "base/test/scoped_feature_list.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/base/ui_test_utils.h" -#include "components/embedder_support/origin_trials/features.h" -#include "components/embedder_support/switches.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/content_features.h" -#include "content/public/test/browser_test.h" -#include "content/public/test/browser_test_utils.h" -#include "content/public/test/url_loader_interceptor.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -namespace { -constexpr char kBaseDataDir[] = "content/test/data/attribution_reporting"; -constexpr char kOriginTrialTestPublicKey[] = - "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA="; -} // namespace - -// Chrome layer equivalent to -// content/browser/conversion_origin_trial_browsertest.cc. Usage restrictions -// are not implemented within content/shell. -class ConversionsUsageRestrictionTrialBrowserTestBase - : public InProcessBrowserTest { - public: - ConversionsUsageRestrictionTrialBrowserTestBase() = default; - - void SetUpOnMainThread() override { - // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since - // the origin trial token in the response is associated with a fixed - // origin, whereas EmbeddedTestServer serves content on a random port. - url_loader_interceptor_ = - std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating( - [](content::URLLoaderInterceptor::RequestParams* params) -> bool { - if (params->url_request.url.path_piece() != - "/impression_with_third_party_trial.html" && - params->url_request.url.path_piece() != - "/third_party_token_injector.js") { - return false; - } - - content::URLLoaderInterceptor::WriteResponse( - base::StrCat( - {kBaseDataDir, params->url_request.url.path_piece()}), - params->client.get()); - return true; - })); - } - - void TearDownOnMainThread() override { url_loader_interceptor_.reset(); } - - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitchASCII(embedder_support::kOriginTrialPublicKey, - kOriginTrialTestPublicKey); - } - - private: - std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_; -}; - -class ConversionsOriginTrialSubsetExclusionBrowserTest - : public ConversionsUsageRestrictionTrialBrowserTestBase { - public: - ConversionsOriginTrialSubsetExclusionBrowserTest() { - // Disable the alternative usage feature, this should prevent the OT token - // from enabling the API. - feature_list_.InitWithFeatures( - {}, {embedder_support::kConversionMeasurementAPIAlternativeUsage}); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -IN_PROC_BROWSER_TEST_F(ConversionsOriginTrialSubsetExclusionBrowserTest, - InSubsetExclusion_TrialDisabled) { - EXPECT_TRUE(ui_test_utils::NavigateToURL( - browser(), - GURL("https://example.test/impression_with_third_party_trial.html"))); - - EXPECT_EQ(false, EvalJs(browser()->tab_strip_model()->GetActiveWebContents(), - "document.featurePolicy.features().includes('" - "attribution-reporting')")); -} - -class ConversionsOriginTrialNoSubsetExclusionBrowserTest - : public ConversionsUsageRestrictionTrialBrowserTestBase { - public: - ConversionsOriginTrialNoSubsetExclusionBrowserTest() { - // Enable the alternative usage feature, this should allow the OT token to - // enable the API. - feature_list_.InitWithFeatures( - {embedder_support::kConversionMeasurementAPIAlternativeUsage}, {}); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -IN_PROC_BROWSER_TEST_F(ConversionsOriginTrialNoSubsetExclusionBrowserTest, - OutOfSubsetExclusion_TrialEnabled) { - EXPECT_TRUE(ui_test_utils::NavigateToURL( - browser(), - GURL("https://example.test/impression_with_third_party_trial.html"))); - - EXPECT_EQ(true, EvalJs(browser()->tab_strip_model()->GetActiveWebContents(), - "document.featurePolicy.features().includes('" - "attribution-reporting')")); -}
diff --git a/chrome/browser/browsing_topics/browsing_topics_service_browsertest.cc b/chrome/browser/browsing_topics/browsing_topics_service_browsertest.cc index 23a26cf..d8b2cc0 100644 --- a/chrome/browser/browsing_topics/browsing_topics_service_browsertest.cc +++ b/chrome/browser/browsing_topics/browsing_topics_service_browsertest.cc
@@ -9,6 +9,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/browsing_topics/browsing_topics_service.h" +#include "content/public/common/content_features.h" #include "content/public/test/browser_test.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/request_handler_util.h" @@ -90,7 +91,8 @@ public: BrowsingTopicsBrowserTest() { scoped_feature_list_.InitWithFeatures( - /*enabled_features=*/{blink::features::kBrowsingTopics}, + /*enabled_features=*/{blink::features::kBrowsingTopics, + features::kPrivacySandboxAdsAPIsOverride}, /*disabled_features=*/{}); }
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc index 2ecd1adc..a3031bf 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -1294,11 +1294,11 @@ } } - return; + // Send the progress report to the system notification regardless of whether + // Files app window exists as we may need to remove an existing + // notification. } - // If no Files app window exists we send the progress to the system - // notification. notification_manager_->HandleIOTaskProgress(status); } void EventRouter::OnRegistered(guest_os::GuestOsMountProviderRegistry::Id id,
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc index 241c28e..5c8ebc50 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -185,7 +185,8 @@ /*enabled_features=*/ {blink::features::kInterestGroupStorage, blink::features::kAdInterestGroupAPI, blink::features::kFledge, - blink::features::kFencedFrames}, + blink::features::kFencedFrames, + features::kPrivacySandboxAdsAPIsOverride}, /*disabled_features=*/ {}); net::test_server::RegisterDefaultHandlers(embedded_test_server());
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc index 50f36b6c..00a662a 100644 --- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc +++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
@@ -19,6 +19,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "extensions/common/switches.h" +#include "extensions/test/test_extension_dir.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h" @@ -241,4 +242,81 @@ EXPECT_TRUE(test_flags[2].picker_deleted); } +// Not specifying a tab defaults to the extension's background page. +// Service worker-based extensions don't have one, so they must specify +// a tab. This is a regression test for crbug.com/1271590. +IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, ServiceWorkerMustSpecifyTab) { + static constexpr char kManifest[] = + R"({ + "name": "Desktop Capture", + "manifest_version": 3, + "version": "0.1", + "background": { "service_worker": "worker.js" }, + "permissions": ["desktopCapture"] + })"; + + static constexpr char kWorker[] = + R"(chrome.test.runTests([ + function noTabIdSpecified() { + chrome.desktopCapture.chooseDesktopMedia( + ["screen", "window"], + function(id) { + chrome.test.assertLastError( + 'A target tab is required when called from a service ' + + 'worker context.'); + chrome.test.succeed(); + }); + }]))"; + + TestExtensionDir test_dir; + test_dir.WriteManifest(kManifest); + test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kWorker); + + ASSERT_TRUE(RunExtensionTest(test_dir.UnpackedPath(), {}, {})) << message_; +} + +IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, FromServiceWorker) { + static constexpr char kManifest[] = + R"({ + "name": "Desktop Capture", + "manifest_version": 3, + "version": "0.1", + "background": { "service_worker": "worker.js" }, + "permissions": ["desktopCapture", "tabs"] + })"; + + static constexpr char kWorker[] = + R"(chrome.test.runTests([ + function tabIdSpecified() { + chrome.tabs.query({}, function(tabs) { + chrome.test.assertTrue(tabs.length == 1); + chrome.desktopCapture.chooseDesktopMedia( + ["tab"], tabs[0], + function(id) { + chrome.test.assertEq("string", typeof id); + chrome.test.assertTrue(id != ""); + chrome.test.succeed(); + }); + }); + }]))"; + + TestExtensionDir test_dir; + test_dir.WriteManifest(kManifest); + test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kWorker); + + // Open a tab to capture. + embedded_test_server()->ServeFilesFromDirectory(GetTestResourcesParentDir()); + ASSERT_TRUE(StartEmbeddedTestServer()); + ASSERT_TRUE(ui_test_utils::NavigateToURL( + browser(), GetURLForPath("localhost", "/test_file.html"))); + + FakeDesktopMediaPickerFactory::TestFlags test_flags[] = { + {.expect_tabs = true, + .selected_source = MakeFakeWebContentsMediaId(true)}, + }; + picker_factory_.SetTestFlags(test_flags, std::size(test_flags)); + + ASSERT_TRUE(RunExtensionTest(test_dir.UnpackedPath(), {}, {})) << message_; +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc index 9d70865..78ff18d 100644 --- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc +++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -589,6 +589,10 @@ features.Append(GenerateFeatureFlag( "multilingualtyping", base::FeatureList::IsEnabled(chromeos::features::kMultilingualTyping))); + features.Append( + GenerateFeatureFlag("autocorrectparamstuning", + base::FeatureList::IsEnabled( + chromeos::features::kAutocorrectParamsTuning))); results->SetKey("features", std::move(features));
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index dd5dcc1f..bf174be 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1249,7 +1249,6 @@ { "name": "disable-office-editing-component-app", "owners": [ - "chrome-apps-platform-rationalization@google.com", "quickoffice-chrome-eng@google.com" ], "expiry_milestone": 110 @@ -4864,6 +4863,14 @@ "expiry_milestone": 104 }, { + "name": "privacy-sandbox-ads-apis", + "owners": [ + "johnidel", + "jkarlin", + "pauljensen"], + "expiry_milestone": 104 + }, + { "name": "privacy-sandbox-v3-android", "owners": [ "dullweber",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index dc7d3cd..454ff3e 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2130,6 +2130,11 @@ "Enables UI updates for Privacy Guide. This requires #privacy-guide to " "also be enabled"; +const char kPrivacySandboxAdsAPIsOverrideName[] = "Privacy Sandbox Ads APIs"; +const char kPrivacySandboxAdsAPIsOverrideDescription[] = + "Enables Privacy Sandbox APIs: Attribtuion Reporting, Fledge, Topics and " + "their associated features."; + const char kPrivacySandboxV3Name[] = "Privacy Sandbox V3"; const char kPrivacySandboxV3Description[] = "Enables an updated Privacy Sandbox UI. Also enables some related "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index b9288ad..6229130c 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1200,6 +1200,9 @@ extern const char kPrivacyGuide2Name[]; extern const char kPrivacyGuide2Description[]; +extern const char kPrivacySandboxAdsAPIsOverrideName[]; +extern const char kPrivacySandboxAdsAPIsOverrideDescription[]; + extern const char kPrivacySandboxV3Name[]; extern const char kPrivacySandboxV3Description[];
diff --git a/chrome/browser/interest_group/interest_group_permissions_browsertest.cc b/chrome/browser/interest_group/interest_group_permissions_browsertest.cc index 5dd9f55e..f71d200 100644 --- a/chrome/browser/interest_group/interest_group_permissions_browsertest.cc +++ b/chrome/browser/interest_group/interest_group_permissions_browsertest.cc
@@ -15,6 +15,7 @@ #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/pref_names.h" #include "components/prefs/pref_service.h" +#include "content/public/common/content_features.h" #include "content/public/test/browser_test.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -28,7 +29,8 @@ scoped_feature_list_.InitWithFeatures( /*enabled_features=*/ {blink::features::kInterestGroupStorage, - blink::features::kAdInterestGroupAPI, blink::features::kFledge}, + blink::features::kAdInterestGroupAPI, blink::features::kFledge, + features::kPrivacySandboxAdsAPIsOverride}, /*disabled_features=*/ {blink::features::kFencedFrames}); } @@ -202,7 +204,7 @@ scoped_feature_list_.InitWithFeatures( {blink::features::kInterestGroupStorage}, {blink::features::kAdInterestGroupAPI, blink::features::kFledge, - blink::features::kParakeet}); + blink::features::kParakeet, features::kPrivacySandboxAdsAPIsOverride}); } base::test::ScopedFeatureList scoped_feature_list_; }; @@ -222,7 +224,8 @@ public: InterestGroupFledgeOnBrowserTest() { scoped_feature_list_.InitWithFeatures( - {blink::features::kInterestGroupStorage, blink::features::kFledge}, + {blink::features::kInterestGroupStorage, blink::features::kFledge, + features::kPrivacySandboxAdsAPIsOverride}, {blink::features::kAdInterestGroupAPI, blink::features::kParakeet}); } base::test::ScopedFeatureList scoped_feature_list_; @@ -245,7 +248,8 @@ InterestGroupParakeetOnBrowserTest() { scoped_feature_list_.InitWithFeatures( {blink::features::kInterestGroupStorage, blink::features::kParakeet}, - {blink::features::kAdInterestGroupAPI, blink::features::kFledge}); + {blink::features::kAdInterestGroupAPI, blink::features::kFledge, + features::kPrivacySandboxAdsAPIsOverride}); } base::test::ScopedFeatureList scoped_feature_list_; }; @@ -269,7 +273,8 @@ scoped_feature_list_.InitWithFeatures( {blink::features::kInterestGroupStorage, blink::features::kAdInterestGroupAPI}, - {blink::features::kParakeet, blink::features::kFledge}); + {blink::features::kParakeet, blink::features::kFledge, + features::kPrivacySandboxAdsAPIsOverride}); } base::test::ScopedFeatureList scoped_feature_list_; };
diff --git a/chrome/browser/lacros/holding_space_service_lacros_browsertest.cc b/chrome/browser/lacros/holding_space_service_lacros_browsertest.cc index 8d3beb8..8ab67c1 100644 --- a/chrome/browser/lacros/holding_space_service_lacros_browsertest.cc +++ b/chrome/browser/lacros/holding_space_service_lacros_browsertest.cc
@@ -133,7 +133,7 @@ // Verifies that print-to-PDF adds an associated item to holding space. IN_PROC_BROWSER_TEST_P(HoldingSpaceServicePrintToPdfIntegrationBrowserTest, - AddPrintedPdfItem) { + DISABLED_AddPrintedPdfItem) { // If holding space service interface is not available on this version of // ash-chrome, this test suite will no-op. if (!IsServiceAvailable())
diff --git a/chrome/browser/net/profile_network_context_service_browsertest.cc b/chrome/browser/net/profile_network_context_service_browsertest.cc index b58138d..f101a9f 100644 --- a/chrome/browser/net/profile_network_context_service_browsertest.cc +++ b/chrome/browser/net/profile_network_context_service_browsertest.cc
@@ -51,6 +51,7 @@ #include "components/prefs/pref_service.h" #include "components/privacy_sandbox/privacy_sandbox_features.h" #include "components/privacy_sandbox/privacy_sandbox_settings.h" +#include "components/privacy_sandbox/privacy_sandbox_test_util.h" #include "content/public/browser/network_service_instance.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/content_features.h" @@ -804,6 +805,12 @@ ProvideRequestHandlerKeyCommitmentsToNetworkService("a.test"); auto* privacy_sandbox_settings = PrivacySandboxSettingsFactory::GetForProfile(browser()->profile()); + auto privacy_sandbox_delegate = std::make_unique< + privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>(); + privacy_sandbox_delegate->SetupDefaultResponse(/*restricted=*/false, + /*confirmed=*/true); + privacy_sandbox_settings->SetDelegateForTesting( + std::move(privacy_sandbox_delegate)); privacy_sandbox_settings->SetPrivacySandboxEnabled(true); browser()->profile()->GetPrefs()->SetInteger( prefs::kCookieControlsMode,
diff --git a/chrome/browser/policy/messaging_layer/upload/record_upload_request_builder_unittest.cc b/chrome/browser/policy/messaging_layer/upload/record_upload_request_builder_unittest.cc index 6375f03..6f5042ac 100644 --- a/chrome/browser/policy/messaging_layer/upload/record_upload_request_builder_unittest.cc +++ b/chrome/browser/policy/messaging_layer/upload/record_upload_request_builder_unittest.cc
@@ -136,7 +136,8 @@ ASSERT_FALSE(request_payload.has_value()) << request_payload.value(); } -TEST_P(RecordUploadRequestBuilderTest, DenyPoorlyFormedEncryptedRecords) { +TEST_P(RecordUploadRequestBuilderTest, + DISABLED_DenyPoorlyFormedEncryptedRecords) { // Reject empty record. EncryptedRecord record; @@ -202,7 +203,7 @@ } TEST_P(RecordUploadRequestBuilderTest, - DontBuildCompressionRequestIfNoInformation) { + DISABLED_DontBuildCompressionRequestIfNoInformation) { EncryptedRecord compressionless_record = GenerateEncryptedRecord("TEST_INFO"); ASSERT_FALSE(compressionless_record.has_compression_information());
diff --git a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/AdPersonalizationFragment.java b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/AdPersonalizationFragment.java index 50fca7d..379ac1f 100644 --- a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/AdPersonalizationFragment.java +++ b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/AdPersonalizationFragment.java
@@ -81,9 +81,9 @@ List<Topic> blockedTopics = PrivacySandboxBridge.getBlockedTopics(); int description = PrivacySandboxBridge.isPrivacySandboxEnabled() - ? (!currentTopics.isEmpty() - ? R.string.privacy_sandbox_ad_personalization_description_trials_on - : R.string.privacy_sandbox_ad_personalization_description_no_items) + ? (currentTopics.isEmpty() && blockedTopics.isEmpty() + ? R.string.privacy_sandbox_ad_personalization_description_no_items + : R.string.privacy_sandbox_ad_personalization_description_trials_on) : R.string.privacy_sandbox_ad_personalization_description_trials_off; mDescriptionPreference.setSummary(description);
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc index fbfb56e..eaf3d35 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service.cc
@@ -111,6 +111,16 @@ return number_of_days; } +// Returns whether 3P cookies are blocked by |cookie_settings|. This can be +// either through blocking 3P cookies directly, or blocking all cookies. +bool AreThirdPartyCookiesBlocked( + content_settings::CookieSettings* cookie_settings) { + const auto default_content_setting = + cookie_settings->GetDefaultCookieSetting(/*provider_id=*/nullptr); + return cookie_settings->ShouldBlockThirdPartyCookies() || + default_content_setting == ContentSetting::CONTENT_SETTING_BLOCK; +} + } // namespace PrivacySandboxService::PrivacySandboxService() = default; @@ -163,6 +173,11 @@ // further separated from cookie controls. MaybeReconcilePrivacySandboxPref(); + // When the user enters the Privacy Sandbox 3 experiment, the default value + // of their V2 pref must be set. This is a one time operation that is checked + // here to ensure it runs on profile startup. + InitializePrivacySandboxV2Pref(); + // If the Sandbox is currently restricted, disable the V2 preference. The user // must manually enable the sandbox if they stop being restricted. if (IsPrivacySandboxRestricted()) @@ -173,15 +188,8 @@ PrivacySandboxService::DialogType PrivacySandboxService::GetRequiredDialogType() { - const auto cookie_controls_mode = - static_cast<content_settings::CookieControlsMode>( - pref_service_->GetInteger(prefs::kCookieControlsMode)); - const auto default_content_setting = - cookie_settings_->GetDefaultCookieSetting(/*provider_id=*/nullptr); const auto third_party_cookies_blocked = - default_content_setting == ContentSetting::CONTENT_SETTING_BLOCK || - cookie_controls_mode == - content_settings::CookieControlsMode::kBlockThirdParty; + AreThirdPartyCookiesBlocked(cookie_settings_); return GetRequiredDialogTypeInternal(pref_service_, profile_type_, privacy_sandbox_settings_, third_party_cookies_blocked); @@ -356,7 +364,9 @@ } bool PrivacySandboxService::IsPrivacySandboxEnabled() { - return privacy_sandbox_settings_->IsPrivacySandboxEnabled(); + return base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3) + ? pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabledV2) + : pref_service_->GetBoolean(prefs::kPrivacySandboxFlocEnabled); } bool PrivacySandboxService::IsPrivacySandboxManaged() { @@ -374,6 +384,11 @@ } void PrivacySandboxService::SetPrivacySandboxEnabled(bool enabled) { + pref_service_->SetBoolean( + base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3) + ? prefs::kPrivacySandboxManuallyControlledV2 + : prefs::kPrivacySandboxManuallyControlled, + true); privacy_sandbox_settings_->SetPrivacySandboxEnabled(enabled); } @@ -574,6 +589,39 @@ LogPrivacySandboxState(); } +void PrivacySandboxService::InitializePrivacySandboxV2Pref() { + if (!base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3)) + return; + + // The initialization process may turn a preference which is otherwise default + // off, on. The default setting for the user is provided by Finch and may + // change over time (e.g. location change). This init logic is however only + // ever performed once per profile, and so will not attempt to enable if the + // user changes location. + if (pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabledV2Init)) + return; + + pref_service_->SetBoolean(prefs::kPrivacySandboxApisEnabledV2Init, true); + + // This logic should run before the user has had an opporunity to interact + // with the Privacy Sandbox controls. + DCHECK( + !pref_service_->GetBoolean(prefs::kPrivacySandboxManuallyControlledV2)); + + // Users must have the V1 sandbox enabled, 3P cookies enabled, and the + // appropriate feature parameter for the V2 pref to be default enabled. + if (!pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabled)) + return; + + if (AreThirdPartyCookiesBlocked(cookie_settings_)) + return; + + if (!privacy_sandbox::kPrivacySandboxSettings3DefaultOn.Get()) + return; + + pref_service_->SetBoolean(prefs::kPrivacySandboxApisEnabledV2, true); +} + void PrivacySandboxService::StopObserving() { // Removing a non-observing observer is a no-op. sync_service_observer_.Reset(); @@ -629,6 +677,16 @@ PSStartupStates::kDialogOffRestricted); return; } + // Handle manually controlled + if (pref_service_->GetBoolean( + prefs::kPrivacySandboxNoConfirmationManuallyControlled)) { + base::UmaHistogramEnumeration( + privacy_sandbox_startup_histogram, + sandbox_v2_enabled + ? PSStartupStates::kDialogOffManuallyControlledEnabled + : PSStartupStates::kDialogOffManuallyControlledDisabled); + return; + } if (privacy_sandbox::kPrivacySandboxSettings3ConsentRequired.Get()) { if (!pref_service_->GetBoolean(prefs::kPrivacySandboxConsentDecisionMade)) { base::UmaHistogramEnumeration(privacy_sandbox_startup_histogram, @@ -639,7 +697,7 @@ sandbox_v2_enabled ? PSStartupStates::kConsentShownEnabled : PSStartupStates::kConsentShownDisabled); - } else { // Notice required. + } else if (privacy_sandbox::kPrivacySandboxSettings3NoticeRequired.Get()) { if (!pref_service_->GetBoolean(prefs::kPrivacySandboxNoticeDisplayed)) { base::UmaHistogramEnumeration(privacy_sandbox_startup_histogram, PSStartupStates::kDialogWaiting); @@ -649,6 +707,11 @@ sandbox_v2_enabled ? PSStartupStates::kNoticeShownEnabled : PSStartupStates::kNoticeShownDisabled); + } else { // No dialog currently required. + base::UmaHistogramEnumeration( + privacy_sandbox_startup_histogram, + sandbox_v2_enabled ? PSStartupStates::kNoDialogRequiredEnabled + : PSStartupStates::kNoDialogRequiredDisabled); } } @@ -824,6 +887,16 @@ if (privacy_sandbox::kPrivacySandboxSettings3ForceShowNoticeForTesting.Get()) return DialogType::kNotice; + // If neither consent or notice is required, no dialog is required. + if (!privacy_sandbox::kPrivacySandboxSettings3ConsentRequired.Get() && + !privacy_sandbox::kPrivacySandboxSettings3NoticeRequired.Get()) { + return DialogType::kNone; + } + + // Only one of the consent or notice should be required by Finch parameters. + DCHECK(!privacy_sandbox::kPrivacySandboxSettings3ConsentRequired.Get() || + !privacy_sandbox::kPrivacySandboxSettings3NoticeRequired.Get()); + // Start by checking for any previous decision about the dialog, such as // it already having been shown, or not having been shown for some reason. // These checks for previous decisions occur in advance of their corresponding @@ -869,6 +942,13 @@ return DialogType::kNone; } + // If the user wasn't shown a confirmation because they are already manually + // controlling the sandbox, do not attempt to show one. + if (pref_service->GetBoolean( + prefs::kPrivacySandboxNoConfirmationManuallyControlled)) { + return DialogType::kNone; + } + // If the Privacy Sandbox is restricted, no dialog is shown. if (privacy_sandbox_settings->IsPrivacySandboxRestricted()) { pref_service->SetBoolean( @@ -891,6 +971,14 @@ return DialogType::kNone; } + // If the Privacy Sandbox has been manually controlled by the user, no dialog + // is shown. + if (pref_service->GetBoolean(prefs::kPrivacySandboxManuallyControlledV2)) { + pref_service->SetBoolean( + prefs::kPrivacySandboxNoConfirmationManuallyControlled, true); + return DialogType::kNone; + } + // If a user now requires consent, but has previously seen a notice, whether // a consent is shown depends on their current Privacy Sandbox setting. if (privacy_sandbox::kPrivacySandboxSettings3ConsentRequired.Get() && @@ -929,11 +1017,6 @@ DCHECK(!pref_service->GetBoolean(prefs::kPrivacySandboxNoticeDisplayed)); DCHECK(!pref_service->GetBoolean(prefs::kPrivacySandboxConsentDecisionMade)); - // The user should not have been able to enable the Sandbox without a - // previous decision having been made. The exception to this is through test - // only feature parameters, which will have let the user skip confirmation. - DCHECK(!pref_service->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); - // If the user had previously disabled the Privacy Sandbox, no confirmation // will be shown. if (!pref_service->GetBoolean(prefs::kPrivacySandboxApisEnabled)) { @@ -944,9 +1027,11 @@ // Check if the users requires a consent. This information is provided by // feature parameter to allow Finch based geo-targeting. - if (privacy_sandbox::kPrivacySandboxSettings3ConsentRequired.Get()) + if (privacy_sandbox::kPrivacySandboxSettings3ConsentRequired.Get()) { return DialogType::kConsent; + } // Finally a notice is required. + DCHECK(privacy_sandbox::kPrivacySandboxSettings3NoticeRequired.Get()); return DialogType::kNotice; }
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service.h b/chrome/browser/privacy_sandbox/privacy_sandbox_service.h index a561f8a..9b353b5 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service.h +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service.h
@@ -177,13 +177,18 @@ // Sets the FLoC preference to |enabled|. void SetFlocPrefEnabled(bool enabled) const; - // Disables the Privacy Sandbox completely if |enabled| is false, if |enabled| - // is true, more granular checks will still be performed to determine if - // specific APIs are available in specific contexts. + // Disables the Privacy Sandbox completely if |enabled| is false. If |enabled| + // is true, context specific as well as restriction/confirmation checks + // will still be performed to determine if specific APIs are available in + // specific contexts. void SetPrivacySandboxEnabled(bool enabled); - // Used by the UI to check if the API is enabled. Checks the primary - // pref directly. + // Used by the UI to check if the API is enabled. This is a UI function ONLY. + // Checks the primary pref directly, and _only_ the primary pref. There are + // many other reasons that API access may be denied that are not checked by + // this function. All decisions for allowing access to APIs should be routed + // through the PrivacySandboxSettings class. + // TODO(crbug.com/1310157): Rename this function to better reflect this. bool IsPrivacySandboxEnabled(); // Returns whether the state of the API is managed. @@ -288,6 +293,9 @@ NoMetricsRecorded); FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceDialogTest, RestrictedDialog); FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceDialogTest, ManagedNoDialog); + FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceDialogTest, + ManuallyControlledNoDialog); + FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceDialogTest, NoParamNoDialog); FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceDeathTest, GetRequiredDialogType); FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, @@ -314,6 +322,15 @@ PrivacySandboxManagedEnabled); FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, PrivacySandboxManagedDisabled); + FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, + PrivacySandboxManuallyControlledEnabled); + FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, + PrivacySandboxManuallyControlledDisabled); + FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, + PrivacySandboxNoDialogDisabled); + FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, + PrivacySandboxNoDialogEnabled); + FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, InitializeV2Pref); FRIEND_TEST_ALL_PREFIXES(PrivacySandboxServiceTest, PrivacySandboxRestricted); // Should be used only for tests when mocking the service. @@ -357,10 +374,14 @@ kDialogOffManagedEnabled = 9, kDialogOffManagedDisabled = 10, kDialogOffRestricted = 11, + kDialogOffManuallyControlledEnabled = 12, + kDialogOffManuallyControlledDisabled = 13, + kNoDialogRequiredEnabled = 14, + kNoDialogRequiredDisabled = 15, // Add values above this line with a corresponding label in // tools/metrics/histograms/enums.xml - kMaxValue = kDialogOffRestricted, + kMaxValue = kNoDialogRequiredDisabled, }; // Inspects the current sync state and settings to determine if the Privacy @@ -375,6 +396,10 @@ // user out of the sandbox. void ReconcilePrivacySandboxPref(); + // Potentially enables the Privacy Sandbox V2 pref if required based on + // feature parameters and the profiles current state. + void InitializePrivacySandboxV2Pref(); + // Stops any observation of services being performed by this class. void StopObserving();
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc index 060be49..a72191ba 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_service_unittest.cc
@@ -134,33 +134,33 @@ /*new_api_pref=*/true, /*notice_displayed=*/false, /*consent_decision_made=*/false, /*confirmation_not_shown=*/false}, - {/*dcheck_failure=*/true, + {/*dcheck_failure=*/false, /*dialog_type=*/PrivacySandboxService::DialogType::kNone, - /*new_api_pref=*/false}}, + /*new_api_pref=*/true}}, {{/*consent_required=*/true, /*old_api_pref=*/false, /*new_api_pref=*/true, /*notice_displayed=*/false, /*consent_decision_made=*/false, /*confirmation_not_shown=*/false}, - {/*dcheck_failure=*/true, + {/*dcheck_failure=*/false, /*dialog_type=*/PrivacySandboxService::DialogType::kNone, - /*new_api_pref=*/false}}, + /*new_api_pref=*/true}}, {{/*consent_required=*/false, /*old_api_pref=*/true, /*new_api_pref=*/true, /*notice_displayed=*/false, /*consent_decision_made=*/false, /*confirmation_not_shown=*/false}, - {/*dcheck_failure=*/true, - /*dialog_type=*/PrivacySandboxService::DialogType::kNone, - /*new_api_pref=*/false}}, + {/*dcheck_failure=*/false, + /*dialog_type=*/PrivacySandboxService::DialogType::kNotice, + /*new_api_pref=*/true}}, {{/*consent_required=*/true, /*old_api_pref=*/true, /*new_api_pref=*/true, /*notice_displayed=*/false, /*consent_decision_made=*/false, /*confirmation_not_shown=*/false}, - {/*dcheck_failure=*/true, - /*dialog_type=*/PrivacySandboxService::DialogType::kNone, - /*new_api_pref=*/false}}, + {/*dcheck_failure=*/false, + /*dialog_type=*/PrivacySandboxService::DialogType::kConsent, + /*new_api_pref=*/true}}, {{/*consent_required=*/false, /*old_api_pref=*/false, /*new_api_pref=*/false, @@ -618,7 +618,8 @@ feature_list->Reset(); feature_list->InitAndEnableFeatureWithParameters( privacy_sandbox::kPrivacySandboxSettings3, - {{"consent-required", test_state.consent_required ? "true" : "false"}}); + {{"consent-required", test_state.consent_required ? "true" : "false"}, + {"notice-required", !test_state.consent_required ? "true" : "false"}}); pref_service->SetUserPref( prefs::kPrivacySandboxApisEnabled, @@ -669,7 +670,8 @@ } virtual void InitializeBeforeStart() { - mock_delegate()->SetupDefaultResponse(/*restricted=*/false); + mock_delegate()->SetupDefaultResponse(/*restricted=*/false, + /*confirmed=*/true); } virtual profile_metrics::BrowserProfileType GetProfileType() { @@ -911,8 +913,7 @@ base::HistogramTester histogram_tester; feature_list()->Reset(); feature_list()->InitAndEnableFeatureWithParameters( - privacy_sandbox::kPrivacySandboxSettings3, - {{"consent-required", "false" /* consent required */}}); + privacy_sandbox::kPrivacySandboxSettings3, {{"notice-required", "true"}}); prefs()->SetUserPref(prefs::kPrivacySandboxNoConfirmationSandboxDisabled, std::make_unique<base::Value>(false)); prefs()->SetUserPref(prefs::kPrivacySandboxNoticeDisplayed, @@ -1202,7 +1203,7 @@ feature_list()->Reset(); feature_list()->InitAndEnableFeatureWithParameters( privacy_sandbox::kPrivacySandboxSettings3, - {{"consent-required", "false" /* consent required */}}); + {{"notice-required", "true" /* consent required */}}); prefs()->SetUserPref(prefs::kPrivacySandboxNoConfirmationSandboxDisabled, std::make_unique<base::Value>(false)); prefs()->SetUserPref(prefs::kPrivacySandboxNoticeDisplayed, @@ -1230,7 +1231,7 @@ feature_list()->Reset(); feature_list()->InitAndEnableFeatureWithParameters( privacy_sandbox::kPrivacySandboxSettings3, - {{"consent-required", "false" /* consent required */}}); + {{"notice-required", "true" /* consent required */}}); prefs()->SetUserPref(prefs::kPrivacySandboxNoConfirmationSandboxDisabled, std::make_unique<base::Value>(false)); prefs()->SetUserPref(prefs::kPrivacySandboxNoticeDisplayed, @@ -1253,6 +1254,60 @@ PrivacySandboxService::PSStartupStates::kNoticeShownDisabled, 1); } +TEST_F(PrivacySandboxServiceTest, PrivacySandboxManuallyControlledEnabled) { + base::HistogramTester histogram_tester; + feature_list()->InitAndEnableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabledV2, + std::make_unique<base::Value>(true)); + prefs()->SetUserPref(prefs::kPrivacySandboxNoConfirmationManuallyControlled, + std::make_unique<base::Value>(true)); + privacy_sandbox_service()->LogPrivacySandboxState(); + histogram_tester.ExpectUniqueSample(kPrivacySandboxStartupHistogram, + PrivacySandboxService::PSStartupStates:: + kDialogOffManuallyControlledEnabled, + 1); +} + +TEST_F(PrivacySandboxServiceTest, PrivacySandboxManuallyControlledDisabled) { + base::HistogramTester histogram_tester; + feature_list()->InitAndEnableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabledV2, + std::make_unique<base::Value>(false)); + prefs()->SetUserPref(prefs::kPrivacySandboxNoConfirmationManuallyControlled, + std::make_unique<base::Value>(true)); + privacy_sandbox_service()->LogPrivacySandboxState(); + histogram_tester.ExpectUniqueSample(kPrivacySandboxStartupHistogram, + PrivacySandboxService::PSStartupStates:: + kDialogOffManuallyControlledDisabled, + 1); +} + +TEST_F(PrivacySandboxServiceTest, PrivacySandboxNoDialogDisabled) { + base::HistogramTester histogram_tester; + feature_list()->InitAndEnableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabledV2, + std::make_unique<base::Value>(false)); + privacy_sandbox_service()->LogPrivacySandboxState(); + histogram_tester.ExpectUniqueSample( + kPrivacySandboxStartupHistogram, + PrivacySandboxService::PSStartupStates::kNoDialogRequiredDisabled, 1); +} + +TEST_F(PrivacySandboxServiceTest, PrivacySandboxNoDialogEnabled) { + base::HistogramTester histogram_tester; + feature_list()->InitAndEnableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabledV2, + std::make_unique<base::Value>(true)); + privacy_sandbox_service()->LogPrivacySandboxState(); + histogram_tester.ExpectUniqueSample( + kPrivacySandboxStartupHistogram, + PrivacySandboxService::PSStartupStates::kNoDialogRequiredEnabled, 1); +} + TEST_F(PrivacySandboxServiceTest, DialogActionsUMAActions) { base::UserActionTester user_action_tester; @@ -1448,10 +1503,88 @@ browsing_data_remover()->GetLastUsedOriginTypeMaskForTesting()); } +TEST_F(PrivacySandboxServiceTest, InitializeV2Pref) { + // Check that when the feature + parameters dictate, the V2 preference is + // turned on. + feature_list()->InitAndDisableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + privacy_sandbox_service()->InitializePrivacySandboxV2Pref(); + EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); + prefs()->RemoveUserPref(prefs::kPrivacySandboxApisEnabledV2Init); + + feature_list()->Reset(); + feature_list()->InitAndEnableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + privacy_sandbox_service()->InitializePrivacySandboxV2Pref(); + EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); + prefs()->RemoveUserPref(prefs::kPrivacySandboxApisEnabledV2Init); + + feature_list()->Reset(); + feature_list()->InitAndEnableFeatureWithParameters( + privacy_sandbox::kPrivacySandboxSettings3, + {{"setting-default-on", "true"}}); + privacy_sandbox_service()->InitializePrivacySandboxV2Pref(); + EXPECT_TRUE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); + prefs()->RemoveUserPref(prefs::kPrivacySandboxApisEnabledV2); + prefs()->RemoveUserPref(prefs::kPrivacySandboxApisEnabledV2Init); + + // Blocking 3PC should prevent the pref from being enabled. + prefs()->SetUserPref( + prefs::kCookieControlsMode, + std::make_unique<base::Value>(static_cast<int>( + content_settings::CookieControlsMode::kBlockThirdParty))); + privacy_sandbox_service()->InitializePrivacySandboxV2Pref(); + EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); + prefs()->RemoveUserPref(prefs::kPrivacySandboxApisEnabledV2Init); + prefs()->RemoveUserPref(prefs::kCookieControlsMode); + + // Blocking all cookies should prevent the pref from being enabled. + cookie_settings()->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK); + privacy_sandbox_service()->InitializePrivacySandboxV2Pref(); + EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); + prefs()->RemoveUserPref(prefs::kPrivacySandboxApisEnabledV2Init); + cookie_settings()->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW); + + // Having a disabled Privacy Sandbox V1 control should prevent the pref from + // being enabled. + prefs()->SetBoolean(prefs::kPrivacySandboxApisEnabled, false); + privacy_sandbox_service()->InitializePrivacySandboxV2Pref(); + EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); + prefs()->RemoveUserPref(prefs::kPrivacySandboxApisEnabledV2Init); + prefs()->RemoveUserPref(prefs::kPrivacySandboxApisEnabled); + + // Otherwise the pref should be enabled, but only once. + privacy_sandbox_service()->InitializePrivacySandboxV2Pref(); + EXPECT_TRUE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); + prefs()->SetBoolean(prefs::kPrivacySandboxApisEnabledV2, false); + privacy_sandbox_service()->InitializePrivacySandboxV2Pref(); + EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); +} + +class PrivacySandboxPrefInitTest : public PrivacySandboxServiceTest { + void InitializeBeforeStart() override { + feature_list()->InitAndEnableFeatureWithParameters( + privacy_sandbox::kPrivacySandboxSettings3, + {{"setting-default-on", "true"}}); + } +}; + +TEST_F(PrivacySandboxPrefInitTest, InitalizeV2PrefOnStartup) { + // Confirm that the V2 pref has been initialized as part of the service + // startup. Conditions for initialization were set in the test creation. + EXPECT_TRUE(prefs()->GetBoolean(prefs::kPrivacySandboxApisEnabledV2)); +} + class PrivacySandboxRestrictedTest : public PrivacySandboxServiceTest { void InitializeBeforeStart() override { prefs()->SetBoolean(prefs::kPrivacySandboxApisEnabledV2, true); - mock_delegate()->SetupDefaultResponse(/*restricted=*/true); + mock_delegate()->SetupDefaultResponse(/*restricted=*/true, + /*confirmed=*/true); + + // A restriction should override a default on preference. + feature_list()->InitAndEnableFeatureWithParameters( + privacy_sandbox::kPrivacySandboxSettings3, + {{"setting-default-on", "true"}}); } }; @@ -1503,6 +1636,8 @@ profile()->GetTestingPrefService()->SetUserPref( prefs::kPrivacySandboxPreferencesReconciled, std::make_unique<base::Value>(true)); + mock_delegate()->SetupDefaultResponse(/*restricted=*/false, + /*confirmed=*/true); } void ResetReconciledPref() { @@ -2276,6 +2411,14 @@ TEST_F(PrivacySandboxServiceDialogTest, ManagedNoDialog) { // Confirm that when the Privacy Sandbox is managed, that no dialog is // shown. + SetupDialogTestState(feature_list(), prefs(), + {/*consent_required=*/true, + /*old_api_pref=*/true, + /*new_api_pref=*/false, + /*notice_displayed=*/false, + /*consent_decision_made=*/false, + /*confirmation_not_shown=*/false}); + prefs()->SetManagedPref(prefs::kPrivacySandboxApisEnabledV2, base::Value(true)); EXPECT_EQ( @@ -2293,6 +2436,37 @@ privacy_sandbox_settings(), /*third_party_cookies_blocked=*/false)); } +TEST_F(PrivacySandboxServiceDialogTest, ManuallyControlledNoDialog) { + // Confirm that if the Privacy Sandbox V2 is manually controlled by the user, + // that no dialog is shown. + SetupDialogTestState(feature_list(), prefs(), + {/*consent_required=*/true, + /*old_api_pref=*/true, + /*new_api_pref=*/false, + /*notice_displayed=*/false, + /*consent_decision_made=*/false, + /*confirmation_not_shown=*/false}); + prefs()->SetUserPref(prefs::kPrivacySandboxManuallyControlledV2, + base::Value(true)); + EXPECT_EQ( + PrivacySandboxService::DialogType::kNone, + PrivacySandboxService::GetRequiredDialogTypeInternal( + prefs(), profile_metrics::BrowserProfileType::kRegular, + privacy_sandbox_settings(), /*third_party_cookies_blocked=*/false)); +} + +TEST_F(PrivacySandboxServiceDialogTest, NoParamNoDialog) { + // Confirm that if neither the consent or notice parameter is set, no dialog + // is required. + feature_list()->InitAndEnableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + EXPECT_EQ( + PrivacySandboxService::DialogType::kNone, + PrivacySandboxService::GetRequiredDialogTypeInternal( + prefs(), profile_metrics::BrowserProfileType::kRegular, + privacy_sandbox_settings(), /*third_party_cookies_blocked=*/false)); +} + class PrivacySandboxServiceDeathTest : public PrivacySandboxServiceDialogTestBase, public testing::TestWithParam<int> {};
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.cc index a31b09a9..d3933826 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.cc
@@ -7,7 +7,9 @@ #include "base/feature_list.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_manager_factory.h" +#include "components/prefs/pref_service.h" #include "components/privacy_sandbox/privacy_sandbox_features.h" +#include "components/privacy_sandbox/privacy_sandbox_prefs.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/tribool.h" @@ -48,3 +50,26 @@ // No restrictions apply otherwise. return false; } + +bool PrivacySandboxSettingsDelegate::IsPrivacySandboxConfirmed() { + // Confirmation is only required for Privacy Sandbox release 3. + if (!base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3)) + return true; + + // Manually enabling the override feature counts as confirmation. + if (base::FeatureList::IsEnabled( + privacy_sandbox::kOverridePrivacySandboxSettingsLocalTesting)) { + return true; + } + + // Confirmation requires that either the Privacy Sandbox is manually + // controlled, or the user has seen the appropriate level of confirmation. + if (profile_->GetPrefs()->GetBoolean( + prefs::kPrivacySandboxManuallyControlledV2)) + return true; + + return profile_->GetPrefs()->GetBoolean( + privacy_sandbox::kPrivacySandboxSettings3ConsentRequired.Get() + ? prefs::kPrivacySandboxConsentDecisionMade + : prefs::kPrivacySandboxNoticeDisplayed); +}
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h index b9a9e460..0c458fe 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate.h
@@ -17,6 +17,7 @@ // PrivacySandboxSettings::Delegate: bool IsPrivacySandboxRestricted() override; + bool IsPrivacySandboxConfirmed() override; private: Profile* profile_;
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate_unittest.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate_unittest.cc index 9e65a15..f92cd2f7 100644 --- a/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate_unittest.cc +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_settings_delegate_unittest.cc
@@ -9,6 +9,7 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "components/privacy_sandbox/privacy_sandbox_features.h" +#include "components/privacy_sandbox/privacy_sandbox_prefs.h" #include "components/signin/public/identity_manager/account_capabilities_test_mutator.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "content/public/test/browser_task_environment.h" @@ -51,6 +52,9 @@ return adapter_->identity_test_env(); } TestingProfile* profile() { return profile_.get(); } + sync_preferences::TestingPrefServiceSyncable* prefs() { + return profile()->GetTestingPrefService(); + } private: content::BrowserTaskEnvironment browser_task_environment_; @@ -103,3 +107,37 @@ EXPECT_FALSE(delegate()->IsPrivacySandboxRestricted()); } #endif + +TEST_F(PrivacySandboxSettingsDelegateTest, Confirmation_Release3Enabled) { + feature_list()->InitAndEnableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + EXPECT_FALSE(delegate()->IsPrivacySandboxConfirmed()); + + // Manually controlling V1 should not count as confirmation, while V2 should. + prefs()->SetBoolean(prefs::kPrivacySandboxManuallyControlled, true); + EXPECT_FALSE(delegate()->IsPrivacySandboxConfirmed()); + prefs()->SetBoolean(prefs::kPrivacySandboxManuallyControlledV2, true); + EXPECT_TRUE(delegate()->IsPrivacySandboxConfirmed()); + prefs()->SetBoolean(prefs::kPrivacySandboxManuallyControlledV2, false); + + // While a consent is not required, seeing a notice should suffice. + prefs()->SetBoolean(prefs::kPrivacySandboxNoticeDisplayed, true); + EXPECT_TRUE(delegate()->IsPrivacySandboxConfirmed()); + + // If a notice is required, it should not suffice. + feature_list()->Reset(); + feature_list()->InitAndEnableFeatureWithParameters( + privacy_sandbox::kPrivacySandboxSettings3, + {{"consent-required", "true"}}); + EXPECT_FALSE(delegate()->IsPrivacySandboxConfirmed()); + prefs()->SetBoolean(prefs::kPrivacySandboxConsentDecisionMade, true); + EXPECT_TRUE(delegate()->IsPrivacySandboxConfirmed()); +} + +TEST_F(PrivacySandboxSettingsDelegateTest, Confirmation_Release3Disabled) { + // If the Privacy Sandbox Settings 3 feature is disabled, no confirmation is + // required. + feature_list()->InitAndDisableFeature( + privacy_sandbox::kPrivacySandboxSettings3); + EXPECT_TRUE(delegate()->IsPrivacySandboxConfirmed()); +}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index b1e36c1..a3f5b0c 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -42,7 +42,6 @@ "background/logging/log_types.js", "background/logging/output_logger.js", "background/logging/tree_dumper.js", - "background/math_handler.js", "background/output/output.js", "background/output/output_ancestry_info.js", "background/output/output_format_parser.js", @@ -51,7 +50,6 @@ "background/output/output_types.js", "background/panel_command.js", "background/phonetic_data.js", - "background/prefs.js", "background/user_action_monitor.js", "braille/bluetooth_braille_display_manager.js", "braille/bluetooth_braille_display_ui.js", @@ -113,10 +111,12 @@ "background/injected_script_loader.js", "background/keyboard_handler.js", "background/live_regions.js", + "background/math_handler.js", "background/media_automation_handler.js", "background/range_automation_handler.js", "background/page_load_sound_handler.js", "background/pointer_handler.js", + "background/prefs.js", "background/smart_sticky_mode.js", "background/logging/log.js", "braille/braille_key_event_rewriter.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js index ac70485..4161194 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
@@ -16,6 +16,7 @@ import {GestureCommandHandler} from './gesture_command_handler.js'; import {BackgroundKeyboardHandler} from './keyboard_handler.js'; import {LiveRegions} from './live_regions.js'; +import {MathHandler} from './math_handler.js'; import {MediaAutomationHandler} from './media_automation_handler.js'; import {PageLoadSoundHandler} from './page_load_sound_handler.js'; import {RangeAutomationHandler} from './range_automation_handler.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js index 795ddf14..c4addc6 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
@@ -12,6 +12,7 @@ import {BrailleBackground} from './braille_background.js'; import {InjectedScriptLoader} from './injected_script_loader.js'; +import {ChromeVoxPrefs} from './prefs.js'; /** * This is the legacy ChromeVox background object.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js index 28df8f7..122cbd37 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
@@ -16,6 +16,7 @@ import {DesktopAutomationInterface} from './desktop_automation_interface.js'; import {GestureGranularity} from './gesture_command_data.js'; import {GestureInterface} from './gesture_interface.js'; +import {ChromeVoxPrefs} from './prefs.js'; import {SmartStickyMode} from './smart_sticky_mode.js'; const ActionType = chrome.automation.ActionType;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler.js index 24a62ef..607cf40 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler.js
@@ -7,6 +7,9 @@ */ import {ChromeVoxKbHandler} from '../common/keyboard_handler.js'; +import {MathHandler} from './math_handler.js'; +import {ChromeVoxPrefs} from './prefs.js'; + /** * @enum {string} * Internal pass through mode state (see usage below).
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js index 167efb6a..77fa89c0 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
@@ -20,7 +20,6 @@ goog.require('BrailleKeyEvent'); goog.require('BrailleTranslatorManager'); goog.require('ChromeVox'); -goog.require('ChromeVoxPrefs'); goog.require('ChromeVoxState'); goog.require('ChromeVoxStateObserver'); goog.require('CommandHandlerInterface'); @@ -38,7 +37,6 @@ goog.require('LibLouis.FormType'); goog.require('LocaleOutputHelper'); goog.require('LogStore'); -goog.require('MathHandler'); goog.require('Msgs'); goog.require('NavBraille'); goog.require('Output');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/math_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/math_handler.js index 23d905a..811ad78 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/math_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/math_handler.js
@@ -6,12 +6,10 @@ * @fileoverview Handles math output and exploration. */ -goog.provide('MathHandler'); - /** * Initializes math for output and exploration. */ -MathHandler = class { +export class MathHandler { /** * @param {!chrome.automation.AutomationNode} node */ @@ -93,7 +91,7 @@ } return false; } -}; +} /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js index 6acceb3..52c3eda 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js
@@ -8,20 +8,12 @@ * */ -goog.provide('ChromeVoxPrefs'); -goog.provide('RichTextSpeechStyle'); - -goog.require('ConsoleTts'); -goog.require('EventStreamLogger'); -goog.require('ChromeVox'); -goog.require('ExtensionBridge'); - /** * This object has default values of preferences and contains the common * code for working with preferences shared by the Options and Background * pages. */ -ChromeVoxPrefs = class { +export class ChromeVoxPrefs { constructor() { let lastRunVersion = localStorage['lastRunVersion']; if (!lastRunVersion) { @@ -100,7 +92,7 @@ EventStreamLogger.instance.notifyEventStreamFilterChangedAll(value); } } -}; +} /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js index 643e955b..6a79707 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
@@ -6,6 +6,7 @@ * @fileoverview ChromeVox options page. * */ +import {ChromeVoxPrefs} from '../background/prefs.js'; import {TtsBackground} from '../common/tts_background.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js index 1323afd..3bc8cf77 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js
@@ -8,11 +8,11 @@ goog.require('AbstractTts'); goog.require('BluetoothBrailleDisplayUI'); -goog.require('ConsoleTts'); -goog.require('Msgs'); -goog.require('PanelCommand'); goog.require('BrailleTable'); goog.require('BrailleTranslatorManager'); goog.require('ChromeVox'); -goog.require('ChromeVoxPrefs'); +goog.require('ConsoleTts'); +goog.require('EventStreamLogger'); goog.require('ExtensionBridge'); +goog.require('Msgs'); +goog.require('PanelCommand');
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn index 20d2438..6fb97f01 100644 --- a/chrome/browser/resources/new_tab_page/BUILD.gn +++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -4,6 +4,7 @@ import("//chrome/browser/resources/tools/optimize_webui.gni") import("//chrome/common/features.gni") +import("//tools/code_coverage/create_js_source_maps/create_js_source_maps.gni") import("//tools/grit/grit_rule.gni") import("//tools/grit/preprocess_if_expr.gni") import("//tools/polymer/html_to_wrapper.gni") @@ -28,6 +29,7 @@ in_folder = "." out_folder = "$target_gen_dir/$preprocess_folder" in_files = ts_files + enable_removal_comments = true } preprocess_if_expr("preprocess_gen") { @@ -36,6 +38,7 @@ in_folder = target_gen_dir out_folder = "$target_gen_dir/$preprocess_folder" in_files = html_wrapper_files + enable_removal_comments = true } # Copy all Mojom generated JS files used by the NTP to a common location so that @@ -214,3 +217,10 @@ ":preprocess_gen", ] } + +create_js_source_maps("sourcemaps") { + deps = [ + ":preprocess", + ":preprocess_gen", + ] +}
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.html b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.html index 8caf22e8..e8624d0a 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.html
@@ -57,7 +57,7 @@ <div id="resultText" aria-hidden="true" inner-h-t-m-l="[[getResultInnerHtml_(searchResult)]]"> </div> - <iron-icon id="actionTypeIcon" icon="[[getActionTypeIcon_(searchResult)]]"> + <iron-icon id="actionTypeIcon" icon="cr:arrow-forward"> </iron-icon> </div> </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js index a0d60c2..b1a2a4f 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js +++ b/chrome/browser/resources/settings/chromeos/os_settings_search_box/os_search_result_row.js
@@ -12,7 +12,6 @@ import {assert, assertNotReached} from '//resources/js/assert.m.js'; import {FocusRowBehavior} from '//resources/js/cr/ui/focus_row_behavior.m.js'; import {I18nBehavior} from '//resources/js/i18n_behavior.m.js'; -import {loadTimeData} from '//resources/js/load_time_data.m.js'; import {IronA11yAnnouncer} from '//resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js'; import {afterNextRender, flush, html, Polymer, TemplateInstanceBase, Templatizer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -597,14 +596,6 @@ assert(this.searchResult.urlPathWithParameters, 'Url path is empty.'); this.recordSearchResultMetrics_(); - // Enable launching Personalization Hub for settings related to wallpaper, - // ambient mode, user avatar, etc. - const externalUrlToOpen = this.getExternalUrlForSearchResult_(); - if (externalUrlToOpen) { - OpenWindowProxyImpl.getInstance().openURL(externalUrlToOpen); - return; - } - // |this.searchResult.urlPathWithParameters| separates the path and params // by a '?' char. const pathAndOptParams = @@ -717,69 +708,4 @@ return 'os-settings:settings-general'; } }, - - /** - * @return {string} the external url to be opened in a new window. Empty if - * no external url should be opened. - * @private - */ - getExternalUrlForSearchResult_() { - if (!loadTimeData.getBoolean('isPersonalizationHubEnabled')) { - return ''; - } - - const PERSONALIZATION_ROOT_URL = 'chrome://personalization'; - const PERSONALIZATION_AMBIENT_URL = PERSONALIZATION_ROOT_URL + '/ambient'; - const PERSONALIZATION_USER_URL = PERSONALIZATION_ROOT_URL + '/user'; - const PERSONALIZATION_WALLPAPER_URL = - PERSONALIZATION_ROOT_URL + '/wallpaper'; - - const SearchResultType = chromeos.settings.mojom.SearchResultType; - const Setting = chromeos.settings.mojom.Setting; - const Section = chromeos.settings.mojom.Section; - const Subpage = chromeos.settings.mojom.Subpage; - switch (this.searchResult.type) { - case SearchResultType.kSection: { - switch (this.searchResult.id.section) { - case Section.kPersonalization: - return PERSONALIZATION_ROOT_URL; - } - } - case SearchResultType.kSetting: { - switch (this.searchResult.id.setting) { - case Setting.kDarkModeOnOff: - return PERSONALIZATION_ROOT_URL; - case Setting.kAmbientModeOnOff: - case Setting.kAmbientModeSource: - return PERSONALIZATION_AMBIENT_URL; - case Setting.kChangeDeviceAccountImage: - return PERSONALIZATION_USER_URL; - case Setting.kOpenWallpaper: - return PERSONALIZATION_WALLPAPER_URL; - } - } - case SearchResultType.kSubpage: { - switch (this.searchResult.id.subpage) { - case Subpage.kDarkMode: - return PERSONALIZATION_ROOT_URL; - case Subpage.kAmbientMode: - case Subpage.kAmbientModeArtGalleryAlbum: - case Subpage.kAmbientModeGooglePhotosAlbum: - return PERSONALIZATION_AMBIENT_URL; - case Subpage.kChangePicture: - return PERSONALIZATION_USER_URL; - } - } - } - return ''; - }, - - /** - * @return {string} The name of the icon to use. - * @private - */ - getActionTypeIcon_() { - return this.getExternalUrlForSearchResult_() ? 'cr:open-in-new' : - 'cr:arrow-forward'; - }, });
diff --git a/chrome/browser/resources/settings/privacy_sandbox/app.html b/chrome/browser/resources/settings/privacy_sandbox/app.html index 2ad6f2da..77c87c3 100644 --- a/chrome/browser/resources/settings/privacy_sandbox/app.html +++ b/chrome/browser/resources/settings/privacy_sandbox/app.html
@@ -284,9 +284,10 @@ </div> <div class="ad-personalization-section-title"> $i18n{privacySandboxAdPersonalizationDialogTopicsTitle} - <iron-icon id="topicsTooltipIcon" tabindex="0" + <iron-icon id="topicsTooltipIcon" tabindex="0" role="button" aria-describedby="topicsTooltip" icon="cr:info-outline" - on-focus="onShowTooltip_" on-mouseenter="onShowTooltip_"> + on-focus="onShowTooltip_" on-mouseenter="onShowTooltip_" + aria-label="$i18n{privacySandboxAdPersonalizationDialogTopicsTitle}"> </iron-icon> <paper-tooltip id="topicsTooltip" for="topicsTooltipIcon" position="bottom" manual-mode fit-to-visible-bounds> @@ -321,9 +322,10 @@ </div> <div class="ad-personalization-section-title"> $i18n{privacySandboxAdPersonalizationDialogFledgeTitle} - <iron-icon id="fledgeTooltipIcon" tabindex="0" + <iron-icon id="fledgeTooltipIcon" tabindex="0" role="button" aria-describedby="fledgeTooltip" icon="cr:info-outline" - on-focus="onShowTooltip_" on-mouseenter="onShowTooltip_"> + on-focus="onShowTooltip_" on-mouseenter="onShowTooltip_" + aria-label="$i18n{privacySandboxAdPersonalizationDialogFledgeTitle}"> </iron-icon> <paper-tooltip id="fledgeTooltip" for="fledgeTooltipIcon" position="bottom" manual-mode fit-to-visible-bounds> @@ -364,7 +366,7 @@ privacySandboxSettingsView_)]]"> <div class="ad-personalization-title" slot="title"> <cr-icon-button id="adPersonalizationBackButton" - class="icon-arrow-back" + class="icon-arrow-back" aria-label="$i18n{back}" on-click="onAdPersonalizationBackButtonClick_"> </cr-icon-button> <span class="flex">
diff --git a/chrome/browser/resources/settings/privacy_sandbox/app.ts b/chrome/browser/resources/settings/privacy_sandbox/app.ts index 7cea5202..80aaabf 100644 --- a/chrome/browser/resources/settings/privacy_sandbox/app.ts +++ b/chrome/browser/resources/settings/privacy_sandbox/app.ts
@@ -246,7 +246,8 @@ const enabled = this.getPref('privacy_sandbox.apis_enabled_v2').value; if (enabled) { return loadTimeData.getString( - this.topTopics_.length || this.joiningSites_.length ? + this.topTopics_.length || this.blockedTopics_.length || + this.joiningSites_.length || this.blockedSites_.length ? 'privacySandboxAdPersonalizationDialogDescription' : 'privacySandboxAdPersonalizationDialogDescriptionListsEmpty'); }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 86996472..c449ce4 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -2042,6 +2042,8 @@ "app_list/search/mixer.h", "app_list/search/omnibox_answer_result.cc", "app_list/search/omnibox_answer_result.h", + "app_list/search/omnibox_lacros_provider.cc", + "app_list/search/omnibox_lacros_provider.h", "app_list/search/omnibox_provider.cc", "app_list/search/omnibox_provider.h", "app_list/search/omnibox_result.cc",
diff --git a/chrome/browser/ui/app_list/search/omnibox_lacros_provider.cc b/chrome/browser/ui/app_list/search/omnibox_lacros_provider.cc new file mode 100644 index 0000000..fa05697 --- /dev/null +++ b/chrome/browser/ui/app_list/search/omnibox_lacros_provider.cc
@@ -0,0 +1,51 @@ +// 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 "chrome/browser/ui/app_list/search/omnibox_lacros_provider.h" + +#include "base/bind.h" +#include "chrome/browser/ash/crosapi/crosapi_ash.h" +#include "chrome/browser/ash/crosapi/crosapi_manager.h" +#include "chrome/browser/ash/crosapi/search_provider_ash.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_list/app_list_controller_delegate.h" +#include "chromeos/crosapi/mojom/crosapi.mojom.h" + +namespace app_list { + +OmniboxLacrosProvider::OmniboxLacrosProvider( + Profile* profile, + AppListControllerDelegate* list_controller) + : profile_(profile), list_controller_(list_controller) { + DCHECK(profile_); + DCHECK(list_controller_); + + if (crosapi::CrosapiManager::IsInitialized()) { + search_provider_ = + crosapi::CrosapiManager::Get()->crosapi_ash()->search_provider_ash(); + DCHECK(search_provider_); + } +} + +OmniboxLacrosProvider::~OmniboxLacrosProvider() = default; + +void OmniboxLacrosProvider::Start(const std::u16string& query) { + if (!search_provider_) + return; + + search_provider_->Search( + query, base::BindRepeating(&OmniboxLacrosProvider::OnResultsReceived, + weak_factory_.GetWeakPtr())); +} + +ash::AppListSearchResultType OmniboxLacrosProvider::ResultType() const { + return ash::AppListSearchResultType::kOmnibox; +} + +void OmniboxLacrosProvider::OnResultsReceived( + std::vector<crosapi::mojom::SearchResultPtr> results) { + // TODO(crbug.com/1228587): Implement. +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/omnibox_lacros_provider.h b/chrome/browser/ui/app_list/search/omnibox_lacros_provider.h new file mode 100644 index 0000000..e9f8bd8 --- /dev/null +++ b/chrome/browser/ui/app_list/search/omnibox_lacros_provider.h
@@ -0,0 +1,44 @@ +// 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 CHROME_BROWSER_UI_APP_LIST_SEARCH_OMNIBOX_LACROS_PROVIDER_H_ +#define CHROME_BROWSER_UI_APP_LIST_SEARCH_OMNIBOX_LACROS_PROVIDER_H_ + +#include "ash/public/cpp/app_list/app_list_types.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/app_list/search/search_provider.h" +#include "chromeos/crosapi/mojom/launcher_search.mojom.h" + +class AppListControllerDelegate; +class Profile; + +namespace crosapi { +class SearchProviderAsh; +} // namespace crosapi + +namespace app_list { + +class OmniboxLacrosProvider : public SearchProvider { + public: + OmniboxLacrosProvider(Profile* profile, + AppListControllerDelegate* list_controller); + ~OmniboxLacrosProvider() override; + + // SearchProvider: + void Start(const std::u16string& query) override; + ash::AppListSearchResultType ResultType() const override; + + private: + void OnResultsReceived(std::vector<crosapi::mojom::SearchResultPtr> results); + + crosapi::SearchProviderAsh* search_provider_; + Profile* profile_; + AppListControllerDelegate* list_controller_; + + base::WeakPtrFactory<OmniboxLacrosProvider> weak_factory_{this}; +}; + +} // namespace app_list + +#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_OMNIBOX_LACROS_PROVIDER_H_
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc index 16d87ff..b3e14db 100644 --- a/chrome/browser/ui/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -29,6 +29,7 @@ #include "chrome/browser/ui/app_list/search/help_app_provider.h" #include "chrome/browser/ui/app_list/search/keyboard_shortcut_provider.h" #include "chrome/browser/ui/app_list/search/mixer.h" +#include "chrome/browser/ui/app_list/search/omnibox_lacros_provider.h" #include "chrome/browser/ui/app_list/search/omnibox_provider.h" #include "chrome/browser/ui/app_list/search/os_settings_provider.h" #include "chrome/browser/ui/app_list/search/search_controller.h" @@ -106,8 +107,14 @@ profile, list_controller, base::DefaultClock::GetInstance(), model_updater)); - controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>( - profile, list_controller)); + if (app_list_features::IsLauncherLacrosIntegrationEnabled()) { + controller->AddProvider( + omnibox_group_id, + std::make_unique<OmniboxLacrosProvider>(profile, list_controller)); + } else { + controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>( + profile, list_controller)); + } size_t assistant_group_id = controller->AddGroup(kMaxAssistantTextResults); controller->AddProvider(assistant_group_id,
diff --git a/chrome/browser/ui/ash/ambient/ambient_client_impl.cc b/chrome/browser/ui/ash/ambient/ambient_client_impl.cc index 82172c3..8f58000 100644 --- a/chrome/browser/ui/ash/ambient/ambient_client_impl.cc +++ b/chrome/browser/ui/ash/ambient/ambient_client_impl.cc
@@ -111,6 +111,10 @@ bool AmbientClientImpl::IsAmbientModeAllowed() { DCHECK(chromeos::features::IsAmbientModeEnabled()); + if (is_allowed_for_testing_.has_value()) { + return is_allowed_for_testing_.value(); + } + if (ash::DemoSession::IsDeviceInDemoMode()) return false; @@ -141,6 +145,10 @@ return true; } +void AmbientClientImpl::SetAmbientModeAllowedForTesting(bool allowed) { + is_allowed_for_testing_ = allowed; +} + void AmbientClientImpl::RequestAccessToken(GetAccessTokenCallback callback) { auto* profile = GetProfileForActiveUser(); DCHECK(profile);
diff --git a/chrome/browser/ui/ash/ambient/ambient_client_impl.h b/chrome/browser/ui/ash/ambient/ambient_client_impl.h index c9c5b580..a83bf47 100644 --- a/chrome/browser/ui/ash/ambient/ambient_client_impl.h +++ b/chrome/browser/ui/ash/ambient/ambient_client_impl.h
@@ -11,6 +11,7 @@ #include "ash/public/cpp/ambient/ambient_client.h" #include "ash/public/cpp/image_downloader.h" #include "base/memory/weak_ptr.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class GoogleServiceAuthError; @@ -27,6 +28,7 @@ // ash::AmbientClient: bool IsAmbientModeAllowed() override; + void SetAmbientModeAllowedForTesting(bool allowed) override; void RequestAccessToken(GetAccessTokenCallback callback) override; void DownloadImage(const std::string& url, ash::ImageDownloader::DownloadCallback callback) override; @@ -50,6 +52,7 @@ std::map<base::UnguessableToken, std::unique_ptr<signin::AccessTokenFetcher>> token_fetchers_; + absl::optional<bool> is_allowed_for_testing_; base::WeakPtrFactory<AmbientClientImpl> weak_factory_{this}; };
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc index 8fa941b..cc872427 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
@@ -420,13 +420,6 @@ return ui::DragDropTypes::DRAG_COPY; } - ui::mojom::DragOperation OnPerformDrop( - const ui::DropTargetEvent& event) override { - ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone; - PerformDrop(event, output_drag_op); - return output_drag_op; - } - DropCallback GetDropCallback(const ui::DropTargetEvent& event) override { return base::BindOnce(&DropTargetView::PerformDrop, base::Unretained(this)); }
diff --git a/chrome/browser/ui/quick_answers/quick_answers_state_controller_unittest.cc b/chrome/browser/ui/quick_answers/quick_answers_state_controller_unittest.cc index f733b1482..87cde4bf 100644 --- a/chrome/browser/ui/quick_answers/quick_answers_state_controller_unittest.cc +++ b/chrome/browser/ui/quick_answers/quick_answers_state_controller_unittest.cc
@@ -24,11 +24,17 @@ void OnSettingsEnabled(bool settings_enabled) override { settings_enabled_ = settings_enabled; } + void OnApplicationLocaleReady( + const std::string& application_locale) override { + application_locale_ = application_locale; + } bool settings_enabled() const { return settings_enabled_; } + const std::string& application_locale() const { return application_locale_; } private: bool settings_enabled_ = false; + std::string application_locale_; }; class QuickAnswersStateControllerTest : public ChromeQuickAnswersTestBase { @@ -91,6 +97,22 @@ QuickAnswersState::Get()->RemoveObserver(observer()); } +TEST_F(QuickAnswersStateControllerTest, NotifyApplicationLocaleReady) { + QuickAnswersState::Get()->AddObserver(observer()); + + EXPECT_TRUE(QuickAnswersState::Get()->application_locale().empty()); + EXPECT_TRUE(observer()->application_locale().empty()); + + const std::string application_locale = "en-US"; + + // The observer class should get an notification when the pref value changes. + prefs()->SetString(language::prefs::kApplicationLocale, application_locale); + EXPECT_EQ(QuickAnswersState::Get()->application_locale(), application_locale); + EXPECT_EQ(observer()->application_locale(), application_locale); + + QuickAnswersState::Get()->RemoveObserver(observer()); +} + TEST_F(QuickAnswersStateControllerTest, LocaleEligible) { UErrorCode error_code = U_ZERO_ERROR; icu::Locale::setDefault(icu::Locale(ULOC_US), error_code);
diff --git a/chrome/browser/ui/tabs/existing_base_sub_menu_model.cc b/chrome/browser/ui/tabs/existing_base_sub_menu_model.cc index 9dec4757..4796dd1 100644 --- a/chrome/browser/ui/tabs/existing_base_sub_menu_model.cc +++ b/chrome/browser/ui/tabs/existing_base_sub_menu_model.cc
@@ -20,12 +20,6 @@ min_command_id_(min_command_id), parent_new_command_id_(parent_new_command_id) {} -bool ExistingBaseSubMenuModel::GetAcceleratorForCommandId( - int command_id, - ui::Accelerator* accelerator) const { - return false; -} - const gfx::FontList* ExistingBaseSubMenuModel::GetLabelFontListAt( int index) const { if (GetTypeAt(index) == ui::MenuModel::TYPE_TITLE) { @@ -40,14 +34,6 @@ parent_delegate()->IsCommandIdAlerted(parent_new_command_id_); } -bool ExistingBaseSubMenuModel::IsCommandIdChecked(int command_id) const { - return false; -} - -bool ExistingBaseSubMenuModel::IsCommandIdEnabled(int command_id) const { - return true; -} - constexpr int ExistingBaseSubMenuModel::kMinExistingWindowCommandId; constexpr int ExistingBaseSubMenuModel::kMinExistingTabGroupCommandId;
diff --git a/chrome/browser/ui/tabs/existing_base_sub_menu_model.h b/chrome/browser/ui/tabs/existing_base_sub_menu_model.h index 4aa0e15..c2eba01d 100644 --- a/chrome/browser/ui/tabs/existing_base_sub_menu_model.h +++ b/chrome/browser/ui/tabs/existing_base_sub_menu_model.h
@@ -36,14 +36,10 @@ int parent_new_command_id_); // ui::SimpleMenuModel - bool GetAcceleratorForCommandId(int command_id, - ui::Accelerator* accelerator) const override; const gfx::FontList* GetLabelFontListAt(int index) const override; // ui::SimpleMenuModel::Delegate bool IsCommandIdAlerted(int command_id) const override; - bool IsCommandIdChecked(int command_id) const override; - bool IsCommandIdEnabled(int command_id) const override; void ExecuteCommand(int command_id, int event_flags) final; // Command IDs for various submenus.
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc index 8a96045..5a87a59b 100644 --- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc +++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -34,6 +34,7 @@ #include "ui/views/layout/flex_layout.h" #include "ui/views/layout/flex_layout_types.h" #include "ui/views/style/typography.h" +#include "ui/views/view.h" #include "ui/views/view_class_properties.h" namespace { @@ -223,10 +224,10 @@ tab_strip_->OnDragExited(); } -ui::mojom::DragOperation TabStripRegionView::OnPerformDrop( +views::View::DropCallback TabStripRegionView::GetDropCallback( const ui::DropTargetEvent& event) { DCHECK(tab_strip_->WantsToReceiveAllDragEvents()); - return tab_strip_->OnPerformDrop(event); + return tab_strip_->GetDropCallback(event); } void TabStripRegionView::ChildPreferredSizeChanged(views::View* child) {
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.h b/chrome/browser/ui/views/frame/tab_strip_region_view.h index 9740ae4..a788e6e 100644 --- a/chrome/browser/ui/views/frame/tab_strip_region_view.h +++ b/chrome/browser/ui/views/frame/tab_strip_region_view.h
@@ -60,8 +60,7 @@ void OnDragEntered(const ui::DropTargetEvent& event) override; int OnDragUpdated(const ui::DropTargetEvent& event) override; void OnDragExited() override; - ui::mojom::DragOperation OnPerformDrop( - const ui::DropTargetEvent& event) override; + DropCallback GetDropCallback(const ui::DropTargetEvent& event) override; // views::AccessiblePaneView: void ChildPreferredSizeChanged(views::View* child) override;
diff --git a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc index 33b85e0..f139ba7 100644 --- a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc +++ b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc
@@ -83,7 +83,6 @@ bool CanDrop(const OSExchangeData& data) override; void OnDragEntered(const ui::DropTargetEvent& event) override; int OnDragUpdated(const ui::DropTargetEvent& event) override; - DragOperation OnPerformDrop(const ui::DropTargetEvent& event) override; DropCallback GetDropCallback(const ui::DropTargetEvent& event) override; void OnDragExited() override; @@ -136,13 +135,6 @@ return ui::DragDropTypes::DRAG_MOVE; } -DragOperation TestTargetView::OnPerformDrop(const ui::DropTargetEvent& event) { - auto drop_cb = GetDropCallback(event); - ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone; - std::move(drop_cb).Run(event, output_drag_op); - return output_drag_op; -} - views::View::DropCallback TestTargetView::GetDropCallback( const ui::DropTargetEvent& event) { dragging_ = false;
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.cc b/chrome/browser/ui/views/passwords/password_save_update_view.cc index 3c11fbe..745c326 100644 --- a/chrome/browser/ui/views/passwords/password_save_update_view.cc +++ b/chrome/browser/ui/views/passwords/password_save_update_view.cc
@@ -666,11 +666,6 @@ if (!promo_controller) return; - // Make sure the Save/Update bubble doesn't get closed when the IPH bubble is - // opened. - const bool old_close_on_deactivate = close_on_deactivate(); - set_close_on_deactivate(false); - switch (type) { case IPHType::kRegular: if (promo_controller->MaybeShowPromo( @@ -701,8 +696,6 @@ break; } } - - set_close_on_deactivate(old_close_on_deactivate); } void PasswordSaveUpdateView::CloseIPHBubbleIfOpen() {
diff --git a/chrome/browser/ui/views/user_education/help_bubble_factory_views.cc b/chrome/browser/ui/views/user_education/help_bubble_factory_views.cc index a29dbd6..063e4ad 100644 --- a/chrome/browser/ui/views/user_education/help_bubble_factory_views.cc +++ b/chrome/browser/ui/views/user_education/help_bubble_factory_views.cc
@@ -22,24 +22,6 @@ #include "ui/views/interaction/element_tracker_views.h" #include "ui/views/view_utils.h" -namespace { - -// Returns whether losing focus would cause a widget to be destroyed. -// This prevents us from accidentally closing a widget a bubble is anchored to -// at the cost of not being able to directly access the help bubble. -bool BlurWouldCloseWidget(const views::Widget* widget) { - // Right now, we can only ask the question if we know the bubble is - // controlled by a BubbleDialogDelegateView, since runtime type information - // isn't present for any of the other objects involved. - auto* const contents = widget->widget_delegate()->GetContentsView(); - return contents && - views::IsViewClass<views::BubbleDialogDelegateView>(contents) && - static_cast<const views::BubbleDialogDelegateView*>(contents) - ->close_on_deactivate(); -} - -} // namespace - DEFINE_FRAMEWORK_SPECIFIC_METADATA(HelpBubbleViews) DEFINE_FRAMEWORK_SPECIFIC_METADATA(HelpBubbleFactoryViews) @@ -75,8 +57,7 @@ // If the focus isn't in the help bubble, focus the help bubble. // Note that if is_focus_in_ancestor_widget is true, then anchor both exists // and has a widget, so anchor->GetWidget() will always be valid. - if (is_focus_in_ancestor_widget && - !BlurWouldCloseWidget(anchor->GetWidget())) { + if (is_focus_in_ancestor_widget) { help_bubble_view_->GetWidget()->Activate(); help_bubble_view_->RequestFocus(); return true;
diff --git a/chrome/browser/ui/views/user_education/help_bubble_view.cc b/chrome/browser/ui/views/user_education/help_bubble_view.cc index dfedc65..d92b82d 100644 --- a/chrome/browser/ui/views/user_education/help_bubble_view.cc +++ b/chrome/browser/ui/views/user_education/help_bubble_view.cc
@@ -22,6 +22,7 @@ #include "components/strings/grit/components_strings.h" #include "components/variations/variations_associated_data.h" #include "components/vector_icons/vector_icons.h" +#include "ui/base/interaction/element_identifier.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" @@ -281,6 +282,9 @@ } // namespace +DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(HelpBubbleView, + kHelpBubbleElementIdForTesting); + // Explicitly don't use the default DIALOG_SHADOW as it will show a black // outline in dark mode on Mac. Use our own shadow instead. The shadow type is // the same for all other platforms. @@ -558,6 +562,7 @@ SetInitiallyFocusedView(close_button); } + SetProperty(views::kElementIdentifierKey, kHelpBubbleElementIdForTesting); set_margins(gfx::Insets()); set_title_margins(gfx::Insets()); SetButtons(ui::DIALOG_BUTTON_NONE); @@ -578,6 +583,10 @@ SizeToContents(); widget->ShowInactive(); + auto* const anchor_bubble = + anchor_view->GetWidget()->widget_delegate()->AsBubbleDialogDelegate(); + if (anchor_bubble) + anchor_pin_ = anchor_bubble->PreventCloseOnDeactivate(); MaybeStartAutoCloseTimer(); }
diff --git a/chrome/browser/ui/views/user_education/help_bubble_view.h b/chrome/browser/ui/views/user_education/help_bubble_view.h index afbd2ef..0d355c0c 100644 --- a/chrome/browser/ui/views/user_education/help_bubble_view.h +++ b/chrome/browser/ui/views/user_education/help_bubble_view.h
@@ -13,6 +13,7 @@ #include "base/timer/timer.h" #include "chrome/browser/ui/user_education/help_bubble_params.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/base/interaction/element_identifier.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/gfx/geometry/rect.h" #include "ui/views/bubble/bubble_border.h" @@ -35,6 +36,8 @@ class HelpBubbleView : public views::BubbleDialogDelegateView { public: METADATA_HEADER(HelpBubbleView); + DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kHelpBubbleElementIdForTesting); + HelpBubbleView(views::View* anchor_view, HelpBubbleParams params, absl::optional<gfx::Rect> anchor_rect = absl::nullopt); @@ -72,7 +75,7 @@ // localized, and a visible arrow is not shown. absl::optional<gfx::Rect> force_anchor_rect_; - views::ImageView* icon_view_ = nullptr; + base::raw_ptr<views::ImageView> icon_view_ = nullptr; std::vector<views::Label*> labels_; // If the bubble has buttons, it must be focusable. @@ -89,6 +92,10 @@ // than 1 we won't re-read the screenreader hint again. int activate_count_ = 0; + // Prevents the widget we're anchored to from disappearing when it loses + // focus, even if it's marked as close_on_deactivate. + std::unique_ptr<CloseOnDeactivatePin> anchor_pin_; + // Auto close timeout. If the value is 0 (default), the bubble never times // out. base::TimeDelta timeout_;
diff --git a/chrome/browser/ui/views/user_education/help_bubble_view_interactive_uitest.cc b/chrome/browser/ui/views/user_education/help_bubble_view_interactive_uitest.cc index 246b28e5..50b31f68 100644 --- a/chrome/browser/ui/views/user_education/help_bubble_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/user_education/help_bubble_view_interactive_uitest.cc
@@ -2,19 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/ui/user_education/help_bubble_params.h" #include "chrome/browser/ui/views/user_education/help_bubble_view.h" +#include "base/test/bind.h" +#include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/tabs/tab_group_header.h" #include "chrome/browser/ui/views/toolbar/browser_app_menu_button.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "content/public/test/browser_test.h" +#include "ui/base/interaction/expect_call_in_scope.h" +#include "ui/base/interaction/interaction_sequence.h" #include "ui/events/base_event_utils.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/interaction/element_tracker_views.h" #include "ui/views/test/widget_test.h" +#include "ui/views/view_utils.h" class HelpBubbleViewInteractiveTest : public InProcessBrowserTest { public: @@ -57,3 +65,142 @@ EXPECT_FALSE(bubble->GetWidget()->IsActive()); bubble->Close(); } + +// This is a regression test to ensure that help bubbles prevent other bubbles +// they are anchored to from closing on loss of focus. Failing to do this +// results in situations where a user can abort a user education journey by +// entering accessible keyboard navigation commands to try to read the help +// bubble, or by trying to interact with the help bubble with the mouse to e.g. +// close it. +IN_PROC_BROWSER_TEST_F(HelpBubbleViewInteractiveTest, + BubblePreventsCloseOnLossOfFocus) { + UNCALLED_MOCK_CALLBACK(ui::InteractionSequence::CompletedCallback, completed); + + HelpBubbleView* help_bubble_view = nullptr; + + browser()->tab_strip_model()->AddToNewGroup({0}); + auto sequence = + ui::InteractionSequence::Builder() + .SetContext(browser()->window()->GetElementContext()) + .SetCompletedCallback(completed.Get()) + .AddStep( + ui::InteractionSequence::StepBuilder() + .SetElementID(kTabGroupHeaderElementId) + .SetType(ui::InteractionSequence::StepType::kShown) + .SetStartCallback(base::BindLambdaForTesting( + [](ui::InteractionSequence*, + ui::TrackedElement* element) { + // Show the tab group editor bubble. + auto* const view = + element->AsA<views::TrackedElementViews>()->view(); + view->ShowContextMenu( + view->GetLocalBounds().CenterPoint(), + ui::MenuSourceType::MENU_SOURCE_KEYBOARD); + })) + .Build()) + .AddStep( + ui::InteractionSequence::StepBuilder() + .SetElementID(kTabGroupEditorBubbleId) + .SetType(ui::InteractionSequence::StepType::kShown) + .SetMustRemainVisible(true) + .SetStartCallback(base::BindLambdaForTesting( + [&](ui::InteractionSequence*, + ui::TrackedElement* element) { + // Show a help bubble attached to the tab group editor + // bubble. + auto* const anchor_view = + element->AsA<views::TrackedElementViews>()->view(); + HelpBubbleParams params; + params.body_text = u"foo"; + help_bubble_view = + new HelpBubbleView(anchor_view, std::move(params)); + })) + .Build()) + .AddStep( + ui::InteractionSequence::StepBuilder() + .SetElementID(HelpBubbleView::kHelpBubbleElementIdForTesting) + .SetType(ui::InteractionSequence::StepType::kShown) + .SetMustRemainVisible(true) + .SetStartCallback(base::BindLambdaForTesting( + [&](ui::InteractionSequence*, + ui::TrackedElement* element) { + // Activate the help bubble. This should not cause the + // editor to close. + auto* const widget = + element->AsA<views::TrackedElementViews>() + ->view() + ->GetWidget(); + widget->Activate(); + views::test::WidgetActivationWaiter(widget, true) + .Wait(); + })) + .Build()) + .AddStep(ui::InteractionSequence::StepBuilder() + .SetElementID(kTabGroupEditorBubbleId) + .SetType(ui::InteractionSequence::StepType::kShown) + .SetMustBeVisibleAtStart(true) + .SetMustRemainVisible(true) + .SetStartCallback(base::BindLambdaForTesting( + [&](ui::InteractionSequence*, + ui::TrackedElement* element) { + // Activate the editor then close the help bubble. + auto* const widget = + element->AsA<views::TrackedElementViews>() + ->view() + ->GetWidget(); + widget->Activate(); + views::test::WidgetActivationWaiter(widget, true) + .Wait(); + ASSERT_TRUE(widget->IsActive()); + help_bubble_view->GetWidget()->Close(); + })) + .Build()) + .AddStep( + ui::InteractionSequence::StepBuilder() + // Wait for the help bubble to close. + .SetElementID(HelpBubbleView::kHelpBubbleElementIdForTesting) + .SetType(ui::InteractionSequence::StepType::kHidden) + .Build()) + .AddStep( + ui::InteractionSequence::StepBuilder() + .SetElementID(kTabGroupEditorBubbleId) + .SetType(ui::InteractionSequence::StepType::kShown) + .SetMustBeVisibleAtStart(true) + .SetStartCallback(base::BindLambdaForTesting( + [&](ui::InteractionSequence*, + ui::TrackedElement* element) { + // Now that the help bubble is gone, locate the editor + // again and transfer activation to its primary window + // widget (the browser window) + // - this should close the editor as it is no longer + // pinned by the help bubble. + auto* const widget = + element->AsA<views::TrackedElementViews>() + ->view() + ->GetWidget(); + // Delay this in case we're chaining off of the previous + // hidden step; we need the help bubble to fully clean + // up (this wouldn't be an issue in an actual live + // browser because the activation would be due to user + // input and therefore have to be processed via the + // message pump instead of being allowed to execute + // inside the Widget's close logic). + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce( + [](views::Widget* widget) { + widget->GetPrimaryWindowWidget()->Activate(); + }, + base::Unretained(widget))); + })) + .Build()) + .AddStep(ui::InteractionSequence::StepBuilder() + // Verify that the editor bubble closes now that it has + // lost focus. + .SetElementID(kTabGroupEditorBubbleId) + .SetType(ui::InteractionSequence::StepType::kHidden) + .Build()) + .Build(); + + EXPECT_CALL_IN_SCOPE(completed, Run, sequence->RunSynchronouslyForTesting()); +}
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc index 1e0d786..75c176d 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -973,8 +973,12 @@ print_preview_ui()->initiator_title()); initial_settings.SetBoolKey(kSettingPreviewModifiable, print_preview_ui()->source_is_modifiable()); - initial_settings.SetBoolKey(kSettingPreviewIsFromArc, - print_preview_ui()->source_is_arc()); +#if BUILDFLAG(IS_CHROMEOS_ASH) + bool source_is_arc = print_preview_ui()->source_is_arc(); +#else + bool source_is_arc = false; +#endif + initial_settings.SetBoolKey(kSettingPreviewIsFromArc, source_is_arc); initial_settings.SetStringKey(kSettingPrinterName, default_printer); initial_settings.SetBoolKey(kDocumentHasSelection, print_preview_ui()->source_has_selection());
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc index eba14d7..a09bcee 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -737,7 +737,9 @@ return; PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>( print_preview_dialog->GetWebUI()->GetController()); +#if BUILDFLAG(IS_CHROMEOS_ASH) print_preview_ui->source_is_arc_ = params.is_from_arc; +#endif print_preview_ui->source_is_modifiable_ = params.is_modifiable; print_preview_ui->source_has_selection_ = params.has_selection; print_preview_ui->print_selection_only_ = params.selection_only;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h index 43295b6..3d86a760 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -84,7 +84,9 @@ const std::u16string& initiator_title() const { return initiator_title_; } +#if BUILDFLAG(IS_CHROMEOS_ASH) bool source_is_arc() const { return source_is_arc_; } +#endif bool source_is_modifiable() const { return source_is_modifiable_; } @@ -261,8 +263,10 @@ // Weak pointer to the WebUI handler. const raw_ptr<PrintPreviewHandler> handler_; +#if BUILDFLAG(IS_CHROMEOS_ASH) // Indicates whether the source document is from ARC. bool source_is_arc_ = false; +#endif // Indicates whether the source document can be modified. bool source_is_modifiable_ = true;
diff --git a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc index ed47d5f..d875c9f 100644 --- a/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/personalization_section.cc
@@ -212,6 +212,12 @@ if (features::IsGuestModeActive()) return; + if (ash::features::IsPersonalizationHubEnabled()) { + // Personalization search is handled by Personalization Hub when feature is + // on. + return; + } + SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate(); updater.AddSearchTags(GetPersonalizationSearchConcepts());
diff --git a/chrome/browser/web_applications/app_service/web_apps.cc b/chrome/browser/web_applications/app_service/web_apps.cc index a3b86725..cfe76b1 100644 --- a/chrome/browser/web_applications/app_service/web_apps.cc +++ b/chrome/browser/web_applications/app_service/web_apps.cc
@@ -155,6 +155,12 @@ std::move(callback).Run(apps::LaunchResult()); } +void WebApps::LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) { + publisher_helper().ExecuteContextMenuCommand(app_id, shortcut_id, display_id); +} + void WebApps::Connect( mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote, apps::mojom::ConnectOptionsPtr opts) {
diff --git a/chrome/browser/web_applications/app_service/web_apps.h b/chrome/browser/web_applications/app_service/web_apps.h index 84f5314b..88a0cec 100644 --- a/chrome/browser/web_applications/app_service/web_apps.h +++ b/chrome/browser/web_applications/app_service/web_apps.h
@@ -94,6 +94,9 @@ apps::LoadIconCallback callback) override; void LaunchAppWithParams(apps::AppLaunchParams&& params, apps::LaunchCallback callback) override; + void LaunchShortcut(const std::string& app_id, + const std::string& shortcut_id, + int64_t display_id) override; // apps::mojom::Publisher overrides. void Connect(mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote,
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager.cc b/chrome/browser/web_applications/preinstalled_web_app_manager.cc index c42d88d..b2287c4 100644 --- a/chrome/browser/web_applications/preinstalled_web_app_manager.cc +++ b/chrome/browser/web_applications/preinstalled_web_app_manager.cc
@@ -562,6 +562,11 @@ return; } + if (PreinstalledWebAppsDisabled()) { + std::move(callback).Run({}); + return; + } + base::FilePath config_dir = GetConfigDir(); if (config_dir.empty()) { std::move(callback).Run({});
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc b/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc index 634a55d..1f10e70 100644 --- a/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc +++ b/chrome/browser/web_applications/preinstalled_web_app_manager_unittest.cc
@@ -10,6 +10,7 @@ #include <vector> #include "base/bind.h" +#include "base/command_line.h" #include "base/containers/contains.h" #include "base/feature_list.h" #include "base/path_service.h" @@ -28,6 +29,7 @@ #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" #include "chrome/test/base/testing_profile.h" #include "components/account_id/account_id.h" #include "components/sync_preferences/testing_pref_service_syncable.h" @@ -536,4 +538,19 @@ } #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS) +class DisabledPreinstalledWebAppManagerTest + : public PreinstalledWebAppManagerTest { + public: + DisabledPreinstalledWebAppManagerTest() { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kDisablePreinstalledApps); + } +}; + +TEST_F(DisabledPreinstalledWebAppManagerTest, LoadConfigsWhileDisabled) { + EXPECT_EQ(LoadApps(kGoodJsonTestDir).size(), 0u); +} +#endif // #if BUILDFLAG(IS_CHROMEOS) + } // namespace web_app
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc index d1b885208..6a95a912 100644 --- a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc +++ b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc
@@ -42,14 +42,17 @@ } // namespace +bool PreinstalledWebAppsDisabled() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + ::switches::kDisablePreinstalledApps); +} + std::vector<ExternalInstallOptions> GetPreinstalledWebApps() { if (g_preinstalled_app_data_for_testing) return *g_preinstalled_app_data_for_testing; - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - ::switches::kDisablePreinstalledApps)) { + if (PreinstalledWebAppsDisabled()) return {}; - } #if BUILDFLAG(GOOGLE_CHROME_BRANDING) // TODO(crbug.com/1104692): Replace these C++ configs with JSON configs like @@ -121,49 +124,49 @@ migrations.push_back(std::move(migration)); } - if (g_preinstalled_app_data_for_testing) - return migrations; - #if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS) - // Manually hard coded entries from - // https://chrome-internal.googlesource.com/chromeos/overlays/chromeos-overlay/+/main/chromeos-base/chromeos-default-apps/files/web_apps - // for any json configs that include a uninstall_and_replace field. - // This is a temporary measure while the default web app duplication - // issue is cleaned up. - // TODO(crbug.com/1290716): Clean up once no longer needed. - if (IsPreinstalledAppInstallFeatureEnabled( - kMigrateDefaultChromeAppToWebAppsGSuite.name, profile)) { - PreinstalledWebAppMigration keep_migration; - keep_migration.install_url = - GURL("https://keep.google.com/installwebapp?usp=chrome_default"); - keep_migration.expected_web_app_id = kGoogleKeepAppId; - keep_migration.old_chrome_app_id = extension_misc::kGoogleKeepAppId; - migrations.push_back(std::move(keep_migration)); - } + if (!g_preinstalled_app_data_for_testing && !PreinstalledWebAppsDisabled()) { + // Manually hard coded entries from + // https://chrome-internal.googlesource.com/chromeos/overlays/chromeos-overlay/+/main/chromeos-base/chromeos-default-apps/files/web_apps + // for any json configs that include a uninstall_and_replace field. + // This is a temporary measure while the default web app duplication + // issue is cleaned up. + // TODO(crbug.com/1290716): Clean up once no longer needed. + if (IsPreinstalledAppInstallFeatureEnabled( + kMigrateDefaultChromeAppToWebAppsGSuite.name, profile)) { + PreinstalledWebAppMigration keep_migration; + keep_migration.install_url = + GURL("https://keep.google.com/installwebapp?usp=chrome_default"); + keep_migration.expected_web_app_id = kGoogleKeepAppId; + keep_migration.old_chrome_app_id = extension_misc::kGoogleKeepAppId; + migrations.push_back(std::move(keep_migration)); + } - if (IsPreinstalledAppInstallFeatureEnabled( - kMigrateDefaultChromeAppToWebAppsNonGSuite.name, profile)) { - PreinstalledWebAppMigration books_migration; - books_migration.install_url = - GURL("https://play.google.com/books/installwebapp?usp=chromedefault"); - books_migration.expected_web_app_id = kPlayBooksAppId; - books_migration.old_chrome_app_id = extension_misc::kGooglePlayBooksAppId; - migrations.push_back(std::move(books_migration)); + if (IsPreinstalledAppInstallFeatureEnabled( + kMigrateDefaultChromeAppToWebAppsNonGSuite.name, profile)) { + PreinstalledWebAppMigration books_migration; + books_migration.install_url = + GURL("https://play.google.com/books/installwebapp?usp=chromedefault"); + books_migration.expected_web_app_id = kPlayBooksAppId; + books_migration.old_chrome_app_id = extension_misc::kGooglePlayBooksAppId; + migrations.push_back(std::move(books_migration)); - PreinstalledWebAppMigration maps_migration; - maps_migration.install_url = - GURL("https://www.google.com/maps/preview/pwa/ttinstall.html"); - maps_migration.expected_web_app_id = kGoogleMapsAppId; - maps_migration.old_chrome_app_id = extension_misc::kGoogleMapsAppId; - migrations.push_back(std::move(maps_migration)); + PreinstalledWebAppMigration maps_migration; + maps_migration.install_url = + GURL("https://www.google.com/maps/preview/pwa/ttinstall.html"); + maps_migration.expected_web_app_id = kGoogleMapsAppId; + maps_migration.old_chrome_app_id = extension_misc::kGoogleMapsAppId; + migrations.push_back(std::move(maps_migration)); - PreinstalledWebAppMigration movies_migration; - movies_migration.install_url = GURL( - "https://play.google.com/store/movies/" - "installwebapp?usp=chrome_default"); - movies_migration.expected_web_app_id = kGoogleMoviesAppId; - movies_migration.old_chrome_app_id = extension_misc::kGooglePlayMoviesAppId; - migrations.push_back(std::move(movies_migration)); + PreinstalledWebAppMigration movies_migration; + movies_migration.install_url = GURL( + "https://play.google.com/store/movies/" + "installwebapp?usp=chrome_default"); + movies_migration.expected_web_app_id = kGoogleMoviesAppId; + movies_migration.old_chrome_app_id = + extension_misc::kGooglePlayMoviesAppId; + migrations.push_back(std::move(movies_migration)); + } } #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS) return migrations;
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h index 6c2d84b..c0a9283 100644 --- a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h +++ b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h
@@ -15,6 +15,8 @@ namespace web_app { +bool PreinstalledWebAppsDisabled(); + // Returns the list of web apps that should be pre-installed on new profiles. std::vector<ExternalInstallOptions> GetPreinstalledWebApps();
diff --git a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java index dfde561..0942c283 100644 --- a/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java +++ b/chrome/browser/xsurface/android/java/src/org/chromium/chrome/browser/xsurface/FeedActionsHandler.java
@@ -6,6 +6,10 @@ import android.view.View; +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Map; /** @@ -137,4 +141,20 @@ * @param key Key to identify the type of the notice. */ default void reportNoticeDismissed(String key) {} + + /** Types of feeds that can be invalidated. */ + @IntDef({FeedIdentifier.ALL_FEEDS, FeedIdentifier.MAIN_FEED, FeedIdentifier.FOLLOWING_FEED}) + @Retention(RetentionPolicy.SOURCE) + public @interface FeedIdentifier { + int ALL_FEEDS = 0; + int MAIN_FEED = 1; + int FOLLOWING_FEED = 2; + } + + /** + * Requests that the cache of one or all feeds should be invalidated so that that their contents + * are re-fetched the next time the feed is shown. + * @param toInvalidate Identifies which feed or feeds should have their caches invalidated. + */ + default void invalidateContentCacheFor(@FeedIdentifier int toInvalidate) {} }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index c2632e3..938a1983 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1648144749-ccfe60ff8537a513b27416548f37272ec8626ab2.profdata +chrome-linux-main-1648187939-32be12a69eb8bfe1cd98347ae985c46aab73d016.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index f20ea03..f154f00 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1648144749-e50da85dc22932c4d917580e7bd267cfe889b31b.profdata +chrome-mac-arm-main-1648187939-42b0fe3811b3081ce1958f642076e2e290dc2502.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index b72f566..7566652 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1648144749-c9baea862655d2ef23474abda8fce3ac8875e181.profdata +chrome-mac-main-1648187939-bca456cc755ac42c2a52ac2f92bcf1243fed3472.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 88648ef..49ed275 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1648155422-141ba16e22bbbd8aa760dfc86e2f4a05a810e7f1.profdata +chrome-win32-main-1648187939-84b924621540e05a2715db8e2ebe859d79059acd.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index f066b11..e20d5d5 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1648155422-19d2500873166865703fbc30aa2ee02d166c26d0.profdata +chrome-win64-main-1648187939-4e8a9495d3761f4dc4660c426f71b772b1f625a1.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 6ba85101..2eeb0b3 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1590,7 +1590,6 @@ "../browser/apps/platform_apps/platform_app_navigation_redirector_browsertest.cc", "../browser/apps/platform_apps/service_worker_browsertest.cc", "../browser/attribution_reporting/chrome_attribution_browsertest.cc", - "../browser/attribution_reporting/conversions_usage_restriction_trial_browsertest.cc", "../browser/autocomplete/autocomplete_browsertest.cc", "../browser/autofill/autofill_autocomplete_browsertest.cc", "../browser/autofill/autofill_browsertest.cc",
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js index 3ddbf19..762ff31 100644 --- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js +++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js
@@ -214,6 +214,39 @@ assert(!recentlyUsed); }); + test('recently used should be empty after clearing', async () => { + EmojiPickerApiProxyImpl.getInstance().isIncognitoTextField = () => + // first - insert an emoji to populate recently used + new Promise((resolve) => resolve({incognito: false})); + // yield to allow emoji-group and emoji buttons to render. + const emojiButton = (await waitForCondition( + () => findInEmojiPicker( + '[data-group="0"] > emoji-group', + 'emoji-button:nth-child(2)'))) + .shadowRoot.querySelector('button'); + emojiButton.click(); + + // wait until emoji exists in recently used section. + const recentlyUsed = + (await waitForCondition( + () => findInEmojiPicker( + '[data-group=history] > emoji-group', 'emoji-button'))) + .shadowRoot.querySelector('button'); + + // click show clear button + findInEmojiPicker('.group', '#show-clear').click(); + await waitForCondition(() => findInEmojiPicker('.group', '#clear-recents')); + + // click clear button + findInEmojiPicker('.group', '#clear-recents').click(); + + // Expect no more history. + await waitForCondition( + () => findInEmojiPicker('[data-group=history] > emoji-group') + .style.display === 'none', + 'history failed to disappear'); + }); + suite('<emoji-variants>', () => { /** @type {!EmojiButton} */
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts index 84433e56..c585e8f 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts
@@ -4,7 +4,9 @@ import {PersonalizationMain} from 'chrome://personalization/trusted/personalization_main_element.js'; import {Paths, PersonalizationRouter} from 'chrome://personalization/trusted/personalization_router_element.js'; -import {assertDeepEquals, assertEquals} from 'chrome://webui-test/chai_assert.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {waitAfterNextRender} from 'chrome://webui-test/test_util.js'; import {initElement, teardownElement} from './personalization_app_test_utils.js'; @@ -41,6 +43,7 @@ }); test('links to ambient subpage', async () => { + loadTimeData.overrideValues({'isAmbientModeAllowed': true}); personalizationMainElement = initElement(PersonalizationMain); const original = PersonalizationRouter.instance; const goToRoutePromise = new Promise<[Paths, Object]>(resolve => { @@ -61,4 +64,35 @@ assertEquals(Paths.Ambient, path); assertDeepEquals({}, queryParams); }); + + test('no links to ambient subpage', async () => { + loadTimeData.overrideValues({'isAmbientModeAllowed': false}); + personalizationMainElement = initElement(PersonalizationMain); + + const ambientSubpageLink = + personalizationMainElement!.shadowRoot!.getElementById( + 'ambientSubpageLink')!; + assertFalse(!!ambientSubpageLink); + }); + + test('has ambient preview', async () => { + loadTimeData.overrideValues({'isAmbientModeAllowed': true}); + personalizationMainElement = initElement(PersonalizationMain); + await waitAfterNextRender(personalizationMainElement); + + const preview = personalizationMainElement!.shadowRoot!.querySelector( + 'ambient-preview')!; + assertTrue(!!preview); + }); + + test('has no ambient preview', async () => { + loadTimeData.overrideValues({'isAmbientModeAllowed': false}); + personalizationMainElement = initElement(PersonalizationMain); + await waitAfterNextRender(personalizationMainElement); + + + const preview = personalizationMainElement!.shadowRoot!.querySelector( + 'ambient-preview')!; + assertFalse(!!preview); + }); }
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_router_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/personalization_router_element_test.ts index 96ac0f4..b6dd0a4f 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/personalization_router_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_router_element_test.ts
@@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {PersonalizationRouter} from 'chrome://personalization/trusted/personalization_router_element.js'; +import {Paths, PersonalizationRouter} from 'chrome://personalization/trusted/personalization_router_element.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {waitAfterNextRender} from 'chrome://webui-test/test_util.js'; import {initElement} from './personalization_app_test_utils.js'; @@ -16,4 +18,36 @@ initElement(PersonalizationRouter); await reloadCalledPromise; }); + + test('will show ambient subpage if allowed', async () => { + loadTimeData.overrideValues({'isPersonalizationHubEnabled': true}); + loadTimeData.overrideValues({'isAmbientModeAllowed': true}); + const routerElement = initElement(PersonalizationRouter); + PersonalizationRouter.instance().goToRoute(Paths.Ambient); + await waitAfterNextRender(routerElement); + + const mainElement = + routerElement.shadowRoot!.querySelector('personalization-main'); + assertFalse(!!mainElement); + + const ambientSubpage = + routerElement.shadowRoot!.querySelector('ambient-subpage'); + assertTrue(!!ambientSubpage); + }); + + test('will not show ambient subpage if disallowed', async () => { + loadTimeData.overrideValues({'isPersonalizationHubEnabled': true}); + loadTimeData.overrideValues({'isAmbientModeAllowed': false}); + const routerElement = initElement(PersonalizationRouter); + PersonalizationRouter.instance().goToRoute(Paths.Ambient); + await waitAfterNextRender(routerElement); + + const mainElement = + routerElement.shadowRoot!.querySelector('personalization-main'); + assertTrue(!!mainElement); + + const ambientSubpage = + routerElement.shadowRoot!.querySelector('ambient-subpage'); + assertFalse(!!ambientSubpage); + }); }
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_update_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_update_page_test.js index 899f3df..4849a952 100644 --- a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_update_page_test.js +++ b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_update_page_test.js
@@ -115,17 +115,19 @@ const version = '90.1.2.3'; await initializeUpdatePage(version); - const progressComponent = - component.shadowRoot.querySelector('#progressMessage'); - assertEquals('', progressComponent.textContent.trim()); + const updateInstructionsDiv = + component.shadowRoot.querySelector('#updateInstructionsDiv'); + assertFalse(updateInstructionsDiv.hidden); + const updateStatusDiv = + component.shadowRoot.querySelector('#updateStatusDiv'); + assertTrue(updateStatusDiv.hidden); await clickPerformUpdateButton(); service.triggerOsUpdateObserver(OsUpdateOperation.kDownloading, 0.5, 0); await flushTasks(); - // TODO(gavindodd): update with i18n string - assertTrue(progressComponent.textContent.trim().startsWith( - 'OS update progress received ')); + assertTrue(updateInstructionsDiv.hidden); + assertFalse(updateStatusDiv.hidden); }); test('UpdatePageShowHideUnqualifiedComponentsLink', () => {
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js b/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js index 11d02b7..f27cd3e 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_search_box_test.js
@@ -368,57 +368,6 @@ }); test( - 'Keypress Enter on personalization hub result can open a new window', - async () => { - // Enable personalization hub feature. - loadTimeData.overrideValues({isPersonalizationHubEnabled: true}); - assertTrue(loadTimeData.getBoolean('isPersonalizationHubEnabled')); - - const result = fakeResult('Wallpaper', 'personalization?settingId=500'); - result.id.setting = chromeos.settings.mojom.Setting.kOpenWallpaper; - - settingsSearchHandler.setFakeResults([result]); - await simulateSearch('fake query 1'); - await waitForListUpdate(); - - const selectedOsRow = searchBox.getSelectedOsSearchResultRow_(); - assertTrue(!!selectedOsRow); - assertEquals('cr:open-in-new', selectedOsRow.getActionTypeIcon_()); - - // Keypress with Enter key on any row specifically causes navigation to - // selected row's route. This can't happen unless the row is focused. - const enterEvent = new KeyboardEvent( - 'keypress', {cancelable: true, key: 'Enter', keyCode: 13}); - selectedOsRow.$.searchResultContainer.dispatchEvent(enterEvent); - - assertEquals(1, openWindowProxy.getCallCount('openURL')); - }); - - test( - 'Clicking on personalization hub result can open a new window', - async () => { - // Enable personalization hub feature. - loadTimeData.overrideValues({isPersonalizationHubEnabled: true}); - assertTrue(loadTimeData.getBoolean('isPersonalizationHubEnabled')); - - const result = fakeResult('Wallpaper', 'personalization?settingId=500'); - result.id.setting = chromeos.settings.mojom.Setting.kOpenWallpaper; - - settingsSearchHandler.setFakeResults([result]); - await simulateSearch('fake query 1'); - await waitForListUpdate(); - - const selectedOsRow = searchBox.getSelectedOsSearchResultRow_(); - assertTrue(!!selectedOsRow); - assertEquals('cr:open-in-new', selectedOsRow.getActionTypeIcon_()); - - // Clicking on the searchResultContainer of the row opens a new window. - selectedOsRow.$.searchResultContainer.click(); - - assertEquals(1, openWindowProxy.getCallCount('openURL')); - }); - - test( 'Clicking on personalization hub result causes route change' + ' if personalization hub feature is disabled', async () => { @@ -435,7 +384,6 @@ const selectedOsRow = searchBox.getSelectedOsSearchResultRow_(); assertTrue(!!selectedOsRow); - assertEquals('cr:arrow-forward', selectedOsRow.getActionTypeIcon_()); // Clicking on the searchResultContainer of the row correctly changes // the route and dropdown to close.
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index bbda328..3b4f23a 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -2752,8 +2752,8 @@ <message name="IDS_SHIMLESS_RMA_UPDATE_OS_VERY_OUT_OF_DATE" translateable="false" desc="Description when the installed OS is too many versions behind the update."> Chrome OS needs an additional update to get fully up to date </message> - <message name="IDS_SHIMLESS_RMA_UPDATE_OS_OUT_OF_DATE" translateable="false" desc="Description when the installed OS is not the most recent available."> - Chrome OS needs an additional update to get fully up to date. + <message name="IDS_SHIMLESS_RMA_UPDATE_OS_OUT_OF_DATE" translateable="false" desc="The instructions shown when there is a Chrome OS update available."> + Update to the latest version of Chrome OS for an optimized repair process </message> <message name="IDS_SHIMLESS_RMA_UPDATE_OS_NETWORK_UNAVAILABLE" translateable="false" desc="Notice that no network is available when attempting to update Chrome OS."> To check if OS is up to date, connect to the internet in previous screen @@ -2773,6 +2773,9 @@ <message name="IDS_SHIMLESS_RMA_UPDATE_VERSION_AND_RESTART" translateable="false" desc="Label for the button that updates the device to the latest version of Chrome OS then restarts the device."> Update to <ph name="VERSION_NUMBER">$1</ph> & restart </message> + <message name="IDS_SHIMLESS_RMA_UPDATING_OS_VERSION" translateable="false" desc="The message shown while updating the device's OS version."> + Updating OS version + </message> <!-- Manually disable wp page --> <message name="IDS_SHIMLESS_RMA_MANUALLY_DISABLE_WP_INSTRUCTIONS" translateable="false" desc="The text instructions for how to manually disable write-protect on the device."> Disable write-protect to continue to the next screen. Learn how to disable write-protect for this device by viewing the instructions at the device manufacturer's support page. Once you disable write-protect, you will need to leave it disabled until the repair process is finished. Please expect a reboot after disabling write protection.
diff --git a/chromeos/components/quick_answers/BUILD.gn b/chromeos/components/quick_answers/BUILD.gn index 3259b9b..9d987c34 100644 --- a/chromeos/components/quick_answers/BUILD.gn +++ b/chromeos/components/quick_answers/BUILD.gn
@@ -38,6 +38,8 @@ "utils/quick_answers_metrics.h", "utils/quick_answers_utils.cc", "utils/quick_answers_utils.h", + "utils/spell_checker.cc", + "utils/spell_checker.h", "utils/unit_conversion_constants.cc", "utils/unit_conversion_constants.h", "utils/unit_converter.cc", @@ -45,8 +47,10 @@ ] deps = [ "//base", + "//chrome/common:constants", "//chromeos/components/quick_answers/public/cpp:cpp", "//chromeos/components/quick_answers/public/cpp:prefs", + "//chromeos/components/quick_answers/public/mojom", "//chromeos/constants", "//chromeos/services/assistant/public/shared", "//chromeos/services/machine_learning/public/cpp", @@ -56,6 +60,8 @@ "//components/prefs:prefs", "//components/signin/public/base", "//components/signin/public/identity_manager", + "//components/spellcheck/common", + "//content/public/browser", "//net:net", "//services/data_decoder/public/cpp", "//services/network/public/cpp:cpp",
diff --git a/chromeos/components/quick_answers/DEPS b/chromeos/components/quick_answers/DEPS index 34c2af07..4e5168e 100644 --- a/chromeos/components/quick_answers/DEPS +++ b/chromeos/components/quick_answers/DEPS
@@ -1,6 +1,9 @@ include_rules = [ "+ash/public", + "+chrome/common", "+components/language/core/browser", + "+components/spellcheck/common", + "+content/public/browser", "+services/data_decoder/public", "+third_party/hunspell", "+ui/base/l10n",
diff --git a/chromeos/components/quick_answers/public/cpp/quick_answers_state.cc b/chromeos/components/quick_answers/public/cpp/quick_answers_state.cc index fc3f5ee..e3eef81 100644 --- a/chromeos/components/quick_answers/public/cpp/quick_answers_state.cc +++ b/chromeos/components/quick_answers/public/cpp/quick_answers_state.cc
@@ -134,12 +134,17 @@ kQuickAnswersUnitConversionEnabled, base::BindRepeating(&QuickAnswersState::UpdateUnitConversionEnabled, base::Unretained(this))); + pref_change_registrar_->Add( + language::prefs::kApplicationLocale, + base::BindRepeating(&QuickAnswersState::OnApplicationLocaleReady, + base::Unretained(this))); UpdateSettingsEnabled(); UpdateConsentStatus(); UpdateDefinitionEnabled(); UpdateTranslationEnabled(); UpdateUnitConversionEnabled(); + OnApplicationLocaleReady(); prefs_initialized_ = true; @@ -267,14 +272,30 @@ unit_conversion_enabled_ = unit_conversion_enabled; } +void QuickAnswersState::OnApplicationLocaleReady() { + auto locale = pref_change_registrar_->prefs()->GetString( + language::prefs::kApplicationLocale); + if (application_locale_ == locale) { + return; + } + application_locale_ = locale; + + for (auto& observer : observers_) { + observer.OnApplicationLocaleReady(locale); + } + + UpdateEligibility(); +} + void QuickAnswersState::UpdateEligibility() { if (!pref_change_registrar_) return; - std::string locale = pref_change_registrar_->prefs()->GetString( - language::prefs::kApplicationLocale); + if (application_locale_.empty()) + return; + std::string resolved_locale; - l10n_util::CheckAndResolveLocale(locale, &resolved_locale, + l10n_util::CheckAndResolveLocale(application_locale_, &resolved_locale, /*perform_io=*/false); is_eligible_ = IsQuickAnswersAllowedForLocale( resolved_locale, icu::Locale::getDefault().getName());
diff --git a/chromeos/components/quick_answers/public/cpp/quick_answers_state.h b/chromeos/components/quick_answers/public/cpp/quick_answers_state.h index 5700e1e4..1b74634 100644 --- a/chromeos/components/quick_answers/public/cpp/quick_answers_state.h +++ b/chromeos/components/quick_answers/public/cpp/quick_answers_state.h
@@ -35,6 +35,7 @@ class QuickAnswersStateObserver : public base::CheckedObserver { public: virtual void OnSettingsEnabled(bool enabled) {} + virtual void OnApplicationLocaleReady(const std::string& locale) {} }; // A class that holds Quick Answers related prefs and states. @@ -66,6 +67,7 @@ bool definition_enabled() const { return definition_enabled_; } bool translation_enabled() const { return translation_enabled_; } bool unit_conversion_enabled() const { return unit_conversion_enabled_; } + const std::string& application_locale() const { return application_locale_; } bool is_eligible() const { return is_eligible_; } void set_eligibility_for_testing(bool is_eligible) { @@ -84,6 +86,7 @@ void UpdateDefinitionEnabled(); void UpdateTranslationEnabled(); void UpdateUnitConversionEnabled(); + void OnApplicationLocaleReady(); // Called when the feature eligibility might change. void UpdateEligibility(); @@ -104,6 +107,9 @@ // Whether the Quick Answers unit conversion is enabled. bool unit_conversion_enabled_ = true; + // The application locale. + std::string application_locale_; + // Whether the Quick Answers feature is eligible. The value is derived from a // number of other states. bool is_eligible_ = false;
diff --git a/chromeos/components/quick_answers/utils/spell_checker.cc b/chromeos/components/quick_answers/utils/spell_checker.cc new file mode 100644 index 0000000..b2ae686d --- /dev/null +++ b/chromeos/components/quick_answers/utils/spell_checker.cc
@@ -0,0 +1,229 @@ +// 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 "chromeos/components/quick_answers/utils/spell_checker.h" + +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/threading/scoped_blocking_call.h" +#include "chrome/common/chrome_paths.h" +#include "components/spellcheck/common/spellcheck_common.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/service_process_host.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "services/network/public/mojom/url_response_head.mojom.h" + +namespace quick_answers { +namespace { + +constexpr char kDownloadServerUrl[] = + "https://redirector.gvt1.com/edgedl/chrome/dict/"; + +constexpr net::NetworkTrafficAnnotationTag kNetworkTrafficAnnotationTag = + net::DefineNetworkTrafficAnnotation("quick_answers_spellchecker", R"( + semantics { + sender: "Quick answers Spellchecker" + description: + "Download dictionary for Quick answers feature if necessary." + trigger: "Quick answers feature enabled." + data: + "The spell checking language identifier. No user identifier is " + "sent." + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: NO + setting: + "Quick Answers can be enabled/disabled in ChromeOS Settings and" + "is subject to eligibility requirements." + })"); + +constexpr int kMaxRetries = 3; + +base::FilePath GetDictionaryFilePath(const std::string& language) { + base::FilePath dict_dir; + base::PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir); + base::FilePath dict_path = + spellcheck::GetVersionedFileName(language, dict_dir); + return dict_path; +} + +GURL GetDictionaryURL(const std::string& file_name) { + return GURL(std::string(kDownloadServerUrl) + base::ToLowerASCII(file_name)); +} + +bool SaveDictionaryData(std::unique_ptr<std::string> data, + const base::FilePath& file_path) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); + + // Create a temporary file. + base::FilePath tmp_path; + if (!base::CreateTemporaryFileInDir(file_path.DirName(), &tmp_path)) { + LOG(ERROR) << "Failed to create a temporary file."; + return false; + } + + // Write to the temporary file. + size_t bytes_written = + base::WriteFile(tmp_path, data->data(), data->length()); + if (bytes_written != data->length()) { + base::DeleteFile(tmp_path); + LOG(ERROR) << "Failed to write dictionary data to the temporary file"; + return false; + } + + // Atomically rename the temporary file to become the real one. + return base::ReplaceFile(tmp_path, file_path, nullptr); +} + +void RemoveDictionaryFle(const base::FilePath& file_path) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); + + base::DeleteFile(file_path); +} + +} // namespace + +SpellChecker::SpellChecker( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + : url_loader_factory_(url_loader_factory) { + quick_answers_state_observation_.Observe(QuickAnswersState::Get()); +} + +SpellChecker::~SpellChecker() = default; + +void SpellChecker::CheckSpelling(const std::string& word, + CheckSpellingCallback callback) { + if (!dictionary_initialized_) { + std::move(callback).Run(false); + return; + } + + dictionary_->CheckSpelling(word, std::move(callback)); +} + +void SpellChecker::OnSettingsEnabled(bool enabled) { + feature_enabled_ = enabled; + + // Reset spell check service if the feature is disabled. + if (!enabled) { + dictionary_.reset(); + service_.reset(); + return; + } + + if (!dictionary_file_path_.empty()) + InitializeDictionary(); +} + +void SpellChecker::OnApplicationLocaleReady(const std::string& locale) { + dictionary_file_path_ = GetDictionaryFilePath(locale); + + if (feature_enabled_) + InitializeDictionary(); +} + +void SpellChecker::InitializeDictionary() { + DCHECK(!dictionary_file_path_.empty()); + + // If the dictionary is not available, try to download it from the server. + if (!base::PathExists(dictionary_file_path_)) { + auto url = + GetDictionaryURL(dictionary_file_path_.BaseName().MaybeAsASCII()); + + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = url; + resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; + loader_ = network::SimpleURLLoader::Create(std::move(resource_request), + kNetworkTrafficAnnotationTag); + // TODO(b/226221138): Probably use |DownloadToTempFile| instead. + loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + url_loader_factory_.get(), + base::BindOnce(&SpellChecker::OnSimpleURLLoaderComplete, + base::Unretained(this))); + return; + } + + InitializeSpellCheckService(); +} + +void SpellChecker::InitializeSpellCheckService() { + DCHECK(base::PathExists(dictionary_file_path_)); + + if (!service_) { + service_ = content::ServiceProcessHost::Launch<mojom::SpellCheckService>( + content::ServiceProcessHost::Options() + .WithDisplayName("Quick answers spell check service") + .Pass()); + } + + base::File file(dictionary_file_path_, + base::File::FLAG_READ | base::File::FLAG_OPEN); + + service_->CreateDictionary(file.Duplicate(), + base::BindOnce(&SpellChecker::OnDictionaryCreated, + base::Unretained(this))); +} + +void SpellChecker::OnSimpleURLLoaderComplete( + std::unique_ptr<std::string> data) { + int response_code = -1; + if (loader_->ResponseInfo() && loader_->ResponseInfo()->headers) + response_code = loader_->ResponseInfo()->headers->response_code(); + + if (loader_->NetError() != net::OK || ((response_code / 100) != 2)) { + LOG(ERROR) << "Failed to download the dictionary."; + MaybeRetryInitialize(); + return; + } + + // Basic sanity check on the dictionary data. + if (!data || data->size() < 4 || data->compare(0, 4, "BDic") != 0) { + LOG(ERROR) << "Downloaded dictionary data is empty or broken."; + MaybeRetryInitialize(); + return; + } + + if (!SaveDictionaryData(std::move(data), dictionary_file_path_)) { + MaybeRetryInitialize(); + return; + } + + InitializeSpellCheckService(); +} + +void SpellChecker::OnDictionaryCreated( + mojo::PendingRemote<mojom::SpellCheckDictionary> dictionary) { + dictionary_.reset(); + + if (dictionary.is_valid()) { + dictionary_.Bind(std::move(dictionary)); + dictionary_initialized_ = true; + return; + } + + MaybeRetryInitialize(); +} + +void SpellChecker::MaybeRetryInitialize() { + RemoveDictionaryFle(dictionary_file_path_); + + if (num_retries_ >= kMaxRetries) { + LOG(ERROR) << "Service initialize failed after max retries"; + service_.reset(); + return; + } + + ++num_retries_; + InitializeDictionary(); +} + +} // namespace quick_answers
diff --git a/chromeos/components/quick_answers/utils/spell_checker.h b/chromeos/components/quick_answers/utils/spell_checker.h new file mode 100644 index 0000000..5ee1d5a --- /dev/null +++ b/chromeos/components/quick_answers/utils/spell_checker.h
@@ -0,0 +1,80 @@ +// 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 CHROMEOS_COMPONENTS_QUICK_ANSWERS_UTILS_SPELL_CHECKER_H_ +#define CHROMEOS_COMPONENTS_QUICK_ANSWERS_UTILS_SPELL_CHECKER_H_ + +#include <memory> +#include <string> + +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" +#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h" +#include "chromeos/components/quick_answers/public/mojom/spell_check.mojom.h" +#include "mojo/public/cpp/bindings/remote.h" + +namespace network { +class SharedURLLoaderFactory; +class SimpleURLLoader; +} // namespace network + +namespace quick_answers { + +// Utility class for spell check. +class SpellChecker : public QuickAnswersStateObserver { + public: + using CheckSpellingCallback = base::OnceCallback<void(bool)>; + + explicit SpellChecker( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); + + SpellChecker(const SpellChecker&) = delete; + SpellChecker& operator=(const SpellChecker&) = delete; + + ~SpellChecker() override; + + // Check spelling of the given word, run |callback| with true if the word is + // spelled correctly. + void CheckSpelling(const std::string& word, CheckSpellingCallback callback); + + // QuickAnswersStateObserver: + void OnSettingsEnabled(bool enabled) override; + void OnApplicationLocaleReady(const std::string& locale) override; + + private: + void InitializeDictionary(); + void InitializeSpellCheckService(); + + void OnSimpleURLLoaderComplete(std::unique_ptr<std::string> response_body); + + void OnDictionaryCreated( + mojo::PendingRemote<mojom::SpellCheckDictionary> dictionary); + + void MaybeRetryInitialize(); + + // Whether the Quick answers feature is enabled in settings. + bool feature_enabled_ = false; + + // Whether the spell check dictionary has been successfully initialized. + bool dictionary_initialized_ = false; + + // Number of retries used for initializing the spell check service. + int num_retries_ = 0; + + base::FilePath dictionary_file_path_; + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + std::unique_ptr<network::SimpleURLLoader> loader_; + mojo::Remote<mojom::SpellCheckService> service_; + mojo::Remote<mojom::SpellCheckDictionary> dictionary_; + + base::ScopedObservation<QuickAnswersState, QuickAnswersStateObserver> + quick_answers_state_observation_{this}; + + base::WeakPtrFactory<SpellChecker> weak_factory_{this}; +}; + +} // namespace quick_answers + +#endif // CHROMEOS_COMPONENTS_QUICK_ANSWERS_UTILS_SPELL_CHECKER_H_
diff --git a/chromeos/dbus/concierge/concierge_client.cc b/chromeos/dbus/concierge/concierge_client.cc index 60f528299..531beef 100644 --- a/chromeos/dbus/concierge/concierge_client.cc +++ b/chromeos/dbus/concierge/concierge_client.cc
@@ -270,6 +270,12 @@ CallMethod(concierge::kReclaimVmMemoryMethod, request, std::move(callback)); } + void ListVms( + const concierge::ListVmsRequest& request, + DBusMethodCallback<concierge::ListVmsResponse> callback) override { + CallMethod(concierge::kListVmsMethod, request, std::move(callback)); + } + void Init(dbus::Bus* bus) override { concierge_proxy_ = bus->GetObjectProxy( concierge::kVmConciergeServiceName,
diff --git a/chromeos/dbus/concierge/concierge_client.h b/chromeos/dbus/concierge/concierge_client.h index 0d21e41dc..1a7f3bf 100644 --- a/chromeos/dbus/concierge/concierge_client.h +++ b/chromeos/dbus/concierge/concierge_client.h
@@ -283,6 +283,12 @@ DBusMethodCallback<vm_tools::concierge::ReclaimVmMemoryResponse> callback) = 0; + // Lists running VMs. + // |callback| is called after the method call finishes. + virtual void ListVms( + const vm_tools::concierge::ListVmsRequest& request, + DBusMethodCallback<vm_tools::concierge::ListVmsResponse> callback) = 0; + // Creates and initializes the global instance. |bus| must not be null. static void Initialize(dbus::Bus* bus);
diff --git a/chromeos/dbus/concierge/fake_concierge_client.cc b/chromeos/dbus/concierge/fake_concierge_client.cc index 4984b02..5330677 100644 --- a/chromeos/dbus/concierge/fake_concierge_client.cc +++ b/chromeos/dbus/concierge/fake_concierge_client.cc
@@ -380,6 +380,14 @@ base::BindOnce(std::move(callback), reclaim_vm_memory_response_)); } +void FakeConciergeClient::ListVms( + const vm_tools::concierge::ListVmsRequest& request, + DBusMethodCallback<vm_tools::concierge::ListVmsResponse> callback) { + list_vms_call_count_++; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), list_vms_response_)); +} + void FakeConciergeClient::NotifyVmStarted( const vm_tools::concierge::VmStartedSignal& signal) { // Now GetVmInfo can return success.
diff --git a/chromeos/dbus/concierge/fake_concierge_client.h b/chromeos/dbus/concierge/fake_concierge_client.h index 7d3ef9a..fd71f55 100644 --- a/chromeos/dbus/concierge/fake_concierge_client.h +++ b/chromeos/dbus/concierge/fake_concierge_client.h
@@ -140,6 +140,10 @@ DBusMethodCallback<vm_tools::concierge::ReclaimVmMemoryResponse> callback) override; + void ListVms(const vm_tools::concierge::ListVmsRequest& request, + DBusMethodCallback<vm_tools::concierge::ListVmsResponse> + callback) override; + const base::ObserverList<Observer>& observer_list() const { return observer_list_; } @@ -195,6 +199,7 @@ int reclaim_vm_memory_call_count() const { return reclaim_vm_memory_call_count_; } + int list_vms_call_count() const { return list_vms_call_count_; } void set_vm_started_signal_connected(bool connected) { is_vm_started_signal_connected_ = connected; @@ -306,6 +311,10 @@ reclaim_vm_memory_response) { reclaim_vm_memory_response_ = reclaim_vm_memory_response; } + void set_list_vms_response( + absl::optional<vm_tools::concierge::ListVmsResponse> list_vms_response) { + list_vms_response_ = list_vms_response; + } void set_send_create_disk_image_response_delay(base::TimeDelta delay) { send_create_disk_image_response_delay_ = delay; @@ -369,6 +378,7 @@ int resize_disk_image_call_count_ = 0; int set_vm_id_call_count_ = 0; int reclaim_vm_memory_call_count_ = 0; + int list_vms_call_count_ = 0; bool is_vm_started_signal_connected_ = true; bool is_vm_stopped_signal_connected_ = true; @@ -410,6 +420,7 @@ absl::optional<vm_tools::concierge::SetVmIdResponse> set_vm_id_response_; absl::optional<vm_tools::concierge::ReclaimVmMemoryResponse> reclaim_vm_memory_response_; + absl::optional<vm_tools::concierge::ListVmsResponse> list_vms_response_; base::TimeDelta send_create_disk_image_response_delay_; base::TimeDelta send_start_vm_response_delay_;
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni index e9231a3..165f718a 100644 --- a/chromeos/tast_control.gni +++ b/chromeos/tast_control.gni
@@ -172,6 +172,15 @@ "arc.SettingsBridge.vm", "arc.StartStop.vm", "arc.TextToSpeech.vm", + "arc.VMPstoreDump", + + # Flaky on chromeos-eve-chrome. b/226284050. + "crostini.UninstallInvalidApp.bullseye_stable", + "crostini.Xattrs.bullseye_stable", + "crostini.SSHFSMount.bullseye_stable", + "crostini.GPUEnabled.gpu_bullseye_stable", + "crostini.Basic.bullseye_stable", + "crostini.CrashReporter.bullseye_stable", ] # To disable a specific test in lacros_all_tast_tests, add it the following
diff --git a/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.cc b/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.cc index 490cebfe..e64fd6c8 100644 --- a/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.cc +++ b/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.cc
@@ -100,6 +100,15 @@ true); } +void LogVirtualCardEnrollmentStrikeDatabaseEvent( + VirtualCardEnrollmentSource source, + VirtualCardEnrollmentStrikeDatabaseEvent strike_event) { + base::UmaHistogramEnumeration( + "Autofill.VirtualCardEnrollmentStrikeDatabase." + + VirtualCardEnrollmentSourceToMetricSuffix(source), + strike_event); +} + void LogVirtualCardEnrollBubbleLatencySinceUpstream( const base::TimeDelta& latency) { base::UmaHistogramTimes( @@ -124,6 +133,19 @@ } } +const std::string VirtualCardEnrollmentLinkTypeToMetricSuffix( + VirtualCardEnrollmentLinkType link_type) { + switch (link_type) { + case VirtualCardEnrollmentLinkType:: + VIRTUAL_CARD_ENROLLMENT_GOOGLE_PAYMENTS_TOS_LINK: + return "GoogleLegalMessageLink"; + case VirtualCardEnrollmentLinkType::VIRTUAL_CARD_ENROLLMENT_ISSUER_TOS_LINK: + return "IssuerLegalMessageLink"; + case VirtualCardEnrollmentLinkType::VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK: + return "LearnMoreLink"; + } +} + const std::string VirtualCardEnrollmentSourceToMetricSuffix( VirtualCardEnrollmentSource source) { switch (source) { @@ -138,17 +160,4 @@ } } -const std::string VirtualCardEnrollmentLinkTypeToMetricSuffix( - VirtualCardEnrollmentLinkType link_type) { - switch (link_type) { - case VirtualCardEnrollmentLinkType:: - VIRTUAL_CARD_ENROLLMENT_GOOGLE_PAYMENTS_TOS_LINK: - return "GoogleLegalMessageLink"; - case VirtualCardEnrollmentLinkType::VIRTUAL_CARD_ENROLLMENT_ISSUER_TOS_LINK: - return "IssuerLegalMessageLink"; - case VirtualCardEnrollmentLinkType::VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK: - return "LearnMoreLink"; - } -} - } // namespace autofill
diff --git a/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h b/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h index bfe9c3e1..fb084b8 100644 --- a/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h +++ b/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h
@@ -81,6 +81,18 @@ VirtualCardEnrollmentBubbleSource source, bool is_reshow); +// Metrics to measure strikes logged or cleared in strike database. +enum class VirtualCardEnrollmentStrikeDatabaseEvent { + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + + // Strike logged as enrollment bubble was not accepted. + VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKE_LOGGED = 0, + // All strikes cleared as user accepted virtual card enrollment. + VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKES_CLEARED = 1, + kMaxValue = VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKES_CLEARED, +}; + // GetDetailsForEnrollmentRequest related metrics. Attempts and results should // be 1:1 mapping. void LogGetDetailsForEnrollmentRequestAttempt( @@ -103,6 +115,11 @@ VirtualCardEnrollmentLinkType link_type, VirtualCardEnrollmentBubbleSource source); +// Virtual card enrollment strike database event metrics. +void LogVirtualCardEnrollmentStrikeDatabaseEvent( + VirtualCardEnrollmentSource source, + VirtualCardEnrollmentStrikeDatabaseEvent strike_event); + // Latency Since Upstream metrics. Used to determine the time that it takes for // the server calls that need to be made between Save Card Bubble accept and // when the Virtual Card Enroll Bubble is shown.
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc index 50bab1d..0988036 100644 --- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc +++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
@@ -42,10 +42,14 @@ : autofill_client_(autofill_client), personal_data_manager_(personal_data_manager), payments_client_(payments_client) { - if (autofill_client_) { - StrikeDatabaseBase* strike_database = autofill_client->GetStrikeDatabase(); + // |autofill_client_| does not exist on Clank settings page where this flow + // can also be triggered. + if (base::FeatureList::IsEnabled( + features::kAutofillEnableUpdateVirtualCardEnrollment) && + autofill_client_ && autofill_client_->GetStrikeDatabase()) { virtual_card_enrollment_strike_database_ = - std::make_unique<VirtualCardEnrollmentStrikeDatabase>(strike_database); + std::make_unique<VirtualCardEnrollmentStrikeDatabase>( + autofill_client_->GetStrikeDatabase()); } } @@ -58,6 +62,14 @@ RiskAssessmentFunction risk_assessment_function, VirtualCardEnrollmentFieldsLoadedCallback virtual_card_enrollment_fields_loaded_callback) { + // If at strike limit, exit enrollment flow. + if (base::FeatureList::IsEnabled( + features::kAutofillEnableUpdateVirtualCardEnrollment) && + IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + credit_card.guid(), virtual_card_enrollment_source)) { + return; + } + Reset(); DCHECK_NE(virtual_card_enrollment_source, VirtualCardEnrollmentSource::kNone); #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) @@ -66,16 +78,17 @@ DCHECK(autofill_client_); autofill_client_->HideVirtualCardEnrollBubbleAndIconIfVisible(); #endif + state_.virtual_card_enrollment_fields.credit_card = credit_card; risk_assessment_function_ = std::move(risk_assessment_function); virtual_card_enrollment_fields_loaded_callback_ = std::move(virtual_card_enrollment_fields_loaded_callback); // The |card_art_image| might not be synced yet from the sync server which - // will result in a nullptr. This situation can occur in the upstream flow. If - // it is not synced, GetCreditCardArtImageForUrl() will send a fetch request - // to sync the |card_art_image|, and before showing the - // VirtualCardEnrollmentBubble we will try to fetch the |card_art_image| from - // the local cache. + // will result in a nullptr. This situation can occur in the upstream flow. + // If it is not synced, GetCreditCardArtImageForUrl() will send a fetch + // request to sync the |card_art_image|, and before showing the + // VirtualCardEnrollmentBubble we will try to fetch the |card_art_image| + // from the local cache. state_.virtual_card_enrollment_fields.card_art_image = personal_data_manager_->GetCreditCardArtImageForUrl( credit_card.card_art_url()); @@ -120,6 +133,11 @@ OnDidGetUpdateVirtualCardEnrollmentResponse, weak_ptr_factory_.GetWeakPtr(), VirtualCardEnrollmentRequestType::kEnroll)); + if (base::FeatureList::IsEnabled( + features::kAutofillEnableUpdateVirtualCardEnrollment)) { + RemoveAllStrikesToBlockOfferingVirtualCardEnrollment( + state_.virtual_card_enrollment_fields.credit_card.guid()); + } } void VirtualCardEnrollmentManager::Unenroll(int64_t instrument_id) { @@ -150,11 +168,19 @@ VirtualCardEnrollmentRequestType::kUnenroll)); } -bool VirtualCardEnrollmentManager::IsVirtualCardEnrollmentBlocked( - const std::string& guid) const { - return GetVirtualCardEnrollmentStrikeDatabase() && - GetVirtualCardEnrollmentStrikeDatabase()->IsMaxStrikesLimitReached( - guid); +bool VirtualCardEnrollmentManager:: + IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + const std::string& guid, + VirtualCardEnrollmentSource virtual_card_enrollment_source) const { + if (virtual_card_enrollment_source == + VirtualCardEnrollmentSource::kSettingsPage) + return false; + + if (!GetVirtualCardEnrollmentStrikeDatabase()) + return false; + + return GetVirtualCardEnrollmentStrikeDatabase()->IsMaxStrikesLimitReached( + guid); } void VirtualCardEnrollmentManager:: @@ -163,6 +189,12 @@ return; GetVirtualCardEnrollmentStrikeDatabase()->AddStrike(guid); + + // Log that a strike has been recorded. + LogVirtualCardEnrollmentStrikeDatabaseEvent( + state_.virtual_card_enrollment_fields.virtual_card_enrollment_source, + VirtualCardEnrollmentStrikeDatabaseEvent:: + VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKE_LOGGED); } void VirtualCardEnrollmentManager:: @@ -172,6 +204,12 @@ return; GetVirtualCardEnrollmentStrikeDatabase()->ClearStrikes(guid); + + // Log that strikes are being cleared. + LogVirtualCardEnrollmentStrikeDatabaseEvent( + state_.virtual_card_enrollment_fields.virtual_card_enrollment_source, + VirtualCardEnrollmentStrikeDatabaseEvent:: + VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKES_CLEARED); } void VirtualCardEnrollmentManager::SetSaveCardBubbleAcceptedTimestamp( @@ -333,6 +371,11 @@ } void VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled() { + if (base::FeatureList::IsEnabled( + features::kAutofillEnableUpdateVirtualCardEnrollment)) { + AddStrikeToBlockOfferingVirtualCardEnrollment( + state_.virtual_card_enrollment_fields.credit_card.guid()); + } Reset(); }
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h index b0f1397..67c6879a 100644 --- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h +++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
@@ -140,10 +140,12 @@ // Unenrolls the card mapped to the given |instrument_id|. void Unenroll(int64_t instrument_id); - // Returns true if a credit card identified by its |guid| is blocked for - // virtual card enrollment. Does nothing if the strike database is not - // available. - bool IsVirtualCardEnrollmentBlocked(const std::string& guid) const; + // Returns true if a credit card identified by its |guid| is + // blocked for virtual card enrollment and is not attempting to enroll from + // the settings page. Does nothing if the strike database is not available. + bool IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + const std::string& guid, + VirtualCardEnrollmentSource virtual_card_enrollment_source) const; // Adds a strike to block enrollment for credit card identified by its |guid|. // Does nothing if the strike database is not available. @@ -216,6 +218,24 @@ virtual_card_enrollment_fields_loaded_callback_; private: + friend class VirtualCardEnrollmentManagerTest; + FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, + OnDidGetDetailsForEnrollResponse); + FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, + OnDidGetDetailsForEnrollResponse_Reset); + FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, + OnRiskDataLoadedForVirtualCard); + FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, + OnVirtualCardEnrollmentBubbleAccepted); + FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, + StrikeDatabase_BubbleAccepted); + FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, + StrikeDatabase_BubbleBlocked); + FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, + StrikeDatabase_BubbleCanceled); + FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, + StrikeDatabase_SettingsPageNotBlocked); + // Called once the risk data is loaded. The |risk_data| will be used with // |state_|'s |virtual_card_enrollment_fields|'s |credit_card|'s // |instrument_id_| field to make a GetDetailsForEnroll request, and
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc index a95d0f4a..67507a85 100644 --- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc +++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
@@ -12,10 +12,12 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/data_model/credit_card.h" #include "components/autofill/core/browser/data_model/credit_card_art_image.h" +#include "components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h" #include "components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h" #include "components/autofill/core/browser/payments/payments_util.h" #include "components/autofill/core/browser/payments/test_legal_message_line.h" #include "components/autofill/core/browser/payments/test_payments_client.h" +#include "components/autofill/core/browser/payments/test_strike_database.h" #include "components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h" #include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h" #include "components/autofill/core/browser/test_autofill_client.h" @@ -40,6 +42,8 @@ class VirtualCardEnrollmentManagerTest : public testing::Test { public: void SetUp() override { + feature_list_.InitAndEnableFeature( + features::kAutofillEnableUpdateVirtualCardEnrollment); autofill_client_ = std::make_unique<TestAutofillClient>(); autofill_client_->SetPrefs(test::PrefServiceForTesting()); user_prefs_ = autofill_client_->GetPrefs(); @@ -60,6 +64,8 @@ autofill_driver_->GetURLLoaderFactory(), autofill_client_->GetIdentityManager(), personal_data_manager_.get())); + auto test_strike_database = std::make_unique<TestStrikeDatabase>(); + autofill_client_->set_test_strike_database(std::move(test_strike_database)); payments_client_ = static_cast<payments::TestPaymentsClient*>( autofill_client_->GetPaymentsClient()); virtual_card_enrollment_manager_ = @@ -78,6 +84,7 @@ card_ = std::make_unique<CreditCard>(test::GetMaskedServerCard()); card_->set_card_art_url(autofill_client_->form_origin()); card_->set_instrument_id(112233445566); + card_->set_guid("00000000-0000-0000-0000-000000000001"); personal_data_manager_->AddFullServerCreditCard(*card_.get()); } @@ -110,6 +117,7 @@ } protected: + base::test::ScopedFeatureList feature_list_; base::test::TaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; std::unique_ptr<TestAutofillClient> autofill_client_; @@ -312,6 +320,8 @@ raw_ptr<VirtualCardEnrollmentProcessState> state = virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState(); state->vcn_context_token = kTestVcnContextToken; + SetUpCard(); + SetValidCardArtImageForCard(*card_); personal_data_manager_->SetPaymentsCustomerData( std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456")); @@ -506,6 +516,143 @@ } #endif // !BUILDFLAG(IS_ANDROID) +#if !BUILDFLAG(IS_IOS) +TEST_F(VirtualCardEnrollmentManagerTest, StrikeDatabase_BubbleAccepted) { + base::HistogramTester histogram_tester; + raw_ptr<VirtualCardEnrollmentProcessState> state = + virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState(); + state->vcn_context_token = kTestVcnContextToken; + SetUpCard(); + state->virtual_card_enrollment_fields.credit_card = *card_; + personal_data_manager_->SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>("123456")); + EXPECT_FALSE(virtual_card_enrollment_manager_ + ->IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + state->virtual_card_enrollment_fields.credit_card.guid(), + VirtualCardEnrollmentSource::kUpstream)); + + // Reject the bubble and log strike. + virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled(); + EXPECT_EQ( + virtual_card_enrollment_manager_->GetVirtualCardEnrollmentStrikeDatabase() + ->GetStrikes( + state->virtual_card_enrollment_fields.credit_card.guid()), + 1); + + // Ensure a strike has been removed after enrollment accepted. + virtual_card_enrollment_manager_->Enroll(); + EXPECT_EQ( + virtual_card_enrollment_manager_->GetVirtualCardEnrollmentStrikeDatabase() + ->GetStrikes( + state->virtual_card_enrollment_fields.credit_card.guid()), + 0); + + histogram_tester.ExpectBucketCount( + "Autofill.VirtualCardEnrollmentStrikeDatabase." + + VirtualCardEnrollmentSourceToMetricSuffix( + state->virtual_card_enrollment_fields + .virtual_card_enrollment_source), + VirtualCardEnrollmentStrikeDatabaseEvent:: + VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKES_CLEARED, + 1); +} + +TEST_F(VirtualCardEnrollmentManagerTest, StrikeDatabase_BubbleCanceled) { + base::HistogramTester histogram_tester; + raw_ptr<VirtualCardEnrollmentProcessState> state = + virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState(); + state->vcn_context_token = kTestVcnContextToken; + SetUpCard(); + state->virtual_card_enrollment_fields.credit_card = *card_; + personal_data_manager_->SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>("123456")); + EXPECT_FALSE(virtual_card_enrollment_manager_ + ->IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + state->virtual_card_enrollment_fields.credit_card.guid(), + VirtualCardEnrollmentSource::kUpstream)); + + // Reject the bubble and log strike. + virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled(); + + // Ensure a strike has been logged. + EXPECT_EQ( + virtual_card_enrollment_manager_->GetVirtualCardEnrollmentStrikeDatabase() + ->GetStrikes( + state->virtual_card_enrollment_fields.credit_card.guid()), + 1); + + histogram_tester.ExpectBucketCount( + "Autofill.VirtualCardEnrollmentStrikeDatabase." + + VirtualCardEnrollmentSourceToMetricSuffix( + state->virtual_card_enrollment_fields + .virtual_card_enrollment_source), + VirtualCardEnrollmentStrikeDatabaseEvent:: + VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKE_LOGGED, + 1); +} + +TEST_F(VirtualCardEnrollmentManagerTest, StrikeDatabase_BubbleBlocked) { + raw_ptr<VirtualCardEnrollmentProcessState> state = + virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState(); + state->vcn_context_token = kTestVcnContextToken; + SetUpCard(); + state->virtual_card_enrollment_fields.credit_card = *card_; + personal_data_manager_->SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>("123456")); + EXPECT_FALSE(virtual_card_enrollment_manager_ + ->IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + state->virtual_card_enrollment_fields.credit_card.guid(), + VirtualCardEnrollmentSource::kUpstream)); + EXPECT_FALSE(virtual_card_enrollment_manager_ + ->IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + state->virtual_card_enrollment_fields.credit_card.guid(), + VirtualCardEnrollmentSource::kDownstream)); + + for (int i = 0; i < virtual_card_enrollment_manager_ + ->GetVirtualCardEnrollmentStrikeDatabase() + ->GetMaxStrikesLimit(); + i++) { + // Reject the bubble and log strike. + virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled(); + } + + EXPECT_TRUE(virtual_card_enrollment_manager_ + ->IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + state->virtual_card_enrollment_fields.credit_card.guid(), + VirtualCardEnrollmentSource::kUpstream)); + EXPECT_TRUE(virtual_card_enrollment_manager_ + ->IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + state->virtual_card_enrollment_fields.credit_card.guid(), + VirtualCardEnrollmentSource::kDownstream)); +} + +TEST_F(VirtualCardEnrollmentManagerTest, + StrikeDatabase_SettingsPageNotBlocked) { + raw_ptr<VirtualCardEnrollmentProcessState> state = + virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState(); + state->vcn_context_token = kTestVcnContextToken; + SetUpCard(); + state->virtual_card_enrollment_fields.credit_card = *card_; + + personal_data_manager_->SetPaymentsCustomerData( + std::make_unique<PaymentsCustomerData>("123456")); + + for (int i = 0; i < virtual_card_enrollment_manager_ + ->GetVirtualCardEnrollmentStrikeDatabase() + ->GetMaxStrikesLimit(); + i++) { + // Reject the bubble and log strike. + virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled(); + } + + // Make sure enrollment is not blocked through settings page. + EXPECT_FALSE(virtual_card_enrollment_manager_ + ->IsVirtualCardEnrollmentBlockedDueToMaxStrikes( + state->virtual_card_enrollment_fields.credit_card.guid(), + VirtualCardEnrollmentSource::kSettingsPage)); +} +#endif // !BUILDFLAG(IS_IOS) + TEST_F(VirtualCardEnrollmentManagerTest, Metrics_LatencySinceUpstream) { base::HistogramTester histogram_tester; TestAutofillClock test_autofill_clock;
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.cc index 5c3781d..a315de25 100644 --- a/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.cc +++ b/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.cc
@@ -20,18 +20,20 @@ int kCardMaximumStrikes = 3; // The number of days until strikes expire for virtual card enrollment. -constexpr size_t kDaysUntilCardStrikeExpiry = 180; +int kDaysUntilCardStrikeExpiry = 180; VirtualCardEnrollmentStrikeDatabase::VirtualCardEnrollmentStrikeDatabase( StrikeDatabaseBase* strike_database) - : StrikeDatabaseIntegratorBase(strike_database) {} + : StrikeDatabaseIntegratorBase(strike_database) { + RemoveExpiredStrikes(); +} VirtualCardEnrollmentStrikeDatabase::~VirtualCardEnrollmentStrikeDatabase() = default; absl::optional<size_t> VirtualCardEnrollmentStrikeDatabase::GetMaximumEntries() const { - return kMaxStrikeEntities; + return absl::optional<size_t>(kMaxStrikeEntities); } absl::optional<size_t> @@ -51,7 +53,8 @@ absl::optional<base::TimeDelta> VirtualCardEnrollmentStrikeDatabase::GetExpiryTimeDelta() const { // Expiry time is 180 days by default. - return base::Days(kDaysUntilCardStrikeExpiry); + return absl::optional<base::TimeDelta>( + base::Days(kDaysUntilCardStrikeExpiry)); } bool VirtualCardEnrollmentStrikeDatabase::UniqueIdsRequired() const {
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database_unittest.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database_unittest.cc index 463b53c0..4427583 100644 --- a/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database_unittest.cc +++ b/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database_unittest.cc
@@ -55,6 +55,7 @@ int max_strikes = strike_database_->GetMaxStrikesLimit(); std::string test_guid = "00000000-0000-0000-0000-000000000001"; + EXPECT_EQ(strike_database_->GetStrikes(test_guid), 0); strike_database_->AddStrike(test_guid); EXPECT_EQ(strike_database_->GetStrikes(test_guid), 1); EXPECT_FALSE(strike_database_->IsMaxStrikesLimitReached(test_guid));
diff --git a/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc b/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc index 1bdda0d..aa0ec92 100644 --- a/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc +++ b/components/autofill_assistant/browser/actions/action_delegate_util_unittest.cc
@@ -216,7 +216,7 @@ auto element = std::make_unique<ElementFinder::Result>(); content::WebContentsTester::For(web_contents_.get()) ->NavigateAndCommit(GURL("https://www.example.com")); - element->container_frame_host = web_contents_->GetMainFrame(); + element->SetRenderFrameHost(web_contents_->GetMainFrame()); user_data_.selected_login_ = absl::make_optional<WebsiteLoginManager::Login>( GURL("https://www.example.com"), "username"); @@ -239,8 +239,7 @@ TEST_F(ActionDelegateUtilTest, PerformWithFailingPasswordManagerValue) { auto element = std::make_unique<ElementFinder::Result>(); - - element->container_frame_host = web_contents_->GetMainFrame(); + element->SetRenderFrameHost(web_contents_->GetMainFrame()); user_data_.selected_login_ = absl::make_optional<WebsiteLoginManager::Login>( GURL("https://www.example.com"), "username");
diff --git a/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc b/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc index 4a46d59..0eaed9fc 100644 --- a/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/get_element_status_action_unittest.cc
@@ -702,7 +702,7 @@ .WillOnce(WithArgs<1>([this](auto&& callback) { std::unique_ptr<ElementFinder::Result> element = std::make_unique<ElementFinder::Result>(); - element->container_frame_host = web_contents_->GetMainFrame(); + element->SetRenderFrameHost(web_contents_->GetMainFrame()); std::move(callback).Run(OkClientStatus(), std::move(element)); })); EXPECT_CALL(mock_website_login_manager_, GetPasswordForLogin(_, _))
diff --git a/components/autofill_assistant/browser/actions/js_flow_action.cc b/components/autofill_assistant/browser/actions/js_flow_action.cc index 8b069eb4..6303274 100644 --- a/components/autofill_assistant/browser/actions/js_flow_action.cc +++ b/components/autofill_assistant/browser/actions/js_flow_action.cc
@@ -5,6 +5,7 @@ #include "components/autofill_assistant/browser/actions/js_flow_action.h" #include "base/base64.h" #include "base/json/json_writer.h" +#include "base/metrics/field_trial.h" #include "components/autofill_assistant/browser/actions/action_delegate.h" #include "components/autofill_assistant/browser/js_flow_executor_impl.h" #include "components/autofill_assistant/browser/js_flow_util.h" @@ -12,6 +13,17 @@ namespace autofill_assistant { +namespace { + +// When starting a JS flow action, a synthetic field trial is recorded. This is +// used to allow tracking stability metrics as we start using this new action. +// Note there is no control group - this is purely for stability tracking. +const char kJsFlowActionSyntheticFieldTrialName[] = + "AutofillAssistantJsFlowAction"; +const char kJsFlowActionEnabledGroup[] = "Enabled"; + +} // namespace + JsFlowAction::JsFlowAction(ActionDelegate* delegate, const ActionProto& proto) : Action(delegate, proto), js_flow_executor_( @@ -85,6 +97,9 @@ } void JsFlowAction::InternalProcessAction(ProcessActionCallback callback) { + base::FieldTrialList::CreateFieldTrial(kJsFlowActionSyntheticFieldTrialName, + kJsFlowActionEnabledGroup); + js_flow_executor_->Start( proto_.js_flow().js_flow(), base::BindOnce(&JsFlowAction::OnFlowFinished,
diff --git a/components/autofill_assistant/browser/actions/send_keystroke_events_action.cc b/components/autofill_assistant/browser/actions/send_keystroke_events_action.cc index 840ed39..113aa1e 100644 --- a/components/autofill_assistant/browser/actions/send_keystroke_events_action.cc +++ b/components/autofill_assistant/browser/actions/send_keystroke_events_action.cc
@@ -41,14 +41,14 @@ // When dealing with a password field we also want to know the last time that // a user has used it. auto selected_login_opt = delegate_->GetUserData()->selected_login_; + auto* target_render_frame_host = element_.render_frame_host(); if (proto_.send_keystroke_events().value().value_case() == TextValue::kPasswordManagerValue && - selected_login_opt) { + selected_login_opt && target_render_frame_host) { // Origin check is done in PWM based on the - // |target_element.container_frame_host->GetLastCommittedURL()| - selected_login_opt->origin = - element_.container_frame_host->GetLastCommittedURL() - .DeprecatedGetOriginAsURL(); + // |target_render_frame_host->GetLastCommittedURL()| + selected_login_opt->origin = target_render_frame_host->GetLastCommittedURL() + .DeprecatedGetOriginAsURL(); delegate_->GetWebsiteLoginManager()->GetGetLastTimePasswordUsed( *selected_login_opt,
diff --git a/components/autofill_assistant/browser/actions/send_keystroke_events_action_unittest.cc b/components/autofill_assistant/browser/actions/send_keystroke_events_action_unittest.cc index 0470cd0..0779f1cf 100644 --- a/components/autofill_assistant/browser/actions/send_keystroke_events_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/send_keystroke_events_action_unittest.cc
@@ -119,7 +119,7 @@ content::WebContentsTester::For(web_contents_.get()) ->NavigateAndCommit(GURL(kUrl)); element.dom_object.object_data.object_id = "id"; - element.container_frame_host = web_contents_->GetMainFrame(); + element.SetRenderFrameHost(web_contents_->GetMainFrame()); mock_action_delegate_.GetElementStore()->AddElement("e", element.dom_object); EXPECT_CALL(mock_web_controller_, @@ -159,7 +159,7 @@ content::WebContentsTester::For(web_contents_.get()) ->NavigateAndCommit(GURL(kUrl)); element.dom_object.object_data.object_id = "id"; - element.container_frame_host = web_contents_->GetMainFrame(); + element.SetRenderFrameHost(web_contents_->GetMainFrame()); mock_action_delegate_.GetElementStore()->AddElement("e", element.dom_object); EXPECT_CALL(mock_web_controller_,
diff --git a/components/autofill_assistant/browser/user_data_util.cc b/components/autofill_assistant/browser/user_data_util.cc index ffe2306..0a175dab 100644 --- a/components/autofill_assistant/browser/user_data_util.cc +++ b/components/autofill_assistant/browser/user_data_util.cc
@@ -606,7 +606,8 @@ std::move(callback).Run(ClientStatus(PRECONDITION_FAILED), std::string()); return; } - if (!target_element.container_frame_host) { + auto* target_render_frame_host = target_element.render_frame_host(); + if (!target_render_frame_host) { std::move(callback).Run(ClientStatus(PASSWORD_ORIGIN_MISMATCH), std::string()); return; @@ -616,8 +617,8 @@ case PasswordManagerValue::PASSWORD: { auto login = *user_data->selected_login_; // Origin check is done in PWM based on the - // |target_element.container_frame_host->GetLastCommittedURL()| - login.origin = target_element.container_frame_host->GetLastCommittedURL() + // |target_render_frame_host->GetLastCommittedURL()| + login.origin = target_render_frame_host->GetLastCommittedURL() .DeprecatedGetOriginAsURL(); website_login_manager->GetPasswordForLogin( login, base::BindOnce(&OnGetStoredPassword, std::move(callback)));
diff --git a/components/autofill_assistant/browser/user_data_util_unittest.cc b/components/autofill_assistant/browser/user_data_util_unittest.cc index 7703e8c..80bae5f4 100644 --- a/components/autofill_assistant/browser/user_data_util_unittest.cc +++ b/components/autofill_assistant/browser/user_data_util_unittest.cc
@@ -1261,7 +1261,7 @@ GURL("https://www.example.com"), "username"); ElementFinder::Result element; - element.container_frame_host = web_contents_->GetMainFrame(); + element.SetRenderFrameHost(web_contents_->GetMainFrame()); PasswordManagerValue password_manager_value; password_manager_value.set_credential_type(PasswordManagerValue::USERNAME); @@ -1279,7 +1279,7 @@ GURL("https://www.example.com"), "username"); ElementFinder::Result element; - element.container_frame_host = web_contents_->GetMainFrame(); + element.SetRenderFrameHost(web_contents_->GetMainFrame()); PasswordManagerValue password_manager_value; password_manager_value.set_credential_type(PasswordManagerValue::PASSWORD); @@ -1301,7 +1301,7 @@ ElementFinder::Result element; content::WebContentsTester::For(web_contents_.get()) ->NavigateAndCommit(GURL("https://www.example.com")); - element.container_frame_host = web_contents_->GetMainFrame(); + element.SetRenderFrameHost(web_contents_->GetMainFrame()); PasswordManagerValue password_manager_value; password_manager_value.set_credential_type(PasswordManagerValue::PASSWORD); @@ -1382,7 +1382,7 @@ ElementFinder::Result element; content::WebContentsTester::For(web_contents_.get()) ->NavigateAndCommit(GURL("https://www.example.com")); - element.container_frame_host = web_contents_->GetMainFrame(); + element.SetRenderFrameHost(web_contents_->GetMainFrame()); TextValue text_value; text_value.mutable_password_manager_value()->set_credential_type(
diff --git a/components/autofill_assistant/browser/web/click_or_tap_worker.cc b/components/autofill_assistant/browser/web/click_or_tap_worker.cc index f50afda..fa5b4cf 100644 --- a/components/autofill_assistant/browser/web/click_or_tap_worker.cc +++ b/components/autofill_assistant/browser/web/click_or_tap_worker.cc
@@ -31,7 +31,7 @@ /* check_interval= */ base::Milliseconds(0), node_frame_id_); element_position_getter_->Start( - element.container_frame_host, element.object_id(), + element.render_frame_host(), element.object_id(), base::BindOnce(&ClickOrTapWorker::OnGetCoordinates, weak_ptr_factory_.GetWeakPtr())); }
diff --git a/components/autofill_assistant/browser/web/element_finder.cc b/components/autofill_assistant/browser/web/element_finder.cc index a8bd92c..d9791797 100644 --- a/components/autofill_assistant/browser/web/element_finder.cc +++ b/components/autofill_assistant/browser/web/element_finder.cc
@@ -159,10 +159,9 @@ return; } - if (start_element.container_frame_host == nullptr) { + current_frame_ = start_element.render_frame_host(); + if (current_frame_ == nullptr) { current_frame_ = web_contents_->GetMainFrame(); - } else { - current_frame_ = start_element.container_frame_host; } current_frame_id_ = start_element.node_frame_id(); frame_stack_ = start_element.frame_stack(); @@ -244,7 +243,7 @@ ElementFinder::Result ElementFinder::BuildResult(const std::string& object_id) { Result result; - result.container_frame_host = current_frame_; + result.SetRenderFrameHost(current_frame_); result.dom_object.object_data.object_id = object_id; result.dom_object.object_data.node_frame_id = current_frame_id_; return result;
diff --git a/components/autofill_assistant/browser/web/element_finder.h b/components/autofill_assistant/browser/web/element_finder.h index c644b79..2bf03ce5c 100644 --- a/components/autofill_assistant/browser/web/element_finder.h +++ b/components/autofill_assistant/browser/web/element_finder.h
@@ -60,8 +60,9 @@ }; // Result is the fully resolved element that can be used without limitations. - // This means that |container_frame_host| has been found and is not nullptr. - struct Result { + // This means that |render_frame_host()| has been found and is not nullptr. + class Result { + public: Result(); ~Result(); Result(const Result&); @@ -72,8 +73,12 @@ DomObjectFrameStack dom_object; - // The render frame host contains the element. - raw_ptr<content::RenderFrameHost> container_frame_host = nullptr; + content::RenderFrameHost* render_frame_host() const { + if (!render_frame_id_) { + return nullptr; + } + return content::RenderFrameHost::FromID(*render_frame_id_); + } const std::string& object_id() const { return dom_object.object_data.object_id; @@ -90,6 +95,17 @@ bool IsEmpty() const { return object_id().empty() && node_frame_id().empty(); } + + void SetRenderFrameHost(content::RenderFrameHost* render_frame_host) { + if (!render_frame_host) { + return; + } + render_frame_id_ = render_frame_host->GetGlobalId(); + } + + private: + // The id of the render frame host that contains the element. + absl::optional<content::GlobalRenderFrameHostId> render_frame_id_; }; // |web_contents|, |devtools_client| and |user_data| must be valid for the
diff --git a/components/autofill_assistant/browser/web/element_store.cc b/components/autofill_assistant/browser/web/element_store.cc index 12658bf..edbfebd 100644 --- a/components/autofill_assistant/browser/web/element_store.cc +++ b/components/autofill_assistant/browser/web/element_store.cc
@@ -44,7 +44,7 @@ VLOG(1) << __func__ << " failed to resolve frame."; return ClientStatus(CLIENT_ID_RESOLUTION_FAILED); } - out_element->container_frame_host = frame; + out_element->SetRenderFrameHost(frame); return OkClientStatus(); }
diff --git a/components/autofill_assistant/browser/web/element_store_unittest.cc b/components/autofill_assistant/browser/web/element_store_unittest.cc index f638f592..9888072 100644 --- a/components/autofill_assistant/browser/web/element_store_unittest.cc +++ b/components/autofill_assistant/browser/web/element_store_unittest.cc
@@ -87,7 +87,7 @@ ElementFinder::Result result; EXPECT_EQ(ACTION_APPLIED, element_store_->GetElement("1", &result).proto_status()); - EXPECT_EQ(web_contents_->GetMainFrame(), result.container_frame_host); + EXPECT_EQ(web_contents_->GetMainFrame(), result.render_frame_host()); } TEST_F(ElementStoreTest, AddElementToStoreOverwrites) {
diff --git a/components/autofill_assistant/browser/web/fake_element_store.cc b/components/autofill_assistant/browser/web/fake_element_store.cc index 25d4c3cb..2718171 100644 --- a/components/autofill_assistant/browser/web/fake_element_store.cc +++ b/components/autofill_assistant/browser/web/fake_element_store.cc
@@ -25,7 +25,7 @@ out_element->dom_object = it->second; if (web_contents_ != nullptr) { - out_element->container_frame_host = web_contents_->GetMainFrame(); + out_element->SetRenderFrameHost(web_contents_->GetMainFrame()); } return OkClientStatus(); }
diff --git a/components/autofill_assistant/browser/web/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc index b8a2b9a..a2632e6 100644 --- a/components/autofill_assistant/browser/web/web_controller.cc +++ b/components/autofill_assistant/browser/web/web_controller.cc
@@ -732,7 +732,7 @@ element.node_frame_id()); auto* ptr = getter.get(); pending_workers_.emplace_back(std::move(getter)); - ptr->Start(element.container_frame_host, element.object_id(), + ptr->Start(element.render_frame_host(), element.object_id(), base::BindOnce(&WebController::OnWaitUntilElementIsStable, weak_ptr_factory_.GetWeakPtr(), ptr, base::TimeTicks::Now(), std::move(callback))); @@ -1048,8 +1048,8 @@ return; } - ContentAutofillDriver* driver = ContentAutofillDriver::GetForRenderFrameHost( - element.container_frame_host); + ContentAutofillDriver* driver = + ContentAutofillDriver::GetForRenderFrameHost(element.render_frame_host()); if (driver == nullptr) { DVLOG(1) << __func__ << " Failed to get the autofill driver."; std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__), nullptr,
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc index 5773d4cd..88e7612a4 100644 --- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc +++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -602,11 +602,11 @@ bool is_main_frame) { if (is_main_frame) { EXPECT_EQ(shell()->web_contents()->GetMainFrame(), - result.container_frame_host); + result.render_frame_host()); EXPECT_EQ(result.frame_stack().size(), 0u); } else { EXPECT_NE(shell()->web_contents()->GetMainFrame(), - result.container_frame_host); + result.render_frame_host()); EXPECT_GE(result.frame_stack().size(), 1u); } EXPECT_FALSE(result.object_id().empty()); @@ -2758,7 +2758,7 @@ // This makes the devtools action fail. ElementFinder::Result element; element.dom_object.object_data.node_frame_id = "doesnotexist"; - element.container_frame_host = web_contents()->GetMainFrame(); + element.SetRenderFrameHost(web_contents()->GetMainFrame()); EXPECT_EQ(ELEMENT_POSITION_NOT_FOUND, WaitUntilElementIsStable(element, 10, base::Milliseconds(100)) @@ -3210,9 +3210,9 @@ // Create fake element without object id and frame information only. ElementFinder::Result fake_frame_element; - fake_frame_element.container_frame_host = frame_element.container_frame_host; + fake_frame_element.SetRenderFrameHost(frame_element.render_frame_host()); fake_frame_element.dom_object.object_data.node_frame_id = - frame_element.container_frame_host->GetDevToolsFrameToken().ToString(); + frame_element.render_frame_host()->GetDevToolsFrameToken().ToString(); ClientStatus button_status; ElementFinder::Result button_element;
diff --git a/components/browsing_topics/browsing_topics_calculator_unittest.cc b/components/browsing_topics/browsing_topics_calculator_unittest.cc index 79fcfb0..3f0a05c 100644 --- a/components/browsing_topics/browsing_topics_calculator_unittest.cc +++ b/components/browsing_topics/browsing_topics_calculator_unittest.cc
@@ -67,12 +67,15 @@ /*restore_session=*/false); cookie_settings_ = new content_settings::CookieSettings( host_content_settings_map_.get(), &prefs_, false, "chrome-extension"); - privacy_sandbox_settings_ = std::make_unique< - privacy_sandbox::PrivacySandboxSettings>( - std::make_unique< - privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>(), - host_content_settings_map_.get(), cookie_settings_, &prefs_, - /*incognito_profile=*/false); + auto privacy_sandbox_delegate = std::make_unique< + privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate>(); + privacy_sandbox_delegate->SetupDefaultResponse(/*restricted=*/false, + /*confirmed=*/true); + privacy_sandbox_settings_ = + std::make_unique<privacy_sandbox::PrivacySandboxSettings>( + std::move(privacy_sandbox_delegate), + host_content_settings_map_.get(), cookie_settings_, &prefs_, + /*incognito_profile=*/false); topics_site_data_manager_ = std::make_unique<content::TesterBrowsingTopicsSiteDataManager>(
diff --git a/components/feed/core/proto/BUILD.gn b/components/feed/core/proto/BUILD.gn index 4e5922c..2b1d9bc 100644 --- a/components/feed/core/proto/BUILD.gn +++ b/components/feed/core/proto/BUILD.gn
@@ -24,6 +24,7 @@ "v2/wire/chrome_feed_response_metadata.proto", "v2/wire/chrome_fulfillment_info.proto", "v2/wire/client_info.proto", + "v2/wire/client_user_profiles.proto", "v2/wire/consistency_token.proto", "v2/wire/content_id.proto", "v2/wire/content_lifetime.proto",
diff --git a/components/feed/core/proto/v2/wire/action_surface.proto b/components/feed/core/proto/v2/wire/action_surface.proto index 7a280b12..d563581 100644 --- a/components/feed/core/proto/v2/wire/action_surface.proto +++ b/components/feed/core/proto/v2/wire/action_surface.proto
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -syntax = "proto2"; +syntax = "proto3"; package feedwire;
diff --git a/components/feed/core/proto/v2/wire/capability.proto b/components/feed/core/proto/v2/wire/capability.proto index 427be86..b94df7421 100644 --- a/components/feed/core/proto/v2/wire/capability.proto +++ b/components/feed/core/proto/v2/wire/capability.proto
@@ -36,4 +36,5 @@ CONTENT_LIFETIME = 64; OPEN_IN_INCOGNITO = 67; ON_DEVICE_USER_PROFILE = 70; + INVALIDATE_CACHE_COMMAND = 73; }
diff --git a/components/feed/core/proto/v2/wire/client_info.proto b/components/feed/core/proto/v2/wire/client_info.proto index 4b67fa5b..a203639 100644 --- a/components/feed/core/proto/v2/wire/client_info.proto +++ b/components/feed/core/proto/v2/wire/client_info.proto
@@ -28,7 +28,6 @@ repeated DisplayInfo display_info = 6; optional string client_instance_id = 7; optional string advertising_id = 8; - optional string device_country = 9; optional Device device = 10; optional ChromeClientInfo chrome_client_info = 338478298; }
diff --git a/components/feed/core/proto/v2/wire/client_user_profiles.proto b/components/feed/core/proto/v2/wire/client_user_profiles.proto new file mode 100644 index 0000000..674dc6c --- /dev/null +++ b/components/feed/core/proto/v2/wire/client_user_profiles.proto
@@ -0,0 +1,39 @@ +// 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. + +syntax = "proto2"; + +package feedwire; + +option optimize_for = LITE_RUNTIME; + +message ClientUserProfiles { + optional DiscoverUserActionsProfile discover_user_actions_profile = 1; +} +message ActionCounts { + message Counts { + optional uint32 count_1d = 1; + optional uint32 count_7d = 2; + optional uint32 count_30d = 3; + } + enum ActionType { + UNKNOWN = 0; + CLICK = 1; + } + optional ActionType type = 1; + optional Counts counts = 2; +} +message DiscoverUserActionsProfile { + message ContentMediaXEntityActionCounts { + optional uint64 mid = 2; + repeated ActionCounts counts = 3; + } + message CardCategoryXEntityActionCounts { + optional uint64 card_category = 1; + optional uint64 mid = 2; + repeated ActionCounts counts = 3; + } + repeated ContentMediaXEntityActionCounts content_media_x_entity = 2; + repeated CardCategoryXEntityActionCounts card_category_x_entity = 3; +}
diff --git a/components/feed/core/proto/v2/wire/feed_request.proto b/components/feed/core/proto/v2/wire/feed_request.proto index d3a26bc..c7f3973 100644 --- a/components/feed/core/proto/v2/wire/feed_request.proto +++ b/components/feed/core/proto/v2/wire/feed_request.proto
@@ -8,6 +8,7 @@ import "components/feed/core/proto/v2/wire/capability.proto"; import "components/feed/core/proto/v2/wire/client_info.proto"; +import "components/feed/core/proto/v2/wire/client_user_profiles.proto"; import "components/feed/core/proto/v2/wire/consistency_token.proto"; import "components/feed/core/proto/v2/wire/diagnostic_info.proto"; import "components/feed/core/proto/v2/wire/feed_query.proto"; @@ -20,4 +21,5 @@ repeated Capability client_capability = 4; optional ConsistencyToken consistency_token = 5; optional DiagnosticInfo diagnostic_info = 14; + optional ClientUserProfiles client_user_profiles = 16; }
diff --git a/components/feed/core/v2/test/proto_printer.cc b/components/feed/core/v2/test/proto_printer.cc index a0283d8..c6d33de 100644 --- a/components/feed/core/v2/test/proto_printer.cc +++ b/components/feed/core/v2/test/proto_printer.cc
@@ -146,7 +146,6 @@ PRINT_FIELD(display_info); PRINT_FIELD(client_instance_id); PRINT_FIELD(advertising_id); - PRINT_FIELD(device_country); EndMessage(); return *this; }
diff --git a/components/printing/browser/print_manager_utils.cc b/components/printing/browser/print_manager_utils.cc index 737ac37..dacdecf 100644 --- a/components/printing/browser/print_manager_utils.cc +++ b/components/printing/browser/print_manager_utils.cc
@@ -30,12 +30,8 @@ void CreateCompositeClientIfNeeded(content::WebContents* web_contents, const std::string& user_agent) { - // TODO(weili): We only create pdf compositor client and use pdf compositor - // service when site-per-process or isolate-origins flag/feature is enabled, - // or top-document-isolation feature is enabled. This may not cover all cases - // where OOPIF is used such as isolate-extensions, but should be good for - // feature testing purpose. Eventually, we will remove this check and use pdf - // compositor service by default for printing. + // TODO(crbug.com/1022917): Once ShouldPdfCompositorBeEnabledForOopifs() + // always returns true, just remove the check altogether. if (site_isolation::SiteIsolationPolicy:: ShouldPdfCompositorBeEnabledForOopifs()) { PrintCompositeClient::CreateForWebContents(web_contents);
diff --git a/components/printing/common/print.mojom b/components/printing/common/print.mojom index 5afad24..7a79f3b0 100644 --- a/components/printing/common/print.mojom +++ b/components/printing/common/print.mojom
@@ -25,7 +25,9 @@ // Parameters required to do print preview. [EnableIf=enable_print_preview] struct RequestPrintPreviewParams { + [EnableIf=is_chromeos_ash] bool is_from_arc = false; + bool is_modifiable = false; bool webnode_only = false; bool has_selection = false;
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc index 06652157..eb2ccdf 100644 --- a/components/printing/renderer/print_render_frame_helper.cc +++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -1362,10 +1362,12 @@ if (ipc_nesting_level_ > kAllowedIpcDepthForPrint) return; +#if BUILDFLAG(IS_CHROMEOS_ASH) if (print_renderer) { print_renderer_.Bind(std::move(print_renderer)); print_preview_context_.SetIsForArc(true); } +#endif blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); @@ -1389,10 +1391,12 @@ print_preview_context_.OnPrintPreview(); +#if BUILDFLAG(IS_CHROMEOS_ASH) if (print_preview_context_.IsForArc()) { base::UmaHistogramEnumeration("Arc.PrintPreview.PreviewEvent", PREVIEW_EVENT_REQUESTED, PREVIEW_EVENT_MAX); } +#endif if (!print_preview_context_.source_frame()) { DidFinishPrinting(FAIL_PREVIEW); @@ -1410,10 +1414,12 @@ return; } +#if BUILDFLAG(IS_CHROMEOS_ASH) // Save the job settings if a PrintRenderer will be used to create the preview // document. if (print_renderer_) print_renderer_job_settings_ = std::move(settings); +#endif // Set the options from document if we are previewing a pdf and send a // message to browser. @@ -1599,8 +1605,12 @@ } CreatePreviewDocumentResult result = CreatePreviewDocument(); - if (result != CREATE_IN_PROGRESS) - DidFinishPrinting(result == CREATE_SUCCESS ? OK : FAIL_PREVIEW); +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (result == CREATE_IN_PROGRESS) + return; +#endif + + DidFinishPrinting(result == CREATE_SUCCESS ? OK : FAIL_PREVIEW); } PrintRenderFrameHelper::CreatePreviewDocumentResult @@ -1608,18 +1618,23 @@ if (!print_pages_params_ || CheckForCancel() || !preview_ui_) return CREATE_FAIL; +#if BUILDFLAG(IS_CHROMEOS_ASH) if (print_preview_context_.IsForArc()) { base::UmaHistogramEnumeration("Arc.PrintPreview.PreviewEvent", PREVIEW_EVENT_CREATE_DOCUMENT, PREVIEW_EVENT_MAX); } +#endif const mojom::PrintParams& print_params = *print_pages_params_->params; const std::vector<uint32_t>& pages = print_pages_params_->pages; bool require_document_metafile = - print_renderer_ || print_params.printed_doc_type != mojom::SkiaDocumentType::kMSKP; +#if BUILDFLAG(IS_CHROMEOS_ASH) + require_document_metafile = require_document_metafile || print_renderer_; +#endif + if (!print_preview_context_.CreatePreviewDocument( std::move(prep_frame_view_), pages, print_params.printed_doc_type, print_params.document_cookie, require_document_metafile)) { @@ -1660,6 +1675,7 @@ if (CheckForCancel()) return CREATE_FAIL; +#if BUILDFLAG(IS_CHROMEOS_ASH) // If a PrintRenderer has been provided, use it to create the preview // document. if (print_renderer_) { @@ -1671,6 +1687,7 @@ print_params.document_cookie, begin_time)); return CREATE_IN_PROGRESS; } +#endif if (print_pages_params_->params->printed_doc_type == mojom::SkiaDocumentType::kMSKP) { @@ -2535,7 +2552,9 @@ is_loading_ = print_preview_context_.source_frame()->WillPrintSoon(); } +#if BUILDFLAG(IS_CHROMEOS_ASH) const bool is_from_arc = print_preview_context_.IsForArc(); +#endif const bool is_modifiable = print_preview_context_.IsModifiable(); const bool has_selection = print_preview_context_.HasSelection(); @@ -2547,7 +2566,9 @@ snapshotter_ = render_frame()->CreateAXTreeSnapshotter(ui::AXMode::kPDF); auto params = mojom::RequestPrintPreviewParams::New(); +#if BUILDFLAG(IS_CHROMEOS_ASH) params->is_from_arc = is_from_arc; +#endif params->is_modifiable = is_modifiable; params->has_selection = has_selection; switch (type) { @@ -2626,10 +2647,12 @@ } } +#if BUILDFLAG(IS_CHROMEOS_ASH) if (print_preview_context_.IsForArc()) { base::UmaHistogramEnumeration("Arc.PrintPreview.PreviewEvent", PREVIEW_EVENT_INITIATED, PREVIEW_EVENT_MAX); } +#endif GetPrintManagerHost()->RequestPrintPreview(std::move(params)); } @@ -2853,9 +2876,12 @@ state_ = INITIALIZED; if (report_error) { DCHECK_NE(PREVIEW_ERROR_NONE, error_); - base::UmaHistogramEnumeration(is_for_arc_ ? "Arc.PrintPreview.RendererError" - : "PrintPreview.RendererError", - error_, PREVIEW_ERROR_LAST_ENUM); + const char* name = "PrintPreview.RendererError"; +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (is_for_arc_) + name = "Arc.PrintPreview.RendererError"; +#endif + base::UmaHistogramEnumeration(name, error_, PREVIEW_ERROR_LAST_ENUM); } ClearContext(); } @@ -2871,10 +2897,12 @@ return state_ == RENDERING || state_ == DONE; } +#if BUILDFLAG(IS_CHROMEOS_ASH) bool PrintRenderFrameHelper::PrintPreviewContext::IsForArc() const { DCHECK_NE(state_, UNINITIALIZED); return is_for_arc_; } +#endif bool PrintRenderFrameHelper::PrintPreviewContext::IsPlugin() const { DCHECK(state_ != UNINITIALIZED); @@ -2901,9 +2929,11 @@ return static_cast<size_t>(current_page_index_) == pages_to_render_.size(); } +#if BUILDFLAG(IS_CHROMEOS_ASH) void PrintRenderFrameHelper::PrintPreviewContext::SetIsForArc(bool is_for_arc) { is_for_arc_ = is_for_arc; } +#endif void PrintRenderFrameHelper::PrintPreviewContext::set_error( enum PrintPreviewErrorBuckets error) {
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h index 2b70311..0235941 100644 --- a/components/printing/renderer/print_render_frame_helper.h +++ b/components/printing/renderer/print_render_frame_helper.h
@@ -181,9 +181,11 @@ // CREATE_IN_PROGRESS signifies that the preview document is being rendered // asynchronously by a PrintRenderer. enum CreatePreviewDocumentResult { - CREATE_SUCCESS, - CREATE_IN_PROGRESS, - CREATE_FAIL, + CREATE_SUCCESS = 0, +#if BUILDFLAG(IS_CHROMEOS_ASH) + CREATE_IN_PROGRESS = 1, +#endif + CREATE_FAIL = 2, }; enum PrintingResult { @@ -485,12 +487,14 @@ // Used to check the prerendering status. const std::unique_ptr<Delegate> delegate_; +#if BUILDFLAG(IS_CHROMEOS_ASH) // Settings used by a PrintRenderer to create a preview document. base::Value print_renderer_job_settings_; // Used to render print documents from an external source (ARC, Crostini, // etc.). mojo::AssociatedRemote<mojom::PrintRenderer> print_renderer_; +#endif #if BUILDFLAG(ENABLE_PRINT_PREVIEW) // Used to notify the browser of preview UI actions. @@ -554,7 +558,9 @@ // Helper functions uint32_t GetNextPageNumber(); bool IsRendering() const; +#if BUILDFLAG(IS_CHROMEOS_ASH) bool IsForArc() const; +#endif bool IsPlugin() const; bool IsModifiable() const; bool HasSelection(); @@ -562,7 +568,9 @@ bool IsFinalPageRendered() const; // Setters +#if BUILDFLAG(IS_CHROMEOS_ASH) void SetIsForArc(bool is_for_arc); +#endif void set_error(enum PrintPreviewErrorBuckets error); // Getters @@ -625,8 +633,10 @@ // True, if the document source is modifiable. e.g. HTML and not PDF. bool is_modifiable_ = true; +#if BUILDFLAG(IS_CHROMEOS_ASH) // True, if the document source is from ARC. bool is_for_arc_ = false; +#endif // Specifies the total number of pages in the print ready metafile. int print_ready_metafile_page_count_ = 0;
diff --git a/components/privacy_sandbox/privacy_sandbox_features.cc b/components/privacy_sandbox/privacy_sandbox_features.cc index 68f0b09..b247aec 100644 --- a/components/privacy_sandbox/privacy_sandbox_features.cc +++ b/components/privacy_sandbox/privacy_sandbox_features.cc
@@ -8,8 +8,12 @@ const base::Feature kPrivacySandboxSettings3{"PrivacySandboxSettings3", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::FeatureParam<bool> kPrivacySandboxSettings3DefaultOn{ + &kPrivacySandboxSettings3, "setting-default-on", false}; const base::FeatureParam<bool> kPrivacySandboxSettings3ConsentRequired{ &kPrivacySandboxSettings3, "consent-required", false}; +const base::FeatureParam<bool> kPrivacySandboxSettings3NoticeRequired{ + &kPrivacySandboxSettings3, "notice-required", false}; const base::FeatureParam<bool> kPrivacySandboxSettings3DisableDialogForTesting{ &kPrivacySandboxSettings3, "disable-dialog-for-testing", false}; const base::FeatureParam<bool> @@ -21,4 +25,8 @@ const base::FeatureParam<bool> kPrivacySandboxSettings3ShowSampleDataForTesting{ &kPrivacySandboxSettings3, "show-sample-data", false}; +const base::Feature kOverridePrivacySandboxSettingsLocalTesting{ + "OverridePrivacySandboxSettingsLocalTesting", + base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace privacy_sandbox
diff --git a/components/privacy_sandbox/privacy_sandbox_features.h b/components/privacy_sandbox/privacy_sandbox_features.h index a724071..62e75e0 100644 --- a/components/privacy_sandbox/privacy_sandbox_features.h +++ b/components/privacy_sandbox/privacy_sandbox_features.h
@@ -12,7 +12,17 @@ // Enables the third release of the Privacy Sandbox settings. extern const base::Feature kPrivacySandboxSettings3; +// Determines whether the user facing controls for Privacy Sandbox Settings 3 +// should be default on. +extern const base::FeatureParam<bool> kPrivacySandboxSettings3DefaultOn; +// When true, the user will be shown a consent to enable the Privacy Sandbox +// release 3, if they accept the APIs will become active. Only one of this and +// the below notice feature should be enabled at any one time. extern const base::FeatureParam<bool> kPrivacySandboxSettings3ConsentRequired; +// When true, the user will be shown a notice, after which the Privacy Sandbox +// 3 APIs will become active. Only one of this and the above consent feature +// should be enabled at any one time. +extern const base::FeatureParam<bool> kPrivacySandboxSettings3NoticeRequired; // Feature parameters which should exclusively be used for testing purposes. // Enabling any of these parameters may result in the Privacy Sandbox prefs @@ -27,6 +37,8 @@ extern const base::FeatureParam<bool> kPrivacySandboxSettings3ShowSampleDataForTesting; +extern const base::Feature kOverridePrivacySandboxSettingsLocalTesting; + } // namespace privacy_sandbox #endif // COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_FEATURES_H_
diff --git a/components/privacy_sandbox/privacy_sandbox_prefs.cc b/components/privacy_sandbox/privacy_sandbox_prefs.cc index 14f3d904..393bb02a 100644 --- a/components/privacy_sandbox/privacy_sandbox_prefs.cc +++ b/components/privacy_sandbox/privacy_sandbox_prefs.cc
@@ -14,9 +14,15 @@ const char kPrivacySandboxApisEnabledV2[] = "privacy_sandbox.apis_enabled_v2"; +const char kPrivacySandboxApisEnabledV2Init[] = + "privacy_sandbox.apis_enabled_v2_init"; + const char kPrivacySandboxManuallyControlled[] = "privacy_sandbox.manually_controlled"; +const char kPrivacySandboxManuallyControlledV2[] = + "privacy_sandbox.manually_controlled_v2"; + const char kPrivacySandboxPreferencesReconciled[] = "privacy_sandbox.preferences_reconciled"; @@ -53,6 +59,9 @@ extern const char kPrivacySandboxNoConfirmationThirdPartyCookiesBlocked[] = "privacy_sandbox.no_confirmation_3PC_blocked"; +extern const char kPrivacySandboxNoConfirmationManuallyControlled[] = + "privacy_sandbox.no_confirmation_manually_controlled"; + extern const char kPrivacySandboxDisabledInsufficientConfirmation[] = "privacy_sandbox.disabled_insufficient_confirmation"; @@ -65,9 +74,12 @@ prefs::kPrivacySandboxApisEnabled, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); registry->RegisterBooleanPref(prefs::kPrivacySandboxApisEnabledV2, false); + registry->RegisterBooleanPref(prefs::kPrivacySandboxApisEnabledV2Init, false); registry->RegisterBooleanPref( prefs::kPrivacySandboxManuallyControlled, false, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + registry->RegisterBooleanPref(prefs::kPrivacySandboxManuallyControlledV2, + false); registry->RegisterBooleanPref(prefs::kPrivacySandboxPreferencesReconciled, false); registry->RegisterBooleanPref(prefs::kPrivacySandboxPageViewed, false); @@ -92,6 +104,8 @@ registry->RegisterBooleanPref( prefs::kPrivacySandboxNoConfirmationThirdPartyCookiesBlocked, false); registry->RegisterBooleanPref( + prefs::kPrivacySandboxNoConfirmationManuallyControlled, false); + registry->RegisterBooleanPref( prefs::kPrivacySandboxDisabledInsufficientConfirmation, false); }
diff --git a/components/privacy_sandbox/privacy_sandbox_prefs.h b/components/privacy_sandbox/privacy_sandbox_prefs.h index 702fc54..568681d 100644 --- a/components/privacy_sandbox/privacy_sandbox_prefs.h +++ b/components/privacy_sandbox/privacy_sandbox_prefs.h
@@ -22,11 +22,23 @@ // enabled. extern const char kPrivacySandboxApisEnabledV2[]; +// Un-synced boolean pref. This is set to true when the one-time initialization +// of the users kPrivacySandboxApisEnabledV2 has run. Some users may have the V2 +// pref enabled by default by the PrivacySandboxService. +extern const char kPrivacySandboxApisEnabledV2Init[]; + // Synced boolean that indicates if a user has manually toggled the settings // associated with the PrivacySandboxSettings feature. +// TODO(crbug.com/1292898): Deprecate this preference once all users have been +// migrated to the V2 pref. extern const char kPrivacySandboxManuallyControlled[]; -// Boolean to indicate whether or not the preferecnes have been reconciled for +// Un-synced boolean pref. This is a replacement for the synced preference +// above. It it set to true when the user manually toggles the setting on the +// updated settings page. +extern const char kPrivacySandboxManuallyControlledV2[]; + +// Boolean to indicate whether or not the preferences have been reconciled for // this device. This occurs for each device once when privacy sandbox is first // enabled. extern const char kPrivacySandboxPreferencesReconciled[]; @@ -84,6 +96,10 @@ // profile because the third party cookies were being blocked. extern const char kPrivacySandboxNoConfirmationThirdPartyCookiesBlocked[]; +// Boolean that indicates a Privacy Sandbox confirmation was not shown to the +// profile because the Privacy Sandbox is being manually controlled. +extern const char kPrivacySandboxNoConfirmationManuallyControlled[]; + // Boolean that indicates the user's Privacy Sandbox setting was disabled // automatically because they do not have the correct level of confirmation. extern const char kPrivacySandboxDisabledInsufficientConfirmation[];
diff --git a/components/privacy_sandbox/privacy_sandbox_settings.cc b/components/privacy_sandbox/privacy_sandbox_settings.cc index 5dcb1c92..3f43dc20 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings.cc +++ b/components/privacy_sandbox/privacy_sandbox_settings.cc
@@ -339,9 +339,18 @@ } bool PrivacySandboxSettings::IsPrivacySandboxEnabled() const { - // If the delegate is restricting access, the Privacy Sandbox is disabled. - if (delegate_->IsPrivacySandboxRestricted()) + // If the delegate is restricting access, or indicates confirmation has not + // occurred, the Privacy Sandbox is disabled. + if (delegate_->IsPrivacySandboxRestricted() || + !delegate_->IsPrivacySandboxConfirmed()) { return false; + } + + // For Measurement and Relevance APIs, we explicitly do not require the + // underlying pref to be enabled if there is a local flag enabling the APIs to + // allow for local testing. + bool should_override_setting_for_local_testing = base::FeatureList::IsEnabled( + privacy_sandbox::kOverridePrivacySandboxSettingsLocalTesting); // Which preference is consulted is dependent on whether release 3 of the // settings is available. @@ -350,20 +359,23 @@ if (incognito_profile_) return false; - // For Privacy Sadnbox Settings 3, APIs may be restricted via the delegate. + if (should_override_setting_for_local_testing) { + return true; + } + + // For Privacy Sandbox Settings 3, APIs may be restricted via the delegate. // The V2 pref was introduced with the 3rd Privacy Sandbox release. return pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabledV2); } + if (should_override_setting_for_local_testing) + return true; + return pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabled); } void PrivacySandboxSettings::SetPrivacySandboxEnabled(bool enabled) { - pref_service_->SetBoolean(prefs::kPrivacySandboxManuallyControlled, true); - - // Only apply the decision to the appropriate preference. Confirmation logic - // DCHECKS that the user has not been able to enable the V2 preference - // without seeing a dialog. + // Only apply the decision to the appropriate preference. if (base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3)) { pref_service_->SetBoolean(prefs::kPrivacySandboxApisEnabledV2, enabled); } else { @@ -406,6 +418,11 @@ observers_.RemoveObserver(observer); } +void PrivacySandboxSettings::SetDelegateForTesting( + std::unique_ptr<Delegate> delegate) { + delegate_ = std::move(delegate); +} + PrivacySandboxSettings::PrivacySandboxSettings() = default; bool PrivacySandboxSettings::IsPrivacySandboxEnabledForContext(
diff --git a/components/privacy_sandbox/privacy_sandbox_settings.h b/components/privacy_sandbox/privacy_sandbox_settings.h index d76c179..b1a4b3f 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings.h +++ b/components/privacy_sandbox/privacy_sandbox_settings.h
@@ -59,6 +59,12 @@ // consulted on every access check, and it is acceptable for this to change // return value over the life of the service. virtual bool IsPrivacySandboxRestricted() = 0; + + // Allows the delegate to express the concept of confirmation, e.g. a notice + // or consent, required before Privacy Sandbox operation can occur. This is + // checked on every access check, and must return true for Privacy Sandbox + // APIs to run. + virtual bool IsPrivacySandboxConfirmed() = 0; }; PrivacySandboxSettings( @@ -149,16 +155,18 @@ const url::Origin& top_frame_origin, const std::vector<GURL>& auction_parties); - // Returns whether the profile has the Privacy Sandbox enabled. This directly - // reflects the state of the main privacy sandbox control, and does not - // consider any cookie settings. A return value of false means that no - // Privacy Sandbox operations can occur. A return value of true must be - // followed up with the appropriate IsXAllowed() call. + // Returns whether the profile has the Privacy Sandbox enabled. This consults + // the main preference, as well as the delegate to check whether the sandbox + // is restricted, or has not been confirmed. It does not consider any cookie + // settings. A return value of false means that no Privacy Sandbox operations + // can occur. A return value of true must be followed up with the appropriate + // IsXAllowed() call. bool IsPrivacySandboxEnabled() const; // Disables the Privacy Sandbox completely if |enabled| is false, if |enabled| - // is true, more granular checks will still be performed to determine if - // specific APIs are available in specific contexts. + // is true, more granular checks will still be performed, and the delegate + // consulted, to determine if specific APIs are available in specific + // contexts. void SetPrivacySandboxEnabled(bool enabled); // Returns whether Trust Tokens are "generally" available. A return value of @@ -182,6 +190,9 @@ void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); + // Overrides the internal delegate for test purposes. + void SetDelegateForTesting(std::unique_ptr<Delegate> delegate); + protected: // Protected default constructor to allow mocking in tests. PrivacySandboxSettings();
diff --git a/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc b/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc index a64acbe..b9246e3 100644 --- a/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc +++ b/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc
@@ -70,7 +70,8 @@ } virtual void InitializeDelegateBeforeStart() { - mock_delegate()->SetupDefaultResponse(/*restricted=*/false); + mock_delegate()->SetupDefaultResponse(/*restricted=*/false, + /*confirmed=*/true); } virtual bool IsIncognitoProfile() { return false; } @@ -93,9 +94,11 @@ return &browser_task_environment_; } + protected: + base::test::ScopedFeatureList feature_list_; + private: content::BrowserTaskEnvironment browser_task_environment_; - base::test::ScopedFeatureList feature_list_; raw_ptr<privacy_sandbox_test_util::MockPrivacySandboxSettingsDelegate> mock_delegate_; sync_preferences::TestingPrefServiceSyncable prefs_; @@ -863,6 +866,9 @@ TEST_P(PrivacySandboxSettingsMockDelegateTest, IsPrivacySandboxRestricted) { // When the sandbox is otherwise enabled, the delegate returning true for // IsPrivacySandboxRestricted() should disable the sandbox. + ON_CALL(*mock_delegate(), IsPrivacySandboxConfirmed).WillByDefault([=]() { + return true; + }); privacy_sandbox_settings()->SetPrivacySandboxEnabled(true); EXPECT_CALL(*mock_delegate(), IsPrivacySandboxRestricted()) .Times(1) @@ -882,8 +888,64 @@ EXPECT_FALSE(privacy_sandbox_settings()->IsPrivacySandboxEnabled()); } +TEST_P(PrivacySandboxSettingsMockDelegateTest, IsPrivacySandboxConfirmed) { + // When the sandbox is otherwise enabled, the delegate returning false for + // IsPrivacySandboxConfirmed() should disable the sandbox. + ON_CALL(*mock_delegate(), IsPrivacySandboxRestricted).WillByDefault([=]() { + return false; + }); + privacy_sandbox_settings()->SetPrivacySandboxEnabled(true); + EXPECT_CALL(*mock_delegate(), IsPrivacySandboxConfirmed()) + .Times(1) + .WillOnce(testing::Return(false)); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivacySandboxEnabled()); + + privacy_sandbox_settings()->SetPrivacySandboxEnabled(true); + EXPECT_CALL(*mock_delegate(), IsPrivacySandboxConfirmed()) + .Times(1) + .WillOnce(testing::Return(true)); + EXPECT_TRUE(privacy_sandbox_settings()->IsPrivacySandboxEnabled()); + + // The delegate should not override a disabled sandbox. + privacy_sandbox_settings()->SetPrivacySandboxEnabled(false); + EXPECT_CALL(*mock_delegate(), IsPrivacySandboxConfirmed()) + .Times(1) + .WillOnce(testing::Return(true)); + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivacySandboxEnabled()); +} + INSTANTIATE_TEST_SUITE_P(PrivacySandboxSettingsMockDelegateTestInstance, PrivacySandboxSettingsMockDelegateTest, testing::Bool()); +class PrivacySandboxSettingLocalOverrideTest + : public PrivacySandboxSettingsTest { + void InitializeFeaturesBeforeStart() override { + if (GetParam()) { + feature_list_.InitWithFeatures( + {privacy_sandbox::kPrivacySandboxSettings3, + privacy_sandbox::kOverridePrivacySandboxSettingsLocalTesting}, + /*disabled_features=*/{}); + } else { + feature_list_.InitWithFeatures( + {privacy_sandbox::kPrivacySandboxSettings3}, + {privacy_sandbox::kOverridePrivacySandboxSettingsLocalTesting}); + } + } +}; + +TEST_P(PrivacySandboxSettingLocalOverrideTest, FollowsOverrideBehavior) { + // When the Release 3 flag is enabled, APIs should always be disabled in + // incognito. The Release 3 flag is set based on the test param. + privacy_sandbox_settings()->SetPrivacySandboxEnabled(false); + if (GetParam()) + EXPECT_TRUE(privacy_sandbox_settings()->IsPrivacySandboxEnabled()); + else + EXPECT_FALSE(privacy_sandbox_settings()->IsPrivacySandboxEnabled()); +} + +INSTANTIATE_TEST_SUITE_P(PrivacySandboxSettingLocalOverrideTestInstance, + PrivacySandboxSettingLocalOverrideTest, + testing::Bool()); + } // namespace privacy_sandbox
diff --git a/components/privacy_sandbox/privacy_sandbox_test_util.h b/components/privacy_sandbox/privacy_sandbox_test_util.h index f36bae7..a4fec3a 100644 --- a/components/privacy_sandbox/privacy_sandbox_test_util.h +++ b/components/privacy_sandbox/privacy_sandbox_test_util.h
@@ -33,12 +33,16 @@ public: MockPrivacySandboxSettingsDelegate(); ~MockPrivacySandboxSettingsDelegate() override; - void SetupDefaultResponse(bool restricted) { + void SetupDefaultResponse(bool restricted, bool confirmed) { ON_CALL(*this, IsPrivacySandboxRestricted).WillByDefault([=]() { return restricted; }); + ON_CALL(*this, IsPrivacySandboxConfirmed).WillByDefault([=]() { + return confirmed; + }); } MOCK_METHOD(bool, IsPrivacySandboxRestricted, (), (override)); + MOCK_METHOD(bool, IsPrivacySandboxConfirmed, (), (override)); }; // Define an additional content setting value to simulate an unmanaged default
diff --git a/components/services/app_service/public/cpp/intent_filter_util.cc b/components/services/app_service/public/cpp/intent_filter_util.cc index bed5aabe..b433edfb 100644 --- a/components/services/app_service/public/cpp/intent_filter_util.cc +++ b/components/services/app_service/public/cpp/intent_filter_util.cc
@@ -405,6 +405,38 @@ return false; } +size_t IntentFilterUrlMatchLength(const apps::IntentFilterPtr& intent_filter, + const GURL& url) { + apps::Intent intent(url); + if (!intent.MatchFilter(intent_filter)) { + return 0; + } + // If the filter matches, all URL components match, so a kPattern condition + // matches and we add up the length of the filter's URL components (scheme, + // host, path). + size_t path_length = 0; + for (const apps::ConditionPtr& condition : intent_filter->conditions) { + if (condition->condition_type == apps::ConditionType::kPattern) { + for (const apps::ConditionValuePtr& value : condition->condition_values) { + switch (value->match_type) { + case apps::PatternMatchType::kLiteral: + case apps::PatternMatchType::kPrefix: + path_length = std::max(path_length, value->value.size()); + break; + default: + // the rest are ignored. + break; + } + } + } + } + if (path_length == 0) { + return 0; + } + return url.scheme_piece().size() + /*length("://")*/ 3 + + url.host_piece().size() + path_length; +} + } // namespace apps_util namespace apps {
diff --git a/components/services/app_service/public/cpp/intent_filter_util.h b/components/services/app_service/public/cpp/intent_filter_util.h index e69396a..c7c3dd6 100644 --- a/components/services/app_service/public/cpp/intent_filter_util.h +++ b/components/services/app_service/public/cpp/intent_filter_util.h
@@ -87,6 +87,14 @@ bool IsSupportedLinkForApp(const std::string& app_id, const apps::mojom::IntentFilterPtr& intent_filter); +// If |intent_filter| matches a URL by prefix, return the length of the longest +// match. For example, if the filter matches "https://example.org/app/*", the +// longest match for the URL "https://example.org/app/foo/bar" is the length of +// "https://example.org/app/" (24). If |intent_filter| does not match |url|, or +// if the filter does not match a prefix (e.g. glob), 0 is returned. +size_t IntentFilterUrlMatchLength(const apps::IntentFilterPtr& intent_filter, + const GURL& url); + } // namespace apps_util namespace apps {
diff --git a/components/services/app_service/public/cpp/intent_filter_util_unittest.cc b/components/services/app_service/public/cpp/intent_filter_util_unittest.cc index b48c3b9..a535726 100644 --- a/components/services/app_service/public/cpp/intent_filter_util_unittest.cc +++ b/components/services/app_service/public/cpp/intent_filter_util_unittest.cc
@@ -600,3 +600,51 @@ EXPECT_EQ(condition->condition_values[0]->value, "7"); } } + +TEST_F(IntentFilterUtilTest, TestIntentFilterUrlMatchLength) { + const auto kPrefix = apps::PatternMatchType::kPrefix; + const auto kLiteral = apps::PatternMatchType::kLiteral; + const auto kGlob = apps::PatternMatchType::kGlob; + struct Test { + std::string filter_url; + std::string matched_url; + apps::PatternMatchType pattern_match_type; + size_t expected; + }; + std::vector<Test> tests{ + {"https://prefix.a.com/a", "https://prefix.a.com/a", kPrefix, 22}, + {"https://prefix.a.com/a", "https://prefix.a.com/a?x=y", kPrefix, 22}, + {"https://prefix.a.com/a", "https://prefix.a.com/a/b", kPrefix, 22}, + {"https://prefix.a.com/", "https://prefix.a.com/", kPrefix, 21}, + {"https://prefix.a.com", "https://prefix.a.com", kPrefix, 21}, + {"https://prefix.a.com/a", "", kPrefix, 0}, + {"https://prefix.a.com/a/b", "https://prefix.a.com/a", kPrefix, 0}, + {"https://prefix.a.com/a", "https://prefix.a.com/", kPrefix, 0}, + {"https://prefix.a.com/a", "https://prefix.a.org/a", kPrefix, 0}, + {"https://prefix.a.com/a", "http://prefix.a.com/a", kPrefix, 0}, + + {"https://exact.a.com/a", "https://exact.a.com/a", kLiteral, 21}, + {"https://exact.a.com/", "https://exact.a.com/", kLiteral, 20}, + {"https://exact.a.com", "https://exact.a.com", kLiteral, 20}, + {"https://exact.a.com/a", "https://exact.a.com/a/b", kLiteral, 0}, + {"https://exact.a.com/a/b", "https://exact.a.com/a", kLiteral, 0}, + {"https://exact.a.com/a", "https://exact.a.org/a", kLiteral, 0}, + {"https://exact.a.com/a", "http://exact.a.com/a", kLiteral, 0}, + + // Glob is not supported. + {"https://glob.a.com/a/.*", "https://glob.a.com/a", kGlob, 0}, + {"https://glob.a.com/a/.*", "https://glob.a.com/a/b", kGlob, 0}, + {"https://glob.a.com/a/.*/b", "https://glob.a.com/a/b", kGlob, 0}, + }; + for (size_t i = 0; i < tests.size(); ++i) { + const auto& test = tests[i]; + GURL filter_url(test.filter_url); + GURL matched_url(test.matched_url); + auto filter = MakeFilter(filter_url.scheme(), filter_url.host(), + filter_url.path(), test.pattern_match_type); + EXPECT_EQ(apps_util::IntentFilterUrlMatchLength(filter, matched_url), + test.expected) + << "Test #" << i << " url=" << test.matched_url + << " filter=" << test.filter_url; + } +}
diff --git a/components/services/heap_profiling/public/cpp/profiling_client.cc b/components/services/heap_profiling/public/cpp/profiling_client.cc index 964890d3..70de019 100644 --- a/components/services/heap_profiling/public/cpp/profiling_client.cc +++ b/components/services/heap_profiling/public/cpp/profiling_client.cc
@@ -49,7 +49,6 @@ if (started_profiling_) return; started_profiling_ = true; - base::trace_event::MallocDumpProvider::GetInstance()->DisableMetrics(); #if BUILDFLAG(IS_APPLE) // On macOS, this call is necessary to shim malloc zones that were created
diff --git a/components/site_isolation/site_isolation_policy.cc b/components/site_isolation/site_isolation_policy.cc index d7caa5a3..4ed12c9 100644 --- a/components/site_isolation/site_isolation_policy.cc +++ b/components/site_isolation/site_isolation_policy.cc
@@ -337,17 +337,23 @@ // static bool SiteIsolationPolicy::ShouldPdfCompositorBeEnabledForOopifs() { - // We only create pdf compositor client and use pdf compositor service when - // one of the site isolation modes that forces OOPIFs is on. This includes - // full site isolation on desktop, password-triggered site isolation on - // Android for high-memory devices, and/or isolated origins specified via - // command line, enterprise policy, or field trials. +#if BUILDFLAG(IS_ANDROID) + // TODO(crbug.com/1022917): Always enable on Android, at which point, this + // method should go away. // - // TODO(weili, thestig): Eventually, we should remove this check and use pdf - // compositor service by default for printing. + // Only use the PDF compositor when one of the site isolation modes that + // forces OOPIFs is on. This includes: + // - Full site isolation, which may be forced on. + // - Password-triggered site isolation for high-memory devices + // - Isolated origins specified via command line, enterprise policy, or field + // trials. return content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites() || IsIsolationForPasswordSitesEnabled() || content::SiteIsolationPolicy::AreIsolatedOriginsEnabled(); +#else + // Always use the PDF compositor on non-mobile platforms. + return true; +#endif } } // namespace site_isolation
diff --git a/components/sync/PRESUBMIT.py b/components/sync/PRESUBMIT.py index 29fc4ab..0b80a04 100644 --- a/components/sync/PRESUBMIT.py +++ b/components/sync/PRESUBMIT.py
@@ -220,8 +220,7 @@ def IsTitleCased(string): - return reduce(lambda bool1, bool2: bool1 and bool2, - [s[0].isupper() for s in string.split(' ')]) + return all([s[0].isupper() for s in string.split(' ')]) def FormatPresubmitError(output_api, message, affected_lines): @@ -334,7 +333,7 @@ StripTrailingS(map_entry.root_tag)): return [ FormatPresubmitError( - output_api,'root tag "%s" does not match model type. It should' + output_api,'root tag "%s" does not match model type. It should ' 'be "%s"' % (map_entry.root_tag, expected_root_tag), map_entry.affected_lines)] return []
diff --git a/components/sync/PRESUBMIT_test.py b/components/sync/PRESUBMIT_test.py index feb8ffce..2403e83 100755 --- a/components/sync/PRESUBMIT_test.py +++ b/components/sync/PRESUBMIT_test.py
@@ -162,7 +162,7 @@ def _testChange(self, modeltype_literal): mock_input_api = MockInputApi() mock_input_api.files = [ - MockFile(os.path.abspath('./protocol/sync.proto'), + MockFile(os.path.abspath('./protocol/entity_specifics.proto'), MOCK_PROTOFILE_CONTENTS), MockFile(os.path.abspath('./base/model_type.cc'), MOCK_MODELTYPE_CONTENTS % (modeltype_literal))
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc index 553c3be..51a2be13 100644 --- a/components/viz/service/display/gl_renderer.cc +++ b/components/viz/service/display/gl_renderer.cc
@@ -1188,7 +1188,7 @@ surface->getCanvas()->save(); gfx::RRectF clip_rect(backdrop_filter_bounds.value()); surface->getCanvas()->setMatrix( - SkMatrix(backdrop_filter_bounds_transform.matrix())); + backdrop_filter_bounds_transform.matrix().asM33()); surface->getCanvas()->clipRRect(SkRRect(clip_rect), SkClipOp::kIntersect, true /* antialias */); surface->getCanvas()->resetMatrix();
diff --git a/components/viz/service/display/software_renderer.cc b/components/viz/service/display/software_renderer.cc index 730b7f03..945245b 100644 --- a/components/viz/service/display/software_renderer.cc +++ b/components/viz/service/display/software_renderer.cc
@@ -189,7 +189,7 @@ gfx::Transform screen_transform = current_frame()->window_matrix * current_frame()->projection_matrix; SkRRect result; - if (SkRRect(rrect).transform(SkMatrix(screen_transform.matrix()), &result)) { + if (SkRRect(rrect).transform(screen_transform.matrix().asM33(), &result)) { // Skia applies the current matrix to clip rects so we reset it temporarily. SkMatrix current_matrix = current_canvas_->getTotalMatrix(); current_canvas_->resetMatrix(); @@ -825,7 +825,7 @@ return nullptr; SkMatrix filter_backdrop_transform = - SkMatrix(contents_device_transform_inverse.matrix()); + contents_device_transform_inverse.matrix().asM33(); filter_backdrop_transform.preTranslate(backdrop_rect.x(), backdrop_rect.y()); SkBitmap backdrop_bitmap = GetBackdropBitmap(backdrop_rect); @@ -877,7 +877,7 @@ // Clip the filtered image to the (rounded) bounding box of the element. if (backdrop_filter_bounds) { - canvas.setMatrix(SkMatrix(backdrop_filter_bounds_transform.matrix())); + canvas.setMatrix(backdrop_filter_bounds_transform.matrix().asM33()); canvas.clipRRect(SkRRect(*backdrop_filter_bounds), SkClipOp::kIntersect, true /* antialias */); canvas.resetMatrix();
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc index 7bf9860..3fe0dec 100644 --- a/content/browser/android/synchronous_compositor_host.cc +++ b/content/browser/android/synchronous_compositor_host.cc
@@ -384,7 +384,7 @@ canvas->getBaseLayerSize().height()); SkIRect canvas_clip = canvas->getDeviceClipBounds(); params->clip = gfx::SkIRectToRect(canvas_clip); - params->transform.matrix() = canvas->getTotalMatrix(); + params->transform = gfx::Transform(canvas->getTotalMatrix()); if (params->size.IsEmpty()) return true;
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc index 83827f5..54b2b645 100644 --- a/content/browser/attribution_reporting/attributions_browsertest.cc +++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -154,6 +154,7 @@ // Sets up the blink runtime feature for ConversionMeasurement. command_line->AppendSwitch( switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitch(switches::kEnableBlinkTestFeatures); } void SetUpOnMainThread() override {
diff --git a/content/browser/attribution_reporting/attributions_origin_trial_browsertest.cc b/content/browser/attribution_reporting/attributions_origin_trial_browsertest.cc deleted file mode 100644 index 98decd9..0000000 --- a/content/browser/attribution_reporting/attributions_origin_trial_browsertest.cc +++ /dev/null
@@ -1,158 +0,0 @@ -// Copyright 2019 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 <vector> - -#include "base/strings/strcat.h" -#include "base/test/bind.h" -#include "base/test/scoped_feature_list.h" -#include "build/build_config.h" -#include "content/browser/attribution_reporting/attribution_manager_impl.h" -#include "content/browser/attribution_reporting/stored_source.h" -#include "content/browser/storage_partition_impl.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/navigation_handle.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/storage_partition.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/common/content_switches.h" -#include "content/public/test/browser_test.h" -#include "content/public/test/browser_test_utils.h" -#include "content/public/test/content_browser_test.h" -#include "content/public/test/content_browser_test_utils.h" -#include "content/public/test/test_navigation_observer.h" -#include "content/public/test/url_loader_interceptor.h" -#include "content/shell/browser/shell.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/common/features.h" -#include "url/gurl.h" - -namespace content { - -namespace { -constexpr char kBaseDataDir[] = "content/test/data/attribution_reporting/"; -} - -class AttributionsOriginTrialBrowserTest : public ContentBrowserTest { - public: - AttributionsOriginTrialBrowserTest() = default; - - void SetUpOnMainThread() override { - ContentBrowserTest::SetUpOnMainThread(); - - // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since - // the origin trial token in the response is associated with a fixed - // origin, whereas EmbeddedTestServer serves content on a random port. - url_loader_interceptor_ = - std::make_unique<URLLoaderInterceptor>(base::BindLambdaForTesting( - [&](URLLoaderInterceptor::RequestParams* params) -> bool { - URLLoaderInterceptor::WriteResponse( - base::StrCat( - {kBaseDataDir, params->url_request.url.path_piece()}), - params->client.get()); - return true; - })); - } - - void TearDownOnMainThread() override { url_loader_interceptor_.reset(); } - - WebContents* web_contents() { return shell()->web_contents(); } - - private: - std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_; -}; - -IN_PROC_BROWSER_TEST_F(AttributionsOriginTrialBrowserTest, - OriginTrialEnabled_FeatureDetected) { - EXPECT_TRUE(NavigateToURL( - shell(), GURL("https://example.test/impression_with_origin_trial.html"))); - - EXPECT_EQ(true, EvalJs(shell(), - "document.featurePolicy.features().includes('" - "attribution-reporting')")); - EXPECT_EQ(true, EvalJs(shell(), "window.attributionReporting !== undefined")); -} - -IN_PROC_BROWSER_TEST_F(AttributionsOriginTrialBrowserTest, - OriginTrialDisabled_FeatureNotDetected) { - // Navigate to a page without an OT token. - EXPECT_TRUE(NavigateToURL( - shell(), GURL("https://example.test/page_with_impression_creator.html"))); - - EXPECT_EQ(false, EvalJs(shell(), - "document.featurePolicy.features().includes('" - "conversion-measurement')")); - EXPECT_EQ(true, EvalJs(shell(), "window.attributionReporting === undefined")); -} - -#if BUILDFLAG(IS_LINUX) -// TODO(https://crbug.com/1121464): Flaky on linux. -#define MAYBE_OriginTrialEnabled_ImpressionRegistered \ - DISABLED_OriginTrialEnabled_ImpressionRegistered -#else -#define MAYBE_OriginTrialEnabled_ImpressionRegistered \ - OriginTrialEnabled_ImpressionRegistered -#endif - -IN_PROC_BROWSER_TEST_F(AttributionsOriginTrialBrowserTest, - MAYBE_OriginTrialEnabled_ImpressionRegistered) { - EXPECT_TRUE(NavigateToURL( - shell(), GURL("https://example.test/impression_with_origin_trial.html"))); - - EXPECT_TRUE(ExecJs(shell(), R"( - createImpressionTag({id: 'link', - url: 'https://example.test/page_with_conversion_redirect.html', - data: '1', - destination: 'https://example.test/'});)")); - - TestNavigationObserver observer(web_contents()); - EXPECT_TRUE(ExecJs(shell(), "simulateClick('link');")); - observer.Wait(); - - AttributionManagerImpl* attribution_manager = - static_cast<StoragePartitionImpl*>( - web_contents()->GetBrowserContext()->GetDefaultStoragePartition()) - ->GetAttributionManager(); - - base::RunLoop run_loop; - - // Verify we have received and logged an impression for the origin trial. - attribution_manager->GetActiveSourcesForWebUI(base::BindLambdaForTesting( - [&](std::vector<StoredSource> impressions) -> void { - EXPECT_EQ(1u, impressions.size()); - run_loop.Quit(); - })); - run_loop.Run(); -} - -// TODO(johnidel): Add tests that exercise the conversion side logic as well. -// This requires also using an embedded test server because the -// UrlLoadInterceptor cannot properly redirect the conversion pings. - -class AttributionsOriginTrialNoBrowserFeatureBrowserTest - : public AttributionsOriginTrialBrowserTest { - public: - AttributionsOriginTrialNoBrowserFeatureBrowserTest() { - feature_list_.InitAndDisableFeature( - blink::features::kConversionMeasurement); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -IN_PROC_BROWSER_TEST_F(AttributionsOriginTrialNoBrowserFeatureBrowserTest, - BrowserSideLogicNotEnabled_FeatureNotDetected) { - EXPECT_TRUE(NavigateToURL( - shell(), GURL("https://example.test/impression_with_origin_trial.html"))); - - EXPECT_EQ(false, EvalJs(shell(), - "document.featurePolicy.features().includes('" - "attribution-reporting')")); - EXPECT_EQ(true, EvalJs(shell(), "window.attributionReporting === undefined")); -} - -} // namespace content
diff --git a/content/browser/attribution_reporting/privacy_sandbox_ads_apis_browsertest.cc b/content/browser/attribution_reporting/privacy_sandbox_ads_apis_browsertest.cc new file mode 100644 index 0000000..82745dd0 --- /dev/null +++ b/content/browser/attribution_reporting/privacy_sandbox_ads_apis_browsertest.cc
@@ -0,0 +1,216 @@ +// Copyright 2019 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 <vector> + +#include "base/strings/strcat.h" +#include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" +#include "content/browser/storage_partition_impl.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" +#include "content/public/test/url_loader_interceptor.h" +#include "content/shell/browser/shell.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" +#include "url/gurl.h" + +namespace content { + +namespace { +constexpr char kBaseDataDir[] = "content/test/data/attribution_reporting/"; +} + +class PrivacySandboxAdsAPIsBrowserTestBase : public ContentBrowserTest { + public: + PrivacySandboxAdsAPIsBrowserTestBase() = default; + + void SetUpOnMainThread() override { + ContentBrowserTest::SetUpOnMainThread(); + + // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since + // the origin trial token in the response is associated with a fixed + // origin, whereas EmbeddedTestServer serves content on a random port. + url_loader_interceptor_ = + std::make_unique<URLLoaderInterceptor>(base::BindLambdaForTesting( + [&](URLLoaderInterceptor::RequestParams* params) -> bool { + URLLoaderInterceptor::WriteResponse( + base::StrCat( + {kBaseDataDir, params->url_request.url.path_piece()}), + params->client.get()); + return true; + })); + } + + void TearDownOnMainThread() override { url_loader_interceptor_.reset(); } + + WebContents* web_contents() { return shell()->web_contents(); } + + private: + std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_; +}; + +class PrivacySandboxAdsAPIsAllEnabledBrowserTest + : public PrivacySandboxAdsAPIsBrowserTestBase { + public: + PrivacySandboxAdsAPIsAllEnabledBrowserTest() { + feature_list_.InitWithFeatures( + {blink::features::kPrivacySandboxAdsAPIs, + blink::features::kBrowsingTopics, blink::features::kFledge}, + /*disabled_features=*/{}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PrivacySandboxAdsAPIsAllEnabledBrowserTest, + OriginTrialEnabled_FeatureDetected) { + EXPECT_TRUE(NavigateToURL( + shell(), GURL("https://example.test/page_with_ads_apis_ot.html"))); + + EXPECT_EQ(true, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "attribution-reporting')")); + EXPECT_EQ(true, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "browsing-topics')")); + EXPECT_EQ(true, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "join-ad-interest-group')")); + + EXPECT_EQ(true, EvalJs(shell(), "window.attributionReporting !== undefined")); + EXPECT_EQ(true, EvalJs(shell(), "document.browsingTopics !== undefined")); + EXPECT_EQ(true, EvalJs(shell(), "navigator.runAdAuction !== undefined")); + EXPECT_EQ(true, + EvalJs(shell(), "navigator.joinAdInterestGroup !== undefined")); +} + +IN_PROC_BROWSER_TEST_F(PrivacySandboxAdsAPIsAllEnabledBrowserTest, + OriginTrialDisabled_FeatureNotDetected) { + // Navigate to a page without an OT token. + EXPECT_TRUE(NavigateToURL( + shell(), GURL("https://example.test/page_without_ads_apis_ot.html"))); + + EXPECT_EQ(false, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "attribution-reporting')")); + EXPECT_EQ(false, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "browsing-topics')")); + EXPECT_EQ(false, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "join-ad-interest-group')")); + + EXPECT_EQ(true, EvalJs(shell(), "window.attributionReporting === undefined")); + EXPECT_EQ(true, EvalJs(shell(), "document.browsingTopics === undefined")); + EXPECT_EQ(true, EvalJs(shell(), "navigator.runAdAuction === undefined")); + EXPECT_EQ(true, + EvalJs(shell(), "navigator.joinAdInterestGroup === undefined")); +} + +class PrivacySandboxAdsAPIsTopicsDisabledBrowserTest + : public PrivacySandboxAdsAPIsBrowserTestBase { + public: + PrivacySandboxAdsAPIsTopicsDisabledBrowserTest() { + feature_list_.InitWithFeatures({blink::features::kPrivacySandboxAdsAPIs}, + {blink::features::kBrowsingTopics}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PrivacySandboxAdsAPIsTopicsDisabledBrowserTest, + OriginTrialEnabled_CorrectFeaturesDetected) { + EXPECT_TRUE(NavigateToURL( + shell(), GURL("https://example.test/page_with_ads_apis_ot.html"))); + + EXPECT_EQ(true, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "attribution-reporting')")); + EXPECT_EQ(false, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "browsing-topics')")); + + EXPECT_EQ(true, EvalJs(shell(), "window.attributionReporting !== undefined")); + EXPECT_EQ(false, EvalJs(shell(), "document.browsingTopics !== undefined")); +} + +class PrivacySandboxAdsAPIsFledgeDisabledBrowserTest + : public PrivacySandboxAdsAPIsBrowserTestBase { + public: + PrivacySandboxAdsAPIsFledgeDisabledBrowserTest() { + feature_list_.InitWithFeatures({blink::features::kPrivacySandboxAdsAPIs}, + {blink::features::kFledge}); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PrivacySandboxAdsAPIsFledgeDisabledBrowserTest, + OriginTrialEnabled_CorrectFeaturesDetected) { + EXPECT_TRUE(NavigateToURL( + shell(), GURL("https://example.test/page_with_ads_apis_ot.html"))); + + EXPECT_EQ(true, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "attribution-reporting')")); + EXPECT_EQ(false, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "join-ad-interest-group')")); + + EXPECT_EQ(true, EvalJs(shell(), "window.attributionReporting !== undefined")); + EXPECT_EQ(false, EvalJs(shell(), "navigator.runAdAuction !== undefined")); + EXPECT_EQ(false, + EvalJs(shell(), "navigator.joinAdInterestGroup !== undefined")); +} + +class PrivacySandboxAdsAPIsDisabledBrowserTest + : public PrivacySandboxAdsAPIsBrowserTestBase { + public: + PrivacySandboxAdsAPIsDisabledBrowserTest() { + feature_list_.InitAndDisableFeature( + blink::features::kPrivacySandboxAdsAPIs); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(PrivacySandboxAdsAPIsDisabledBrowserTest, + BaseFeatureDisabled_FeatureNotDetected) { + EXPECT_TRUE(NavigateToURL( + shell(), GURL("https://example.test/page_with_ads_apis_ot.html"))); + + EXPECT_EQ(false, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "attribution-reporting')")); + EXPECT_EQ(false, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "browsing-topics')")); + EXPECT_EQ(false, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "join-ad-interest-group')")); + + EXPECT_EQ(true, EvalJs(shell(), "window.attributionReporting === undefined")); + EXPECT_EQ(true, EvalJs(shell(), "document.browsingTopics === undefined")); + EXPECT_EQ(true, EvalJs(shell(), "navigator.runAdAuction === undefined")); + EXPECT_EQ(true, + EvalJs(shell(), "navigator.joinAdInterestGroup === undefined")); +} + +} // namespace content
diff --git a/content/browser/attribution_reporting/source_declaration_browsertest.cc b/content/browser/attribution_reporting/source_declaration_browsertest.cc index 4e9ac3d..330b83f 100644 --- a/content/browser/attribution_reporting/source_declaration_browsertest.cc +++ b/content/browser/attribution_reporting/source_declaration_browsertest.cc
@@ -98,6 +98,7 @@ // Sets up the blink runtime feature for ConversionMeasurement. command_line->AppendSwitch( switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitch(switches::kEnableBlinkTestFeatures); } };
diff --git a/content/browser/attribution_reporting/trigger_registration_browsertest.cc b/content/browser/attribution_reporting/trigger_registration_browsertest.cc index 49a6ca47..90b2b4c 100644 --- a/content/browser/attribution_reporting/trigger_registration_browsertest.cc +++ b/content/browser/attribution_reporting/trigger_registration_browsertest.cc
@@ -90,6 +90,7 @@ // Sets up the blink runtime feature for ConversionMeasurement. command_line->AppendSwitch( switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitch(switches::kEnableBlinkTestFeatures); } };
diff --git a/content/browser/fenced_frame/fenced_frame_browsertest.cc b/content/browser/fenced_frame/fenced_frame_browsertest.cc index 0423f83..244c05b 100644 --- a/content/browser/fenced_frame/fenced_frame_browsertest.cc +++ b/content/browser/fenced_frame/fenced_frame_browsertest.cc
@@ -880,6 +880,35 @@ } } +// Tests that an input event targeted to a fenced frame correctly +// triggers a user interaction notification for WebContentsObservers. +IN_PROC_BROWSER_TEST_F(FencedFrameBrowserTest, UserInteractionForFencedFrame) { + ASSERT_TRUE(https_server()->Start()); + const GURL main_url = https_server()->GetURL("c.test", "/title1.html"); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + RenderFrameHostImplWrapper primary_rfh(primary_main_frame_host()); + + const GURL fenced_frame_url = + https_server()->GetURL("c.test", "/fenced_frames/title1.html"); + RenderFrameHostImplWrapper fenced_frame_rfh( + fenced_frame_test_helper().CreateFencedFrame(primary_rfh.get(), + fenced_frame_url)); + + ::testing::NiceMock<MockWebContentsObserver> web_contents_observer( + web_contents()); + EXPECT_CALL(web_contents_observer, DidGetUserInteraction(testing::_)) + .Times(1); + + // Target an event to the fenced frame's RenderWidgetHostView. + blink::WebMouseEvent mouse_event( + blink::WebInputEvent::Type::kMouseDown, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::GetStaticTimeStampForTests()); + mouse_event.button = blink::WebPointerProperties::Button::kLeft; + mouse_event.SetPositionInWidget(5, 5); + fenced_frame_rfh->GetRenderWidgetHost()->ForwardMouseEvent(mouse_event); +} + namespace { enum class FrameTypeWithOrigin {
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc index 4a1c5261..b8613fb 100644 --- a/content/browser/interest_group/interest_group_browsertest.cc +++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -245,7 +245,8 @@ {blink::features::kInterestGroupStorage, blink::features::kAdInterestGroupAPI, blink::features::kParakeet, blink::features::kFledge, blink::features::kAllowURNsInIframes, - blink::features::kBiddingAndScoringDebugReportingAPI}, + blink::features::kBiddingAndScoringDebugReportingAPI, + features::kPrivacySandboxAdsAPIsOverride}, /*disabled_features=*/ {blink::features::kFencedFrames}); }
diff --git a/content/browser/loader/navigation_early_hints_browsertest.cc b/content/browser/loader/navigation_early_hints_browsertest.cc index 4213c80..8f8d730d 100644 --- a/content/browser/loader/navigation_early_hints_browsertest.cc +++ b/content/browser/loader/navigation_early_hints_browsertest.cc
@@ -501,7 +501,14 @@ EXPECT_TRUE(NavigateToURL(shell(), net::QuicSimpleTestServer::GetFileURL( kPageWithHintedScriptPath))); PreloadedResources preloads = WaitForPreloadedResources(); - EXPECT_TRUE(preloads.empty()); + EXPECT_EQ(preloads.size(), 1UL); + + GURL preloaded_url = net::QuicSimpleTestServer::GetFileURL(kHintedScriptPath); + auto it = preloads.find(preloaded_url); + ASSERT_NE(it, preloads.end()); + ASSERT_FALSE(it->second.was_canceled); + ASSERT_TRUE(it->second.error_code.has_value()); + EXPECT_EQ(it->second.error_code.value(), net::OK); } IN_PROC_BROWSER_TEST_F(NavigationEarlyHintsTest, RedirectSameOrigin) {
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 3f06e6b8..ce15866 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -81,7 +81,6 @@ #include "ppapi/buildflags/buildflags.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "services/network/public/cpp/constants.h" -#include "services/network/public/cpp/cors/cors.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/request_destination.h" #include "services/network/public/cpp/url_util.h" @@ -1477,10 +1476,9 @@ early_hints.was_resource_hints_received = early_hints_manager_->WasResourceHintsReceived(); - // Make Early Hints manager outlive this loader only when the final response - // succeeds. Dropping the manager cancels inflight preloads. - if (response_head && response_head->headers && - network::cors::IsOkStatus(response_head->headers->response_code())) { + // Make Early Hints manager outlive this loader only when the response + // headers are available. Dropping the manager cancels inflight preloads. + if (response_head && response_head->headers) { early_hints.manager = std::move(early_hints_manager_); } }
diff --git a/content/browser/media/media_license_manager.cc b/content/browser/media/media_license_manager.cc index 50e9039..31b42b6 100644 --- a/content/browser/media/media_license_manager.cc +++ b/content/browser/media/media_license_manager.cc
@@ -25,6 +25,7 @@ #include "base/task/thread_pool.h" #include "base/threading/sequence_bound.h" #include "base/threading/sequenced_task_runner_handle.h" +#include "components/services/storage/public/cpp/buckets/bucket_locator.h" #include "components/services/storage/public/cpp/buckets/constants.h" #include "components/services/storage/public/cpp/constants.h" #include "content/browser/media/media_license_database.h" @@ -525,13 +526,6 @@ storage::QuotaErrorOr<storage::BucketInfo> result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // TODO(crbug.com/1231162): Handle failure case. - DCHECK(result.ok()); - - // All receivers associated with `storage_key` will be bound to the same host. - auto storage_host = std::make_unique<MediaLicenseStorageHost>( - this, result->ToBucketLocator()); - auto it = pending_receivers_.find(storage_key); if (it == pending_receivers_.end()) { // No receivers to bind. @@ -547,6 +541,23 @@ pending_receivers_.erase(it); DCHECK_GT(receivers_list.size(), 0u); + storage::BucketLocator bucket_locator; + if (result.ok()) { + bucket_locator = result->ToBucketLocator(); + } else { + // Use the null locator, but update the `storage_key` field so + // `storage_host` can be identified when it is to be removed from `hosts_`. + // We could consider falling back to using an in-memory database in this + // case, but failing here seems easier to reason about from a website + // author's point of view. + DCHECK(bucket_locator.id.is_null()); + bucket_locator.storage_key = storage_key; + } + + // All receivers associated with `storage_key` will be bound to the same host. + auto storage_host = + std::make_unique<MediaLicenseStorageHost>(this, bucket_locator); + for (auto& context_and_receiver : receivers_list) { storage_host->BindReceiver(context_and_receiver.first, std::move(context_and_receiver.second));
diff --git a/content/browser/media/media_license_manager_unittest.cc b/content/browser/media/media_license_manager_unittest.cc index a4593219..7e210a77 100644 --- a/content/browser/media/media_license_manager_unittest.cc +++ b/content/browser/media/media_license_manager_unittest.cc
@@ -128,7 +128,7 @@ } protected: - scoped_refptr<storage::QuotaManager> quota_manager_; + scoped_refptr<storage::MockQuotaManager> quota_manager_; scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; scoped_refptr<storage::FileSystemContext> file_system_context_; @@ -276,6 +276,31 @@ EXPECT_TRUE(base::PathExists(database_file.DirName())); } +TEST_F(MediaLicenseManagerTest, BucketCreationFailed) { + const std::string kTestData("Test Data"); + mojo::Remote<media::mojom::CdmStorage> remote; + blink::StorageKey storage_key = + blink::StorageKey::CreateFromStringForTesting(kExampleOrigin); + storage::BucketLocator bucket = GetOrCreateBucket(storage_key); + MediaLicenseManager::BindingContext binding_context(storage_key, kCdmType); + + // Disable the quota database, causing GetOrCreateBucket() to fail. + quota_manager_->SetDisableDatabase(/*disable=*/true); + + // Open CDM storage for a storage key. + manager_->OpenCdmStorage(binding_context, + remote.BindNewPipeAndPassReceiver()); + // Opening a CDM file should fail. + base::test::TestFuture<media::mojom::CdmStorage::Status, + mojo::PendingAssociatedRemote<media::mojom::CdmFile>> + open_future; + remote->Open("test_file", open_future.GetCallback()); + + auto result = open_future.Take(); + EXPECT_EQ(std::get<0>(result), media::mojom::CdmStorage::Status::kFailure); + EXPECT_FALSE(std::get<1>(result).is_valid()); +} + class MediaLicenseManagerIncognitoTest : public MediaLicenseManagerTest { void SetUp() override { // Still create this dir so the teardown will confirm it remains empty (on
diff --git a/content/browser/media/media_license_storage_host.cc b/content/browser/media/media_license_storage_host.cc index 0c634f0..0c028ec 100644 --- a/content/browser/media/media_license_storage_host.cc +++ b/content/browser/media/media_license_storage_host.cc
@@ -52,6 +52,12 @@ OpenCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (bucket_locator_.id.is_null()) { + DVLOG(1) << "Could not retrieve valid bucket."; + std::move(callback).Run(Status::kFailure, mojo::NullAssociatedRemote()); + return; + } + if (file_name.empty()) { DVLOG(1) << "No file specified."; std::move(callback).Run(Status::kFailure, mojo::NullAssociatedRemote()); @@ -63,8 +69,6 @@ return; } - // TODO(crbug.com/1231162): Notify the quota system of a write. - const BindingContext& binding_context = receivers_.current_context(); db_.AsyncCall(&MediaLicenseDatabase::OpenFile) .WithArgs(binding_context.cdm_type, file_name) @@ -138,8 +142,6 @@ WriteFileCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // TODO(crbug.com/1231162): Notify the quota system of a write. - db_.AsyncCall(&MediaLicenseDatabase::WriteFile) .WithArgs(cdm_type, file_name, data) .Then(base::BindOnce(&MediaLicenseStorageHost::DidWriteFile, @@ -169,11 +171,10 @@ DeleteFileCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // TODO(crbug.com/1231162): Notify the quota system of a write. - db_.AsyncCall(&MediaLicenseDatabase::DeleteFile) .WithArgs(cdm_type, file_name) - .Then(std::move(callback)); + .Then(base::BindOnce(&MediaLicenseStorageHost::DidWriteFile, + weak_factory_.GetWeakPtr(), std::move(callback))); } void MediaLicenseStorageHost::DeleteBucketData(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 2afbf96..c21b0c44 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -212,16 +212,22 @@ WebContentsImpl::FriendWrapper::CreatedCallback>>::DestructorAtExit g_created_callbacks = LAZY_INSTANCE_INITIALIZER; -bool HasMatchingWidgetHost(FrameTree* tree, RenderWidgetHost* host) { +bool HasMatchingWidgetHost(FrameTree* tree, RenderWidgetHostImpl* host) { // This method scans the frame tree rather than checking whether // host->delegate() == this, which allows it to return false when the host // for a frame that is pending or pending deletion. if (!host) return false; - for (FrameTreeNode* node : tree->Nodes()) { - if (node->current_frame_host()->GetRenderWidgetHost() == host) + for (FrameTreeNode* node : tree->NodesIncludingInnerTreeNodes()) { + // We might cross a WebContents boundary here, but it's fine as we are only + // comparing the RWHI with the given `host`, which is always guaranteed to + // belong to the same WebContents as `tree`. + if (node->current_frame_host()->GetRenderWidgetHost() == host) { + DCHECK_EQ(WebContentsImpl::FromFrameTreeNode(node), + WebContentsImpl::FromRenderWidgetHostImpl(host)); return true; + } } return false; }
diff --git a/content/browser/web_contents/web_drag_dest_mac.mm b/content/browser/web_contents/web_drag_dest_mac.mm index 6455404..dab3703 100644 --- a/content/browser/web_contents/web_drag_dest_mac.mm +++ b/content/browser/web_contents/web_drag_dest_mac.mm
@@ -204,8 +204,11 @@ NSDragOperation mask = info->operation_mask; // Give the delegate an opportunity to cancel the drag. - _canceled = !_webContents->GetDelegate()->CanDragEnter( - _webContents, *dropData, static_cast<DragOperationsMask>(mask)); + if (auto* delegate = _webContents->GetDelegate()) { + _canceled = !delegate->CanDragEnter(_webContents, *dropData, + static_cast<DragOperationsMask>(mask)); + } + if (_canceled) return NSDragOperationNone;
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index e9db09d..9ee1655 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -326,6 +326,8 @@ blink::features::kAdInterestGroupAPIRestrictedPolicyByDefault}, {"AllowContentInitiatedDataUrlNavigations", features::kAllowContentInitiatedDataUrlNavigations}, + {"AttributionReporting", features::kPrivacySandboxAdsAPIsOverride, + kSetOnlyIfOverridden}, {"AutofillShadowDOM", blink::features::kAutofillShadowDOM}, {"AndroidDownloadableFontsMatching", features::kAndroidDownloadableFontsMatching}, @@ -346,7 +348,8 @@ {"EditingNG", blink::features::kEditingNG}, {"ElementSuperRareData", blink::features::kElementSuperRareData}, {"FileHandling", blink::features::kFileHandlingAPI}, - {"Fledge", blink::features::kFledge}, + {"Fledge", features::kPrivacySandboxAdsAPIsOverride, + kSetOnlyIfOverridden}, {"FontAccess", blink::features::kFontAccess}, {"FontSrcLocalMatching", features::kFontSrcLocalMatching}, {"ForceSynchronousHTMLParsing", @@ -376,7 +379,8 @@ {"ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes", blink::features:: kThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes}, - {"TopicsAPI", blink::features::kBrowsingTopics}, + {"TopicsAPI", features::kPrivacySandboxAdsAPIsOverride, + kSetOnlyIfOverridden}, {"TrustedDOMTypes", features::kTrustedDOMTypes}, {"UserAgentClientHint", blink::features::kUserAgentClientHint}, {"ViewportHeightClientHintHeader",
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 8ce64f9..fdcce6e 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -666,6 +666,11 @@ const base::Feature kHighPriorityBeforeUnload{ "HighPriorityBeforeUnload", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables exposure of ads APIs in the renderer: Attribution Reporting, +// FLEDGE, Topics. +const base::Feature kPrivacySandboxAdsAPIsOverride{ + "PrivacySandboxAdsAPIsOverride", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables Private Network Access checks for all types of web workers. // // This affects initial worker script fetches, fetches initiated by workers
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index d8a30f7..4114347 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -165,6 +165,7 @@ CONTENT_EXPORT extern const base::Feature kPepperCrossOriginRedirectRestriction; CONTENT_EXPORT extern const base::Feature kPictureInPictureV2; CONTENT_EXPORT extern const base::Feature kHighPriorityBeforeUnload; +CONTENT_EXPORT extern const base::Feature kPrivacySandboxAdsAPIsOverride; CONTENT_EXPORT extern const base::Feature kPrivateNetworkAccessForWorkers; CONTENT_EXPORT extern const base::Feature kPrivateNetworkAccessRespectPreflightResults;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 1a4e2941..6f1b651 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1107,7 +1107,7 @@ "../browser/attribution_reporting/attribution_internals_browsertest.cc", "../browser/attribution_reporting/attribution_src_browsertest.cc", "../browser/attribution_reporting/attributions_browsertest.cc", - "../browser/attribution_reporting/attributions_origin_trial_browsertest.cc", + "../browser/attribution_reporting/privacy_sandbox_ads_apis_browsertest.cc", "../browser/attribution_reporting/source_declaration_browsertest.cc", "../browser/attribution_reporting/trigger_registration_browsertest.cc", "../browser/back_forward_cache_basics_browsertest.cc",
diff --git a/content/test/data/attribution_reporting/impression_with_origin_trial.html b/content/test/data/attribution_reporting/impression_with_origin_trial.html index d2b5b326..07d4852 100644 --- a/content/test/data/attribution_reporting/impression_with_origin_trial.html +++ b/content/test/data/attribution_reporting/impression_with_origin_trial.html
@@ -2,8 +2,8 @@ <head> <!-- TODO(johnidel): Find a better way to provide this toke, as this has an expiration in 2033. Generate this token with the command: - generate_token.py https://example.test ConversionMeasurement --expire-timestamp=2000000000 --> - <meta http-equiv="origin-trial" content="AyiEpqRSCsaH3iE8GrZXh/DPVQPQr21JkMfKwjBFQKXHORXnLsT2AVEbhAECynhD0Um/tHnHHgN/mKJ8JWd1lAUAAABgeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiQ29udmVyc2lvbk1lYXN1cmVtZW50IiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9"> + generate_token.py https://example.test AttributionReporting --expire-timestamp=2000000000 --> + <meta http-equiv="origin-trial" content="A5RM267BZhqCOmeoEBNC6xxxFokBf5MLgeHTUD8VhToVaNidt/g6UEjsplcBlcI6jyzWdP0MGMzj4ab3S7CVkgUAAABfeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiQXR0cmlidXRpb25SZXBvcnRpbmciLCAiZXhwaXJ5IjogMjAwMDAwMDAwMH0="> <script src="register_impression.js"></script> </head> </html>
diff --git a/content/test/data/attribution_reporting/page_with_ads_apis_ot.html b/content/test/data/attribution_reporting/page_with_ads_apis_ot.html new file mode 100644 index 0000000..5a253b2e --- /dev/null +++ b/content/test/data/attribution_reporting/page_with_ads_apis_ot.html
@@ -0,0 +1,8 @@ +<html> + <head> + <!-- TODO(johnidel): Find a better way to provide this token, as this has an expiration in 2033. + Generate this token with the command: + generate_token.py https://example.test PrivacySandboxAdsAPIs --expire-timestamp=2000000000 --> + <meta http-equiv="origin-trial" content="A5tnx3M8YgPvr7n0sKItbVfImY3JFbP+KhW5eL3wxOHDTKpJ/AcBbmFpEx8Feve0uzgxVIfCPSjw++Gv1GCPkQUAAABgeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiUHJpdmFjeVNhbmRib3hBZHNBUElzIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9"> + </head> +</html>
diff --git a/content/test/data/attribution_reporting/page_without_ads_apis_ot.html b/content/test/data/attribution_reporting/page_without_ads_apis_ot.html new file mode 100644 index 0000000..d0903c6e --- /dev/null +++ b/content/test/data/attribution_reporting/page_without_ads_apis_ot.html
@@ -0,0 +1,3 @@ +<html> + This page does not enable the Ads APIs OT. +</html>
diff --git a/content/test/data/attribution_reporting/third_party_token_injector.js b/content/test/data/attribution_reporting/third_party_token_injector.js index 22c6c7f..33a52febd 100644 --- a/content/test/data/attribution_reporting/third_party_token_injector.js +++ b/content/test/data/attribution_reporting/third_party_token_injector.js
@@ -7,7 +7,7 @@ // Third party OT token with subset usage restriction. Expires in 2033. // Generated using: -// python generate_token.py https://example.test ConversionMeasurement \ +// python generate_token.py https://example.test AttributionReporting \ // --usage-restriction=subset --is-third-party --expire-timestamp=2000000000 -meta.content = 'A8xSVOSM2Fo25Ot5f+WXIRxAVTNK+R4JLQZvX0gbwUWq6PWGggKsIi/6HvkDNmDK64/dGOo2fJwUW4Fi7NRRhQ8AAACJeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImlzVGhpcmRQYXJ0eSI6IHRydWUsICJ1c2FnZSI6ICJzdWJzZXQiLCAiZmVhdHVyZSI6ICJDb252ZXJzaW9uTWVhc3VyZW1lbnQiLCAiZXhwaXJ5IjogMjAwMDAwMDAwMH0='; +meta.content = 'AwcYHeC1CwkNTksEvdIHHIDSuz+xzNsrkeDgg+6zlRWO8sljNr19o/rzFp2cLekz2arxAdag8AYK7e8yMynF4woAAACIeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiQXR0cmlidXRpb25SZXBvcnRpbmciLCAiZXhwaXJ5IjogMjAwMDAwMDAwMCwgImlzVGhpcmRQYXJ0eSI6IHRydWUsICJ1c2FnZSI6ICJzdWJzZXQifQ=='; document.head.appendChild(meta);
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md index f498732..3977126 100644 --- a/infra/config/generated/cq-builders.md +++ b/infra/config/generated/cq-builders.md
@@ -458,7 +458,7 @@ as required builders. * [android-12-x64-rel](https://ci.chromium.org/p/chromium/builders/try/android-12-x64-rel) ([definition](https://cs.chromium.org/search?q=+file:/try.star$+""android-12-x64-rel"")) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+""android-12-x64-rel"")) - * Experiment percentage: 20.0 + * Experiment percentage: 50.0 * [android-pie-arm64-coverage-experimental-rel](https://ci.chromium.org/p/chromium/builders/try/android-pie-arm64-coverage-experimental-rel) ([definition](https://cs.chromium.org/search?q=+file:/try.star$+""android-pie-arm64-coverage-experimental-rel"")) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+""android-pie-arm64-coverage-experimental-rel"")) * Experiment percentage: 3.0
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index efda8bf..602480e 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -279,7 +279,7 @@ } builders { name: "chromium/try/android-12-x64-rel" - experiment_percentage: 20 + experiment_percentage: 50 location_regexp: ".*" location_regexp_exclude: ".+/[+]/docs/.+" location_regexp_exclude: ".+/[+]/infra/config/.+"
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star index 4bc6501..dcf9fd0 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
@@ -47,7 +47,7 @@ # branch_selector = branches.STANDARD_MILESTONE, main_list_view = "try", tryjob = try_.job( - experiment_percentage = 20, + experiment_percentage = 50, ), )
diff --git a/ios/web/js_messaging/web_frame_impl_inttest.mm b/ios/web/js_messaging/web_frame_impl_inttest.mm index a7d16a01..8171b36 100644 --- a/ios/web/js_messaging/web_frame_impl_inttest.mm +++ b/ios/web/js_messaging/web_frame_impl_inttest.mm
@@ -7,7 +7,6 @@ #import <WebKit/WebKit.h> #include "base/bind.h" -#include "base/ios/ios_util.h" #import "base/strings/sys_string_conversions.h" #import "base/test/ios/wait_util.h" #import "ios/web/js_messaging/java_script_content_world.h" @@ -266,10 +265,6 @@ // function via |CallJavaScriptFunction| on the main frame in the page content // world. TEST_F(WebFrameImplIntTest, CallJavaScriptFunctionMainFramePageContentWorld) { - if (!base::ios::IsRunningOnIOS14OrLater()) { - return; - } - ASSERT_TRUE(LoadHtml("<p>")); ExecuteJavaScript(@"__gCrWeb = {};" @"__gCrWeb['fakeFunction'] = function() {" @@ -283,20 +278,18 @@ NSTimeInterval js_timeout = kWaitForJSCompletionTimeout; __block bool called = false; - if (@available(ios 14, *)) { - JavaScriptContentWorld world(GetBrowserState(), WKContentWorld.pageWorld); + JavaScriptContentWorld world(GetBrowserState(), WKContentWorld.pageWorld); - std::vector<base::Value> function_params; - EXPECT_TRUE(main_frame_impl->CallJavaScriptFunctionInContentWorld( - "fakeFunction", function_params, &world, - base::BindOnce(^(const base::Value* value) { - ASSERT_TRUE(value->is_string()); - EXPECT_EQ(value->GetString(), "10"); - called = true; - }), - // Increase feature timeout in order to fail on test specific timeout. - base::Seconds(2 * js_timeout))); - } + std::vector<base::Value> function_params; + EXPECT_TRUE(main_frame_impl->CallJavaScriptFunctionInContentWorld( + "fakeFunction", function_params, &world, + base::BindOnce(^(const base::Value* value) { + ASSERT_TRUE(value->is_string()); + EXPECT_EQ(value->GetString(), "10"); + called = true; + }), + // Increase feature timeout in order to fail on test specific timeout. + base::Seconds(2 * js_timeout))); EXPECT_TRUE(WaitUntilConditionOrTimeout(js_timeout, ^bool { return called; @@ -307,21 +300,15 @@ // function via |CallJavaScriptFunction| on the main frame in an isolated // world. TEST_F(WebFrameImplIntTest, CallJavaScriptFunctionMainFrameIsolatedWorld) { - if (!base::ios::IsRunningOnIOS14OrLater()) { - return; - } - ASSERT_TRUE(LoadHtml("<p>")); - if (@available(ios 14, *)) { - WKWebView* web_view = - [web::test::GetWebController(web_state()) ensureWebViewCreated]; - test::ExecuteJavaScript(web_view, WKContentWorld.defaultClientWorld, - @"__gCrWeb = {};" - @"__gCrWeb['fakeFunction'] = function() {" - @" return '10';" - @"}"); - } + WKWebView* web_view = + [web::test::GetWebController(web_state()) ensureWebViewCreated]; + test::ExecuteJavaScript(web_view, WKContentWorld.defaultClientWorld, + @"__gCrWeb = {};" + @"__gCrWeb['fakeFunction'] = function() {" + @" return '10';" + @"}"); web::WebFrameImpl* main_frame_impl = static_cast<web::WebFrameImpl*>( web_state()->GetWebFramesManager()->GetMainWebFrame()); @@ -330,21 +317,19 @@ NSTimeInterval js_timeout = kWaitForJSCompletionTimeout; __block bool called = false; - if (@available(ios 14, *)) { - JavaScriptContentWorld world(GetBrowserState(), - WKContentWorld.defaultClientWorld); + JavaScriptContentWorld world(GetBrowserState(), + WKContentWorld.defaultClientWorld); - std::vector<base::Value> function_params; - EXPECT_TRUE(main_frame_impl->CallJavaScriptFunctionInContentWorld( - "fakeFunction", function_params, &world, - base::BindOnce(^(const base::Value* value) { - ASSERT_TRUE(value->is_string()); - EXPECT_EQ(value->GetString(), "10"); - called = true; - }), - // Increase feature timeout in order to fail on test specific timeout. - base::Seconds(2 * js_timeout))); - } + std::vector<base::Value> function_params; + EXPECT_TRUE(main_frame_impl->CallJavaScriptFunctionInContentWorld( + "fakeFunction", function_params, &world, + base::BindOnce(^(const base::Value* value) { + ASSERT_TRUE(value->is_string()); + EXPECT_EQ(value->GetString(), "10"); + called = true; + }), + // Increase feature timeout in order to fail on test specific timeout. + base::Seconds(2 * js_timeout))); EXPECT_TRUE(WaitUntilConditionOrTimeout(js_timeout, ^bool { return called;
diff --git a/media/base/video_util.cc b/media/base/video_util.cc index 8d7037e..e5affe4 100644 --- a/media/base/video_util.cc +++ b/media/base/video_util.cc
@@ -879,7 +879,7 @@ if (dst_frame.format() == PIXEL_FORMAT_I420 && src_frame.format() == PIXEL_FORMAT_NV12) { - if (src_frame.visible_rect() == dst_frame.visible_rect()) { + if (src_frame.visible_rect().size() == dst_frame.visible_rect().size()) { // Both frames have the same size, only NV12-to-I420 conversion is // required. int error = libyuv::NV12ToI420( @@ -940,7 +940,7 @@ if (dst_frame.format() == PIXEL_FORMAT_NV12 && src_frame.format() == PIXEL_FORMAT_I420) { - if (src_frame.visible_rect() == dst_frame.visible_rect()) { + if (src_frame.visible_rect().size() == dst_frame.visible_rect().size()) { // Both frames have the same size, only I420-to-NV12 conversion is // required. int error = libyuv::I420ToNV12(
diff --git a/media/video/software_video_encoder_test.cc b/media/video/software_video_encoder_test.cc index 21d7ccc..4c8e816 100644 --- a/media/video/software_video_encoder_test.cc +++ b/media/video/software_video_encoder_test.cc
@@ -79,10 +79,9 @@ gfx::Size size, VideoDecoder::OutputCB output_cb, std::vector<uint8_t> extra_data = std::vector<uint8_t>()) { - gfx::Rect visible_rect(size.width(), size.height()); VideoDecoderConfig config( codec_, profile_, VideoDecoderConfig::AlphaMode::kIsOpaque, - VideoColorSpace::JPEG(), VideoTransformation(), size, visible_rect, + VideoColorSpace::JPEG(), VideoTransformation(), size, gfx::Rect(size), size, extra_data, EncryptionScheme::kUnencrypted); if (codec_ == VideoCodec::kH264 || codec_ == VideoCodec::kVP8) { @@ -652,7 +651,8 @@ auto original_frame = frames_to_encode[i]; auto decoded_frame = decoded_frames[i]; EXPECT_EQ(decoded_frame->timestamp(), original_frame->timestamp()); - EXPECT_EQ(decoded_frame->visible_rect(), original_frame->visible_rect()); + EXPECT_EQ(decoded_frame->visible_rect().size(), + original_frame->visible_rect().size()); if (decoded_frame->format() != original_frame->format()) { // The frame was converted from RGB to YUV, we can't easily compare to // the original frame, so we're going to compare with a new white frame.
diff --git a/net/socket/websocket_transport_connect_sub_job.cc b/net/socket/websocket_transport_connect_sub_job.cc index 1668fdb..807d69c8 100644 --- a/net/socket/websocket_transport_connect_sub_job.cc +++ b/net/socket/websocket_transport_connect_sub_job.cc
@@ -134,16 +134,7 @@ type_(type), websocket_endpoint_lock_manager_(websocket_endpoint_lock_manager) {} -WebSocketTransportConnectSubJob::~WebSocketTransportConnectSubJob() { - // We don't worry about cancelling the TCP connect, since ~StreamSocket will - // take care of it. - if (next()) { - DCHECK_EQ(STATE_OBTAIN_LOCK_COMPLETE, next_state_); - // The ~Waiter destructor will remove this object from the waiting list. - } else if (next_state_ == STATE_TRANSPORT_CONNECT_COMPLETE) { - websocket_endpoint_lock_manager_->UnlockEndpoint(CurrentAddress()); - } -} +WebSocketTransportConnectSubJob::~WebSocketTransportConnectSubJob() = default; // Start connecting. int WebSocketTransportConnectSubJob::Start() { @@ -164,7 +155,6 @@ case STATE_OBTAIN_LOCK_COMPLETE: // TODO(ricea): Add a WebSocket-specific LOAD_STATE ? return LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET; - case STATE_TRANSPORT_CONNECT: case STATE_TRANSPORT_CONNECT_COMPLETE: case STATE_DONE: return LOAD_STATE_CONNECTING; @@ -211,10 +201,6 @@ DCHECK_EQ(OK, rv); rv = DoEndpointLockComplete(); break; - case STATE_TRANSPORT_CONNECT: - DCHECK_EQ(OK, rv); - rv = DoTransportConnect(); - break; case STATE_TRANSPORT_CONNECT_COMPLETE: rv = DoTransportConnectComplete(rv); break; @@ -237,11 +223,6 @@ } int WebSocketTransportConnectSubJob::DoEndpointLockComplete() { - next_state_ = STATE_TRANSPORT_CONNECT; - return OK; -} - -int WebSocketTransportConnectSubJob::DoTransportConnect() { // TODO(ricea): Update global g_last_connect_time and report // ConnectInterval. next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE; @@ -249,9 +230,16 @@ // TODO(https://crbug.com/1123197): Pass a non-null NetworkQualityEstimator. NetworkQualityEstimator* network_quality_estimator = nullptr; - transport_socket_ = client_socket_factory()->CreateTransportClientSocket( - one_address, nullptr, network_quality_estimator, net_log().net_log(), - net_log().source()); + // This class now owns an endpoint lock. Wrap `socket` in a + // `WebSocketStreamSocket` to take ownership of the lock and release it when + // the socket goes out of scope. + std::unique_ptr<StreamSocket> socket = + client_socket_factory()->CreateTransportClientSocket( + one_address, nullptr, network_quality_estimator, net_log().net_log(), + net_log().source()); + transport_socket_ = std::make_unique<WebSocketStreamSocket>( + std::move(socket), websocket_endpoint_lock_manager_, CurrentAddress()); + // This use of base::Unretained() is safe because transport_socket_ is // destroyed in the destructor. return transport_socket_->Connect(base::BindOnce( @@ -261,7 +249,8 @@ int WebSocketTransportConnectSubJob::DoTransportConnectComplete(int result) { next_state_ = STATE_DONE; if (result != OK) { - websocket_endpoint_lock_manager_->UnlockEndpoint(CurrentAddress()); + // Drop the socket to release the endpoint lock. + transport_socket_.reset(); if (current_address_index_ + 1 < addresses_.size()) { // Try falling back to the next address in the list. @@ -273,12 +262,6 @@ return result; } - // On success, need to register the socket with the - // WebSocketEndpointLockManager. - transport_socket_ = std::make_unique<WebSocketStreamSocket>( - std::move(transport_socket_), websocket_endpoint_lock_manager_, - CurrentAddress()); - return result; }
diff --git a/net/socket/websocket_transport_connect_sub_job.h b/net/socket/websocket_transport_connect_sub_job.h index cc5d759..71ad315 100644 --- a/net/socket/websocket_transport_connect_sub_job.h +++ b/net/socket/websocket_transport_connect_sub_job.h
@@ -68,7 +68,6 @@ STATE_NONE, STATE_OBTAIN_LOCK, STATE_OBTAIN_LOCK_COMPLETE, - STATE_TRANSPORT_CONNECT, STATE_TRANSPORT_CONNECT_COMPLETE, STATE_DONE, }; @@ -83,7 +82,6 @@ int DoLoop(int result); int DoEndpointLock(); int DoEndpointLockComplete(); - int DoTransportConnect(); int DoTransportConnectComplete(int result); const raw_ptr<WebSocketTransportConnectJob> parent_job_;
diff --git a/services/device/generic_sensor/platform_sensor_fusion.h b/services/device/generic_sensor/platform_sensor_fusion.h index 70d172bb..70515f0 100644 --- a/services/device/generic_sensor/platform_sensor_fusion.h +++ b/services/device/generic_sensor/platform_sensor_fusion.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/containers/flat_map.h" +#include "base/gtest_prod_util.h" #include "services/device/generic_sensor/platform_sensor.h" #include "services/device/generic_sensor/platform_sensor_provider_base.h" @@ -72,6 +73,12 @@ bool StartSensor(const PlatformSensorConfiguration& configuration) override; void StopSensor() override; + PlatformSensorFusionAlgorithm* fusion_algorithm() const { + return fusion_algorithm_.get(); + } + + FRIEND_TEST_ALL_PREFIXES(PlatformSensorFusionTest, OnSensorReadingChanged); + private: SensorReading reading_; std::unique_ptr<PlatformSensorFusionAlgorithm> fusion_algorithm_;
diff --git a/services/device/generic_sensor/platform_sensor_fusion_algorithm.h b/services/device/generic_sensor/platform_sensor_fusion_algorithm.h index d3f8214d..af03c49 100644 --- a/services/device/generic_sensor/platform_sensor_fusion_algorithm.h +++ b/services/device/generic_sensor/platform_sensor_fusion_algorithm.h
@@ -25,6 +25,7 @@ virtual ~PlatformSensorFusionAlgorithm(); void set_threshold(double threshold) { threshold_ = threshold; } + double threshold() const { return threshold_; } void set_fusion_sensor(PlatformSensorFusion* fusion_sensor) { fusion_sensor_ = fusion_sensor;
diff --git a/services/device/generic_sensor/platform_sensor_fusion_unittest.cc b/services/device/generic_sensor/platform_sensor_fusion_unittest.cc index 29206b1..41bd1c0c 100644 --- a/services/device/generic_sensor/platform_sensor_fusion_unittest.cc +++ b/services/device/generic_sensor/platform_sensor_fusion_unittest.cc
@@ -7,13 +7,16 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/memory/ref_counted.h" +#include "base/run_loop.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "services/device/generic_sensor/absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.h" #include "services/device/generic_sensor/fake_platform_sensor_and_provider.h" +#include "services/device/generic_sensor/generic_sensor_consts.h" #include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h" #include "services/device/generic_sensor/platform_sensor.h" #include "services/device/generic_sensor/platform_sensor_fusion.h" +#include "services/device/generic_sensor/platform_sensor_fusion_algorithm.h" #include "services/device/generic_sensor/platform_sensor_provider.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,6 +28,100 @@ using mojom::SensorType; +namespace { + +void ExpectNoReadingChangedEvent(MockPlatformSensorClient* sensor_client, + mojom::SensorType sensor_type) { + base::RunLoop run_loop; + EXPECT_CALL(*sensor_client, OnSensorReadingChanged(sensor_type)).Times(0); + run_loop.RunUntilIdle(); +} + +void ExpectReadingChangedEvent(MockPlatformSensorClient* sensor_client, + mojom::SensorType sensor_type) { + base::RunLoop run_loop; + EXPECT_CALL(*sensor_client, OnSensorReadingChanged(sensor_type)) + .WillOnce(Invoke([&](SensorType) { run_loop.Quit(); })); + run_loop.Run(); +} + +// Attempts to add a new reading to the sensor owned by |sensor_client|, and +// asserts that it does not lead to OnSensorReadingChanged() being called (i.e. +// PlatformSensor's significance check has failed). +void AddNewReadingAndExpectNoReadingChangedEvent( + MockPlatformSensorClient* sensor_client, + const SensorReading& new_reading, + mojom::SensorType sensor_type) { + scoped_refptr<FakePlatformSensor> fake_sensor = + static_cast<FakePlatformSensor*>(sensor_client->sensor().get()); + fake_sensor->AddNewReading(new_reading); + ExpectNoReadingChangedEvent(sensor_client, sensor_type); +} + +// Add a new reading to the sensor owned by |sensor_client|, and expect reading +// change event. +void AddNewReadingAndExpectReadingChangedEvent( + MockPlatformSensorClient* sensor_client, + const SensorReading& new_reading, + mojom::SensorType sensor_type) { + scoped_refptr<FakePlatformSensor> fake_sensor = + static_cast<FakePlatformSensor*>(sensor_client->sensor().get()); + fake_sensor->AddNewReading(new_reading); + ExpectReadingChangedEvent(sensor_client, sensor_type); +} + +void FusionAlgorithmCopyLowLevelValues(const SensorReading& low_level_reading, + SensorReading* fused_reading) { + fused_reading->raw.values[0] = low_level_reading.raw.values[0]; + fused_reading->raw.values[1] = low_level_reading.raw.values[1]; + fused_reading->raw.values[2] = low_level_reading.raw.values[2]; +} + +void FusionAlgorithmSubtractEpsilonFromX(const SensorReading& low_level_reading, + SensorReading* fused_reading) { + fused_reading->raw.values[0] = low_level_reading.raw.values[0] - kEpsilon; + fused_reading->raw.values[1] = low_level_reading.raw.values[1]; + fused_reading->raw.values[2] = low_level_reading.raw.values[2]; +} + +// A PlatformSensorFusionAlgorithm whose fusion algorithm can be customized +// at runtime via set_fusion_function(). +class CustomizableFusionAlgorithm : public PlatformSensorFusionAlgorithm { + public: + using FusionFunction = + base::RepeatingCallback<void(const SensorReading& low_level_reading, + SensorReading* fused_reading)>; + static constexpr mojom::SensorType kLowLevelSensorType = + SensorType::ACCELEROMETER; + static constexpr mojom::SensorType kFusionSensorType = SensorType::GRAVITY; + + CustomizableFusionAlgorithm() + : PlatformSensorFusionAlgorithm(kFusionSensorType, + {kLowLevelSensorType}) {} + ~CustomizableFusionAlgorithm() override = default; + + bool GetFusedDataInternal(mojom::SensorType which_sensor_changed, + SensorReading* fused_reading) override { + EXPECT_EQ(which_sensor_changed, kLowLevelSensorType); + + SensorReading low_level_reading; + EXPECT_TRUE(fusion_sensor_->GetSourceReading(kLowLevelSensorType, + &low_level_reading)); + + fusion_function_.Run(low_level_reading, fused_reading); + return true; + } + + void set_fusion_function(FusionFunction fusion_function) { + fusion_function_ = std::move(fusion_function); + } + + private: + FusionFunction fusion_function_; +}; + +} // namespace + class PlatformSensorFusionTest : public testing::Test { public: PlatformSensorFusionTest() { @@ -334,4 +431,194 @@ client.get(), PlatformSensorConfiguration(30.0))); } +TEST_F(PlatformSensorFusionTest, FusionIsSignificantlyDifferent) { + // Due to inaccuracy of calculations between doubles, difference between two + // input values has to be bigger than the threshold value used in + // significantly different check. + CustomizableFusionAlgorithm fusion_algorithm; + + const double kValueToFlipThreshold = fusion_algorithm.threshold() + kEpsilon; + const double kValueNotToFlipThreshold = + fusion_algorithm.threshold() - kEpsilon; + SensorReading reading1; + SensorReading reading2; + // Made up test values. + reading1.raw.values[0] = reading2.raw.values[0] = 0.1; + reading1.raw.values[1] = reading2.raw.values[1] = 0.5; + reading1.raw.values[2] = reading2.raw.values[2] = 5.0; + reading1.raw.values[3] = reading2.raw.values[3] = 10.0; + + // Compared values are same. + // reading1: 0.1, 0.5, 5.0, 10.0 + // reading2: 0.1, 0.5, 5.0, 10.0 + EXPECT_FALSE( + fusion_algorithm.IsReadingSignificantlyDifferent(reading1, reading2)); + + // Compared values do not significantly differ from each other. + // reading1: 0.1, 0.5, 5.0, 10.0 + // reading2: 0.1, 0.5, 5.0, 10.00001 + reading2.raw.values[3] = reading2.raw.values[3] + kValueNotToFlipThreshold; + EXPECT_FALSE( + fusion_algorithm.IsReadingSignificantlyDifferent(reading1, reading2)); + + // Compared values significantly differ from each other. + // reading1: 0.1, 0.5, 5.0, 10.0 + // reading2: 0.1, 0.5, 5.0, 10.11001 + reading2.raw.values[3] = reading2.raw.values[3] + kValueToFlipThreshold; + EXPECT_TRUE( + fusion_algorithm.IsReadingSignificantlyDifferent(reading1, reading2)); +} + +TEST_F(PlatformSensorFusionTest, OnSensorReadingChanged) { + // Accelerometer is selected as low-level sensor. + CreateAccelerometer(); + EXPECT_TRUE(accelerometer_); + auto client_low_level_ = + std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( + accelerometer_); + + CreateFusionSensor(std::make_unique<CustomizableFusionAlgorithm>()); + ASSERT_TRUE(fusion_sensor_); + auto* fusion_algorithm = static_cast<CustomizableFusionAlgorithm*>( + fusion_sensor_->fusion_algorithm()); + EXPECT_EQ(CustomizableFusionAlgorithm::kFusionSensorType, + fusion_sensor_->GetType()); + + auto client_fusion = + std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( + fusion_sensor_); + fusion_sensor_->StartListening(client_fusion.get(), + PlatformSensorConfiguration(10)); + + // Made up test values. + const double kTestValueX = 0.6; + const double kTestValueY = 0.9; + const double kTestValueZ = 1.1; + const double kValueToFlipThreshold = fusion_algorithm->threshold() * 2; + + struct TestSensorReading { + const struct { + double x; + double y; + double z; + } input, expected; + const bool expect_reading_changed_event; + }; + + const struct { + TestSensorReading low_level; + TestSensorReading fusion; + CustomizableFusionAlgorithm::FusionFunction fusion_function; + } kTestSteps[] = { + // Test set 1 + // Triggers low-level and fusion reading as initial sensor + // values are zero. + {// Low-level sensor + {{kTestValueX, kTestValueY, kTestValueZ}, + {kTestValueX, kTestValueY, kTestValueZ}, + true}, + // Fusion sensor + {{kTestValueX, kTestValueY, kTestValueZ}, + {kTestValueX, kTestValueY, kTestValueZ}, + true}, + base::BindRepeating(&FusionAlgorithmCopyLowLevelValues)}, + + // Test set 2 + // Triggers low-level reading event, but not fusion sensor reading event + // as fusion sensor values are not changed compared to test set 1. + {// Low-level sensor + {{kTestValueX + kEpsilon, kTestValueY, kTestValueZ}, + {kTestValueX, kTestValueY, kTestValueZ}, + true}, + // Fusion sensor + {{kTestValueX, kTestValueY, kTestValueZ}, + {kTestValueX, kTestValueY, kTestValueZ}, + false}, + base::BindRepeating(&FusionAlgorithmSubtractEpsilonFromX)}, + + // Test set 3 + // Test set has same values as previous values so low-level and fusion + // reading event is not expected. + {// Low-level sensor + {{kTestValueX + kEpsilon, kTestValueY, kTestValueZ}, + {kTestValueX, kTestValueY, kTestValueZ}, + false}, + // Fusion sensor + {{kTestValueX, kTestValueY, kTestValueZ}, + {kTestValueX, kTestValueY, kTestValueZ}, + false}, + base::BindRepeating(&FusionAlgorithmSubtractEpsilonFromX)}, + + // Test set 4 + // In current code as fusion sensor values are rounded before + // PlatformSensorFusionAlgorithm::IsReadingSignificantlyDifferent() call + // the difference between values must much bigger than threshold value. + {// Low-level sensor + {{kTestValueX + kValueToFlipThreshold, kTestValueY, kTestValueZ}, + {kTestValueX + kValueToFlipThreshold, kTestValueY, kTestValueZ}, + true}, + // Fusion sensor + {{kTestValueX + kValueToFlipThreshold, kTestValueY, kTestValueZ}, + {kTestValueX + kValueToFlipThreshold, kTestValueY, kTestValueZ}, + true}, + base::BindRepeating(&FusionAlgorithmCopyLowLevelValues)}, + }; + + for (const auto& test_step : kTestSteps) { + fusion_algorithm->set_fusion_function(test_step.fusion_function); + + // First add low-level sensor readings. + SensorReading reading; + reading.accel.x = test_step.low_level.input.x; + reading.accel.y = test_step.low_level.input.y; + reading.accel.z = test_step.low_level.input.z; + + // Code checks if PlatformSensor::OnSensorReadingChanged() is called + // or not called as expected. + if (test_step.low_level.expect_reading_changed_event) { + AddNewReadingAndExpectReadingChangedEvent( + client_low_level_.get(), reading, + CustomizableFusionAlgorithm::kLowLevelSensorType); + } else { + AddNewReadingAndExpectNoReadingChangedEvent( + client_low_level_.get(), reading, + CustomizableFusionAlgorithm::kLowLevelSensorType); + } + + if (test_step.fusion.expect_reading_changed_event) { + ExpectReadingChangedEvent(client_fusion.get(), + CustomizableFusionAlgorithm::kFusionSensorType); + } else { + ExpectNoReadingChangedEvent( + client_fusion.get(), CustomizableFusionAlgorithm::kFusionSensorType); + } + + // Once new values are added, we can check that low-level sensors and + // fusion sensor have correct values. + // Check rounded low-level sensor values. + EXPECT_TRUE(accelerometer_->GetLatestReading(&reading)); + EXPECT_DOUBLE_EQ(test_step.low_level.expected.x, reading.accel.x); + EXPECT_DOUBLE_EQ(test_step.low_level.expected.y, reading.accel.y); + EXPECT_DOUBLE_EQ(test_step.low_level.expected.z, reading.accel.z); + + // Check raw low-level sensor values. + EXPECT_TRUE(accelerometer_->GetLatestRawReading(&reading)); + EXPECT_DOUBLE_EQ(test_step.low_level.input.x, reading.accel.x); + EXPECT_DOUBLE_EQ(test_step.low_level.input.y, reading.accel.y); + EXPECT_DOUBLE_EQ(test_step.low_level.input.z, reading.accel.z); + + // Check rounded fusion sensor values. + EXPECT_TRUE(fusion_sensor_->GetLatestReading(&reading)); + EXPECT_DOUBLE_EQ(test_step.fusion.expected.x, reading.accel.x); + EXPECT_DOUBLE_EQ(test_step.fusion.expected.y, reading.accel.y); + EXPECT_DOUBLE_EQ(test_step.fusion.expected.z, reading.accel.z); + + // Check raw fusion sensor values. + EXPECT_TRUE(fusion_sensor_->GetLatestRawReading(&reading)); + EXPECT_DOUBLE_EQ(test_step.fusion.input.x, reading.accel.x); + EXPECT_DOUBLE_EQ(test_step.fusion.input.y, reading.accel.y); + EXPECT_DOUBLE_EQ(test_step.fusion.input.z, reading.accel.z); + } +} + } // namespace device
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index b138a6b..148c72e9 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5795,7 +5795,7 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "isolate_profile_data": true, @@ -5803,14 +5803,14 @@ "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "dimension_sets": [ @@ -5937,7 +5937,7 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "isolate_profile_data": true, @@ -5945,14 +5945,14 @@ "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 86cec13..006d68a 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -85114,7 +85114,7 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "isolate_profile_data": true, @@ -85122,14 +85122,14 @@ "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -85231,7 +85231,7 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "isolate_profile_data": true, @@ -85239,14 +85239,14 @@ "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -86613,21 +86613,21 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "dimension_sets": [ @@ -86755,21 +86755,21 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "dimension_sets": [ @@ -88310,21 +88310,21 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "dimension_sets": [ @@ -88452,21 +88452,21 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "dimension_sets": [ @@ -89203,21 +89203,21 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -89299,21 +89299,21 @@ }, { "args": [ - "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome", "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter" ], "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" }, - "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4962.0", + "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 102.0.4963.0", "swarming": { "can_use_on_swarming_builders": true, "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v102.0.4962.0", - "revision": "version:102.0.4962.0" + "location": "lacros_version_skew_tests_v102.0.4963.0", + "revision": "version:102.0.4963.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index d7d35f0e..3f6590a 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -28,16 +28,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4962.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v102.0.4963.0/test_ash_chrome', '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter', ], - 'identifier': 'Lacros version skew testing ash 102.0.4962.0', + 'identifier': 'Lacros version skew testing ash 102.0.4963.0', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v102.0.4962.0', - 'revision': 'version:102.0.4962.0', + 'location': 'lacros_version_skew_tests_v102.0.4963.0', + 'revision': 'version:102.0.4963.0', }, ], },
diff --git a/third_party/blink/common/client_hints/enabled_client_hints_unittest.cc b/third_party/blink/common/client_hints/enabled_client_hints_unittest.cc index 08eb889f..26101764 100644 --- a/third_party/blink/common/client_hints/enabled_client_hints_unittest.cc +++ b/third_party/blink/common/client_hints/enabled_client_hints_unittest.cc
@@ -382,10 +382,10 @@ // The Origin Trial token expires in 2033. Generate a new token by then, or // find a better way to re-generate a test trial token. static constexpr char kValidOriginTrialToken[] = - "A1ZeT+cUjeN+YRlvnoNP67cBtEZqx9Z4Gx/AmfsCIHvyULWM6t12q1Kd6YWHdMtF/" - "eC6MYGv0GMwIZo2J380WQ0AAABceyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6NDQ0N" - "DQiLCAiZmVhdHVyZSI6ICJQYXJ0aXRpb25lZENvb2tpZXMiLCAiZXhwaXJ5IjogMTY0ODE2M" - "jU4Mn0="; + "A4s/" + "iPKfhEfgqQIIuz4zLuCpONpXOuYyJFBhBx1MfgS1aNhFujyhsg4lkfTRfjzQCI3aUbMwtNm2" + "5elLTR4UIgAAAABceyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6NDQ0NDQiLCAiZmVh" + "dHVyZSI6ICJQYXJ0aXRpb25lZENvb2tpZXMiLCAiZXhwaXJ5IjogMjAwMDAwMDAwMH0="; VerifyClientHintEnabledWithOriginTrialToken( kValidOriginTrialToken, @@ -397,10 +397,10 @@ EnabledPartitionedCookiesClientHintWithInvalidOriginTrialToken) { // Changed the first character of the token in the last test. static constexpr char kValidOriginTrialToken[] = - "B1ZeT+cUjeN+YRlvnoNP67cBtEZqx9Z4Gx/AmfsCIHvyULWM6t12q1Kd6YWHdMtF/" - "eC6MYGv0GMwIZo2J380WQ0AAABceyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6NDQ0N" - "DQiLCAiZmVhdHVyZSI6ICJQYXJ0aXRpb25lZENvb2tpZXMiLCAiZXhwaXJ5IjogMTY0ODE2M" - "jU4Mn0="; + "B4s/" + "iPKfhEfgqQIIuz4zLuCpONpXOuYyJFBhBx1MfgS1aNhFujyhsg4lkfTRfjzQCI3aUbMwtNm2" + "5elLTR4UIgAAAABceyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6NDQ0NDQiLCAiZmVh" + "dHVyZSI6ICJQYXJ0aXRpb25lZENvb2tpZXMiLCAiZXhwaXJ5IjogMjAwMDAwMDAwMH0="; VerifyClientHintEnabledWithOriginTrialToken( kValidOriginTrialToken,
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index b4ddaa8..fb2c40ed 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -152,6 +152,9 @@ const base::Feature kLayoutNGBlockInInline{"LayoutNGBlockInInline", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kPrivacySandboxAdsAPIs{"PrivacySandboxAdsAPIs", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kMixedContentAutoupgrade{"AutoupgradeMixedContent", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index b7af993d..8093cad 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -66,6 +66,7 @@ BLINK_COMMON_EXPORT extern const base::Feature kViewportHeightClientHintHeader; BLINK_COMMON_EXPORT extern const base::Feature kFullUserAgent; BLINK_COMMON_EXPORT extern const base::Feature kPath2DPaintCache; +BLINK_COMMON_EXPORT extern const base::Feature kPrivacySandboxAdsAPIs; enum class FencedFramesImplementationType { kShadowDOM,
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index bad6236..91bac78 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3505,6 +3505,8 @@ kComputePressureObserver_Unobserve = 4184, kComputePressureObserver_Disconnect = 4185, kComputePressureObserver_TakeRecords = 4186, + kPrivacySandboxAdsAPIs = 4187, + kFledge = 4188, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index bd3c987..a3c1f019 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -4791,28 +4791,40 @@ return false; HeapVector<std::pair<Member<Element>, Member<Element>>> activatable_targets; - for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(*this)) { - auto* ancestor_element = DynamicTo<Element>(ancestor); - if (!ancestor_element) + for (Node* previous = this; previous; + previous = FlatTreeTraversal::Previous(*previous)) { + Element* prior_element = DynamicTo<Element>(previous); + if (!prior_element) continue; - if (auto* context = ancestor_element->GetDisplayLockContext()) { + if (auto* context = prior_element->GetDisplayLockContext()) { // If any of the ancestors is not activatable for the given reason, we // can't activate. if (context->IsLocked() && !context->IsActivatable(reason)) return false; - activatable_targets.push_back(std::make_pair( - ancestor_element, &ancestor.GetTreeScope().Retarget(*this))); + // Collect display-locked ancestors and shaping-deferred prior elements. + if (FlatTreeTraversal::Contains(*prior_element, *this) || + (prior_element->GetLayoutObject() && + prior_element->GetLayoutObject()->IsShapingDeferred())) { + activatable_targets.push_back(std::make_pair( + prior_element, &prior_element->GetTreeScope().Retarget(*this))); + } } } bool activated = false; for (const auto& target : activatable_targets) { - // Dispatch event on activatable ancestor (target.first), with - // the retargeted element (target.second) as the |activatedElement|. if (auto* context = target.first->GetDisplayLockContext()) { if (context->ShouldCommitForActivation(reason)) { activated = true; - context->CommitForActivationWithSignal(target.second, reason); + if (target.first->GetLayoutObject() && + target.first->GetLayoutObject()->IsShapingDeferred()) { + // Unlock shaping-deferred IFCs permanently. + context->SetRequestedState(EContentVisibility::kVisible); + } else { + // Dispatch event on activatable ancestor (target.first), with + // the retargeted element (target.second) as the |activated_element|. + context->CommitForActivationWithSignal(target.second, reason); + } } } }
diff --git a/third_party/blink/renderer/core/frame/attribution_reporting.idl b/third_party/blink/renderer/core/frame/attribution_reporting.idl index 301f307..44843ac 100644 --- a/third_party/blink/renderer/core/frame/attribution_reporting.idl +++ b/third_party/blink/renderer/core/frame/attribution_reporting.idl
@@ -7,7 +7,7 @@ // https://github.com/WICG/conversion-measurement-api/ [ Exposed=Window, - RuntimeEnabled=ConversionMeasurement, + RuntimeEnabled=AttributionReporting, SecureContext ] interface AttributionReporting { [CallWith=ScriptState, RaisesException] Promise<void> registerSource(DOMString url);
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.cc b/third_party/blink/renderer/core/frame/attribution_src_loader.cc index 63810da..abb000a 100644 --- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc +++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -287,7 +287,7 @@ LocalDOMWindow* window = local_frame_->DomWindow(); DCHECK(window); - if (!RuntimeEnabledFeatures::ConversionMeasurementEnabled(window)) + if (!RuntimeEnabledFeatures::AttributionReportingEnabled(window)) return RegisterResult::kNotAllowed; const bool feature_policy_enabled = window->IsFeatureEnabled( @@ -323,6 +323,13 @@ return RegisterResult::kUntrustworthyOrigin; } + UseCounter::Count(window, mojom::blink::WebFeature::kConversionAPIAll); + + // Only record the ads APIs counter if enabled in that manner. + if (RuntimeEnabledFeatures::PrivacySandboxAdsAPIsEnabled(window)) { + UseCounter::Count(window, mojom::blink::WebFeature::kPrivacySandboxAdsAPIs); + } + return RegisterResult::kSuccess; }
diff --git a/third_party/blink/renderer/core/frame/window_attribution_reporting.idl b/third_party/blink/renderer/core/frame/window_attribution_reporting.idl index 69cf0be..ad3edaa 100644 --- a/third_party/blink/renderer/core/frame/window_attribution_reporting.idl +++ b/third_party/blink/renderer/core/frame/window_attribution_reporting.idl
@@ -5,7 +5,7 @@ // Attribution Reporting API: https://github.com/wicg/conversion-measurement-api [ ImplementedAs=AttributionReporting, - RuntimeEnabled=ConversionMeasurement, + RuntimeEnabled=AttributionReporting, SecureContext ] partial interface Window { readonly attribute AttributionReporting attributionReporting;
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.idl b/third_party/blink/renderer/core/html/html_anchor_element.idl index 05545606..1ae36239 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.idl +++ b/third_party/blink/renderer/core/html/html_anchor_element.idl
@@ -41,7 +41,7 @@ [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute USVString attributionReportTo; [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute DOMString attributionExpiry; [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute DOMString attributionSourcePriority; - [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute USVString attributionSrc; + [RuntimeEnabled=AttributionReporting, CEReactions,Reflect] attribute USVString attributionSrc; // obsolete members // https://html.spec.whatwg.org/C/#HTMLAnchorElement-partial
diff --git a/third_party/blink/renderer/core/html/html_image_element.idl b/third_party/blink/renderer/core/html/html_image_element.idl index aed92e1c..dfec08c 100644 --- a/third_party/blink/renderer/core/html/html_image_element.idl +++ b/third_party/blink/renderer/core/html/html_image_element.idl
@@ -46,7 +46,7 @@ [RuntimeEnabled=LazyImageLoading, CEReactions, Reflect, ReflectOnly=("lazy", "eager", "auto"), ReflectMissing="auto", ReflectInvalid="auto"] attribute DOMString loading; // Attribution Reporting - [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute USVString attributionSrc; + [RuntimeEnabled=AttributionReporting, CEReactions,Reflect] attribute USVString attributionSrc; // obsolete members // https://html.spec.whatwg.org/C/#HTMLImageElement-partial
diff --git a/third_party/blink/renderer/core/layout/deferred_shaping_test.cc b/third_party/blink/renderer/core/layout/deferred_shaping_test.cc index bc43914..29ad409 100644 --- a/third_party/blink/renderer/core/layout/deferred_shaping_test.cc +++ b/third_party/blink/renderer/core/layout/deferred_shaping_test.cc
@@ -254,6 +254,25 @@ GetElementById("target2")->clientWidth()); } +TEST_F(DeferredShapingTest, ScrollIntoView) { + SetBodyInnerHTML(R"HTML(<div style="height:1800px"></div> +<div><p id="prior">IFC</p></div> +<div style="height:3600px"></div> +<p id="ancestor">IFC<span style="display:inline-block" id="target"></sapn></p> +)HTML"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_TRUE(IsDefer("prior")); + EXPECT_TRUE(IsLocked("prior")); + EXPECT_TRUE(IsDefer("ancestor")); + EXPECT_TRUE(IsLocked("ancestor")); + + GetElementById("target")->scrollIntoView(); + EXPECT_FALSE(IsDefer("prior")); + EXPECT_FALSE(IsLocked("prior")); + EXPECT_FALSE(IsDefer("ancestor")); + EXPECT_FALSE(IsLocked("ancestor")); +} + TEST_F(DeferredShapingTest, NonLayoutNGBlockFlow) { SetBodyInnerHTML(R"HTML( <div style="height:1800px"></div>
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc index d1a80dff..de9559fd 100644 --- a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc +++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
@@ -491,6 +491,9 @@ if (trial_name == "Portals") return base::FeatureList::IsEnabled(features::kPortals); + if (trial_name == "PrivacySandboxAdsAPIs") + return base::FeatureList::IsEnabled(features::kPrivacySandboxAdsAPIs); + if (trial_name == "FencedFrames") return base::FeatureList::IsEnabled(features::kFencedFrames); @@ -507,10 +510,6 @@ return base::FeatureList::IsEnabled( features::kSpeculationRulesPrefetchProxy); } - if (trial_name == "ConversionMeasurement" && - !base::FeatureList::IsEnabled(features::kConversionMeasurement)) { - return false; - } if (trial_name == "Prerender2") return base::FeatureList::IsEnabled(features::kPrerender2); @@ -518,6 +517,22 @@ return true; } +Vector<OriginTrialFeature> OriginTrialContext::RestrictedFeaturesForTrial( + const String& trial_name) { + if (trial_name == "PrivacySandboxAdsAPIs") { + Vector<OriginTrialFeature> restricted; + if (!base::FeatureList::IsEnabled(features::kFledge)) + restricted.push_back(OriginTrialFeature::kFledge); + if (!base::FeatureList::IsEnabled(features::kBrowsingTopics)) + restricted.push_back(OriginTrialFeature::kTopicsAPI); + if (!base::FeatureList::IsEnabled(features::kConversionMeasurement)) + restricted.push_back(OriginTrialFeature::kAttributionReporting); + return restricted; + } + + return {}; +} + OriginTrialStatus OriginTrialContext::EnableTrialFromName( const String& trial_name, base::Time expiry_time) { @@ -526,6 +541,9 @@ return OriginTrialStatus::kTrialNotAllowed; } + Vector<OriginTrialFeature> restricted = + RestrictedFeaturesForTrial(trial_name); + bool did_enable_feature = false; for (OriginTrialFeature feature : origin_trials::FeaturesForTrial(trial_name.Utf8())) { @@ -535,6 +553,13 @@ continue; } + if (restricted.Contains(feature)) { + DVLOG(1) << "EnableTrialFromName: feature " << static_cast<int>(feature) + << " is restricted from being enabled via the trial: " + << trial_name << "."; + continue; + } + did_enable_feature = true; enabled_features_.insert(feature);
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context.h b/third_party/blink/renderer/core/origin_trials/origin_trial_context.h index 97d38d4..89824099 100644 --- a/third_party/blink/renderer/core/origin_trials/origin_trial_context.h +++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context.h
@@ -192,6 +192,13 @@ // invalid in the browser's present configuration). bool CanEnableTrialFromName(const StringView& trial_name); + // Returns features which are currently restricted for a given trial name, + // these features *will not* be enabled by the origin trial infrastructure if + // the given trial is enabled. The corresponding runtime features may still be + // enabled via command line flags, etc. + Vector<OriginTrialFeature> RestrictedFeaturesForTrial( + const String& trial_name); + // Enable features by trial name. Returns true or false to indicate whether // some features are enabled as the result. OriginTrialStatus EnableTrialFromName(const String& trial_name,
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc index 9c9bc240..30af2646 100644 --- a/third_party/blink/renderer/core/page/create_window.cc +++ b/third_party/blink/renderer/core/page/create_window.cc
@@ -70,9 +70,9 @@ LocalDOMWindow* dom_window) { WebWindowFeatures window_features; - bool conversion_measurement_enabled = + bool attribution_reporting_enabled = dom_window && - RuntimeEnabledFeatures::ConversionMeasurementEnabled(dom_window); + RuntimeEnabledFeatures::AttributionReportingEnabled(dom_window); // This code follows the HTML spec, specifically // https://html.spec.whatwg.org/C/#concept-window-open-features-tokenize @@ -160,7 +160,7 @@ if (!ui_features_were_disabled && key_string != "noopener" && key_string != "noreferrer" && - (!conversion_measurement_enabled || key_string != "attributionsrc")) { + (!attribution_reporting_enabled || key_string != "attributionsrc")) { ui_features_were_disabled = true; window_features.menu_bar_visible = false; window_features.status_bar_visible = false; @@ -201,7 +201,7 @@ window_features.background = true; } else if (key_string == "persistent") { window_features.persistent = true; - } else if (conversion_measurement_enabled && + } else if (attribution_reporting_enabled && key_string == "attributionsrc") { window_features.impression = dom_window->GetFrame()->GetAttributionSrcLoader()->RegisterNavigation(
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 b/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 index 24f4a25..369c7be 100644 --- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 +++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5
@@ -191,7 +191,7 @@ { name: "AttributionReporting", permissions_policy_name: "attribution-reporting", - depends_on: ["ConversionMeasurement"], + depends_on: ["AttributionReporting"], }, { name: "CrossOriginIsolated",
diff --git a/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc b/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc index 6b6c26f..98f1718c6 100644 --- a/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc +++ b/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc
@@ -801,6 +801,18 @@ /*discard_duplicates=*/true); } +void RecordCommonFledgeUseCounters(Document* document) { + if (!document) + return; + UseCounter::Count(document, mojom::blink::WebFeature::kFledge); + // Only record the ads APIs counter if enabled in that manner. + if (RuntimeEnabledFeatures::PrivacySandboxAdsAPIsEnabled( + document->GetExecutionContext())) { + UseCounter::Count(document, + mojom::blink::WebFeature::kPrivacySandboxAdsAPIs); + } +} + } // namespace NavigatorAuction::NavigatorAuction(Navigator& navigator) @@ -887,6 +899,7 @@ const AuctionAdInterestGroup* group, double duration_seconds, ExceptionState& exception_state) { + RecordCommonFledgeUseCounters(navigator.DomWindow()->document()); const ExecutionContext* context = ExecutionContext::From(script_state); if (!context->IsFeatureEnabled( blink::mojom::PermissionsPolicyFeature::kJoinAdInterestGroup)) { @@ -926,6 +939,7 @@ Navigator& navigator, const AuctionAdInterestGroup* group, ExceptionState& exception_state) { + RecordCommonFledgeUseCounters(navigator.DomWindow()->document()); ExecutionContext* context = ExecutionContext::From(script_state); if (!context->IsFeatureEnabled( blink::mojom::PermissionsPolicyFeature::kJoinAdInterestGroup)) { @@ -953,6 +967,7 @@ void NavigatorAuction::updateAdInterestGroups(ScriptState* script_state, Navigator& navigator, ExceptionState& exception_state) { + RecordCommonFledgeUseCounters(navigator.DomWindow()->document()); ExecutionContext* context = ExecutionContext::From(script_state); if (!context->IsFeatureEnabled( blink::mojom::PermissionsPolicyFeature::kJoinAdInterestGroup)) { @@ -994,6 +1009,7 @@ Navigator& navigator, const AuctionAdConfig* config, ExceptionState& exception_state) { + RecordCommonFledgeUseCounters(navigator.DomWindow()->document()); const ExecutionContext* context = ExecutionContext::From(script_state); if (!context->IsFeatureEnabled( blink::mojom::PermissionsPolicyFeature::kRunAdAuction)) { @@ -1018,6 +1034,7 @@ Navigator& navigator, uint16_t num_ad_components, ExceptionState& exception_state) { + RecordCommonFledgeUseCounters(navigator.DomWindow()->document()); const auto& ad_auction_components = navigator.DomWindow()->document()->Loader()->AdAuctionComponents(); Vector<String> out;
diff --git a/third_party/blink/renderer/modules/browsing_topics/browsing_topics_document_supplement.cc b/third_party/blink/renderer/modules/browsing_topics/browsing_topics_document_supplement.cc index 4514913..9d938d2 100644 --- a/third_party/blink/renderer/modules/browsing_topics/browsing_topics_document_supplement.cc +++ b/third_party/blink/renderer/modules/browsing_topics/browsing_topics_document_supplement.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/public/mojom/permissions_policy/document_policy_feature.mojom-blink.h" #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-blink.h" #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-blink.h" +#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h" @@ -57,6 +58,12 @@ return ScriptPromise(); } + if (RuntimeEnabledFeatures::PrivacySandboxAdsAPIsEnabled( + document.GetExecutionContext())) { + UseCounter::Count(document, + mojom::blink::WebFeature::kPrivacySandboxAdsAPIs); + } + ScriptPromiseResolver* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise();
diff --git a/third_party/blink/renderer/platform/media/watch_time_reporter_unittest.cc b/third_party/blink/renderer/platform/media/watch_time_reporter_unittest.cc index 4128cb20..369856e 100644 --- a/third_party/blink/renderer/platform/media/watch_time_reporter_unittest.cc +++ b/third_party/blink/renderer/platform/media/watch_time_reporter_unittest.cc
@@ -662,7 +662,7 @@ wtr_->OnPlaying(); EXPECT_EQ(!has_video_, IsMonitoring()); - Initialize(true, true, gfx::Size(100, 100)); + Initialize(true, true, kSizeTooSmall); wtr_->OnPlaying(); EXPECT_EQ(!has_video_, IsMonitoring());
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index c1dbd8f..aaa43004 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -200,6 +200,12 @@ status: "experimental", }, { + name: "AttributionReporting", + origin_trial_feature_name: "PrivacySandboxAdsAPIs", + origin_trial_allows_third_party: true, + status: "experimental", + }, + { name: "AudioOutputDevices", // Android does not yet support switching of audio output devices status: {"Android": "", "default": "stable"}, @@ -481,9 +487,7 @@ }, { name: "ConversionMeasurement", - origin_trial_feature_name: "ConversionMeasurement", - origin_trial_allows_third_party: true, - status: "experimental", + status: "test", }, { name: "CooperativeScheduling" @@ -1135,7 +1139,8 @@ }, { name: "Fledge", - origin_trial_feature_name: "Fledge", + origin_trial_feature_name: "PrivacySandboxAdsAPIs", + origin_trial_allows_third_party: true, }, { name: "Focusgroup", @@ -1946,6 +1951,13 @@ name: "PriorityHints", status: "stable", }, + // The RTE feature encompasses multiple APIs, including: Attribution + // Reporting, FLEDGE, and Topics. + { + name: "PrivacySandboxAdsAPIs", + origin_trial_feature_name: "PrivacySandboxAdsAPIs", + origin_trial_allows_third_party: true, + }, { name: "PrivateNetworkAccessNonSecureContextsAllowed", origin_trial_feature_name: "PrivateNetworkAccessNonSecureContextsAllowed", @@ -2313,6 +2325,8 @@ }, { name: "TopicsAPI", + origin_trial_feature_name: "PrivacySandboxAdsAPIs", + origin_trial_allows_third_party: true, }, // This feature allows touch dragging and a context menu to occur // simultaneously, with the assumption that the menu is non-modal. Without
diff --git a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc index 1b26c221..ffc431d4 100644 --- a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc +++ b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
@@ -481,8 +481,8 @@ SkIRect canvas_clip = canvas->getDeviceClipBounds(); gfx::Rect viewport = gfx::SkIRectToRect(canvas_clip); - gfx::Transform transform(gfx::Transform::kSkipInitialization); - transform.matrix() = canvas->getTotalMatrix(); // Converts 3x3 matrix to 4x4. + // Converts 3x3 matrix to 4x4. + gfx::Transform transform(canvas->getTotalMatrix()); // We will resize the Display to ensure it covers the entire |viewport|, so // save it for later.
diff --git a/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc b/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc index ccc5a611..559b06f 100644 --- a/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc +++ b/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc
@@ -215,7 +215,7 @@ } SkCanvas canvas(bitmap); canvas.clipRect(gfx::RectToSkRect(params->clip)); - canvas.concat(SkMatrix(params->transform.matrix())); + canvas.concat(params->transform.matrix().asM33()); layer_tree_frame_sink_->DemandDrawSw(&canvas); }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index f29cee1..bccd58c 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -6335,7 +6335,7 @@ crbug.com/1201365 virtual/portals/http/tests/inspector-protocol/portals/device-emulation-portals.js [ Pass Timeout ] # Sheriff 2021-04-22 -crbug.com/1191990 [ Linux ] http/tests/serviceworker/clients-openwindow.html [ Failure Pass ] +crbug.com/1191990 http/tests/serviceworker/clients-openwindow.html [ Failure Pass ] # Sheriff 2021-04-23 crbug.com/1198832 [ Linux ] external/wpt/css/css-sizing/aspect-ratio/replaced-element-003.html [ Failure Pass ] @@ -7605,7 +7605,6 @@ # Sheriff 2022-03-21: More flaky tests. crbug.com/1277696 [ Mac ] fast/loader/reload-zero-byte-plugin.html [ Failure Pass ] crbug.com/1272376 [ Mac ] plugins/plugin-document-back-forward.html [ Failure Pass ] -crbug.com/1191990 [ Mac ] http/tests/serviceworker/clients-openwindow.html [ Pass Timeout ] # Sheriff 2022-03-23: More flaky tests. crbug.com/1309483 [ Win7 ] virtual/gpu-rasterization/images/directly-composited-image-orientation.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 943d157..0ebca07f 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1052,7 +1052,7 @@ "http/tests/inspector-protocol/storage/interest-groups.js" ], "args": [ - "--enable-features=InterestGroupStorage,AdInterestGroupAPI,Fledge,FencedFrames:implementation_type/shadow_dom" + "--enable-features=InterestGroupStorage,AdInterestGroupAPI,Fledge,PrivacySandboxAdsAPIsOverride,FencedFrames:implementation_type/shadow_dom" ] }, {
diff --git a/third_party/blink/web_tests/external/wpt/loading/early-hints/404-with-early-hints.h2.window.js b/third_party/blink/web_tests/external/wpt/loading/early-hints/404-with-early-hints.h2.window.js new file mode 100644 index 0000000..f28208a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/loading/early-hints/404-with-early-hints.h2.window.js
@@ -0,0 +1,10 @@ +// META: script=/common/utils.js +// META: script=resources/early-hints-helpers.sub.js + +test(() => { + const params = new URLSearchParams(); + params.set("resource-url", + SAME_ORIGIN_RESOURCES_URL + "/square.png?" + token()); + const test_url = "resources/404-with-early-hints.h2.py?" + params.toString(); + window.location.replace(new URL(test_url, window.location)); +});
diff --git a/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/404-with-early-hints.h2.py b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/404-with-early-hints.h2.py new file mode 100644 index 0000000..bb75bc0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/404-with-early-hints.h2.py
@@ -0,0 +1,24 @@ +import os + + +def handle_headers(frame, request, response): + resource_url = request.GET.first(b"resource-url").decode() + link_header_value = "<{}>; rel=preload; as=image".format(resource_url) + early_hints = [ + (b":status", b"103"), + (b"link", link_header_value), + ] + response.writer.write_raw_header_frame(headers=early_hints, + end_headers=True) + + response.status = 404 + response.headers[b"content-type"] = "text/html" + response.write_status_headers() + + +def main(request, response): + current_dir = os.path.dirname(os.path.realpath(__file__)) + file_path = os.path.join(current_dir, "404-with-early-hints.html") + with open(file_path, "r") as f: + test_content = f.read() + response.writer.write_data(item=test_content, last=True)
diff --git a/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/404-with-early-hints.html b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/404-with-early-hints.html new file mode 100644 index 0000000..2d351b0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/404-with-early-hints.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="early-hints-helpers.sub.js"></script> +<body> +<script> +promise_test(async (t) => { + const params = new URLSearchParams(window.location.search); + const resource_url = params.get("resource-url"); + await fetchImage(resource_url); + assert_true(isPreloadedByEarlyHints(resource_url)); +}, "404 with an early hints preload."); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/early-hints-helpers.sub.js b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/early-hints-helpers.sub.js index 9eb1db3..a3e0fd58 100644 --- a/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/early-hints-helpers.sub.js +++ b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/early-hints-helpers.sub.js
@@ -45,18 +45,37 @@ } /** + * Fetches a script or an image. + * + * @param {string} element - "script" or "img". + * @param {string} url - URL of the resource. + */ +async function fetchResource(element, url) { + return new Promise((resolve, reject) => { + const el = document.createElement(element); + el.src = url; + el.onload = resolve; + el.onerror = _ => reject(new Error("Failed to fetch resource: " + url)); + document.body.appendChild(el); + }); +} + +/** * Fetches a script. * * @param {string} url */ async function fetchScript(url) { - return new Promise((resolve, reject) => { - const el = document.createElement("script"); - el.src = url; - el.onload = resolve; - el.onerror = _ => reject(new Error("Failed to fetch script")); - document.body.appendChild(el); - }); + return fetchResource("script", url); +} + +/** + * Fetches an image. + * + * @param {string} url + */ + async function fetchImage(url) { + return fetchResource("img", url); } /**
diff --git a/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/square.png b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/square.png new file mode 100644 index 0000000..01c9666a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/square.png Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/square.png.headers b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/square.png.headers new file mode 100644 index 0000000..175cdf8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/loading/early-hints/resources/square.png.headers
@@ -0,0 +1 @@ +cache-control: max-age=600
diff --git a/third_party/webrtc_overrides/field_trial.cc b/third_party/webrtc_overrides/field_trial.cc index 21883da..51f1c058 100644 --- a/third_party/webrtc_overrides/field_trial.cc +++ b/third_party/webrtc_overrides/field_trial.cc
@@ -16,9 +16,5 @@ base::StringPiece(trial_name.data(), trial_name.length())); } -std::string FindFullName(const std::string& trial_name) { - return base::FieldTrialList::FindFullName(trial_name); -} - } // namespace field_trial } // namespace webrtc
diff --git a/tools/code_coverage/create_js_source_maps/create_js_source_maps.gni b/tools/code_coverage/create_js_source_maps/create_js_source_maps.gni index 8beaac3..2812c42 100644 --- a/tools/code_coverage/create_js_source_maps/create_js_source_maps.gni +++ b/tools/code_coverage/create_js_source_maps/create_js_source_maps.gni
@@ -24,7 +24,8 @@ } } } - outputs = [ "$target_gen_dir/{{source}}.map" ] + rebased = rebase_path("{{source}}.map", root_out_dir, "/") + outputs = [ "$root_out_dir/$rebased" ] args = [ "{{source}}" ] } }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index d959489..258bfea 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -7630,6 +7630,11 @@ <int value="5" label="User cancelled the bubble"/> </enum> +<enum name="AutofillVirtualCardEnrollmentStrikeDatabaseEvent"> + <int value="0" label="One strike logged"/> + <int value="1" label="All strikes cleared"/> +</enum> + <enum name="AutofillVirtualCardManualFallbackBubbleFieldClicked"> <int value="0" label="Card number"/> <int value="1" label="Expiration month"/> @@ -37587,6 +37592,8 @@ <int value="4184" label="ComputePressureObserver_Unobserve"/> <int value="4185" label="ComputePressureObserver_Disconnect"/> <int value="4186" label="ComputePressureObserver_TakeRecords"/> + <int value="4187" label="PrivacySandboxAdsAPIs"/> + <int value="4188" label="Fledge"/> </enum> <enum name="FeaturePolicyAllowlistType"> @@ -44783,6 +44790,8 @@ <int value="9" label="Fault bit set during boot"/> <int value="10" label="MCU flash update failed"/> <int value="11" label="SPI flash update failed"/> + <int value="12" label="MCU flash update sent but requested again on reboot"/> + <int value="13" label="SPI flash update sent but requested again on reboot"/> </enum> <enum name="HrefTranslatePrefsFilterStatus"> @@ -51848,6 +51857,7 @@ <int value="-2020024440" label="scroll-end-effect"/> <int value="-2018579114" label="ImprovedKeyboardShortcuts:enabled"/> <int value="-2017953534" label="enable-hosted-app-shim-creation"/> + <int value="-2017821808" label="PrivacySandboxAdsAPIsOverride:disabled"/> <int value="-2017778637" label="PrintSaveToDrive:disabled"/> <int value="-2015293660" label="AccessibilityExposeDisplayNone:disabled"/> <int value="-2014948560" label="TabGroupsAutoCreate:enabled"/> @@ -55388,6 +55398,7 @@ <int value="399177140" label="FillingPasswordsFromAnyOrigin:enabled"/> <int value="399398207" label="OmniboxUIExperimentVerticalMarginLimitToNonTouchOnly:enabled"/> + <int value="400239639" label="PrivacySandboxAdsAPIsOverride:enabled"/> <int value="400272381" label="LazyFrameLoading:disabled"/> <int value="400322063" label="ash-disable-screen-orientation-lock"/> <int value="401606992" label="AnimatedImageResume:enabled"/> @@ -81931,6 +81942,10 @@ <int value="9" label="Dialog Off, Managed, Enabled"/> <int value="10" label="Dialog Off, Managed, Disabled"/> <int value="11" label="Dialog Off, User is restricted"/> + <int value="12" label="Dialog Off, Manually Controlled, Enabled"/> + <int value="13" label="Dialog Off, Manually Controlled, Disabled"/> + <int value="14" label="Dialog not required, Enabled"/> + <int value="15" label="Dialog not required, Disabled"/> </enum> <enum name="SettingsResetPromptConfigError">
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml index 53ac9c9..59837ed 100644 --- a/tools/metrics/histograms/metadata/autofill/histograms.xml +++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -3610,6 +3610,21 @@ variants="Autofill.VirtualCardEnrollmentSource"/> </histogram> +<histogram + name="Autofill.VirtualCardEnrollmentStrikeDatabase.{EnrollmentSource}" + enum="AutofillVirtualCardEnrollmentStrikeDatabaseEvent" + expires_after="2023-04-01"> + <owner>alexandertekle@google.com</owner> + <owner>payments-autofill-team@google.com</owner> + <summary> + Logged when a strike is registered in the virtual card enrollment strike + database because a user rejects the bubble, or when strikes are cleared + because the user accepted enrollment. + </summary> + <token key="EnrollmentSource" + variants="Autofill.VirtualCardEnrollmentSource"/> +</histogram> + <histogram name="Autofill.VirtualCardManualFallbackBubble.FieldClicked" enum="AutofillVirtualCardManualFallbackBubbleFieldClicked" expires_after="2023-04-01">
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 24e10b80..335bdce 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -13,8 +13,8 @@ "remote_path": "perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell" }, "mac": { - "hash": "815295f9d6329edb5a5a0b64c04637417b2d8dd5", - "remote_path": "perfetto_binaries/trace_processor_shell/mac/8c8fafb6ff4b4a715b868915840fc95040290ef7/trace_processor_shell" + "hash": "647302801554811912ab7fedb81e5455625a9303", + "remote_path": "perfetto_binaries/trace_processor_shell/mac/d89b25832b668dcf2d55bccbfb57f9a24723b869/trace_processor_shell" }, "mac_arm64": { "hash": "c0397e87456ad6c6a7aa0133e5b81c97adbab4ab",
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index 6a31e56..8b525dcd 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc
@@ -472,7 +472,7 @@ } void Canvas::Transform(const gfx::Transform& transform) { - canvas_->concat(SkMatrix(transform.matrix())); + canvas_->concat(transform.matrix().asM33()); } SkBitmap Canvas::GetBitmap() const {
diff --git a/ui/gfx/geometry/matrix44.cc b/ui/gfx/geometry/matrix44.cc index 4afa537..ced4c6d 100644 --- a/ui/gfx/geometry/matrix44.cc +++ b/ui/gfx/geometry/matrix44.cc
@@ -1054,41 +1054,32 @@ /////////////////////////////////////////////////////////////////////////////// -static void initFromMatrix(SkScalar dst[4][4], const SkMatrix& src) { - dst[0][0] = src[SkMatrix::kMScaleX]; - dst[1][0] = src[SkMatrix::kMSkewX]; - dst[2][0] = 0; - dst[3][0] = src[SkMatrix::kMTransX]; - dst[0][1] = src[SkMatrix::kMSkewY]; - dst[1][1] = src[SkMatrix::kMScaleY]; - dst[2][1] = 0; - dst[3][1] = src[SkMatrix::kMTransY]; - dst[0][2] = 0; - dst[1][2] = 0; - dst[2][2] = 1; - dst[3][2] = 0; - dst[0][3] = src[SkMatrix::kMPersp0]; - dst[1][3] = src[SkMatrix::kMPersp1]; - dst[2][3] = 0; - dst[3][3] = src[SkMatrix::kMPersp2]; -} - Matrix44::Matrix44(const SkMatrix& src) { - this->operator=(src); -} - -Matrix44& Matrix44::operator=(const SkMatrix& src) { - initFromMatrix(fMat, src); + fMat[0][0] = src[SkMatrix::kMScaleX]; + fMat[1][0] = src[SkMatrix::kMSkewX]; + fMat[2][0] = 0; + fMat[3][0] = src[SkMatrix::kMTransX]; + fMat[0][1] = src[SkMatrix::kMSkewY]; + fMat[1][1] = src[SkMatrix::kMScaleY]; + fMat[2][1] = 0; + fMat[3][1] = src[SkMatrix::kMTransY]; + fMat[0][2] = 0; + fMat[1][2] = 0; + fMat[2][2] = 1; + fMat[3][2] = 0; + fMat[0][3] = src[SkMatrix::kMPersp0]; + fMat[1][3] = src[SkMatrix::kMPersp1]; + fMat[2][3] = 0; + fMat[3][3] = src[SkMatrix::kMPersp2]; if (src.isIdentity()) { this->setTypeMask(kIdentity_Mask); } else { this->recomputeTypeMask(); } - return *this; } -Matrix44::operator SkMatrix() const { +SkMatrix Matrix44::asM33() const { SkMatrix dst; dst[SkMatrix::kMScaleX] = fMat[0][0];
diff --git a/ui/gfx/geometry/matrix44.h b/ui/gfx/geometry/matrix44.h index 7cf337d..df8864be 100644 --- a/ui/gfx/geometry/matrix44.h +++ b/ui/gfx/geometry/matrix44.h
@@ -49,6 +49,13 @@ // This is the underlying data structure of Transform. Don't use this type // directly. The public methods can be called through Transform::matrix(). +// +// This class was originally SkMatrix44, then moved into Chromium as +// skia::Matrix44, then moved here. For now this class mostly follows the +// Skia coding style, especially the naming convention. This is to make the +// API of this class similar to SkM44 to ease experiment with different +// underlying matrix data structure of Transform. +// class GEOMETRY_SKIA_EXPORT Matrix44 { public: enum Uninitialized_Constructor { kUninitialized_Constructor }; @@ -111,15 +118,10 @@ * [ g h i ] [ 0 0 1 0 ] * [ g h 0 i ] */ - explicit Matrix44(const SkMatrix&); - Matrix44& operator=(const SkMatrix& src); + explicit Matrix44(const SkMatrix& sk_matrix); - // TODO: make this explicit (will need to guard that change to update chrome, - // etc. -#ifndef SK_SUPPORT_LEGACY_IMPLICIT_CONVERSION_MATRIX44 - explicit -#endif - operator SkMatrix() const; + // Inverse conversion of the above. + SkMatrix asM33() const; /** * Return a reference to a const identity matrix
diff --git a/ui/gfx/geometry/transform.cc b/ui/gfx/geometry/transform.cc index 52f76fd..e132843 100644 --- a/ui/gfx/geometry/transform.cc +++ b/ui/gfx/geometry/transform.cc
@@ -477,7 +477,7 @@ return; SkRect src = RectFToSkRect(*rect); - SkMatrix(matrix_).mapRect(&src); + matrix_.asM33().mapRect(&src); *rect = SkRectToRectF(src); } @@ -490,7 +490,7 @@ return false; SkRect src = RectFToSkRect(*rect); - SkMatrix(inverse).mapRect(&src); + inverse.asM33().mapRect(&src); *rect = SkRectToRectF(src); return true; } @@ -501,7 +501,7 @@ // SkMatrix::preservesAxisAlignment is stricter (it lacks the kEpsilon // test). So after converting our Matrix44 to SkMatrix, round // relevant values less than kEpsilon to zero. - SkMatrix rounded_matrix(matrix_); + SkMatrix rounded_matrix = matrix_.asM33(); if (std::abs(rounded_matrix.get(SkMatrix::kMScaleX)) < kEpsilon) rounded_matrix.set(SkMatrix::kMScaleX, 0.0f); if (std::abs(rounded_matrix.get(SkMatrix::kMSkewX)) < kEpsilon)
diff --git a/ui/ozone/platform/wayland/common/wayland_util.cc b/ui/ozone/platform/wayland/common/wayland_util.cc index 8823a54..d9ca7d33 100644 --- a/ui/ozone/platform/wayland/common/wayland_util.cc +++ b/ui/ozone/platform/wayland/common/wayland_util.cc
@@ -301,7 +301,7 @@ gfx::Transform transform; transform.Scale(sk_scale, sk_scale); SkPath path_in_dips; - path_in_pixels.transform(SkMatrix(transform.matrix()), &path_in_dips); + path_in_pixels.transform(transform.matrix().asM33(), &path_in_dips); return path_in_dips; }
diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc index 430fe26..8bc7bd90d5 100644 --- a/ui/ozone/platform/x11/x11_window.cc +++ b/ui/ozone/platform/x11/x11_window.cc
@@ -924,7 +924,7 @@ SkPath path_in_dip; if (native_region.getBoundaryPath(&path_in_dip)) { SkPath path_in_pixels; - path_in_dip.transform(SkMatrix(transform.matrix()), &path_in_pixels); + path_in_dip.transform(transform.matrix().asM33(), &path_in_pixels); xregion = x11::CreateRegionFromSkPath(path_in_pixels); } else { xregion = std::make_unique<std::vector<x11::Rectangle>>();
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc index eaa5dfe..67cd135 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -5,11 +5,14 @@ #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include <algorithm> +#include <set> #include <utility> #include <vector> #include "base/bind.h" +#include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/metrics/histogram_macros.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -383,10 +386,49 @@ base::ScopedObservation<View, ViewObserver> observation_{this}; }; +class BubbleDialogDelegateView::CloseOnDeactivatePin::Pins { + public: + Pins() = default; + ~Pins() = default; + + bool is_pinned() const { return !pins_.empty(); } + + base::WeakPtr<Pins> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } + + void AddPin(CloseOnDeactivatePin* pin) { + const auto result = pins_.insert(pin); + DCHECK(result.second); + } + + void RemovePin(CloseOnDeactivatePin* pin) { + const auto result = pins_.erase(pin); + DCHECK(result); + } + + protected: + std::set<CloseOnDeactivatePin*> pins_; + base::WeakPtrFactory<Pins> weak_ptr_factory_{this}; +}; + +BubbleDialogDelegate::CloseOnDeactivatePin::CloseOnDeactivatePin( + base::WeakPtr<Pins> pins) + : pins_(pins) { + pins_->AddPin(this); +} + +BubbleDialogDelegate::CloseOnDeactivatePin::~CloseOnDeactivatePin() { + Pins* const pins = pins_.get(); + if (pins) + pins->RemovePin(this); +} + BubbleDialogDelegate::BubbleDialogDelegate(View* anchor_view, BubbleBorder::Arrow arrow, BubbleBorder::Shadow shadow) - : arrow_(arrow), shadow_(shadow) { + : arrow_(arrow), + shadow_(shadow), + close_on_deactivate_pins_( + std::make_unique<CloseOnDeactivatePin::Pins>()) { SetOwnedByWidget(true); SetAnchorView(anchor_view); SetArrow(arrow); @@ -578,6 +620,16 @@ return anchor_view_observer_->anchor_view(); } +bool BubbleDialogDelegate::ShouldCloseOnDeactivate() const { + return close_on_deactivate_ && !close_on_deactivate_pins_->is_pinned(); +} + +std::unique_ptr<BubbleDialogDelegate::CloseOnDeactivatePin> +BubbleDialogDelegate::PreventCloseOnDeactivate() { + return base::WrapUnique( + new CloseOnDeactivatePin(close_on_deactivate_pins_->GetWeakPtr())); +} + void BubbleDialogDelegate::SetHighlightedButton(Button* highlighted_button) { bool visible = GetWidget() && GetWidget()->IsVisible(); // If the Widget is visible, ensure the old highlight (if any) is removed @@ -857,7 +909,7 @@ } void BubbleDialogDelegate::OnDeactivate() { - if (close_on_deactivate_ && GetWidget()) + if (ShouldCloseOnDeactivate() && GetWidget()) GetWidget()->CloseWithReason(views::Widget::ClosedReason::kLostFocus); }
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.h b/ui/views/bubble/bubble_dialog_delegate_view.h index 954927f..393c58d 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.h +++ b/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -10,6 +10,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "build/build_config.h" #include "ui/accessibility/ax_enums.mojom-forward.h" #include "ui/base/class_property.h" @@ -144,10 +145,35 @@ // Miscellaneous bubble behaviors: // + // Represents a pin that prevents a widget from closing on deactivation, even + // if `close_on_deactivate` is set to true. Prevents closing on deactivation + // until its destruction; if it outlives the widget it does nothing. + class VIEWS_EXPORT CloseOnDeactivatePin { + public: + virtual ~CloseOnDeactivatePin(); + + CloseOnDeactivatePin(const CloseOnDeactivatePin&) = delete; + void operator=(const CloseOnDeactivatePin&) = delete; + + private: + class Pins; + friend class BubbleDialogDelegate; + explicit CloseOnDeactivatePin(base::WeakPtr<Pins> pins); + + const base::WeakPtr<Pins> pins_; + }; + // Whether the bubble closes when it ceases to be the active window. - bool close_on_deactivate() const { return close_on_deactivate_; } void set_close_on_deactivate(bool close) { close_on_deactivate_ = close; } + // Returns whether the bubble should close on deactivation. May not match + // `close_on_deactivate` if PreventCloseOnDeactivate() has been called. + bool ShouldCloseOnDeactivate() const; + + // Prevents close-on-deactivate for the duration of the lifetime of the pin + // that is returned. The pin does nothing after the widget is closed. + std::unique_ptr<CloseOnDeactivatePin> PreventCloseOnDeactivate(); + // Explicitly set the button to automatically highlight when the bubble is // shown. By default the anchor is highlighted, if it is a button. // @@ -360,6 +386,7 @@ // A flag controlling bubble closure on deactivation. bool close_on_deactivate_ = true; + std::unique_ptr<CloseOnDeactivatePin::Pins> close_on_deactivate_pins_; // Whether the |anchor_widget_| (or the |highlighted_button_tracker_|, when // provided) should be highlighted when this bubble is shown.
diff --git a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc index 8ce56ef..d8e01cd 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -521,6 +521,79 @@ } } +TEST_F(BubbleDialogDelegateViewTest, PinBlocksCloseOnDeactivate) { + std::unique_ptr<Widget> anchor_widget = + CreateTestWidget(Widget::InitParams::TYPE_WINDOW); + BubbleDialogDelegateView* bubble_delegate = + new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); + bubble_delegate->set_close_on_deactivate(true); + Widget* bubble_widget = + BubbleDialogDelegateView::CreateBubble(bubble_delegate); + + // Pin the bubble so it does not go away on loss of focus. + auto pin = bubble_delegate->PreventCloseOnDeactivate(); + bubble_widget->Show(); + anchor_widget->Activate(); + EXPECT_FALSE(bubble_widget->IsClosed()); + + // Unpin the window. The next time the bubble loses activation, it should + // close as expected. + pin.reset(); + bubble_widget->Activate(); + EXPECT_FALSE(bubble_widget->IsClosed()); + anchor_widget->Activate(); + EXPECT_TRUE(bubble_widget->IsClosed()); +} + +TEST_F(BubbleDialogDelegateViewTest, CloseOnDeactivatePinCanOutliveBubble) { + std::unique_ptr<Widget> anchor_widget = + CreateTestWidget(Widget::InitParams::TYPE_WINDOW); + BubbleDialogDelegateView* bubble_delegate = + new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); + bubble_delegate->set_close_on_deactivate(true); + Widget* bubble_widget = + BubbleDialogDelegateView::CreateBubble(bubble_delegate); + + // Pin the bubble so it does not go away on loss of focus. + auto pin = bubble_delegate->PreventCloseOnDeactivate(); + bubble_widget->Show(); + anchor_widget->Activate(); + EXPECT_FALSE(bubble_widget->IsClosed()); + bubble_widget->CloseNow(); + pin.reset(); +} + +TEST_F(BubbleDialogDelegateViewTest, MultipleCloseOnDeactivatePins) { + std::unique_ptr<Widget> anchor_widget = + CreateTestWidget(Widget::InitParams::TYPE_WINDOW); + BubbleDialogDelegateView* bubble_delegate = + new TestBubbleDialogDelegateView(anchor_widget->GetContentsView()); + bubble_delegate->set_close_on_deactivate(true); + Widget* bubble_widget = + BubbleDialogDelegateView::CreateBubble(bubble_delegate); + + // Pin the bubble so it does not go away on loss of focus. + auto pin = bubble_delegate->PreventCloseOnDeactivate(); + auto pin2 = bubble_delegate->PreventCloseOnDeactivate(); + bubble_widget->Show(); + anchor_widget->Activate(); + + // Unpinning one pin does not reset the state; both must be unpinned. + pin.reset(); + bubble_widget->Activate(); + EXPECT_FALSE(bubble_widget->IsClosed()); + anchor_widget->Activate(); + EXPECT_FALSE(bubble_widget->IsClosed()); + + // Fully unpin the window. The next time the bubble loses activation, + // it should close as expected. + pin2.reset(); + bubble_widget->Activate(); + EXPECT_FALSE(bubble_widget->IsClosed()); + anchor_widget->Activate(); + EXPECT_TRUE(bubble_widget->IsClosed()); +} + TEST_F(BubbleDialogDelegateViewTest, CustomTitle) { std::unique_ptr<Widget> anchor_widget = CreateTestWidget(Widget::InitParams::TYPE_WINDOW);
diff --git a/ui/views/cocoa/drag_drop_client_mac_unittest.mm b/ui/views/cocoa/drag_drop_client_mac_unittest.mm index 01b1c29..c2007da6 100644 --- a/ui/views/cocoa/drag_drop_client_mac_unittest.mm +++ b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -145,10 +145,6 @@ return ui::DragDropTypes::DRAG_COPY; } - DragOperation OnPerformDrop(const ui::DropTargetEvent& event) override { - return DragOperation::kMove; - } - views::View::DropCallback GetDropCallback( const ui::DropTargetEvent& event) override { return base::BindOnce([](const ui::DropTargetEvent& event, @@ -323,12 +319,6 @@ DragDropCloseView(const DragDropCloseView&) = delete; DragDropCloseView& operator=(const DragDropCloseView&) = delete; - // View: - DragOperation OnPerformDrop(const ui::DropTargetEvent& event) override { - ui::mojom::DragOperation output_drag_op = ui::mojom::DragOperation::kNone; - PerformDrop(event, output_drag_op); - return output_drag_op; - } views::View::DropCallback GetDropCallback( const ui::DropTargetEvent& event) override { // base::Unretained is safe here because in the tests the view isn't deleted @@ -345,7 +335,7 @@ } }; -// Tests that closing Widget on OnPerformDrop does not crash. +// Tests that closing Widget on drop does not crash. TEST_F(DragDropClientMacTest, CloseWidgetOnDrop) { OSExchangeData data; const std::u16string& text = u"text"; @@ -360,7 +350,7 @@ EXPECT_EQ(DragUpdate(nil), NSDragOperationCopy); EXPECT_EQ(Drop(), NSDragOperationMove); - // OnPerformDrop() will have deleted the widget. + // Drop callback will have deleted the widget. widget_ = nullptr; }
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc index 7b1508a..ed6ed43b 100644 --- a/ui/views/focus/focus_manager.cc +++ b/ui/views/focus/focus_manager.cc
@@ -642,7 +642,7 @@ // variable. base::WeakPtr<Widget> widget_weak_ptr = widget_->GetWeakPtr(); const bool close_widget_on_deactivate = - widget_delegate->close_on_deactivate(); + widget_delegate->ShouldCloseOnDeactivate(); #endif // The parent view must be focused for it to process events.
diff --git a/ui/views/view.cc b/ui/views/view.cc index a77ad92b..c9e0779 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -1167,8 +1167,7 @@ SkFloatToScalar(paint_info.paint_recording_scale_x()), SkFloatToScalar(paint_info.paint_recording_scale_y())); - clip_path_in_parent.transform( - SkMatrix(to_parent_recording_space.matrix())); + clip_path_in_parent.transform(to_parent_recording_space.matrix().asM33()); clip_recorder.ClipPathWithAntiAliasing(clip_path_in_parent); } } @@ -1826,10 +1825,6 @@ void View::OnDragExited() {} -ui::mojom::DragOperation View::OnPerformDrop(const ui::DropTargetEvent& event) { - return ui::mojom::DragOperation::kNone; -} - void View::OnDragDone() {} View::DropCallback View::GetDropCallback(const ui::DropTargetEvent& event) {
diff --git a/ui/views/view.h b/ui/views/view.h index f7ad6d1e..fe318cb9 100644 --- a/ui/views/view.h +++ b/ui/views/view.h
@@ -1328,7 +1328,7 @@ // OnDragEntered is sent to the view when the mouse first enters the view, // as the mouse moves around within the view OnDragUpdated is invoked. // If the user releases the mouse over the view and OnDragUpdated returns a - // valid drop, then OnPerformDrop is invoked. If the mouse moves outside the + // valid drop, then GetDropCallback is invoked. If the mouse moves outside the // view or over another view that wants the drag, OnDragExited is invoked. // // Similar to mouse events, the deepest view under the mouse is first checked @@ -1354,7 +1354,7 @@ // OnDragEntered is invoked when the mouse enters this view during a drag and // drop session and CanDrop returns true. This is immediately // followed by an invocation of OnDragUpdated, and eventually one of - // OnDragExited or OnPerformDrop. + // OnDragExited or GetDropCallback. virtual void OnDragEntered(const ui::DropTargetEvent& event); // Invoked during a drag and drop session while the mouse is over the view. @@ -1367,13 +1367,6 @@ // when the drag session was canceled and the mouse was over the view. virtual void OnDragExited(); - // Invoked during a drag and drop session when OnDragUpdated returns a valid - // operation and the user release the mouse. - // TODO(crbug.com/1175682): Remove OnPerformDrop and switch to GetDropCallback - // instead. - virtual ui::mojom::DragOperation OnPerformDrop( - const ui::DropTargetEvent& event); - // Invoked from DoDrag after the drag completes. This implementation does // nothing, and is intended for subclasses to do cleanup. virtual void OnDragDone();
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc index 9c2f483..f643d3f 100644 --- a/ui/views/view_unittest.cc +++ b/ui/views/view_unittest.cc
@@ -2932,7 +2932,7 @@ transform.Translate(1.0, 1.0); // convert to a 3x3 matrix. - const SkMatrix& matrix = SkMatrix(transform.matrix()); + SkMatrix matrix = transform.matrix().asM33(); EXPECT_EQ(210, matrix.getTranslateX()); EXPECT_EQ(-55, matrix.getTranslateY()); @@ -2953,7 +2953,7 @@ transform.ConcatTransform(t3); // convert to a 3x3 matrix - const SkMatrix& matrix = SkMatrix(transform.matrix()); + SkMatrix matrix = transform.matrix().asM33(); EXPECT_EQ(210, matrix.getTranslateX()); EXPECT_EQ(-55, matrix.getTranslateY());
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc index 1c9525d..4b0282059 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -820,7 +820,7 @@ SkPath window_mask = GetWindowMask(GetWidget()); // Convert SkPath in DIPs to pixels. if (!window_mask.isEmpty()) - window_mask.transform(SkMatrix(GetRootTransform().matrix())); + window_mask.transform(GetRootTransform().matrix().asM33()); return window_mask; }