diff --git a/BUILD.gn b/BUILD.gn index 054be18..fb616b20 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -862,7 +862,7 @@ if (toolchain_has_rust) { deps += [ "//mojo/public/rust", - "//mojo/public/rust:tests", + "//mojo/public/rust:mojo_rust_tests", ] } if (enable_rust) {
diff --git a/DEPS b/DEPS index 73137bb7..ff5a57e1 100644 --- a/DEPS +++ b/DEPS
@@ -253,23 +253,23 @@ # 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': 'b61366b54f7bc3105ea1fd4122ca38af3cdf573c', + 'skia_revision': '404c7e1b39108ae8a8fe33fdd8e65ada1c427a45', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '18423014a6b2c15a702f943784aafa25f00662f0', + 'v8_revision': 'f47485017f0d2086ad30087834cf0b1dc6cb7b5a', # 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': '19fd3bc5e74bfd6b0acd9af0445b8d46c9ba3cba', + 'angle_revision': '6cb08a2203e3f83933366f55487a887a3da00bd2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '58d1eecc2ec8b6e6d374b037c1acddf73d25f68e', + 'swiftshader_revision': '7089ef18891d212b674a56c5077e19c99c6ff586', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '52cd2170b9ad1f550764629d5820e07438627213', + 'pdfium_revision': 'efe5fd20f952e08f82046f654ab4f7dcd8f42fea', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -320,7 +320,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'd62cc7b2945f2197f62dc94aef9290848533486f', + 'catapult_revision': '4a800603ab8a7e9e2569ec63fe618501d5f8145e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -368,7 +368,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '74bd0d6136bdedcdd593988cfd20c7d9e710c250', + 'dawn_revision': 'd1c8d9fdd149b61767dc68fb0751f7e0ab1821d6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -704,7 +704,7 @@ Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248', 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + '2e203922c2ce00e482285868720a34ab0eaff613', + 'url': Var('chromium_git') + '/website.git' + '@' + 'b1ba8148df8bf7cef2f31ec8882381688780f334', }, 'src/ios/third_party/earl_grey2/src': { @@ -1131,7 +1131,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c0af61c8dd0fee6a483aacbf64a57d46ba80355e', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4bda2abfcf6e5debf6e0463f987a8432a56e06e1', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1268,7 +1268,7 @@ }, 'src/third_party/hunspell_dictionaries': - Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '18e09b9197a3b1d771c077c530d1a4ebad04c167', + Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'ffe6214af017611f2e9e6a6874eab8ec5eb84514', 'src/third_party/icu': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '1fa4e3959ec6637182b7318ac1d382799454806d', @@ -1514,7 +1514,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '3a7d7533cecebf657e35406980bf1afb5fcd23b2', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '11de3dcf8b4e4c727906a0fb055b5493e9d2de82', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1592,7 +1592,7 @@ 'packages': [ { 'package': 'fuchsia/third_party/android/aemu/release/linux-amd64', - 'version': 'AIgTYYgmdPs_av1pbLnt22Gxu-76Czug5UIdTco3LvIC' + 'version': 'b3xywTDMiV57Y73i6_dK84wODQR2dwjLDwU021ku_MwC' }, ], 'condition': 'host_os == "linux" and checkout_fuchsia', @@ -1735,7 +1735,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '008969e4d83211e112f83143bd7932f30e4ef549', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '66557e1af3f95a70753e782224d13a6186ed0d2e', + Var('webrtc_git') + '/src.git' + '@' + 'f57d74f205e4ada2c9459353d810645ae1b8b15e', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1805,7 +1805,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ff371f589f6cf0a6722a0af47e85c3936dd71e06', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6c5b18ac58f6b9d12a32cabbb906e47a80608eac', 'condition': 'checkout_src_internal', }, @@ -1813,7 +1813,7 @@ 'packages': [ { 'package': 'chromeos_internal/assistant/ambient', - 'version': '2JMBtDZyOScy9MApnSIBxYDEYBloph9vTPpsNXbj5sIC', + 'version': 'QaQPsJVRox-LlhpeXyQF7DVWgFSyXJ9Fx7gPl6nqBmgC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1846,7 +1846,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'Y3aKDqGDNcaCVlbJG8zV2kt0Ar6wVQ3TeQKwrYGwpoQC', + 'version': 'yhcxPzgsNouEH49-qseUMUvKblP-uQcy_xK1cGxedy4C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1857,7 +1857,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'OKnx_7haPDur8NwqZ5ArrIhHD9q_pBhj4IcMscnOQGYC', + 'version': 'i_H_17jDvytnrmJzB09yjzaJvnEAt3-d_jOwIOsKKl8C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/aw_browser_policy_connector.cc b/android_webview/browser/aw_browser_policy_connector.cc index 26b77ed9..ac89bcac 100644 --- a/android_webview/browser/aw_browser_policy_connector.cc +++ b/android_webview/browser/aw_browser_policy_connector.cc
@@ -50,13 +50,9 @@ policy::key::kURLBlocklist))); // HTTP Negotiate authentication - handlers->AddHandler(std::make_unique<policy::SimpleDeprecatingPolicyHandler>( - std::make_unique<policy::SimplePolicyHandler>( - policy::key::kAuthServerWhitelist, prefs::kAuthServerAllowlist, - base::Value::Type::STRING), - std::make_unique<policy::SimplePolicyHandler>( - policy::key::kAuthServerAllowlist, prefs::kAuthServerAllowlist, - base::Value::Type::STRING))); + handlers->AddHandler(std::make_unique<policy::SimplePolicyHandler>( + policy::key::kAuthServerAllowlist, prefs::kAuthServerAllowlist, + base::Value::Type::STRING)); handlers->AddHandler(std::make_unique<policy::SimplePolicyHandler>( policy::key::kAuthAndroidNegotiateAccountType, prefs::kAuthAndroidNegotiateAccountType, base::Value::Type::STRING));
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java index dc7c2c96..dd3f383 100644 --- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java +++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java
@@ -31,6 +31,9 @@ void setForceDark(int forceDarkMode); int getForceDark(); + void setAlgorithmicDarkeningAllowed(boolean allow); + boolean isAlgorithmicDarkeningAllowed(); + @Retention(RetentionPolicy.SOURCE) @interface ForceDarkBehavior { int FORCE_DARK_ONLY = 0;
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebSettingsAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebSettingsAdapter.java index 4e61e38..53ee4787 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebSettingsAdapter.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/SupportLibWebSettingsAdapter.java
@@ -132,6 +132,27 @@ } @Override + public void setAlgorithmicDarkeningAllowed(boolean allow) { + if (!AwDarkMode.isSimplifiedDarkModeEnabled()) { + Log.w(TAG, + "setAlgorithmicDarkeningAllowed() is a no-op in an app with" + + "targetSdkVersion<T"); + return; + } + mAwSettings.setAlgorithmicDarkeningAllowed(allow); + } + + @Override + public boolean isAlgorithmicDarkeningAllowed() { + if (!AwDarkMode.isSimplifiedDarkModeEnabled()) { + Log.w(TAG, + "isAlgorithmicDarkeningAllowed() is a no-op in an app with targetSdkVersion<T"); + return false; + } + return mAwSettings.isAlgorithmicDarkeningAllowed(); + } + + @Override public void setWebAuthnSupport(int support) { // Currently a no-op while this functionality is built out. }
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 8a32ffc..fdb4e7d1 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2331,6 +2331,7 @@ "ambient/ui/jitter_calculator_unittest.cc", "ambient/ui/media_string_view_unittest.cc", "ambient/ui/photo_view_unittest.cc", + "ambient/util/ambient_util_unittest.cc", "app_menu/notification_menu_controller_unittest.cc", "app_menu/notification_menu_view_unittest.cc", "app_menu/notification_overflow_view_unittest.cc",
diff --git a/ash/ambient/model/ambient_animation_attribution_provider_unittest.cc b/ash/ambient/model/ambient_animation_attribution_provider_unittest.cc index a203b91..eb8b236 100644 --- a/ash/ambient/model/ambient_animation_attribution_provider_unittest.cc +++ b/ash/ambient/model/ambient_animation_attribution_provider_unittest.cc
@@ -110,8 +110,9 @@ : AmbientAnimationAttributionProviderTest( GenerateLottieCustomizableIdForTesting(0) + "Attribution", GenerateLottieCustomizableIdForTesting(1) + "Attribution", - GenerateLottieCustomizableIdForTesting(0) + "Asset", - GenerateLottieCustomizableIdForTesting(1) + "Asset") {} + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", /*idx=*/1), + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", + /*idx=*/2)) {} }; class AmbientAnimationAttributionProviderTest1DynamicAsset @@ -122,7 +123,8 @@ "static-text-node", GenerateLottieCustomizableIdForTesting(1) + "Attribution", "static-asset-id", - GenerateLottieCustomizableIdForTesting(1) + "Asset") {} + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", + /*idx=*/1)) {} }; TEST_F(AmbientAnimationAttributionProviderTest2DynamicAssets,
diff --git a/ash/ambient/model/ambient_animation_photo_config.cc b/ash/ambient/model/ambient_animation_photo_config.cc index 3cc90374..cc397dd 100644 --- a/ash/ambient/model/ambient_animation_photo_config.cc +++ b/ash/ambient/model/ambient_animation_photo_config.cc
@@ -6,20 +6,56 @@ #include "ash/ambient/util/ambient_util.h" #include "ash/utility/lottie_util.h" +#include "base/containers/flat_map.h" +#include "base/logging.h" +#include "base/notreached.h" #include "cc/paint/skottie_resource_metadata.h" namespace ash { namespace { -size_t GetNumDynamicAssetsInAnimation( - const cc::SkottieResourceMetadataMap& skottie_resource_metadata) { - size_t num_dynamic_assets = 0; - for (const auto& resource_pair : skottie_resource_metadata.asset_storage()) { - const std::string& asset_id = resource_pair.first; - if (IsCustomizableLottieId(asset_id)) - ++num_dynamic_assets; +void ParseDynamicAssetsIdsInAnimation( + const cc::SkottieResourceMetadataMap& skottie_resource_metadata, + std::size_t& num_total_positions_out, + std::size_t& num_assets_per_position_out) { + base::flat_map<std::string, std::size_t> position_to_num_assets; + std::string position_id; + int idx = 0; + for (const auto& [asset_id, _] : skottie_resource_metadata.asset_storage()) { + if (!IsCustomizableLottieId(asset_id)) { + DVLOG(4) << "Ignoring static image asset id"; + continue; + } + + if (!ambient::util::ParseDynamicLottieAssetId(asset_id, position_id, idx)) { + NOTREACHED() << "Lottie file contains invalid dynamic asset id " + << asset_id; + } + + auto iter = + position_to_num_assets.try_emplace(position_id, /*initial count*/ 0) + .first; + ++iter->second; } - return num_dynamic_assets; + + if (position_to_num_assets.empty()) { + num_total_positions_out = 0; + num_assets_per_position_out = 0; + return; + } + + // Currently, it's expected that all positions in the animations have the same + // number of assets assigned to it. If this fails, the animation is invalid + // and must be updated by the designer as the rest of the pipeline was not + // designed with case in mind. + num_total_positions_out = position_to_num_assets.size(); + num_assets_per_position_out = position_to_num_assets.begin()->second; + for (const auto& [position, num_assets_assigned] : position_to_num_assets) { + if (num_assets_assigned != num_assets_per_position_out) { + LOG(FATAL) << "Position " << position << " has " << num_assets_assigned + << "assets. Expected " << num_assets_per_position_out; + } + } } } // namespace @@ -28,13 +64,15 @@ const cc::SkottieResourceMetadataMap& skottie_resource_metadata) { AmbientPhotoConfig config; config.should_split_topics = true; - // Unlike the slideshow screensaver, the animated screensaver has - // motion/activity in it. So in the worst case scenario, we can repeat the - // animation cycle with the same set of image assets indefinitely and the - // screen won't burn. Hence, only 1 set of assets is required in the buffer. - config.num_topic_sets_to_buffer = 1; - config.topic_set_size = - GetNumDynamicAssetsInAnimation(skottie_resource_metadata); + + // Example: If there are 6 positions and 2 assets per position, this will + // initially prepare and buffer 6 * 2 = 12 topics. Afterwards, all future + // refreshes will prepare 6 topics, effectively giving each position a new + // topic. + ParseDynamicAssetsIdsInAnimation( + skottie_resource_metadata, + /*num_total_positions_out=*/config.topic_set_size, + /*num_assets_per_position_out=*/config.num_topic_sets_to_buffer); // Once an animation cycle starts rendering (including the very first // cycle), start preparing the next set of decoded topics for the next
diff --git a/ash/ambient/model/ambient_animation_photo_config_unittest.cc b/ash/ambient/model/ambient_animation_photo_config_unittest.cc index 36d7b793..e5a6326 100644 --- a/ash/ambient/model/ambient_animation_photo_config_unittest.cc +++ b/ash/ambient/model/ambient_animation_photo_config_unittest.cc
@@ -14,25 +14,78 @@ using ::testing::Eq; -TEST(AmbientAnimationPhotoConfigTest, SetsTopicSetSize) { +TEST(AmbientAnimationPhotoConfigTest, SetsTopicSetFields) { cc::SkottieResourceMetadataMap skottie_resource_metadata; - EXPECT_THAT(CreateAmbientAnimationPhotoConfig(skottie_resource_metadata) - .topic_set_size, - Eq(0u)); + AmbientPhotoConfig config = + CreateAmbientAnimationPhotoConfig(skottie_resource_metadata); + EXPECT_THAT(config.topic_set_size, Eq(0u)); + EXPECT_THAT(config.num_topic_sets_to_buffer, Eq(0u)); + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( "test-resource-path", "test-resource-name-0", - GenerateLottieCustomizableIdForTesting(/*unique_id=*/0), + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", /*idx=*/1), /*size=*/absl::nullopt)); - EXPECT_THAT(CreateAmbientAnimationPhotoConfig(skottie_resource_metadata) - .topic_set_size, - Eq(1u)); ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( - "test-resource-path", "test-resource-name-1", - GenerateLottieCustomizableIdForTesting(/*unique_id=*/1), + "test-resource-path", "test-resource-name-0", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"B", /*idx=*/1), /*size=*/absl::nullopt)); - EXPECT_THAT(CreateAmbientAnimationPhotoConfig(skottie_resource_metadata) - .topic_set_size, - Eq(2u)); + config = CreateAmbientAnimationPhotoConfig(skottie_resource_metadata); + EXPECT_THAT(config.topic_set_size, Eq(2u)); + EXPECT_THAT(config.num_topic_sets_to_buffer, Eq(1u)); + + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", /*idx=*/2), + /*size=*/absl::nullopt)); + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"B", /*idx=*/2), + /*size=*/absl::nullopt)); + config = CreateAmbientAnimationPhotoConfig(skottie_resource_metadata); + EXPECT_THAT(config.topic_set_size, Eq(2u)); + EXPECT_THAT(config.num_topic_sets_to_buffer, Eq(2u)); +} + +TEST(AmbientAnimationPhotoConfigTest, DoesNotCountStaticAssets) { + cc::SkottieResourceMetadataMap skottie_resource_metadata; + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", /*idx=*/1), + /*size=*/absl::nullopt)); + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"B", /*idx=*/1), + /*size=*/absl::nullopt)); + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", "StaticAssetId1", + /*size=*/absl::nullopt)); + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", "StaticAssetId2", + /*size=*/absl::nullopt)); + AmbientPhotoConfig config = + CreateAmbientAnimationPhotoConfig(skottie_resource_metadata); + EXPECT_THAT(config.topic_set_size, Eq(2u)); + EXPECT_THAT(config.num_topic_sets_to_buffer, Eq(1u)); +} + +TEST(AmbientAnimationPhotoConfigTest, FatalIfAnimationAssetIdsInvalid) { + cc::SkottieResourceMetadataMap skottie_resource_metadata; + // Position A and Position B have a different number of assets assigned to + // them. This is currently considered invalid. + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", /*idx=*/1), + /*size=*/absl::nullopt)); + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", /*idx=*/2), + /*size=*/absl::nullopt)); + ASSERT_TRUE(skottie_resource_metadata.RegisterAsset( + "test-resource-path", "test-resource-name-0", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"B", /*idx=*/1), + /*size=*/absl::nullopt)); + EXPECT_DEATH_IF_SUPPORTED( + CreateAmbientAnimationPhotoConfig(skottie_resource_metadata), ""); } } // namespace ash
diff --git a/ash/ambient/model/ambient_animation_photo_provider_unittest.cc b/ash/ambient/model/ambient_animation_photo_provider_unittest.cc index 74679a8..311ec2a 100644 --- a/ash/ambient/model/ambient_animation_photo_provider_unittest.cc +++ b/ash/ambient/model/ambient_animation_photo_provider_unittest.cc
@@ -17,6 +17,7 @@ #include "base/files/file_path.h" #include "base/memory/scoped_refptr.h" #include "base/scoped_observation.h" +#include "base/strings/string_number_conversions.h" #include "cc/paint/skottie_frame_data.h" #include "cc/paint/skottie_resource_metadata.h" #include "testing/gmock/include/gmock/gmock.h" @@ -92,10 +93,13 @@ cc::SkottieResourceMetadataMap BuildSkottieResourceMetadata() const { cc::SkottieResourceMetadataMap resource_metadata; - for (int i = 0; i < kNumDynamicAssets; ++i) { + char position_id = 'A'; + for (int i = 0; i < kNumDynamicAssets; ++i, ++position_id) { CHECK(resource_metadata.RegisterAsset( "dummy-resource-path", "dummy-resource-name", - GenerateLottieCustomizableIdForTesting(i), /*size=*/absl::nullopt)); + GenerateLottieDynamicAssetIdForTesting( + /*position=*/std::string(1, position_id), /*idx=*/1), + /*size=*/absl::nullopt)); } return resource_metadata; } @@ -122,9 +126,12 @@ std::array<absl::optional<gfx::Size>, kNumDynamicAssets> asset_sizes = std::array<absl::optional<gfx::Size>, kNumDynamicAssets>()) { std::vector<scoped_refptr<ImageAsset>> all_assets; - for (int asset_idx = 0; asset_idx < kNumDynamicAssets; ++asset_idx) { + char position_id = 'A'; + for (int asset_idx = 0; asset_idx < kNumDynamicAssets; + ++asset_idx, ++position_id) { all_assets.push_back( - LoadAsset(GenerateLottieCustomizableIdForTesting(asset_idx), + LoadAsset(GenerateLottieDynamicAssetIdForTesting( + /*position=*/std::string(1, position_id), /*idx=*/1), asset_sizes[asset_idx])); } return all_assets; @@ -403,10 +410,14 @@ EXPECT_CALL( observer, OnDynamicImageAssetsRefreshed(AllOf( - ElementsAre(Key(GenerateLottieCustomizableIdForTesting(0)), - Key(GenerateLottieCustomizableIdForTesting(1)), - Key(GenerateLottieCustomizableIdForTesting(2)), - Key(GenerateLottieCustomizableIdForTesting(3))), + ElementsAre(Key(GenerateLottieDynamicAssetIdForTesting( + /*position=*/"A", /*idx=*/1)), + Key(GenerateLottieDynamicAssetIdForTesting( + /*position=*/"B", /*idx=*/1)), + Key(GenerateLottieDynamicAssetIdForTesting( + /*position=*/"C", /*idx=*/1)), + Key(GenerateLottieDynamicAssetIdForTesting( + /*position=*/"D", /*idx=*/1))), UnorderedElementsAre(Pair(_, TopicHasDetails("attribution-a")), Pair(_, TopicHasDetails("attribution-b")), Pair(_, TopicHasDetails("attribution-c")), @@ -428,10 +439,14 @@ EXPECT_CALL( observer, OnDynamicImageAssetsRefreshed(AllOf( - ElementsAre(Key(GenerateLottieCustomizableIdForTesting(0)), - Key(GenerateLottieCustomizableIdForTesting(1)), - Key(GenerateLottieCustomizableIdForTesting(2)), - Key(GenerateLottieCustomizableIdForTesting(3))), + ElementsAre(Key(GenerateLottieDynamicAssetIdForTesting( + /*position=*/"A", /*idx=*/1)), + Key(GenerateLottieDynamicAssetIdForTesting( + /*position=*/"B", /*idx=*/1)), + Key(GenerateLottieDynamicAssetIdForTesting( + /*position=*/"C", /*idx=*/1)), + Key(GenerateLottieDynamicAssetIdForTesting( + /*position=*/"D", /*idx=*/1))), UnorderedElementsAre(Pair(_, TopicHasDetails("attribution-e")), Pair(_, TopicHasDetails("attribution-f")), Pair(_, TopicHasDetails("attribution-g")),
diff --git a/ash/ambient/test/ambient_test_util.cc b/ash/ambient/test/ambient_test_util.cc index 0e509c5..29543a1 100644 --- a/ash/ambient/test/ambient_test_util.cc +++ b/ash/ambient/test/ambient_test_util.cc
@@ -9,6 +9,7 @@ #include "base/check.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "cc/paint/skottie_resource_metadata.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -19,12 +20,21 @@ {kLottieCustomizableIdPrefix, base::NumberToString(unique_id)}); } +std::string GenerateLottieDynamicAssetIdForTesting(base::StringPiece position, + int idx) { + CHECK(!position.empty()); + return base::StringPrintf("%s_Photo_Position%s_%d", + kLottieCustomizableIdPrefix.data(), position.data(), + idx); +} + AmbientPhotoConfig GenerateAnimationConfigWithNAssets(int num_assets) { cc::SkottieResourceMetadataMap resource_metadata; for (int i = 0; i < num_assets; ++i) { CHECK(resource_metadata.RegisterAsset( "test-resource-path", "test-resource-name", - GenerateLottieCustomizableIdForTesting(/*unique_id=*/i), + GenerateLottieDynamicAssetIdForTesting( + /*position=*/base::NumberToString(i), /*idx=*/1), /*size=*/absl::nullopt)); } return CreateAmbientAnimationPhotoConfig(resource_metadata);
diff --git a/ash/ambient/test/ambient_test_util.h b/ash/ambient/test/ambient_test_util.h index f3969cc..77856a7f 100644 --- a/ash/ambient/test/ambient_test_util.h +++ b/ash/ambient/test/ambient_test_util.h
@@ -7,13 +7,21 @@ #ifndef ASH_AMBIENT_TEST_AMBIENT_TEST_UTIL_H_ #define ASH_AMBIENT_TEST_AMBIENT_TEST_UTIL_H_ +#include "base/strings/string_piece.h" + namespace ash { struct AmbientPhotoConfig; -// Generates a customizable lottie id that incorporates the |unique_id| in it. +// Generates a generic customizable lottie id that incorporates the |unique_id| +// in it. std::string GenerateLottieCustomizableIdForTesting(int unique_id); +// Generates a lottie dynamic image asset id for testing purposes (see +// ParseDynamicLottieAssetId() for details). +std::string GenerateLottieDynamicAssetIdForTesting(base::StringPiece position, + int idx); + // Returns an AmbientPhotoConfig for a lottie animation with the number of // assets specified by |num_assets|, AmbientPhotoConfig GenerateAnimationConfigWithNAssets(int num_assets);
diff --git a/ash/ambient/ui/ambient_animation_view.cc b/ash/ambient/ui/ambient_animation_view.cc index 7fe24e0..ef298ec8 100644 --- a/ash/ambient/ui/ambient_animation_view.cc +++ b/ash/ambient/ui/ambient_animation_view.cc
@@ -29,6 +29,7 @@ #include "cc/paint/skottie_wrapper.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/compositor/compositor.h" +#include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/lottie/animation.h" #include "ui/views/border.h" @@ -181,8 +182,9 @@ glanceable_info_container_->SetCrossAxisAlignment( views::BoxLayout::CrossAxisAlignment::kStart); glanceable_info_container_->SetBorder(CreateGlanceableInfoBorder()); - glanceable_info_container_->AddChildView( - std::make_unique<GlanceableInfoView>(view_delegate, kTimeFontSizeDip)); + glanceable_info_container_->AddChildView(std::make_unique<GlanceableInfoView>( + view_delegate, kTimeFontSizeDip, + /*time_temperature_font_color=*/gfx::kGoogleGrey900)); } void AmbientAnimationView::AnimationWillStartPlaying(
diff --git a/ash/ambient/ui/ambient_animation_view_unittest.cc b/ash/ambient/ui/ambient_animation_view_unittest.cc index 15e9a8e..1d6d117 100644 --- a/ash/ambient/ui/ambient_animation_view_unittest.cc +++ b/ash/ambient/ui/ambient_animation_view_unittest.cc
@@ -67,8 +67,8 @@ auto static_resources = std::make_unique<FakeAmbientAnimationStaticResources>(); static_resources->SetLottieData(cc::CreateCustomLottieDataWith2Assets( - GenerateLottieCustomizableIdForTesting(/*unique_id=*/0), - GenerateLottieCustomizableIdForTesting(/*unique_id=*/1))); + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", /*idx=*/1), + GenerateLottieDynamicAssetIdForTesting(/*position=*/"B", /*idx=*/1))); model_ = std::make_unique<AmbientBackendModel>(CreateAmbientAnimationPhotoConfig(
diff --git a/ash/ambient/ui/ambient_info_view.cc b/ash/ambient/ui/ambient_info_view.cc index d6d8ddae..cc9543e 100644 --- a/ash/ambient/ui/ambient_info_view.cc +++ b/ash/ambient/ui/ambient_info_view.cc
@@ -96,8 +96,10 @@ layout->set_between_child_spacing(kSpacingDip + shadow_insets.top() + shadow_insets.bottom()); - glanceable_info_view_ = AddChildView( - std::make_unique<GlanceableInfoView>(delegate_, kTimeFontSizeDip)); + glanceable_info_view_ = AddChildView(std::make_unique<GlanceableInfoView>( + delegate_, kTimeFontSizeDip, /*time_temperature_font_color=*/ + ambient::util::GetContentLayerColor( + AshColorProvider::ContentLayerType::kTextColorPrimary))); glanceable_info_view_->SetPaintToLayer(); details_label_ = AddLabel(this);
diff --git a/ash/ambient/ui/glanceable_info_view.cc b/ash/ambient/ui/glanceable_info_view.cc index 1ff300c..0278347e 100644 --- a/ash/ambient/ui/glanceable_info_view.cc +++ b/ash/ambient/ui/glanceable_info_view.cc
@@ -76,8 +76,11 @@ } // namespace GlanceableInfoView::GlanceableInfoView(AmbientViewDelegate* delegate, - int time_font_size_dip) - : delegate_(delegate), time_font_size_dip_(time_font_size_dip) { + int time_font_size_dip, + SkColor time_temperature_font_color) + : delegate_(delegate), + time_font_size_dip_(time_font_size_dip), + time_temperature_font_color_(time_temperature_font_color) { DCHECK(delegate); DCHECK_GT(time_font_size_dip_, 0); SetID(AmbientViewID::kAmbientGlanceableInfoView); @@ -156,10 +159,8 @@ Shell::Get()->system_tray_model()->clock())); gfx::FontList time_font_list = GetTimeFontList(time_font_size_dip_); time_view_->SetTextFont(time_font_list); - time_view_->SetTextColor( - ambient::util::GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary), - /*auto_color_readability_enabled=*/false); + time_view_->SetTextColor(time_temperature_font_color_, + /*auto_color_readability_enabled=*/false); // Remove the internal spacing in `time_view_` and adjust spacing for shadows. time_view_->SetBorder(views::CreateEmptyBorder( -kUnifiedTrayTextTopPadding, -kUnifiedTrayTimeLeftPadding, 0, @@ -180,8 +181,7 @@ // Inits the temp view. temperature_ = AddChildView(std::make_unique<views::Label>()); temperature_->SetAutoColorReadabilityEnabled(false); - temperature_->SetEnabledColor(ambient::util::GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); + temperature_->SetEnabledColor(time_temperature_font_color_); temperature_->SetFontList(GetWeatherTemperatureFontList()); temperature_->SetBorder(views::CreateEmptyBorder( 0, 0, GetFontDescent(time_font_list) - GetTemperatureFontDescent(), 0));
diff --git a/ash/ambient/ui/glanceable_info_view.h b/ash/ambient/ui/glanceable_info_view.h index 669c4ed..c51d589 100644 --- a/ash/ambient/ui/glanceable_info_view.h +++ b/ash/ambient/ui/glanceable_info_view.h
@@ -8,6 +8,7 @@ #include "ash/ambient/model/ambient_backend_model.h" #include "ash/ambient/model/ambient_backend_model_observer.h" #include "base/scoped_observation.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/views/view.h" namespace views { @@ -29,7 +30,9 @@ public: METADATA_HEADER(GlanceableInfoView); - GlanceableInfoView(AmbientViewDelegate* delegate, int time_font_size_dip); + GlanceableInfoView(AmbientViewDelegate* delegate, + int time_font_size_dip, + SkColor time_temperature_font_color); GlanceableInfoView(const GlanceableInfoView&) = delete; GlanceableInfoView& operator=(const GlanceableInfoView&) = delete; ~GlanceableInfoView() override; @@ -58,6 +61,7 @@ AmbientViewDelegate* const delegate_ = nullptr; const int time_font_size_dip_; + const SkColor time_temperature_font_color_; base::ScopedObservation<AmbientBackendModel, AmbientBackendModelObserver> scoped_backend_model_observer_{this};
diff --git a/ash/ambient/util/ambient_util.cc b/ash/ambient/util/ambient_util.cc index 1110fad..b498dfe 100644 --- a/ash/ambient/util/ambient_util.cc +++ b/ash/ambient/util/ambient_util.cc
@@ -10,7 +10,10 @@ #include "ash/public/cpp/ambient/ambient_client.h" #include "ash/public/cpp/ambient/proto/photo_cache_entry.pb.h" #include "ash/style/ash_color_provider.h" +#include "ash/utility/lottie_util.h" #include "base/no_destructor.h" +#include "base/strings/strcat.h" +#include "third_party/re2/src/re2/re2.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/color/color_id.h" #include "ui/color/color_provider.h" @@ -90,6 +93,17 @@ } } +bool ParseDynamicLottieAssetId(base::StringPiece asset_id, + std::string& position_id, + int& idx) { + static const base::NoDestructor<std::string> kAssetIdPatternStr( + base::StrCat({kLottieCustomizableIdPrefix, + R"(_Photo_Position([[:alnum:]]+)_([[:digit:]]+).*)"})); + static const base::NoDestructor<RE2> kAssetIdPattern( + kAssetIdPatternStr->data()); + return RE2::FullMatch(asset_id.data(), *kAssetIdPattern, &position_id, &idx); +} + } // namespace util } // namespace ambient } // namespace ash
diff --git a/ash/ambient/util/ambient_util.h b/ash/ambient/util/ambient_util.h index 32d4d515..fae607dd2 100644 --- a/ash/ambient/util/ambient_util.h +++ b/ash/ambient/util/ambient_util.h
@@ -5,11 +5,14 @@ #ifndef ASH_AMBIENT_UTIL_AMBIENT_UTIL_H_ #define ASH_AMBIENT_UTIL_AMBIENT_UTIL_H_ +#include <string> + #include "ash/ash_export.h" #include "ash/login/ui/lock_screen.h" #include "ash/public/cpp/ambient/ambient_backend_controller.h" #include "ash/public/cpp/ambient/proto/photo_cache_entry.pb.h" #include "ash/style/ash_color_provider.h" +#include "base/strings/string_piece.h" #include "ui/gfx/font_list.h" #include "ui/gfx/shadow_value.h" @@ -42,6 +45,36 @@ ASH_EXPORT bool IsAmbientModeTopicTypeAllowed(::ambient::TopicType topic); +// A "dynamic" asset is a placeholder in an ambient Lottie animation where a +// photo of interest goes (ex: from a user’s google photos album). This +// contrasts with a "static" asset, which is a fixed image in the animation that +// does not change between animation cycles. +// +// The dynamic asset ids for ambient mode take the following format: +// "_CrOS_Photo_Position<position_id>_<idx>". +// +// A "position" represents a physical location on the screen where a photo +// appears. Its identifier is arbitrary and opaque. But there may be multiple +// assets assigned to a given position. For example, if an animation has a +// cross-fade transition from image 1 to image 2, there may be 2 image assets +// in the animation that share the same position id. However, their indices +// (the last element of the identifier) will be different. Example: +// "_CrOS_Photo_PositionA_1" +// "_CrOS_Photo_PositionA_2" +// ... +// +// The only requirement for the index is that it must reflect the order in which +// that asset appears at its position. The absolute index values do not matter. +// +// Note this naming convention is agreed upon with the animation designer, so +// any changes to the logic must be confirmed with them. +// +// Returns false and leaves the output arguments untouched if the |asset_id| +// does not match the naming convention above. +ASH_EXPORT bool ParseDynamicLottieAssetId(base::StringPiece asset_id, + std::string& position_id, + int& idx); + } // namespace util } // namespace ambient } // namespace ash
diff --git a/ash/ambient/util/ambient_util_unittest.cc b/ash/ambient/util/ambient_util_unittest.cc new file mode 100644 index 0000000..2d1e85d --- /dev/null +++ b/ash/ambient/util/ambient_util_unittest.cc
@@ -0,0 +1,48 @@ +// 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 "ash/ambient/util/ambient_util.h" + +#include <string> + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { +namespace ambient { +namespace util { +namespace { +using ::testing::Eq; +} // namespace + +TEST(AmbientUtilTest, ParseDynamicLottieAssetId) { + std::string position; + int idx = 0; + EXPECT_FALSE(ParseDynamicLottieAssetId("StaticAsset", position, idx)); + EXPECT_FALSE(ParseDynamicLottieAssetId("_CrOS_UnknownAsset", position, idx)); + ASSERT_TRUE( + ParseDynamicLottieAssetId("_CrOS_Photo_PositionA_1", position, idx)); + EXPECT_THAT(position, Eq("A")); + EXPECT_THAT(idx, Eq(1)); + ASSERT_TRUE( + ParseDynamicLottieAssetId("_CrOS_Photo_PositionB_1", position, idx)); + EXPECT_THAT(position, Eq("B")); + EXPECT_THAT(idx, Eq(1)); + ASSERT_TRUE(ParseDynamicLottieAssetId("_CrOS_Photo_PositionTopLeft_1", + position, idx)); + EXPECT_THAT(position, Eq("TopLeft")); + EXPECT_THAT(idx, Eq(1)); + ASSERT_TRUE(ParseDynamicLottieAssetId("_CrOS_Photo_PositionTopRight_2", + position, idx)); + EXPECT_THAT(position, Eq("TopRight")); + EXPECT_THAT(idx, Eq(2)); + ASSERT_TRUE( + ParseDynamicLottieAssetId("_CrOS_Photo_PositionA_1.png", position, idx)); + EXPECT_THAT(position, Eq("A")); + EXPECT_THAT(idx, Eq(1)); +} + +} // namespace util +} // namespace ambient +} // namespace ash
diff --git a/ash/app_list/views/productivity_launcher_search_view.cc b/ash/app_list/views/productivity_launcher_search_view.cc index 05c8976..bd7b5ab 100644 --- a/ash/app_list/views/productivity_launcher_search_view.cc +++ b/ash/app_list/views/productivity_launcher_search_view.cc
@@ -18,9 +18,11 @@ #include "ash/constants/ash_features.h" #include "ash/controls/rounded_scroll_bar.h" #include "ash/public/cpp/app_list/app_list_color_provider.h" +#include "ash/public/cpp/app_list/app_list_features.h" #include "ash/strings/grit/ash_strings.h" #include "base/bind.h" #include "base/check.h" +#include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "base/strings/string_number_conversions.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -47,6 +49,11 @@ // Insets for the vertical scroll bar. constexpr gfx::Insets kVerticalScrollInsets(1, 0, 1, 1); +// The amount of time after search result animations are preempted during which +// result animations should be sped up. +constexpr base::TimeDelta kForcedFastAnimationInterval = + base::Milliseconds(500); + } // namespace ProductivityLauncherSearchView::ProductivityLauncherSearchView( @@ -169,6 +176,28 @@ if (search_box_view_->HasSearch()) { using AnimationInfo = SearchResultContainerView::ResultsAnimationInfo; AnimationInfo aggregate_animation_info; + // Search result changes within `kForcedFastAnimationInterval` of + // `search_result_fast_update_time_` should also use fast animations and + // refresh the timestamp. + if (search_result_fast_update_time_.has_value() && + app_list_features::IsDynamicSearchUpdateAnimationEnabled()) { + const base::TimeDelta time_since_last_update = + base::TimeTicks::Now() - search_result_fast_update_time_.value(); + if (time_since_last_update < kForcedFastAnimationInterval) { + aggregate_animation_info.use_short_animations = true; + } + } + if (!aggregate_animation_info.use_short_animations && + app_list_features::IsDynamicSearchUpdateAnimationEnabled()) { + // Scan result_container_views_ to see if there are any in progress + // animations that would be preempted. + for (SearchResultContainerView* view : result_container_views_) { + if (view->HasAnimatingChildView()) { + aggregate_animation_info.use_short_animations = true; + } + } + } + for (SearchResultContainerView* view : result_container_views_) { absl::optional<AnimationInfo> container_animation_info = view->ScheduleResultAnimations(aggregate_animation_info); @@ -182,6 +211,14 @@ first_result_view = view->GetFirstResultView(); } } + // Update the `search_result_fast_update_time_` if fast animations were + // used. + if (aggregate_animation_info.use_short_animations) + search_result_fast_update_time_ = base::TimeTicks::Now(); + + // Records metrics on whether shortened search animations were used. + base::UmaHistogramBoolean("Ash.SearchResultUpdateAnimationShortened", + aggregate_animation_info.use_short_animations); } Layout();
diff --git a/ash/app_list/views/productivity_launcher_search_view.h b/ash/app_list/views/productivity_launcher_search_view.h index 0c13c29..7a5274b 100644 --- a/ash/app_list/views/productivity_launcher_search_view.h +++ b/ash/app_list/views/productivity_launcher_search_view.h
@@ -125,6 +125,9 @@ // Timer used to delay calls to NotifyA11yResultsChanged(). base::OneShotTimer notify_a11y_results_changed_timer_; + // Stores the last time fast search result update animations were used. + absl::optional<base::TimeTicks> search_result_fast_update_time_; + // The last reported number of search results shown by all containers. int last_search_result_count_ = 0; };
diff --git a/ash/app_list/views/search_result_container_view.cc b/ash/app_list/views/search_result_container_view.cc index 0b1a5a2..061d9c8a 100644 --- a/ash/app_list/views/search_result_container_view.cc +++ b/ash/app_list/views/search_result_container_view.cc
@@ -41,6 +41,11 @@ return absl::nullopt; } +bool SearchResultContainerView::HasAnimatingChildView() { + NOTREACHED(); + return false; +} + void SearchResultContainerView::Update() { update_factory_.InvalidateWeakPtrs(); num_results_ = DoUpdate();
diff --git a/ash/app_list/views/search_result_container_view.h b/ash/app_list/views/search_result_container_view.h index cbd97c5..2db0709 100644 --- a/ash/app_list/views/search_result_container_view.h +++ b/ash/app_list/views/search_result_container_view.h
@@ -64,6 +64,9 @@ // The number of views that are animating (either title or result views). int animating_views = 0; + + // Whether fast search result update animations should be used. + bool use_short_animations = false; }; // Schedules animations for result list updates. Expected to be implemented @@ -75,6 +78,9 @@ virtual absl::optional<ResultsAnimationInfo> ScheduleResultAnimations( const ResultsAnimationInfo& aggregate_animation_info); + // Returns whether the container view has any animating child views. + virtual bool HasAnimatingChildView(); + bool horizontally_traversable() const { return horizontally_traversable_; } // Allows a container to define its traversal behavior
diff --git a/ash/app_list/views/search_result_list_view.cc b/ash/app_list/views/search_result_list_view.cc index b2ebedf9..a9024cc7 100644 --- a/ash/app_list/views/search_result_list_view.cc +++ b/ash/app_list/views/search_result_list_view.cc
@@ -62,6 +62,8 @@ constexpr static base::TimeDelta kIdentityTranslationDuration = base::Milliseconds(200); +constexpr static base::TimeDelta kFastFadeInDuration = base::Milliseconds(0); + // TODO(crbug.com/1199206): Move this into SharedAppListConfig once the UI for // categories is more developed. constexpr size_t kMaxResultsWithCategoricalSearch = 3; @@ -314,8 +316,10 @@ auto schedule_animation = [this, ¤t_animation_info, &aggregate_animation_info](views::View* view) { - ShowViewWithAnimation(view, current_animation_info.total_views + - aggregate_animation_info.total_views); + ShowViewWithAnimation(view, + current_animation_info.total_views + + aggregate_animation_info.total_views, + current_animation_info.use_short_animations); ++current_animation_info.animating_views; }; @@ -344,10 +348,29 @@ return current_animation_info; } +bool SearchResultListView::HasAnimatingChildView() { + auto is_animating = [](views::View* view) { + return (view->GetVisible() && view->layer() && + view->layer()->GetAnimator() && + view->layer()->GetAnimator()->is_animating()); + }; + + if (is_animating(title_label_)) + return true; + + for (size_t i = 0; i < search_result_views_.size(); ++i) { + if (is_animating(GetResultViewAt(i))) + return true; + } + return false; +} + void SearchResultListView::ShowViewWithAnimation(views::View* view, - int position) { - // Abort any in-progress layer animation. + int position, + bool use_short_animations) { DCHECK(view->layer()->GetAnimator()); + + // Abort any in-progress layer animation. view->layer()->GetAnimator()->AbortAllAnimations(); // Animation spec: @@ -372,9 +395,12 @@ .SetTransform(view, translate_down) .Then() .SetOpacity(view, 1.0f, gfx::Tween::LINEAR) - .SetDuration(kFadeInDuration) + .SetDuration(use_short_animations ? kFastFadeInDuration : kFadeInDuration) .At(base::TimeDelta()) - .SetDuration(kIdentityTranslationDuration) + .SetDuration( + use_short_animations + ? app_list_features::DynamicSearchUpdateAnimationDuration() + : kIdentityTranslationDuration) .SetTransform(view, gfx::Transform(), gfx::Tween::LINEAR_OUT_SLOW_IN); }
diff --git a/ash/app_list/views/search_result_list_view.h b/ash/app_list/views/search_result_list_view.h index 74982f6a..f02f6491e 100644 --- a/ash/app_list/views/search_result_list_view.h +++ b/ash/app_list/views/search_result_list_view.h
@@ -103,10 +103,14 @@ SearchResultView* GetResultViewAt(size_t index) override; absl::optional<ResultsAnimationInfo> ScheduleResultAnimations( const ResultsAnimationInfo& aggregate_animation_info) override; + bool HasAnimatingChildView() override; // Fades the view in and animates a vertical transform based on the view's - // position in the overall search container view. - void ShowViewWithAnimation(views::View* view, int position); + // position in the overall search container view. Returns whether fast + // animations were used. + void ShowViewWithAnimation(views::View* view, + int position, + bool use_short_animations); AppListMainView* app_list_main_view() const { return main_view_; }
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc index 780fb04..3ddc08ce 100644 --- a/ash/ash_prefs.cc +++ b/ash/ash_prefs.cc
@@ -50,6 +50,7 @@ #include "ash/wm/desks/desks_restore_util.h" #include "ash/wm/desks/persistent_desks_bar_controller.h" #include "ash/wm/desks/templates/desks_templates_util.h" +#include "ash/wm/lock_state_controller.h" #include "ash/wm/window_cycle/window_cycle_controller.h" #include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h" #include "chromeos/services/assistant/public/cpp/assistant_prefs.h" @@ -130,6 +131,7 @@ PowerPrefs::RegisterLocalStatePrefs(registry); DisplayPrefs::RegisterLocalStatePrefs(registry); LoginExpandedPublicAccountView::RegisterLocalStatePrefs(registry); + LockStateController::RegisterPrefs(registry); quick_pair::Mediator::RegisterLocalStatePrefs(registry); TopShortcutsView::RegisterLocalStatePrefs(registry); }
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index dc763bb..fadd269 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1936,6 +1936,18 @@ <message name="IDS_ASH_DESKS_DESK_NAME_COMMIT" desc="Alert when the desk name is committed"> Desk name was changed to <ph name="DESK_NAME">$1</ph> </message> + <message name="IDS_ASH_DESKS_COMBINE_DESKS_DESCRIPTION" desc="The tooltip and context menu text that describes the action of closing a desk and moving its windows to another desk."> + Combine with <ph name="DESK_NAME">$1</ph> + </message> + <message name="IDS_ASH_DESKS_CLOSE_ALL_DESCRIPTION" desc="The tooltip and context menu text that describes the action of closing a desk and all of its windows."> + Close desk and windows + </message> + <message name="IDS_ASH_DESKS_CLOSE_ALL_TOAST_TEXT" desc="Text provided in toast that notifies user that they have closed a desk and all of its windows."> + Desk and windows have been closed + </message> + <message name="IDS_ASH_DESKS_CLOSE_ALL_UNDO_TEXT" desc="Label for the undo button in the close-all toast."> + Undo + </message> <!-- Status tray charging strings. --> <message name="IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_TITLE" desc="The title of a notification indicating that a low-current USB charger has been connected.">
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_DESCRIPTION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..6710382 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +e750f98895cd72c8c44a4e0483f27308903f61b2 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_TOAST_TEXT.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_TOAST_TEXT.png.sha1 new file mode 100644 index 0000000..d151dac --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_TOAST_TEXT.png.sha1
@@ -0,0 +1 @@ +27268ca5ae9969af1a49514ce310c37a8e5f5617 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_UNDO_TEXT.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_UNDO_TEXT.png.sha1 new file mode 100644 index 0000000..ffba2ac3 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_DESKS_CLOSE_ALL_UNDO_TEXT.png.sha1
@@ -0,0 +1 @@ +c393a07db5d0009cd628328d2dd43230353f92be \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_COMBINE_DESKS_DESCRIPTION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_COMBINE_DESKS_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..16b058506 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_DESKS_COMBINE_DESKS_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +25df02de9ee6d53b52c43f2f96f8a51abedd1d3a \ No newline at end of file
diff --git a/ash/bluetooth_devices_observer.h b/ash/bluetooth_devices_observer.h index 5fcc8e7..7e3bcc7b 100644 --- a/ash/bluetooth_devices_observer.h +++ b/ash/bluetooth_devices_observer.h
@@ -5,6 +5,7 @@ #ifndef ASH_BLUETOOTH_DEVICES_OBSERVER_H_ #define ASH_BLUETOOTH_DEVICES_OBSERVER_H_ +#include "ash/ash_export.h" #include "base/callback.h" #include "base/memory/weak_ptr.h" #include "device/bluetooth/bluetooth_adapter.h" @@ -17,7 +18,8 @@ // ui::InputDeviceEventObserver as InputDeviceEventObserver does not have // knowledge about bluetooth device status thus does not send notifications of // bluetooth device changes. -class BluetoothDevicesObserver : public device::BluetoothAdapter::Observer { +class ASH_EXPORT BluetoothDevicesObserver + : public device::BluetoothAdapter::Observer { public: // Note |device| can be nullptr here if only the bluetooth adapter status // changes.
diff --git a/ash/components/arc/mojom/file_system.mojom b/ash/components/arc/mojom/file_system.mojom index d1ba40a..f4638b4 100644 --- a/ash/components/arc/mojom/file_system.mojom +++ b/ash/components/arc/mojom/file_system.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 21 +// Next MinVersion: 22 module arc.mojom; @@ -269,6 +269,16 @@ int64 capacity_bytes; }; +// Returned output for OpenFileSessionToWrite. +struct FileSession { + // Unique ID for the URL that is opened and mapped to a ParcelFileDescriptor + // object to be closed after the ChromeOS file operation(s). + string url_id; + + // FD for writing or reading the file specified by the URL. + handle fd; +}; + // Next method ID: 12 interface FileSystemHost { // Returns the name of the file specified by the URL. @@ -323,8 +333,10 @@ (FileSelectorElements elements); }; -// Deprecated method IDs: 5 -// Next method ID: 24 +// The browser process is using this interface in ArcFileSystemOperationRunner, +// the ARC process implements this interface used by ArcFileSystemService. +// Deprecated method IDs: 5, 18 +// Next method ID: 26 interface FileSystemInstance { // Notes about Android Documents Provider: // @@ -440,15 +452,24 @@ // URL. [MinVersion=1] OpenFileToRead@2(string url) => (handle? fd); - // Asks the ContentResolver to get a FD to write the file specified by the - // URL. - [MinVersion=13] OpenFileToWrite@18(string url) => (handle? fd); + // DEPRECATED. Use OpenFileSessionToWrite() instead. + [MinVersion=13] DEPRECATED_OpenFileToWrite@18(string url) => (handle? fd); // Asks the ContentResolver to get a FD to read the thumbnail of a // DocumentsProvider file specified by the URL. The thumbnail should be close // in size (width and height) but not necessarily the same as |size_hint|. [MinVersion=15] OpenThumbnail@21(string url, Size size_hint) => (handle? fd); + // Closes the ParcelFileDescriptor corresponding to the url_id. An error + // message can be sent to the ContentProvider as needed. + [MinVersion=21] CloseFileSession@24(string url_id, string error_message); + + // Asks the ContentResolver to get a FD to write to the file specified by the + // URL. FileSession is returned with a unique ID corresponding to the open + // session so the file can be closed properly after remote write operation. + [MinVersion=21] OpenFileSessionToWrite@25(url.mojom.Url url) => + (FileSession? file_session); + // Uninstalls a document watcher. // // After this method call returns, OnDocumentChanged() will never be called @@ -486,5 +507,5 @@ // ensure that the user is correctly aware of the URLs and the activity they // are passing. [MinVersion=19] OpenUrlsWithPermissionAndWindowInfo@23( - OpenUrlsRequest request, WindowInfo window_info) => (); + OpenUrlsRequest request, WindowInfo window_info) => (); };
diff --git a/ash/components/arc/test/fake_file_system_instance.cc b/ash/components/arc/test/fake_file_system_instance.cc index 1a3f80e..d38cde5a 100644 --- a/ash/components/arc/test/fake_file_system_instance.cc +++ b/ash/components/arc/test/fake_file_system_instance.cc
@@ -200,6 +200,13 @@ roots_.insert(std::make_pair(key, root)); } +void FakeFileSystemInstance::AddOpenSession(const std::string& url_id, + const int fd) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_EQ(0u, open_urls_.count(url_id)); + open_urls_.insert(std::make_pair(url_id, fd)); +} + void FakeFileSystemInstance::SetGetLastChangeTimeCallback( GetLastChangeTimeCallback ctime_callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -381,8 +388,9 @@ base::BindOnce(std::move(callback), std::move(wrapped_handle))); } -void FakeFileSystemInstance::OpenFileToWrite(const std::string& url, - OpenFileToWriteCallback callback) { +void FakeFileSystemInstance::DEPRECATED_OpenFileToWrite( + const std::string& url, + DEPRECATED_OpenFileToWriteCallback callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); auto iter = files_.find(url); if (iter == files_.end()) { @@ -404,6 +412,46 @@ base::BindOnce(std::move(callback), std::move(wrapped_handle))); } +void FakeFileSystemInstance::CloseFileSession( + const std::string& url_id, + const std::string& error_message) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + auto iter = open_urls_.find(url_id); + if (iter != open_urls_.end()) + return; + open_urls_.erase(url_id); +} + +void FakeFileSystemInstance::OpenFileSessionToWrite( + const GURL& url, + OpenFileSessionToWriteCallback callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + constexpr char kUrlId[] = "url_id"; + auto iter = files_.find(url.spec()); + if (iter == files_.end()) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), mojom::FileSessionPtr())); + return; + } + const File& file = iter->second; + base::ScopedFD fd = + file.seekable == File::Seekable::YES + ? CreateRegularFileDescriptor(file, base::File::Flags::FLAG_OPEN | + base::File::Flags::FLAG_WRITE) + : CreateStreamFileDescriptorToWrite(file.url); + DCHECK(fd.is_valid()); + AddOpenSession(kUrlId, fd.get()); + mojo::ScopedHandle wrapped_handle = + mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(fd))); + DCHECK(wrapped_handle.is_valid()); + mojom::FileSessionPtr file_session = mojom::FileSession::New(); + file_session->url_id = kUrlId; + file_session->fd = std::move(wrapped_handle); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), std::move(file_session))); +} + void FakeFileSystemInstance::OpenThumbnail(const std::string& url, const gfx::Size& size_hint, OpenThumbnailCallback callback) {
diff --git a/ash/components/arc/test/fake_file_system_instance.h b/ash/components/arc/test/fake_file_system_instance.h index 3d62231..314fafe4 100644 --- a/ash/components/arc/test/fake_file_system_instance.h +++ b/ash/components/arc/test/fake_file_system_instance.h
@@ -19,6 +19,7 @@ #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" #include "storage/browser/file_system/watcher_manager.h" +#include "url/gurl.h" namespace arc { @@ -32,7 +33,8 @@ // - GetFileSize() // - GetMimeType() // - OpenFileToRead() -// - OpenFileToWrite() +// - CloseFileSession() +// - OpenFileSessionToWrite() // Fake files for those functions can be set up by AddFile(). // // Documents provider based functions are: @@ -54,8 +56,8 @@ // added with AddDocument(). // - GetRecentDocuments() returns recent documents in the same order as they // were added with AddRecentDocument(). -// - OpenFileToRead() and OpenFileToWrite() will fail unless AddFile() for the -// file to open is called beforehand. +// - OpenFileToRead(), OpenFileSessionToWrite() will fail unless AddFile() for +// the file to open is called beforehand. // - Callbacks are never invoked synchronously. // - All member functions must be called on the same thread. class FakeFileSystemInstance : public mojom::FileSystemInstance { @@ -83,9 +85,9 @@ std::string url; // The content of a file, which can be read by OpenFileToRead(). - // When Seekable.NO is specified and OpenFileToWrite() is called, this - // |content| will be ignored and bytes written to FD from OpenFileToWrite() - // will be read by OpenFileToRead(). + // When Seekable.NO is specified and OpenFileSessionToWrite() is called, + // this |content| will be ignored and bytes written to FD from + // OpenFileSessionToWrite() will be read by OpenFileToRead(). std::string content; // The MIME type of a file. @@ -231,6 +233,9 @@ // Adds a root accessible by document provider based methods. void AddRoot(const Root& root); + // Add a file descriptor accessible by a URL ID. + void AddOpenSession(const std::string& url_id, const int fd); + // Fake the GetLastChangedTime implementation. void SetGetLastChangeTimeCallback(GetLastChangeTimeCallback ctime_callback); @@ -277,11 +282,11 @@ const std::string& document_id, const base::FilePath& path); - // Returns the content written to the FD returned by OpenFileToWrite(). + // Returns the content written to the FD returned by OpenFileSessionToWrite(). std::string GetFileContent(const std::string& url); - // Returns the content written to the FD returned by OpenFileToWrite(), up to - // |bytes| bytes. + // Returns the content written to the FD returned by OpenFileSessionToWrite(), + // up to |bytes| bytes. std::string GetFileContent(const std::string& url, size_t bytes); // For clearing the list of handled requests @@ -343,8 +348,14 @@ InitCallback callback) override; void OpenFileToRead(const std::string& url, OpenFileToReadCallback callback) override; - void OpenFileToWrite(const std::string& url, - OpenFileToWriteCallback callback) override; + // TODO(b/220547241): Remove DEPRECATED function from file_system.mojom. + void DEPRECATED_OpenFileToWrite( + const std::string& url, + DEPRECATED_OpenFileToWriteCallback callback) override; + void CloseFileSession(const std::string& url_id, + const std::string& error_message) override; + void OpenFileSessionToWrite(const GURL& url, + OpenFileSessionToWriteCallback callback) override; void OpenThumbnail(const std::string& url, const gfx::Size& size_hint, OpenThumbnailCallback callback) override; @@ -405,7 +416,7 @@ // Mapping from a content URL to a read end of a pipe. // The corresponding write end should have been returned from - // OpenFileToWrite() on non-seekable file entry. + // OpenFileSessionToWrite() on non-seekable file entry. std::map<std::string, base::ScopedFD> pipe_read_ends_; // Mapping from a document key to a document. @@ -426,6 +437,9 @@ // Mapping from a watcher ID to a document key. std::map<int64_t, DocumentKey> watcher_to_document_; + // Mapping of open URL ID to a file descriptor. + std::map<std::string, int> open_urls_; + // List of all OpenUrlsRequests made to the fake_file_system_instance std::vector<mojom::OpenUrlsRequestPtr> handled_url_requests_;
diff --git a/ash/components/device_activity/BUILD.gn b/ash/components/device_activity/BUILD.gn index 93b5866..9f56dad 100644 --- a/ash/components/device_activity/BUILD.gn +++ b/ash/components/device_activity/BUILD.gn
@@ -63,7 +63,9 @@ "//base/test:test_support", "//chromeos/network", "//chromeos/network:test_support", + "//chromeos/system:system", "//components/prefs:test_support", + "//components/version_info:channel", "//dbus", "//services/device/public/cpp:test_support", "//services/network:test_support",
diff --git a/ash/components/device_activity/daily_use_case_impl.cc b/ash/components/device_activity/daily_use_case_impl.cc index 16db049..f7b3b349 100644 --- a/ash/components/device_activity/daily_use_case_impl.cc +++ b/ash/components/device_activity/daily_use_case_impl.cc
@@ -9,6 +9,7 @@ #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "components/prefs/pref_service.h" +#include "components/version_info/channel.h" #include "third_party/private_membership/src/private_membership_rlwe_client.h" namespace ash { @@ -16,13 +17,15 @@ namespace psm_rlwe = private_membership::rlwe; -DailyUseCaseImpl::DailyUseCaseImpl(PrefService* local_state, - const std::string& psm_device_active_secret) +DailyUseCaseImpl::DailyUseCaseImpl(const std::string& psm_device_active_secret, + version_info::Channel chromeos_channel, + PrefService* local_state) : DeviceActiveUseCase( - local_state, psm_device_active_secret, + chromeos_channel, prefs::kDeviceActiveLastKnownDailyPingTimestamp, - private_membership::rlwe::RlweUseCase::CROS_FRESNEL_DAILY) {} + private_membership::rlwe::RlweUseCase::CROS_FRESNEL_DAILY, + local_state) {} DailyUseCaseImpl::~DailyUseCaseImpl() = default; @@ -46,8 +49,12 @@ // Create fresh |DeviceMetadata| object. // Note every dimension added to this proto must be approved by privacy. DeviceMetadata* device_metadata = import_request.mutable_device_metadata(); - device_metadata->set_hardware_id(GetFullHardwareClass()); device_metadata->set_chromeos_version(GetChromeOSVersion()); + device_metadata->set_chromeos_channel(GetChromeOSChannel()); + + // TODO(hirthanan): This is used for debugging purposes until crbug/1289722 + // has launched. + device_metadata->set_hardware_id(GetFullHardwareClass()); return import_request; }
diff --git a/ash/components/device_activity/daily_use_case_impl.h b/ash/components/device_activity/daily_use_case_impl.h index 20d2bcb..63f5ba9 100644 --- a/ash/components/device_activity/daily_use_case_impl.h +++ b/ash/components/device_activity/daily_use_case_impl.h
@@ -11,6 +11,10 @@ class PrefService; +namespace version_info { +enum class Channel; +} // namespace version_info + namespace ash { namespace device_activity { @@ -21,8 +25,9 @@ class COMPONENT_EXPORT(ASH_DEVICE_ACTIVITY) DailyUseCaseImpl : public DeviceActiveUseCase { public: - DailyUseCaseImpl(PrefService* local_state, - const std::string& psm_device_active_secret); + DailyUseCaseImpl(const std::string& psm_device_active_secret, + version_info::Channel chromeos_channel, + PrefService* local_state); DailyUseCaseImpl(const DailyUseCaseImpl&) = delete; DailyUseCaseImpl& operator=(const DailyUseCaseImpl&) = delete; ~DailyUseCaseImpl() override; @@ -30,6 +35,10 @@ // Generate the window identifier for the kCrosDaily use case. // For example, the daily use case should generate a window identifier // formatted: yyyyMMdd. + // + // It is generated on demand each time the state machine leaves the idle + // state. It is reused by several states. It is reset to nullopt. This field + // is used apart of PSM Import request. std::string GenerateUTCWindowIdentifier(base::Time ts) const override; // Generate Fresnel PSM import request body.
diff --git a/ash/components/device_activity/daily_use_case_impl_unittest.cc b/ash/components/device_activity/daily_use_case_impl_unittest.cc index 6451f32..7bd32ce 100644 --- a/ash/components/device_activity/daily_use_case_impl_unittest.cc +++ b/ash/components/device_activity/daily_use_case_impl_unittest.cc
@@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "base/time/time.h" #include "components/prefs/testing_pref_service.h" +#include "components/version_info/channel.h" #include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/private_membership/src/private_membership_rlwe_client.h" @@ -23,6 +24,9 @@ // Initialize fake values used by the |DailyUseCaseImpl|. constexpr char kFakePsmDeviceActiveSecret[] = "FAKE_PSM_DEVICE_ACTIVE_SECRET"; +const version_info::Channel kFakeChromeOSChannel = + version_info::Channel::STABLE; + } // namespace class DailyUseCaseImplTest : public testing::Test { @@ -37,7 +41,7 @@ void SetUp() override { DeviceActivityController::RegisterPrefs(local_state_.registry()); daily_use_case_impl_ = std::make_unique<DailyUseCaseImpl>( - &local_state_, kFakePsmDeviceActiveSecret); + kFakePsmDeviceActiveSecret, kFakeChromeOSChannel, &local_state_); } void TearDown() override { daily_use_case_impl_.reset(); } @@ -117,11 +121,12 @@ EXPECT_TRUE( base::Time::FromString("01 Jan 2022 00:00:00 GMT", &last_daily_ts)); + daily_use_case_impl_->SetLastKnownPingTimestamp(last_daily_ts); + EXPECT_TRUE( base::Time::FromString("05 Jan 2022 00:00:00 GMT", ¤t_daily_ts)); - EXPECT_TRUE(daily_use_case_impl_->IsDevicePingRequired(last_daily_ts, - current_daily_ts)); + EXPECT_TRUE(daily_use_case_impl_->IsDevicePingRequired(current_daily_ts)); } TEST_F(DailyUseCaseImplTest, PingNotRequiredInOverlappingUTCWindows) { @@ -130,11 +135,12 @@ EXPECT_TRUE( base::Time::FromString("01 Jan 2022 12:59:59 GMT", &last_daily_ts)); + daily_use_case_impl_->SetLastKnownPingTimestamp(last_daily_ts); + EXPECT_TRUE( base::Time::FromString("01 Jan 2022 15:59:59 GMT", ¤t_daily_ts)); - EXPECT_FALSE(daily_use_case_impl_->IsDevicePingRequired(last_daily_ts, - current_daily_ts)); + EXPECT_FALSE(daily_use_case_impl_->IsDevicePingRequired(current_daily_ts)); } TEST_F(DailyUseCaseImplTest, CheckIfPingRequiredInUTCBoundaryCases) { @@ -143,22 +149,24 @@ EXPECT_TRUE( base::Time::FromString("01 Jan 2022 23:59:59 GMT", &last_daily_ts)); + daily_use_case_impl_->SetLastKnownPingTimestamp(last_daily_ts); + EXPECT_TRUE( base::Time::FromString("02 Jan 2022 00:00:00 GMT", ¤t_daily_ts)); - EXPECT_TRUE(daily_use_case_impl_->IsDevicePingRequired(last_daily_ts, - current_daily_ts)); + EXPECT_TRUE(daily_use_case_impl_->IsDevicePingRequired(current_daily_ts)); // Set last_daily_ts as a date after current_daily_ts. EXPECT_TRUE( base::Time::FromString("02 Jan 2022 00:00:00 GMT", &last_daily_ts)); + daily_use_case_impl_->SetLastKnownPingTimestamp(last_daily_ts); + EXPECT_TRUE( base::Time::FromString("01 Jan 2022 23:59:59 GMT", ¤t_daily_ts)); // Since the current_daily_ts is prior to the last_daily_ts, the function // should return false. - EXPECT_FALSE(daily_use_case_impl_->IsDevicePingRequired(last_daily_ts, - current_daily_ts)); + EXPECT_FALSE(daily_use_case_impl_->IsDevicePingRequired(current_daily_ts)); } TEST_F(DailyUseCaseImplTest, SameDayTimestampsHaveSameWindowId) {
diff --git a/ash/components/device_activity/device_active_use_case.cc b/ash/components/device_activity/device_active_use_case.cc index e8887d0..d8f5b56 100644 --- a/ash/components/device_activity/device_active_use_case.cc +++ b/ash/components/device_activity/device_active_use_case.cc
@@ -25,14 +25,16 @@ } // namespace DeviceActiveUseCase::DeviceActiveUseCase( - PrefService* local_state, const std::string& psm_device_active_secret, + version_info::Channel chromeos_channel, const std::string& use_case_pref_key, - psm_rlwe::RlweUseCase psm_use_case) - : local_state_(local_state), - psm_device_active_secret_(psm_device_active_secret), + psm_rlwe::RlweUseCase psm_use_case, + PrefService* local_state) + : psm_device_active_secret_(psm_device_active_secret), + chromeos_channel_(chromeos_channel), use_case_pref_key_(use_case_pref_key), psm_use_case_(psm_use_case), + local_state_(local_state), statistics_provider_( chromeos::system::StatisticsProvider::GetInstance()) {} @@ -42,12 +44,12 @@ return local_state_; } -// Return the last known daily ping timestamp from local state pref. +// Return the last known ping timestamp from local state pref. base::Time DeviceActiveUseCase::GetLastKnownPingTimestamp() const { return GetLocalState()->GetTime(use_case_pref_key_); } -// Set the last known daily ping timestamp in local state pref. +// Set the last known ping timestamp in local state pref. void DeviceActiveUseCase::SetLastKnownPingTimestamp(base::Time new_ts) { GetLocalState()->SetTime(use_case_pref_key_, new_ts); } @@ -66,6 +68,9 @@ // nullopt the psm_id_ if a new window_id gets assigned. psm_id_ = absl::nullopt; + + // Reset |psm_rlwe_client_| since it also depends on psm_id value. + psm_rlwe_client_.reset(); } std::string DeviceActiveUseCase::GetDigestString( @@ -87,7 +92,8 @@ return psm_id_; } -void DeviceActiveUseCase::SetPsmIdentifier(psm_rlwe::RlwePlaintextId psm_id) { +void DeviceActiveUseCase::SetPsmIdentifier( + absl::optional<psm_rlwe::RlwePlaintextId> psm_id) { psm_id_ = psm_id; } @@ -97,16 +103,18 @@ void DeviceActiveUseCase::SetPsmRlweClient( std::unique_ptr<psm_rlwe::PrivateMembershipRlweClient> psm_rlwe_client) { - if (psm_rlwe_client) { - VLOG(1) << "Empty psm_rlwe_client passed to setter."; - return; - } + DCHECK(psm_rlwe_client); + // Re-assigning the unique_ptr will reset the old unique_ptr. psm_rlwe_client_ = std::move(psm_rlwe_client); } -bool DeviceActiveUseCase::IsDevicePingRequired(base::Time prev_ping_ts, - base::Time new_ping_ts) const { +bool DeviceActiveUseCase::IsDevicePingRequired(base::Time new_ping_ts) const { + // Check the last recorded ping timestamp in local state prefs. + // This variable has the default Unix Epoch value if the device is + // new, powerwashed, recovered, or a RMA device. + base::Time prev_ping_ts = GetLastKnownPingTimestamp(); + std::string prev_ping_window_id = GenerateUTCWindowIdentifier(prev_ping_ts); std::string new_ping_window_id = GenerateUTCWindowIdentifier(new_ping_ts); @@ -131,6 +139,22 @@ return version_info::GetMajorVersionNumber(); } +Channel DeviceActiveUseCase::GetChromeOSChannel() const { + switch (chromeos_channel_) { + case version_info::Channel::CANARY: + return Channel::CHANNEL_CANARY; + case version_info::Channel::DEV: + return Channel::CHANNEL_DEV; + case version_info::Channel::BETA: + return Channel::CHANNEL_BETA; + case version_info::Channel::STABLE: + return Channel::CHANNEL_STABLE; + case version_info::Channel::UNKNOWN: + default: + return Channel::CHANNEL_UNKNOWN; + } +} + absl::optional<psm_rlwe::RlwePlaintextId> DeviceActiveUseCase::GeneratePsmIdentifier() const { const std::string psm_use_case = psm_rlwe::RlweUseCase_Name(GetPsmUseCase());
diff --git a/ash/components/device_activity/device_active_use_case.h b/ash/components/device_activity/device_active_use_case.h index e652fc6..18051d3 100644 --- a/ash/components/device_activity/device_active_use_case.h +++ b/ash/components/device_activity/device_active_use_case.h
@@ -5,6 +5,7 @@ #ifndef ASH_COMPONENTS_DEVICE_ACTIVITY_USE_CASE_H_ #define ASH_COMPONENTS_DEVICE_ACTIVITY_USE_CASE_H_ +#include "ash/components/device_activity/fresnel_service.pb.h" #include "base/component_export.h" #include "base/time/time.h" #include "third_party/private_membership/src/private_membership_rlwe_client.h" @@ -17,19 +18,21 @@ } // namespace system } // namespace chromeos +namespace version_info { +enum class Channel; +} // namespace version_info + namespace ash { namespace device_activity { -// Forward declaration from fresnel_service.proto. -class ImportDataRequest; - // Base class for device active use cases. class COMPONENT_EXPORT(ASH_DEVICE_ACTIVITY) DeviceActiveUseCase { public: - DeviceActiveUseCase(PrefService* local_state, - const std::string& psm_device_active_secret, + DeviceActiveUseCase(const std::string& psm_device_active_secret, + version_info::Channel chromeos_channel, const std::string& use_case_pref_key, - private_membership::rlwe::RlweUseCase psm_use_case); + private_membership::rlwe::RlweUseCase psm_use_case, + PrefService* local_state); DeviceActiveUseCase(const DeviceActiveUseCase&) = delete; DeviceActiveUseCase& operator=(const DeviceActiveUseCase&) = delete; virtual ~DeviceActiveUseCase(); @@ -71,21 +74,23 @@ absl::optional<private_membership::rlwe::RlwePlaintextId> GetPsmIdentifier(); - void SetPsmIdentifier(private_membership::rlwe::RlwePlaintextId psm_id); + void SetPsmIdentifier( + absl::optional<private_membership::rlwe::RlwePlaintextId> psm_id); // Returns memory address to the |psm_rlwe_client_| unique pointer, or null if // not set. private_membership::rlwe::PrivateMembershipRlweClient* GetPsmRlweClient(); + // Generated on demand each time the state machine leaves the idle state. + // Client Generates protos used in request body of Oprf and Query requests. void SetPsmRlweClient( std::unique_ptr<private_membership::rlwe::PrivateMembershipRlweClient> psm_rlwe_client); - // Determines if |prev_ping_ts| occurred in a different active window then - // |new_ping_ts| for a given device. Performing this check helps reduce QPS to - // the |CheckingMembership| network requests. - bool IsDevicePingRequired(base::Time prev_ping_ts, - base::Time new_ping_ts) const; + // Determine if a device ping is needed for a given device window. + // Performing this check helps reduce QPS to the |CheckingMembership| + // network requests. + bool IsDevicePingRequired(base::Time new_ping_ts) const; protected: // Retrieve full hardware class from MachineStatistics. @@ -96,27 +101,31 @@ // Retrieve the ChromeOS major version number. std::string GetChromeOSVersion() const; + // Retrieve the ChromeOS release channel. + Channel GetChromeOSChannel() const; + private: - // Generate the PSM identifier, used to identify a fixed - // window of time for device active counting. Privacy compliance is guaranteed - // by retrieving the |psm_device_active_secret_| from chromeos, and - // performing an additional HMAC-SHA256 hash on generated plaintext string. + // Field is used to identify a fixed window of time for device active + // counting. Privacy compliance is guaranteed by retrieving the + // |psm_device_active_secret_| from chromeos, and performing an additional + // HMAC-SHA256 hash on generated plaintext string. + // + // Generated on demand each time the state machine leaves the idle state. + // It is reused by several states. It is reset to nullopt. + // This field is used apart of PSM Oprf, Query, and Import requests. absl::optional<private_membership::rlwe::RlwePlaintextId> GeneratePsmIdentifier() const; - // Update last stored device active ping timestamps for PSM use cases. - // On powerwash/recovery update |local_state_| to the most recent timestamp - // |CheckMembership| was performed, as |local_state_| gets deleted. - // |local_state_| outlives the lifetime of this class. - // Used local state prefs are initialized by |DeviceActivityController|. - PrefService* const local_state_; - // The ChromeOS platform code will provide a derived PSM device active secret // via callback. // // This secret is used to generate a PSM identifier for the reporting window. const std::string psm_device_active_secret_; + // |ChromeBrowserMainPartsAsh| passes the ChromeOS channel through the class + // constructor. + const version_info::Channel chromeos_channel_; + // Key used to query the local state pref for the last ping timestamp by use // case. // For example, the monthly use case will store the key mapping to the last @@ -126,6 +135,13 @@ // The PSM dataset on the serverside is segmented by the PSM use case. const private_membership::rlwe::RlweUseCase psm_use_case_; + // Update last stored device active ping timestamps for PSM use cases. + // On powerwash/recovery update |local_state_| to the most recent timestamp + // |CheckMembership| was performed, as |local_state_| gets deleted. + // |local_state_| outlives the lifetime of this class. + // Used local state prefs are initialized by |DeviceActivityController|. + PrefService* const local_state_; + // Singleton lives throughout class lifetime. chromeos::system::StatisticsProvider* const statistics_provider_;
diff --git a/ash/components/device_activity/device_activity_client.cc b/ash/components/device_activity/device_activity_client.cc index 8fd4fae..c6d4c09b 100644 --- a/ash/components/device_activity/device_activity_client.cc +++ b/ash/components/device_activity/device_activity_client.cc
@@ -4,19 +4,12 @@ #include "ash/components/device_activity/device_activity_client.h" -#include "ash/components/device_activity/fresnel_pref_names.h" +#include "ash/components/device_activity/device_active_use_case.h" #include "ash/components/device_activity/fresnel_service.pb.h" -#include "base/i18n/time_formatting.h" // TODO(https://crbug.com/1269900): Migrate to use SFUL library. #include "base/metrics/histogram_functions.h" #include "base/strings/strcat.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "components/prefs/pref_service.h" -#include "components/version_info/version_info.h" -#include "crypto/hmac.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" @@ -141,110 +134,31 @@ return resource_request; } -// TODO(https://crbug.com/1262177): currently the PSM use cases are not synced -// with google3. Update to retrieve from synced RlweUseCase in file: -// third_party/private_membership/src/private_membership_rlwe.proto. -constexpr psm_rlwe::RlweUseCase kDailyPsmUseCase = - psm_rlwe::RlweUseCase::CROS_FRESNEL_DAILY; - -// Generate the window identifier for the kCrosDaily use case. -// For example, the daily use case should generate a window identifier -// formatted: yyyyMMdd. -// TODO(https://crbug.com/1262187): This window identifier will need to support -// more use cases in the future. Currently it only supports the kCrosDaily use -// case. -std::string GenerateUTCWindowIdentifier(base::Time ts) { - base::Time::Exploded exploded; - ts.UTCExplode(&exploded); - return base::StringPrintf("%04d%02d%02d", exploded.year, exploded.month, - exploded.day_of_month); -} - -// Calculates an HMAC of |message| using |key|, encoded as a hexadecimal string. -// Return empty string if HMAC fails. -std::string GetDigestString(const std::string& key, - const std::string& message) { - crypto::HMAC hmac(crypto::HMAC::SHA256); - std::vector<uint8_t> digest(hmac.DigestLength()); - if (!hmac.Init(key) || !hmac.Sign(message, &digest[0], digest.size())) { - return std::string(); - } - return base::HexEncode(&digest[0], digest.size()); -} - -// Generate the PSM identifier, used to identify a fixed -// window of time for device active counting. Privacy compliance is guaranteed -// by retrieving the |psm_device_active_secret_| from chromeos, and -// performing an additional HMAC-SHA256 hash on generated plaintext string. -absl::optional<psm_rlwe::RlwePlaintextId> GeneratePsmIdentifier( - const std::string& psm_device_active_secret, - const std::string& psm_use_case, - const std::string& window_id) { - if (psm_device_active_secret.empty() || psm_use_case.empty() || - window_id.empty()) - return absl::nullopt; - - std::string unhashed_psm_id = - base::JoinString({psm_use_case, window_id}, "|"); - - // Convert bytes to hex to avoid encoding/decoding proto issues across - // client/server. - std::string psm_id_hex = - GetDigestString(psm_device_active_secret, unhashed_psm_id); - - if (!psm_id_hex.empty()) { - psm_rlwe::RlwePlaintextId psm_rlwe_id; - psm_rlwe_id.set_sensitive_id(psm_id_hex); - return psm_rlwe_id; - } - - // Failed HMAC-SHA256 hash on PSM id. - return absl::nullopt; -} - -// Determines if |prev_ping_ts| occurred in a different daily active window then -// |new_ping_ts| for a given device. Performing this check helps reduce QPS to -// the |CheckingMembership| network requests. -// TODO(https://crbug.com/1262187): This function will need to get modified to -// support kCrosMonthly and kCrosAllTime use cases. -bool IsDailyDeviceActivePingRequired(base::Time prev_ping_ts, - base::Time new_ping_ts) { - std::string prev_ping_ts_period = GenerateUTCWindowIdentifier(prev_ping_ts); - std::string new_ping_ts_period = GenerateUTCWindowIdentifier(new_ping_ts); - - return prev_ping_ts < new_ping_ts && - prev_ping_ts_period != new_ping_ts_period; -} - } // namespace DeviceActivityClient::DeviceActivityClient( NetworkStateHandler* handler, - PrefService* local_state, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, std::unique_ptr<PsmDelegate> psm_delegate, std::unique_ptr<base::RepeatingTimer> report_timer, const std::string& fresnel_base_url, const std::string& api_key, - const std::string& psm_device_active_secret, - const std::string& full_hardware_class) + std::vector<std::unique_ptr<DeviceActiveUseCase>> use_cases) : network_state_handler_(handler), - local_state_(local_state), url_loader_factory_(url_loader_factory), psm_delegate_(std::move(psm_delegate)), report_timer_(std::move(report_timer)), fresnel_base_url_(fresnel_base_url), api_key_(api_key), - psm_device_active_secret_(psm_device_active_secret), - full_hardware_class_(full_hardware_class) { + use_cases_(std::move(use_cases)) { DCHECK(network_state_handler_); - DCHECK(local_state_); DCHECK(url_loader_factory_); DCHECK(psm_delegate_); DCHECK(report_timer_); + DCHECK(!use_cases_.empty()); report_timer_->Start(FROM_HERE, kTimeToRepeat, this, - &DeviceActivityClient::TransitionOutOfIdle); + &DeviceActivityClient::ReportUseCases); network_state_handler_->AddObserver(this, FROM_HERE); DefaultNetworkChanged(network_state_handler_->DefaultNetwork()); @@ -275,7 +189,7 @@ } void DeviceActivityClient::OnNetworkOnline() { - TransitionOutOfIdle(); + ReportUseCases(); } GURL DeviceActivityClient::GetFresnelURL() const { @@ -305,62 +219,70 @@ return base_url.ReplaceComponents(replacements); } -void DeviceActivityClient::InitializeDeviceMetadata( - DeviceMetadata* device_metadata) { - device_metadata->set_chromeos_version(version_info::GetMajorVersionNumber()); - device_metadata->set_hardware_id(full_hardware_class_); -} - // TODO(https://crbug.com/1262189): Add callback to report actives only after // synchronizing the system clock. -void DeviceActivityClient::TransitionOutOfIdle() { +void DeviceActivityClient::ReportUseCases() { + DCHECK(!use_cases_.empty()); + if (!network_connected_ || state_ != State::kIdle) { - TransitionToIdle(); + TransitionToIdle(nullptr); return; } - // Check the last recorded daily ping timestamp in local state prefs. - // This variable has the default Unix Epoch value if the device is - // new, powerwashed, recovered, or a RMA device. - base::Time last_recorded_daily_ping_time = - local_state_->GetTime(prefs::kDeviceActiveLastKnownDailyPingTimestamp); - // The network is connected and the client |state_| is kIdle. last_transition_out_of_idle_time_ = base::Time::Now(); + for (auto& use_case : use_cases_) { + // Ownership of the use cases will be maintained by the |use_cases_| vector. + pending_use_cases_.push(use_case.get()); + } + + DeviceActiveUseCase* current_use_case = pending_use_cases_.front(); + pending_use_cases_.pop(); + + TransitionOutOfIdle(current_use_case); +} + +void DeviceActivityClient::TransitionOutOfIdle( + DeviceActiveUseCase* current_use_case) { + DCHECK(current_use_case); + // Begin phase one of checking membership if the device has not pinged yet // within the given use case window. // TODO(https://crbug.com/1262187): Remove hardcoded use case when adding // support for additional use cases (i.e MONTHLY, ALL_TIME, etc.). - if (IsDailyDeviceActivePingRequired(last_recorded_daily_ping_time, - last_transition_out_of_idle_time_)) { - current_day_window_id_ = - GenerateUTCWindowIdentifier(last_transition_out_of_idle_time_); - current_day_psm_id_ = GeneratePsmIdentifier( - psm_device_active_secret_, psm_rlwe::RlweUseCase_Name(kDailyPsmUseCase), - current_day_window_id_.value()); + if (current_use_case->IsDevicePingRequired( + last_transition_out_of_idle_time_)) { + current_use_case->SetWindowIdentifier( + current_use_case->GenerateUTCWindowIdentifier( + last_transition_out_of_idle_time_)); + auto current_psm_id = current_use_case->GetPsmIdentifier(); // Check if the PSM id is generated. - if (!current_day_psm_id_.has_value()) { - TransitionToIdle(); + if (!current_psm_id.has_value()) { + TransitionToIdle(current_use_case); return; } std::vector<psm_rlwe::RlwePlaintextId> psm_rlwe_ids = { - current_day_psm_id_.value()}; + current_psm_id.value()}; auto status_or_client = psm_delegate_->CreatePsmClient( - psm_rlwe::RlweUseCase::CROS_FRESNEL_DAILY, psm_rlwe_ids); + current_use_case->GetPsmUseCase(), psm_rlwe_ids); if (!status_or_client.ok()) { - TransitionToIdle(); + TransitionToIdle(current_use_case); return; } - psm_rlwe_client_ = std::move(status_or_client.value()); - // During rollout, we perform CheckIn without CheckMembership for powerwash, - // recovery, or RMA devices. - TransitionToCheckIn(); + current_use_case->SetPsmRlweClient(std::move(status_or_client.value())); + + // During rollout, we perform CheckIn without CheckMembership for + // powerwash, recovery, or RMA devices. + TransitionToCheckIn(current_use_case); + return; } + + TransitionToIdle(current_use_case); } void DeviceActivityClient::TransitionToHealthCheck() { @@ -406,10 +328,11 @@ RecordDurationStateMetric(state_, state_timer_.Elapsed()); // Transition back to kIdle state after performing a health check on servers. - TransitionToIdle(); + TransitionToIdle(nullptr); } -void DeviceActivityClient::TransitionToCheckMembershipOprf() { +void DeviceActivityClient::TransitionToCheckMembershipOprf( + DeviceActiveUseCase* current_use_case) { DCHECK_EQ(state_, State::kIdle); DCHECK(!url_loader_); @@ -422,10 +345,11 @@ RecordStateCountMetric(state_); // Generate PSM Oprf request body. - const auto status_or_oprf_request = psm_rlwe_client_->CreateOprfRequest(); + const auto status_or_oprf_request = + current_use_case->GetPsmRlweClient()->CreateOprfRequest(); if (!status_or_oprf_request.ok()) { RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); return; } @@ -452,11 +376,12 @@ url_loader_->DownloadToString( url_loader_factory_.get(), base::BindOnce(&DeviceActivityClient::OnCheckMembershipOprfDone, - weak_factory_.GetWeakPtr()), + weak_factory_.GetWeakPtr(), current_use_case), kMaxFresnelResponseSizeBytes); } void DeviceActivityClient::OnCheckMembershipOprfDone( + DeviceActiveUseCase* current_use_case, std::unique_ptr<std::string> response_body) { DCHECK_EQ(state_, State::kCheckingMembershipOprf); @@ -471,14 +396,14 @@ FresnelPsmRlweOprfResponse psm_oprf_response; if (!response_body || !psm_oprf_response.ParseFromString(*response_body)) { RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); return; } // Parse |fresnel_oprf_response| for oprf_response. if (!psm_oprf_response.has_rlwe_oprf_response()) { RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); return; } @@ -486,11 +411,12 @@ psm_oprf_response.rlwe_oprf_response(); RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToCheckMembershipQuery(oprf_response); + TransitionToCheckMembershipQuery(oprf_response, current_use_case); } void DeviceActivityClient::TransitionToCheckMembershipQuery( - const psm_rlwe::PrivateMembershipRlweOprfResponse& oprf_response) { + const psm_rlwe::PrivateMembershipRlweOprfResponse& oprf_response, + DeviceActiveUseCase* current_use_case) { DCHECK_EQ(state_, State::kCheckingMembershipOprf); DCHECK(!url_loader_); @@ -504,10 +430,10 @@ // Generate PSM Query request body. const auto status_or_query_request = - psm_rlwe_client_->CreateQueryRequest(oprf_response); + current_use_case->GetPsmRlweClient()->CreateQueryRequest(oprf_response); if (!status_or_query_request.ok()) { RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); return; } @@ -534,11 +460,12 @@ url_loader_->DownloadToString( url_loader_factory_.get(), base::BindOnce(&DeviceActivityClient::OnCheckMembershipQueryDone, - weak_factory_.GetWeakPtr()), + weak_factory_.GetWeakPtr(), current_use_case), kMaxFresnelResponseSizeBytes); } void DeviceActivityClient::OnCheckMembershipQueryDone( + DeviceActiveUseCase* current_use_case, std::unique_ptr<std::string> response_body) { DCHECK_EQ(state_, State::kCheckingMembershipQuery); @@ -553,31 +480,32 @@ FresnelPsmRlweQueryResponse psm_query_response; if (!response_body || !psm_query_response.ParseFromString(*response_body)) { RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); return; } // Parse |fresnel_query_response| for psm query_response. if (!psm_query_response.has_rlwe_query_response()) { RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); return; } psm_rlwe::PrivateMembershipRlweQueryResponse query_response = psm_query_response.rlwe_query_response(); - auto status_or_response = psm_rlwe_client_->ProcessResponse(query_response); + auto status_or_response = + current_use_case->GetPsmRlweClient()->ProcessResponse(query_response); if (!status_or_response.ok()) { RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); return; } psm_rlwe::MembershipResponseMap membership_response_map = status_or_response.value(); private_membership::MembershipResponse membership_response = - membership_response_map.Get(current_day_psm_id_.value()); + membership_response_map.Get(current_use_case->GetPsmIdentifier().value()); bool is_psm_id_member = membership_response.is_member(); @@ -586,17 +514,19 @@ if (!is_psm_id_member) { RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToCheckIn(); + TransitionToCheckIn(current_use_case); } else { - // Update local state to signal ping has already been sent for current day. - local_state_->SetTime(prefs::kDeviceActiveLastKnownDailyPingTimestamp, - last_transition_out_of_idle_time_); + // Update local state to signal ping has already been sent for use case + // window. + current_use_case->SetLastKnownPingTimestamp( + last_transition_out_of_idle_time_); RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); } } -void DeviceActivityClient::TransitionToCheckIn() { +void DeviceActivityClient::TransitionToCheckIn( + DeviceActiveUseCase* current_use_case) { DCHECK(!url_loader_); state_timer_ = base::ElapsedTimer(); @@ -607,18 +537,9 @@ // Report UMA histogram for transitioning state to |kCheckingIn|. RecordStateCountMetric(state_); - std::string current_psm_id_str = current_day_psm_id_.value().sensitive_id(); - // Generate Fresnel PSM import request body. - device_activity::ImportDataRequest import_request; - import_request.set_window_identifier(current_day_window_id_.value()); - import_request.set_plaintext_identifier(current_psm_id_str); - import_request.set_use_case(kDailyPsmUseCase); - - // Important: Each new dimension added to metadata will need to be approved by - // privacy. - DeviceMetadata* device_metadata = import_request.mutable_device_metadata(); - InitializeDeviceMetadata(device_metadata); + device_activity::ImportDataRequest import_request = + current_use_case->GenerateImportRequestBody(); std::string request_body; import_request.SerializeToString(&request_body); @@ -632,14 +553,16 @@ MISSING_TRAFFIC_ANNOTATION); url_loader_->AttachStringForUpload(request_body, "application/x-protobuf"); url_loader_->SetTimeoutDuration(kImportRequestTimeout); + url_loader_->DownloadToString( url_loader_factory_.get(), base::BindOnce(&DeviceActivityClient::OnCheckInDone, - weak_factory_.GetWeakPtr()), + weak_factory_.GetWeakPtr(), current_use_case), kMaxFresnelResponseSizeBytes); } void DeviceActivityClient::OnCheckInDone( + DeviceActiveUseCase* current_use_case, std::unique_ptr<std::string> response_body) { DCHECK_EQ(state_, State::kCheckingIn); @@ -653,20 +576,33 @@ // Successful import request - PSM ID was imported successfully. if (net_code == net::OK) { // Update local state pref to record reporting device active. - local_state_->SetTime(prefs::kDeviceActiveLastKnownDailyPingTimestamp, - last_transition_out_of_idle_time_); + current_use_case->SetLastKnownPingTimestamp( + last_transition_out_of_idle_time_); } RecordDurationStateMetric(state_, state_timer_.Elapsed()); - TransitionToIdle(); + TransitionToIdle(current_use_case); } -void DeviceActivityClient::TransitionToIdle() { +void DeviceActivityClient::TransitionToIdle( + DeviceActiveUseCase* current_use_case) { DCHECK(!url_loader_); state_ = State::kIdle; - current_day_window_id_ = absl::nullopt; - current_day_psm_id_ = absl::nullopt; + if (current_use_case) { + // This will also reset the |current_use_case| psm_id field. + current_use_case->SetWindowIdentifier(absl::nullopt); + + current_use_case = nullptr; + } + + if (!pending_use_cases_.empty()) { + DeviceActiveUseCase* current_use_case = pending_use_cases_.front(); + pending_use_cases_.pop(); + + TransitionOutOfIdle(current_use_case); + return; + } // Report UMA histogram for transitioning state back to |kIdle|. RecordStateCountMetric(state_);
diff --git a/ash/components/device_activity/device_activity_client.h b/ash/components/device_activity/device_activity_client.h index a5f54156..3448a49b 100644 --- a/ash/components/device_activity/device_activity_client.h +++ b/ash/components/device_activity/device_activity_client.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/component_export.h" +#include "base/containers/queue.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" @@ -25,13 +26,11 @@ class SharedURLLoaderFactory; } // namespace network -class PrefService; - namespace ash { namespace device_activity { -// Forward declaration from fresnel_service.proto. -class DeviceMetadata; +// Forward declaration from device_active_use_case.h +class DeviceActiveUseCase; // Create a delegate which can be used to create fakes in unit tests. // Fake via. delegate is required for creating deterministic unit tests. @@ -50,6 +49,9 @@ // State Transition flow: // kIdle -> kCheckingMembershipOprf -> kCheckingMembershipQuery // -> kIdle or (kCheckingIn -> kIdle) +// +// TODO(https://crbug.com/1302175): Move methods passing DeviceActiveUseCase* to +// methods of DeviceActiveUseCase class. class COMPONENT_EXPORT(ASH_DEVICE_ACTIVITY) DeviceActivityClient : public chromeos::NetworkStateHandlerObserver { public: @@ -82,14 +84,12 @@ // Fires device active pings while the device network is connected. DeviceActivityClient( NetworkStateHandler* handler, - PrefService* local_state, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, std::unique_ptr<PsmDelegate> psm_delegate, std::unique_ptr<base::RepeatingTimer> report_timer, const std::string& fresnel_server_url, const std::string& api_key, - const std::string& psm_device_active_secret, - const std::string& full_hardware_class); + std::vector<std::unique_ptr<DeviceActiveUseCase>> use_cases); DeviceActivityClient(const DeviceActivityClient&) = delete; DeviceActivityClient& operator=(const DeviceActivityClient&) = delete; ~DeviceActivityClient() override; @@ -109,11 +109,13 @@ // Return Fresnel server network request endpoints determined by the |state_|. GURL GetFresnelURL() const; - // Collect device metadata dimensions sent by PSM import. - void InitializeDeviceMetadata(DeviceMetadata* device_metadata); + // Called when device network comes online or |report_timer_| executing. + // Reports each use case in a sequenced order. + void ReportUseCases(); - // Called when device network comes online as well as by |report_timer_|. - void TransitionOutOfIdle(); + // Callback from |ReportUseCases()| handling whether a use case needs + // to be reported for the time window. + void TransitionOutOfIdle(DeviceActiveUseCase* current_use_case); // Send Health Check network request and update |state_|. // Before calling this method: |state_| is expected to be |kIdle|. @@ -126,10 +128,11 @@ // Send Oprf network request and update |state_|. // Before calling this method: |state_| is expected to be |kIdle|. // After calling this method: |state_| set to |kCheckingMembershipOprf|. - void TransitionToCheckMembershipOprf(); + void TransitionToCheckMembershipOprf(DeviceActiveUseCase* current_use_case); // Callback from asynchronous method |TransitionToCheckMembershipOprf|. - void OnCheckMembershipOprfDone(std::unique_ptr<std::string> response_body); + void OnCheckMembershipOprfDone(DeviceActiveUseCase* current_use_case, + std::unique_ptr<std::string> response_body); // Send Query network request and update |state_|. // Before calling this method: |state_| is expected to be @@ -137,23 +140,26 @@ // After calling this method: |state_| set to |kCheckingMembershipQuery|. void TransitionToCheckMembershipQuery( const private_membership::rlwe::PrivateMembershipRlweOprfResponse& - oprf_response); + oprf_response, + DeviceActiveUseCase* current_use_case); // Callback from asynchronous method |TransitionToCheckMembershipQuery|. // Check in PSM id based on |response_body| from CheckMembershipQuery. - void OnCheckMembershipQueryDone(std::unique_ptr<std::string> response_body); + void OnCheckMembershipQueryDone(DeviceActiveUseCase* current_use_case, + std::unique_ptr<std::string> response_body); // Send Import network request and update |state_|. // Before calling this method: |state_| is expected to be either // |kCheckingMembershipQuery| or |kIdle|. // After calling this method: |state_| set to |kCheckingIn|. - void TransitionToCheckIn(); + void TransitionToCheckIn(DeviceActiveUseCase* current_use_case); // Callback from asynchronous method |TransitionToCheckIn|. - void OnCheckInDone(std::unique_ptr<std::string> response_body); + void OnCheckInDone(DeviceActiveUseCase* current_use_case, + std::unique_ptr<std::string> response_body); // Updates |state_| to |kIdle| and resets state based member variables. - void TransitionToIdle(); + void TransitionToIdle(DeviceActiveUseCase* current_use_case); // Tracks the current state of the DeviceActivityClient. State state_ = State::kIdle; @@ -161,16 +167,6 @@ // Keep track of whether the device is connected to the network. bool network_connected_ = false; - // Generated on demand each time the state machine leaves the idle state. - // It is reused by several states. It is reset to nullopt. - // This field is used apart of PSM Import request. - absl::optional<std::string> current_day_window_id_; - - // Generated on demand each time the state machine leaves the idle state. - // It is reused by several states. It is reset to nullopt. - // This field is used apart of PSM Oprf, Query, and Import requests. - absl::optional<private_membership::rlwe::RlwePlaintextId> current_day_psm_id_; - // Time the device last transitioned out of idle state. base::Time last_transition_out_of_idle_time_; @@ -179,11 +175,6 @@ // reported to UMA via. histograms. base::ElapsedTimer state_timer_; - // Generated on demand each time the state machine leaves the idle state. - // Client Generates protos used in request body of Oprf and Query requests. - std::unique_ptr<private_membership::rlwe::PrivateMembershipRlweClient> - psm_rlwe_client_; - // Tracks the visible networks and their properties. // |network_state_handler_| outlives the lifetime of this class. // |ChromeBrowserMainPartsAsh| initializes the network_state object as @@ -191,13 +182,6 @@ // Similarly, |DeviceActivityClient| is destructed before |dbus_services_|. NetworkStateHandler* const network_state_handler_; - // Update last stored device active ping timestamps for PSM use cases. - // On powerwash/recovery update |local_state_| to the most recent timestamp - // |CheckMembership| was performed, as |local_state_| gets deleted. - // |local_state_| outlives the lifetime of this class. - // Used local state prefs are initialized by |DeviceActivityController|. - PrefService* const local_state_; - // Shared |url_loader_| object used to handle ongoing network requests. std::unique_ptr<network::SimpleURLLoader> url_loader_; @@ -220,15 +204,14 @@ // the chrome-internal repository and is not publicly exposed in Chromium. const std::string api_key_; - // The ChromeOS platform code will provide a derived PSM device active secret - // via callback. - // - // This secret is used to generate a PSM identifier for the reporting window. - const std::string psm_device_active_secret_; + // Vector of supported use cases containing the methods and metadata required + // to counting device actives. + const std::vector<std::unique_ptr<DeviceActiveUseCase>> use_cases_; - // The ChromeOS statistics provider class provides the full hardware class - // information of a ChromeOS device. - const std::string full_hardware_class_; + // Contains the use cases to report active for. + // |ReportUseCases| initializes this field using the |use_cases_|. + // |TransitionToIdle| pops from this field to report each pending use case. + std::queue<DeviceActiveUseCase*> pending_use_cases_; // Automatically cancels callbacks when the referent of weakptr gets // destroyed.
diff --git a/ash/components/device_activity/device_activity_client_unittest.cc b/ash/components/device_activity/device_activity_client_unittest.cc index 5a7561f..96f82583 100644 --- a/ash/components/device_activity/device_activity_client_unittest.cc +++ b/ash/components/device_activity/device_activity_client_unittest.cc
@@ -4,9 +4,11 @@ #include "ash/components/device_activity/device_activity_client.h" +#include "ash/components/device_activity/daily_use_case_impl.h" #include "ash/components/device_activity/device_activity_controller.h" #include "ash/components/device_activity/fresnel_pref_names.h" #include "ash/components/device_activity/fresnel_service.pb.h" +#include "ash/components/device_activity/monthly_use_case_impl.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/no_destructor.h" @@ -16,7 +18,9 @@ #include "base/timer/mock_timer.h" #include "chromeos/network/network_state_handler_observer.h" #include "chromeos/network/network_state_test_helper.h" +#include "chromeos/system/fake_statistics_provider.h" #include "components/prefs/testing_pref_service.h" +#include "components/version_info/channel.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" @@ -56,7 +60,9 @@ // Create fake secrets used by the |DeviceActivityClient|. constexpr char kFakePsmDeviceActiveSecret[] = "FAKE_PSM_DEVICE_ACTIVE_SECRET"; constexpr char kFakeFresnelApiKey[] = "FAKE_FRESNEL_API_KEY"; -constexpr char kFakeFullHardwareClass[] = "FAKE_FULL_HARDWARE_CLASS"; + +const version_info::Channel kFakeChromeOSChannel = + version_info::Channel::STABLE; // Number of test cases exist in cros_test_data.binarypb file, which is part of // private_membership third_party library. @@ -118,6 +124,19 @@ std::vector<psm_rlwe::RlwePlaintextId> plaintext_ids_; }; +class FakeDailyUseCaseImpl : public DailyUseCaseImpl { + public: + FakeDailyUseCaseImpl(const std::string& psm_device_active_secret, + version_info::Channel chromeos_channel, + PrefService* local_state) + : DailyUseCaseImpl(psm_device_active_secret, + chromeos_channel, + local_state) {} + FakeDailyUseCaseImpl(const FakeDailyUseCaseImpl&) = delete; + FakeDailyUseCaseImpl& operator=(const FakeDailyUseCaseImpl&) = delete; + ~FakeDailyUseCaseImpl() override = default; +}; + class DeviceActivityClientTest : public testing::Test { public: DeviceActivityClientTest() @@ -185,7 +204,6 @@ network_state_test_helper_ = std::make_unique<NetworkStateTestHelper>( /*use_default_devices_and_services=*/false); - CreateWifiNetworkConfig(); // Initialize |local_state_| prefs used by device_activity_client class. @@ -194,15 +212,24 @@ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_); + chromeos::system::StatisticsProvider::SetTestProvider( + &statistics_provider_); + + // Create vector of device active use cases, which device activity client + // should maintain ownership of. + std::vector<std::unique_ptr<DeviceActiveUseCase>> use_cases; + use_cases.push_back(std::make_unique<FakeDailyUseCaseImpl>( + kFakePsmDeviceActiveSecret, kFakeChromeOSChannel, &local_state_)); + device_activity_client_ = std::make_unique<DeviceActivityClient>( - network_state_test_helper_->network_state_handler(), &local_state_, + network_state_test_helper_->network_state_handler(), test_shared_loader_factory_, std::make_unique<FakePsmDelegate>( psm_test_data_->test_case.ec_cipher_key(), psm_test_data_->test_case.seed(), std::move(psm_test_data_->plaintext_ids)), std::make_unique<base::MockRepeatingTimer>(), kTestFresnelBaseUrl, - kFakeFresnelApiKey, kFakePsmDeviceActiveSecret, kFakeFullHardwareClass); + kFakeFresnelApiKey, std::move(use_cases)); } void TearDown() override {} @@ -253,6 +280,7 @@ std::unique_ptr<DeviceActivityClient> device_activity_client_; std::string wifi_network_service_path_; base::HistogramTester histogram_tester_; + chromeos::system::FakeStatisticsProvider statistics_provider_; }; TEST_F(DeviceActivityClientTest, DefaultStatesAreInitializedProperly) {
diff --git a/ash/components/device_activity/device_activity_controller.cc b/ash/components/device_activity/device_activity_controller.cc index 647b25c1..36ebac8 100644 --- a/ash/components/device_activity/device_activity_controller.cc +++ b/ash/components/device_activity/device_activity_controller.cc
@@ -4,8 +4,11 @@ #include "ash/components/device_activity/device_activity_controller.h" +#include "ash/components/device_activity/daily_use_case_impl.h" +#include "ash/components/device_activity/device_active_use_case.h" #include "ash/components/device_activity/device_activity_client.h" #include "ash/components/device_activity/fresnel_pref_names.h" +#include "ash/components/device_activity/monthly_use_case_impl.h" #include "base/check_op.h" #include "base/time/time.h" #include "base/timer/timer.h" @@ -13,6 +16,7 @@ #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler.h" #include "components/prefs/pref_registry_simple.h" +#include "components/version_info/channel.h" #include "google_apis/google_api_keys.h" #include "third_party/private_membership/src/private_membership_rlwe_client.h" @@ -28,9 +32,6 @@ // TODO(https://crbug.com/1267432): Enable passing base url as a runtime flag. const char kFresnelBaseUrl[] = "https://crosfresnel-pa.googleapis.com"; -// Default value for devices that are missing the hardware class. -const char kHardwareClassKeyNotFound[] = "HARDWARE_CLASS_KEY_NOT_FOUND"; - class PsmDelegateImpl : public PsmDelegate { public: PsmDelegateImpl() = default; @@ -80,6 +81,7 @@ void DeviceActivityController::Start( Trigger trigger, + version_info::Channel chromeos_channel, PrefService* local_state, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { // Wrap with callback from |psm_device_active_secret_| retrieval using @@ -87,44 +89,43 @@ chromeos::SessionManagerClient::Get()->GetPsmDeviceActiveSecret( base::BindOnce(&device_activity::DeviceActivityController:: OnPsmDeviceActiveSecretFetched, - weak_factory_.GetWeakPtr(), trigger, local_state, - url_loader_factory)); + weak_factory_.GetWeakPtr(), trigger, chromeos_channel, + local_state, url_loader_factory)); } void DeviceActivityController::OnPsmDeviceActiveSecretFetched( Trigger trigger, + version_info::Channel chromeos_channel, PrefService* local_state, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& psm_device_active_secret) { // Continue when machine statistics are loaded, to avoid blocking. statistics_provider_->ScheduleOnMachineStatisticsLoaded(base::BindOnce( &device_activity::DeviceActivityController::OnMachineStatisticsLoaded, - weak_factory_.GetWeakPtr(), trigger, local_state, url_loader_factory, - psm_device_active_secret)); + weak_factory_.GetWeakPtr(), trigger, chromeos_channel, local_state, + url_loader_factory, psm_device_active_secret)); } void DeviceActivityController::OnMachineStatisticsLoaded( Trigger trigger, + version_info::Channel chromeos_channel, PrefService* local_state, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& psm_device_active_secret) { - - // Retrieve full hardware class from machine statistics object. - // Default |full_hardware_class| to kHardwareClassKeyNotFound if retrieval - // from machine statistics fails. - std::string full_hardware_class = kHardwareClassKeyNotFound; - - // TODO(hirthanan): Uncomment these lines after crbug/1289722 has launched. - // statistics_provider_->GetMachineStatistic( - // chromeos::system::kHardwareClassKey, &full_hardware_class); + // Initialize all device active use cases, sorted by + // smallest to largest window. i.e. Daily > Monthly> First Active. + // TODO(hirthanan): Add |MonthlyUseCaseImpl| to vector when ready to support + // monthly use case. + std::vector<std::unique_ptr<DeviceActiveUseCase>> use_cases; + use_cases.push_back(std::make_unique<DailyUseCaseImpl>( + psm_device_active_secret, chromeos_channel, local_state)); if (trigger == Trigger::kNetwork) { da_client_network_ = std::make_unique<DeviceActivityClient>( - chromeos::NetworkHandler::Get()->network_state_handler(), local_state, + chromeos::NetworkHandler::Get()->network_state_handler(), url_loader_factory, std::make_unique<PsmDelegateImpl>(), std::make_unique<base::RepeatingTimer>(), kFresnelBaseUrl, - google_apis::GetFresnelAPIKey(), psm_device_active_secret, - full_hardware_class); + google_apis::GetFresnelAPIKey(), std::move(use_cases)); } }
diff --git a/ash/components/device_activity/device_activity_controller.h b/ash/components/device_activity/device_activity_controller.h index 4414bdc..88a39ca 100644 --- a/ash/components/device_activity/device_activity_controller.h +++ b/ash/components/device_activity/device_activity_controller.h
@@ -15,6 +15,10 @@ class PrefRegistrySimple; class PrefService; +namespace version_info { +enum class Channel; +} // namespace version_info + namespace ash { namespace device_activity { @@ -36,6 +40,7 @@ // Start Device Activity reporting for a trigger. void Start(Trigger trigger, + version_info::Channel chromeos_channel, PrefService* local_state, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); @@ -45,12 +50,14 @@ private: void OnPsmDeviceActiveSecretFetched( Trigger trigger, + version_info::Channel chromeos_channel, PrefService* local_state, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& psm_device_active_secret); void OnMachineStatisticsLoaded( Trigger trigger, + version_info::Channel chromeos_channel, PrefService* local_state, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& psm_device_active_secret);
diff --git a/ash/components/device_activity/fresnel_service.proto b/ash/components/device_activity/fresnel_service.proto index 4e84285..85ca5daa 100644 --- a/ash/components/device_activity/fresnel_service.proto +++ b/ash/components/device_activity/fresnel_service.proto
@@ -13,6 +13,16 @@ // This proto represents the data transmitted over network // requests while reporting Device Actives to Fresnel server. +// The possible channels for ChromeOS installations. +// See details in //components/version_info/channel.h +enum Channel { + CHANNEL_UNKNOWN = 0; + CHANNEL_CANARY = 1; + CHANNEL_DEV = 2; + CHANNEL_BETA = 3; + CHANNEL_STABLE = 4; +} + // The Chrome OS device metadata which is sent in PSM import requests. // Each new field to this message requires privacy approval. // Next ID: 6 @@ -29,7 +39,16 @@ // Country code is represented by a 2-letter string (aka ISO 3166-1). // i.e. US for United States of America, CA for Canada. - optional string country_code = 4; + optional string country_code = 3; + + // Reserved for market segment. + reserved 4; + + // ChromeOS channel is used to determine the breakdown of devices that are + // coming from canary, dev, beta, stable, or unknown channels. + // This can be used with the ChromeOS version in order to determine + // questions like, what percentage of devices are in the M100 stable channel. + optional Channel chromeos_channel = 5; } // This proto will represent the data sent to Fresnel used to generate a PSM
diff --git a/ash/components/device_activity/monthly_use_case_impl.cc b/ash/components/device_activity/monthly_use_case_impl.cc index 55bc674..503e253a 100644 --- a/ash/components/device_activity/monthly_use_case_impl.cc +++ b/ash/components/device_activity/monthly_use_case_impl.cc
@@ -9,6 +9,7 @@ #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "components/prefs/pref_service.h" +#include "components/version_info/channel.h" #include "third_party/private_membership/src/private_membership_rlwe_client.h" namespace ash { @@ -17,13 +18,15 @@ namespace psm_rlwe = private_membership::rlwe; MonthlyUseCaseImpl::MonthlyUseCaseImpl( - PrefService* local_state, - const std::string& psm_device_active_secret) + const std::string& psm_device_active_secret, + version_info::Channel chromeos_channel, + PrefService* local_state) : DeviceActiveUseCase( - local_state, psm_device_active_secret, + chromeos_channel, prefs::kDeviceActiveLastKnownMonthlyPingTimestamp, - private_membership::rlwe::RlweUseCase::CROS_FRESNEL_MONTHLY) {} + private_membership::rlwe::RlweUseCase::CROS_FRESNEL_MONTHLY, + local_state) {} MonthlyUseCaseImpl::~MonthlyUseCaseImpl() = default; @@ -47,8 +50,12 @@ // Create fresh |DeviceMetadata| object. // Note every dimension added to this proto must be approved by privacy. DeviceMetadata* device_metadata = import_request.mutable_device_metadata(); - device_metadata->set_hardware_id(GetFullHardwareClass()); device_metadata->set_chromeos_version(GetChromeOSVersion()); + device_metadata->set_chromeos_channel(GetChromeOSChannel()); + + // TODO(hirthanan): This is used for debugging purposes until crbug/1289722 + // has launched. + device_metadata->set_hardware_id(GetFullHardwareClass()); return import_request; }
diff --git a/ash/components/device_activity/monthly_use_case_impl.h b/ash/components/device_activity/monthly_use_case_impl.h index ffce87c..6bb8508 100644 --- a/ash/components/device_activity/monthly_use_case_impl.h +++ b/ash/components/device_activity/monthly_use_case_impl.h
@@ -11,6 +11,10 @@ class PrefService; +namespace version_info { +enum class Channel; +} // namespace version_info + namespace ash { namespace device_activity { @@ -21,8 +25,9 @@ class COMPONENT_EXPORT(ASH_DEVICE_ACTIVITY) MonthlyUseCaseImpl : public DeviceActiveUseCase { public: - MonthlyUseCaseImpl(PrefService* local_state, - const std::string& psm_device_active_secret); + MonthlyUseCaseImpl(const std::string& psm_device_active_secret, + version_info::Channel chromeos_channel, + PrefService* local_state); MonthlyUseCaseImpl(const MonthlyUseCaseImpl&) = delete; MonthlyUseCaseImpl& operator=(const MonthlyUseCaseImpl&) = delete; ~MonthlyUseCaseImpl() override; @@ -30,6 +35,10 @@ // Generate the window identifier for the kCrosMonthly use case. // For example, the monthly use case should generate a window identifier // formatted: yyyyMM. + // + // It is generated on demand each time the state machine leaves the idle + // state. It is reused by several states. It is reset to nullopt. This field + // is used apart of PSM Import request. std::string GenerateUTCWindowIdentifier(base::Time ts) const override; // Generate Fresnel PSM import request body.
diff --git a/ash/components/device_activity/monthly_use_case_impl_unittest.cc b/ash/components/device_activity/monthly_use_case_impl_unittest.cc index 70db30e..83bc657 100644 --- a/ash/components/device_activity/monthly_use_case_impl_unittest.cc +++ b/ash/components/device_activity/monthly_use_case_impl_unittest.cc
@@ -9,6 +9,7 @@ #include "base/strings/string_util.h" #include "base/time/time.h" #include "components/prefs/testing_pref_service.h" +#include "components/version_info/channel.h" #include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/private_membership/src/private_membership_rlwe_client.h" @@ -23,6 +24,9 @@ // Initialize fake values used by the |MonthlyUseCaseImpl|. constexpr char kFakePsmDeviceActiveSecret[] = "FAKE_PSM_DEVICE_ACTIVE_SECRET"; +const version_info::Channel kFakeChromeOSChannel = + version_info::Channel::STABLE; + } // namespace class MonthlyUseCaseImplTest : public testing::Test { @@ -37,7 +41,7 @@ void SetUp() override { DeviceActivityController::RegisterPrefs(local_state_.registry()); monthly_use_case_impl_ = std::make_unique<MonthlyUseCaseImpl>( - &local_state_, kFakePsmDeviceActiveSecret); + kFakePsmDeviceActiveSecret, kFakeChromeOSChannel, &local_state_); } void TearDown() override { monthly_use_case_impl_.reset(); } @@ -118,11 +122,12 @@ EXPECT_TRUE( base::Time::FromString("01 Jan 2022 00:00:00 GMT", &last_monthly_ts)); + monthly_use_case_impl_->SetLastKnownPingTimestamp(last_monthly_ts); + EXPECT_TRUE( base::Time::FromString("25 Feb 2022 00:00:00 GMT", ¤t_monthly_ts)); - EXPECT_TRUE(monthly_use_case_impl_->IsDevicePingRequired(last_monthly_ts, - current_monthly_ts)); + EXPECT_TRUE(monthly_use_case_impl_->IsDevicePingRequired(current_monthly_ts)); } TEST_F(MonthlyUseCaseImplTest, PingNotRequiredInOverlappingUTCWindows) { @@ -131,11 +136,13 @@ EXPECT_TRUE( base::Time::FromString("01 Jan 2022 12:59:59 GMT", &last_monthly_ts)); + monthly_use_case_impl_->SetLastKnownPingTimestamp(last_monthly_ts); + EXPECT_TRUE( base::Time::FromString("25 Jan 2022 15:59:59 GMT", ¤t_monthly_ts)); - EXPECT_FALSE(monthly_use_case_impl_->IsDevicePingRequired( - last_monthly_ts, current_monthly_ts)); + EXPECT_FALSE( + monthly_use_case_impl_->IsDevicePingRequired(current_monthly_ts)); } TEST_F(MonthlyUseCaseImplTest, CheckIfPingRequiredInUTCBoundaryCases) { @@ -144,22 +151,25 @@ EXPECT_TRUE( base::Time::FromString("31 Jan 2022 23:59:59 GMT", &last_monthly_ts)); + monthly_use_case_impl_->SetLastKnownPingTimestamp(last_monthly_ts); + EXPECT_TRUE( base::Time::FromString("01 Feb 2022 00:00:00 GMT", ¤t_monthly_ts)); - EXPECT_TRUE(monthly_use_case_impl_->IsDevicePingRequired(last_monthly_ts, - current_monthly_ts)); + EXPECT_TRUE(monthly_use_case_impl_->IsDevicePingRequired(current_monthly_ts)); // Set last_monthly_ts as a date after current_monthly_ts. EXPECT_TRUE( base::Time::FromString("01 Feb 2022 00:00:00 GMT", &last_monthly_ts)); + monthly_use_case_impl_->SetLastKnownPingTimestamp(last_monthly_ts); + EXPECT_TRUE( base::Time::FromString("31 Jan 2022 23:59:59 GMT", ¤t_monthly_ts)); // Since the current_monthly_ts is prior to the last_monthly_ts, the function // should return false. - EXPECT_FALSE(monthly_use_case_impl_->IsDevicePingRequired( - last_monthly_ts, current_monthly_ts)); + EXPECT_FALSE( + monthly_use_case_impl_->IsDevicePingRequired(current_monthly_ts)); } TEST_F(MonthlyUseCaseImplTest, SameMonthTimestampsHaveSameWindowId) {
diff --git a/ash/components/drivefs/fake_drivefs.cc b/ash/components/drivefs/fake_drivefs.cc index 4a5edfc..7dfc8f6b 100644 --- a/ash/components/drivefs/fake_drivefs.cc +++ b/ash/components/drivefs/fake_drivefs.cc
@@ -99,6 +99,7 @@ mojom::FolderFeature folder_feature; std::string doc_id; int64_t stable_id = 0; + std::string alternate_url; }; class FakeDriveFs::SearchQuery : public mojom::SearchQuery { @@ -277,7 +278,8 @@ bool shared, const mojom::Capabilities& capabilities, const mojom::FolderFeature& folder_feature, - const std::string& doc_id) { + const std::string& doc_id, + const std::string& alternate_url) { auto& stored_metadata = metadata_[path]; stored_metadata.mime_type = mime_type; stored_metadata.original_name = original_name; @@ -291,6 +293,7 @@ if (shared) { stored_metadata.shared = true; } + stored_metadata.alternate_url = alternate_url; } void FakeDriveFs::DisplayConfirmDialog( @@ -342,18 +345,23 @@ ? mojom::FileMetadata::Type::kDirectory : mojom::FileMetadata::Type::kFile; - base::StringPiece prefix; - if (stored_metadata.hosted) { - prefix = "https://document_alternate_link/"; - } else if (info.is_directory) { - prefix = "https://folder_alternate_link/"; + if (!stored_metadata.alternate_url.empty()) { + metadata->alternate_url = stored_metadata.alternate_url; } else { - prefix = "https://file_alternate_link/"; + base::StringPiece prefix; + if (stored_metadata.hosted) { + prefix = "https://document_alternate_link/"; + } else if (info.is_directory) { + prefix = "https://folder_alternate_link/"; + } else { + prefix = "https://file_alternate_link/"; + } + std::string suffix = stored_metadata.original_name.empty() + ? path.BaseName().value() + : stored_metadata.original_name; + metadata->alternate_url = GURL(base::StrCat({prefix, suffix})).spec(); } - std::string suffix = stored_metadata.original_name.empty() - ? path.BaseName().value() - : stored_metadata.original_name; - metadata->alternate_url = GURL(base::StrCat({prefix, suffix})).spec(); + metadata->capabilities = stored_metadata.capabilities.Clone(); metadata->stable_id = stored_metadata.stable_id; if (stored_metadata.hosted) {
diff --git a/ash/components/drivefs/fake_drivefs.h b/ash/components/drivefs/fake_drivefs.h index b3dcda2d..bfe7de2 100644 --- a/ash/components/drivefs/fake_drivefs.h +++ b/ash/components/drivefs/fake_drivefs.h
@@ -62,7 +62,8 @@ bool shared, const mojom::Capabilities& capabilities, const mojom::FolderFeature& folder_feature, - const std::string& doc_id); + const std::string& doc_id, + const std::string& alternate_url); void DisplayConfirmDialog( drivefs::mojom::DialogReasonPtr reason,
diff --git a/ash/constants/ash_pref_names.cc b/ash/constants/ash_pref_names.cc index c1544f8..7f22bb3 100644 --- a/ash/constants/ash_pref_names.cc +++ b/ash/constants/ash_pref_names.cc
@@ -416,6 +416,12 @@ const char kLocalStateDevicePeripheralDataAccessEnabled[] = "settings.local_state_device_pci_data_access_enabled"; +// The timestamps (in milliseconds since UNIX Epoch, aka JavaTime) of the user +// pressed the shutdown button from shelf. +// static +const char kLoginShutdownTimestampPrefName[] = + "ash.shelf.login_shutdown_timestamp"; + // A boolean pref that specifies if the cellular setup notification can be // shown or not. This notification should be shown post-OOBE if the user has a // cellular-capable device but no available cellular networks. It should only be
diff --git a/ash/constants/ash_pref_names.h b/ash/constants/ash_pref_names.h index f9dd68d..e8f5ecc3 100644 --- a/ash/constants/ash_pref_names.h +++ b/ash/constants/ash_pref_names.h
@@ -206,6 +206,9 @@ extern const char kLocalStateDevicePeripheralDataAccessEnabled[]; COMPONENT_EXPORT(ASH_CONSTANTS) +extern const char kLoginShutdownTimestampPrefName[]; + +COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kCanCellularSetupNotificationBeShown[]; // Managed-guest session privacy warning.
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc index 776f4c96..fe0d421 100644 --- a/ash/login/ui/lock_contents_view.cc +++ b/ash/login/ui/lock_contents_view.cc
@@ -569,6 +569,7 @@ LockContentsView::UserState::UserState(const LoginUserInfo& user_info) : account_id(user_info.basic_user_info.account_id) { fingerprint_state = user_info.fingerprint_state; + smart_lock_state = user_info.smart_lock_state; if (user_info.auth_type == proximity_auth::mojom::AuthType::ONLINE_SIGN_IN) force_online_sign_in = true; show_pin_pad_for_password = user_info.show_pin_pad_for_password; @@ -2050,6 +2051,10 @@ to_update_auth |= LoginAuthUserView::AUTH_TAP; if (state->fingerprint_state != FingerprintState::UNAVAILABLE) to_update_auth |= LoginAuthUserView::AUTH_FINGERPRINT; + if (state->smart_lock_state != SmartLockState::kDisabled && + state->smart_lock_state != SmartLockState::kInactive) { + to_update_auth |= LoginAuthUserView::AUTH_SMART_LOCK; + } if (state->auth_factor_is_hiding_password) { to_update_auth |= LoginAuthUserView::AUTH_AUTH_FACTOR_IS_HIDING_PASSWORD;
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h index 75a9ec5..1140d0c 100644 --- a/ash/login/ui/lock_contents_view.h +++ b/ash/login/ui/lock_contents_view.h
@@ -22,6 +22,7 @@ #include "ash/public/cpp/keyboard/keyboard_controller_observer.h" #include "ash/public/cpp/login_accelerators.h" #include "ash/public/cpp/login_types.h" +#include "ash/public/cpp/smartlock_state.h" #include "ash/public/cpp/system_tray_observer.h" #include "base/callback_forward.h" #include "base/memory/raw_ptr.h" @@ -53,7 +54,6 @@ class LoginUserView; class NoteActionLaunchButton; class ScrollableUsersListView; -enum class SmartLockState; namespace mojom { enum class TrayActionState; @@ -276,8 +276,8 @@ bool show_pin_pad_for_password = false; size_t autosubmit_pin_length = 0; absl::optional<EasyUnlockIconInfo> easy_unlock_icon_info = absl::nullopt; - FingerprintState fingerprint_state; - SmartLockState smart_lock_state; + FingerprintState fingerprint_state = FingerprintState::UNAVAILABLE; + SmartLockState smart_lock_state = SmartLockState::kDisabled; bool auth_factor_is_hiding_password = false; // When present, indicates that the TPM is locked. absl::optional<base::TimeDelta> time_until_tpm_unlock = absl::nullopt;
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc index d0410444..ce5a3ffe 100644 --- a/ash/login/ui/lock_contents_view_unittest.cc +++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -171,6 +171,21 @@ generator->MoveMouseTo(user_view->GetBoundsInScreen().CenterPoint()); generator->ClickLeftButton(); } + + void VerifyUpdatingSmartLockStateSetsAuthMethod( + LoginBigUserView* view, + SmartLockState smart_lock_state, + bool should_have_auth_method) { + ASSERT_TRUE(view); + LoginAuthUserView* auth_user_view = view->auth_user(); + ASSERT_TRUE(auth_user_view); + LoginAuthUserView::TestApi test_api(auth_user_view); + AccountId account_id = view->GetCurrentUser().basic_user_info.account_id; + + DataDispatcher()->SetSmartLockState(account_id, smart_lock_state); + EXPECT_EQ(should_have_auth_method, + test_api.HasAuthMethod(LoginAuthUserView::AUTH_SMART_LOCK)); + } }; TEST_F(LockContentsViewUnitTest, DisplayMode) { @@ -3101,6 +3116,45 @@ Mock::VerifyAndClearExpectations(client.get()); } +TEST_F(LockContentsViewUnitTest, UpdatingSmartLockStateSetsAuthMethod) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kSmartLockUIRevamp); + // Build login screen with 1 user. + ui::ScopedAnimationDurationScaleMode non_zero_duration_mode( + ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); + auto* contents = new LockContentsView( + mojom::TrayActionState::kNotAvailable, LockScreen::ScreenType::kLogin, + DataDispatcher(), + std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); + AddUsers(1); + SetWidget(CreateWidgetWithContent(contents)); + LoginBigUserView* big_view = + LockContentsView::TestApi(contents).primary_big_view(); + + std::pair<SmartLockState, bool> state_and_is_auth_method_expected[] = { + {SmartLockState::kDisabled, false}, + {SmartLockState::kInactive, false}, + {SmartLockState::kBluetoothDisabled, true}, + {SmartLockState::kPhoneNotLockable, true}, + {SmartLockState::kPhoneNotFound, true}, + {SmartLockState::kConnectingToPhone, true}, + {SmartLockState::kPhoneNotAuthenticated, true}, + {SmartLockState::kPhoneFoundLockedAndDistant, true}, + {SmartLockState::kPhoneFoundLockedAndProximate, true}, + {SmartLockState::kPhoneFoundUnlockedAndDistant, true}, + {SmartLockState::kPhoneAuthenticated, true}, + {SmartLockState::kPasswordReentryRequired, true}, + {SmartLockState::kPrimaryUserAbsent, true} + + }; + + for (const auto& it : state_and_is_auth_method_expected) { + VerifyUpdatingSmartLockStateSetsAuthMethod( + big_view, /*smart_lock_state=*/it.first, + /*should_have_auth_method=*/it.second); + } +} + TEST_F(LockContentsViewUnitTest, SmartLockStateHidesPasswordView) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(features::kSmartLockUIRevamp); @@ -3114,7 +3168,7 @@ std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher())); LockContentsView::TestApi test_api(contents); AddUsers(1); - const LockContentsView::UserState& user = test_api.users()[0]; + const AccountId account_id = test_api.users()[0].account_id; SetWidget(CreateWidgetWithContent(contents)); LoginBigUserView* big_view = LockContentsView::TestApi(contents).primary_big_view(); @@ -3127,18 +3181,18 @@ // Check that password view is still visible when auth // factor is in kReady state. DataDispatcher()->SetSmartLockState( - user.account_id, SmartLockState::kPhoneFoundLockedAndProximate); + account_id, SmartLockState::kPhoneFoundLockedAndProximate); EXPECT_TRUE(auth_user_view->password_view()->GetVisible()); // Check that password view is no longer visible when auth // factor is in kClickRequired state. - DataDispatcher()->SetSmartLockState(user.account_id, + DataDispatcher()->SetSmartLockState(account_id, SmartLockState::kPhoneAuthenticated); EXPECT_FALSE(auth_user_view->password_view()->GetVisible()); // Check that password view becomes visible when auth // factor is in kErrorPermanent state. - DataDispatcher()->SetSmartLockState(user.account_id, + DataDispatcher()->SetSmartLockState(account_id, SmartLockState::kPasswordReentryRequired); EXPECT_TRUE(auth_user_view->password_view()->GetVisible()); }
diff --git a/ash/login/ui/login_auth_factors_view.cc b/ash/login/ui/login_auth_factors_view.cc index 4526f37..8ef95a3 100644 --- a/ash/login/ui/login_auth_factors_view.cc +++ b/ash/login/ui/login_auth_factors_view.cc
@@ -269,17 +269,14 @@ AuthFactorModel* active_auth_factor = GetHighestPriorityAuthFactor(auth_factors_); if (!active_auth_factor) { - SetVisible(false); return; } PrioritizedAuthFactorViewState state = GetPrioritizedAuthFactorViewState(*active_auth_factor); if (state == PrioritizedAuthFactorViewState::kUnavailable) { - SetVisible(false); return; } - SetVisible(true); if (state != PrioritizedAuthFactorViewState::kErrorForeground) { error_timer_.Stop();
diff --git a/ash/login/ui/login_auth_factors_view_unittest.cc b/ash/login/ui/login_auth_factors_view_unittest.cc index b035bfcc..917d4498 100644 --- a/ash/login/ui/login_auth_factors_view_unittest.cc +++ b/ash/login/ui/login_auth_factors_view_unittest.cc
@@ -223,31 +223,6 @@ bool auth_factor_is_hiding_password_ = false; }; -TEST_F(LoginAuthFactorsViewUnittest, NotVisibleIfNoAuthFactors) { - AddAuthFactors({AuthFactorType::kFingerprint, AuthFactorType::kSmartLock}); - EXPECT_TRUE(view_->GetVisible()); - - LoginAuthFactorsView::TestApi test_api(view_); - auto& auth_factors = test_api.auth_factors(); - auth_factors.clear(); - test_api.UpdateState(); - - EXPECT_FALSE(view_->GetVisible()); -} - -TEST_F(LoginAuthFactorsViewUnittest, NotVisibleIfAuthFactorsUnavailable) { - AddAuthFactors({AuthFactorType::kFingerprint, AuthFactorType::kSmartLock}); - EXPECT_TRUE(view_->GetVisible()); - - for (auto* factor : auth_factors_) { - factor->state_ = AuthFactorState::kUnavailable; - } - LoginAuthFactorsView::TestApi test_api(view_); - test_api.UpdateState(); - - EXPECT_FALSE(view_->GetVisible()); -} - TEST_F(LoginAuthFactorsViewUnittest, TapOrClickCalled) { AddAuthFactors({AuthFactorType::kFingerprint, AuthFactorType::kSmartLock}); auto* factor = auth_factors_[0];
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc index feb62cf4..e27ee6c 100644 --- a/ash/login/ui/login_auth_user_view.cc +++ b/ash/login/ui/login_auth_user_view.cc
@@ -947,6 +947,7 @@ has_pinpad = view->ShouldShowPinPad(); has_toggle = view->ShouldShowToggle(); has_fingerprint = view->HasAuthMethod(LoginAuthUserView::AUTH_FINGERPRINT); + has_smart_lock = view->HasAuthMethod(LoginAuthUserView::AUTH_SMART_LOCK); has_challenge_response = view->HasAuthMethod(LoginAuthUserView::AUTH_CHALLENGE_RESPONSE); auth_disabled = view->HasAuthMethod(LoginAuthUserView::AUTH_DISABLED); @@ -965,6 +966,7 @@ bool has_pinpad = false; bool has_toggle = false; bool has_fingerprint = false; + bool has_smart_lock = false; bool has_challenge_response = false; bool auth_disabled = false; bool tpm_is_locked = false; @@ -1384,9 +1386,14 @@ DCHECK(fingerprint_auth_factor_model_); DCHECK(smart_lock_auth_factor_model_); DCHECK(auth_factors_view_); + // TODO(b/219978360): Should investigate why setting + // |fingerprint_auth_factor_model_| availability here is necessary if state + // management within LockContentsView is working properly. fingerprint_auth_factor_model_->set_available( current_state.has_fingerprint); auth_factors_view_->SetCanUsePin(HasAuthMethod(AUTH_PIN)); + auth_factors_view_->SetVisible(current_state.has_fingerprint || + current_state.has_smart_lock); } else { DCHECK(fingerprint_view_); fingerprint_view_->SetVisible(current_state.has_fingerprint);
diff --git a/ash/login/ui/login_auth_user_view.h b/ash/login/ui/login_auth_user_view.h index aea44b7..f9ea1c3ff 100644 --- a/ash/login/ui/login_auth_user_view.h +++ b/ash/login/ui/login_auth_user_view.h
@@ -54,14 +54,15 @@ // TODO(b/217970801): Remove this field. AUTH_ONLINE_SIGN_IN = 1 << 3, // Force online sign-in. AUTH_FINGERPRINT = 1 << 4, // Use fingerprint to unlock. - AUTH_CHALLENGE_RESPONSE = 1 << 5, // Authenticate via challenge-response + AUTH_SMART_LOCK = 1 << 5, // Use Smart Lock to unlock. + AUTH_CHALLENGE_RESPONSE = 1 << 6, // Authenticate via challenge-response // protocol using security token. - AUTH_DISABLED = 1 << 6, // Disable all the auth methods and show a + AUTH_DISABLED = 1 << 7, // Disable all the auth methods and show a // message to user. - AUTH_DISABLED_TPM_LOCKED = 1 << 7, // Disable all the auth methods due + AUTH_DISABLED_TPM_LOCKED = 1 << 8, // Disable all the auth methods due // to the TPM being locked AUTH_AUTH_FACTOR_IS_HIDING_PASSWORD = - 1 << 8, // Hide the password/pin fields and slide the auth factors + 1 << 9, // Hide the password/pin fields and slide the auth factors // up. This happens, for example, when an auth factor requires // the user to click a button as a final step. Note that if // this bit is set, the password/pin will be hidden even if
diff --git a/ash/login/ui/login_auth_user_view_unittest.cc b/ash/login/ui/login_auth_user_view_unittest.cc index d603272..1663f1d 100644 --- a/ash/login/ui/login_auth_user_view_unittest.cc +++ b/ash/login/ui/login_auth_user_view_unittest.cc
@@ -678,4 +678,30 @@ ExpectModeVisibility(LoginAuthUserView::InputFieldMode::NONE); } +// Regression test for b/217385675. +// LoginAuthFactorsView should only be shown when auth methods are available. +TEST_F(LoginAuthUserViewAuthFactorsUnittest, + AuthFactorsViewNotShownWhenNoAuthFactors) { + auto user = CreateUser("user@domain.com"); + InitializeViewForUser(user); + LoginAuthUserView::TestApi auth_test(view_); + auto* auth_factors_view = auth_test.auth_factors_view(); + + EXPECT_TRUE(auth_factors_view); + EXPECT_FALSE(auth_factors_view->GetVisible()); + + SetAuthMethods(LoginAuthUserView::AuthMethods::AUTH_SMART_LOCK); + EXPECT_TRUE(auth_factors_view->GetVisible()); + + SetAuthMethods(LoginAuthUserView::AuthMethods::AUTH_FINGERPRINT); + EXPECT_TRUE(auth_factors_view->GetVisible()); + + SetAuthMethods(LoginAuthUserView::AuthMethods::AUTH_SMART_LOCK | + LoginAuthUserView::AuthMethods::AUTH_FINGERPRINT); + EXPECT_TRUE(auth_factors_view->GetVisible()); + + SetAuthMethods(LoginAuthUserView::AUTH_NONE); + EXPECT_FALSE(auth_factors_view->GetVisible()); +} + } // namespace ash
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc index ada4e36..0f3f962 100644 --- a/ash/public/cpp/app_list/app_list_features.cc +++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -41,6 +41,8 @@ "ForceShowContinueSection", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kSearchResultInlineIcon{"SearchResultInlineIcon", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kDynamicSearchUpdateAnimation{ + "DynamicSearchUpdateAnimation", base::FEATURE_DISABLED_BY_DEFAULT}; bool IsAppRankerEnabled() { return base::FeatureList::IsEnabled(kEnableAppRanker); @@ -110,10 +112,22 @@ base::FeatureList::IsEnabled(kSearchResultInlineIcon); } +bool IsDynamicSearchUpdateAnimationEnabled() { + // Search update animations are only supported for categorical search. + return IsCategoricalSearchEnabled() && + base::FeatureList::IsEnabled(kDynamicSearchUpdateAnimation); +} + std::string CategoricalSearchType() { return GetFieldTrialParamValueByFeature(kCategoricalSearch, "ranking"); } +base::TimeDelta DynamicSearchUpdateAnimationDuration() { + int ms = base::GetFieldTrialParamByFeatureAsInt( + kDynamicSearchUpdateAnimation, "animation_time", /*default value =*/100); + return base::TimeDelta(base::Milliseconds(ms)); +} + bool IsForceShowContinueSectionEnabled() { return base::FeatureList::IsEnabled(kForceShowContinueSection); }
diff --git a/ash/public/cpp/app_list/app_list_features.h b/ash/public/cpp/app_list/app_list_features.h index dd5dca4a..8c1dd299 100644 --- a/ash/public/cpp/app_list/app_list_features.h +++ b/ash/public/cpp/app_list/app_list_features.h
@@ -8,6 +8,7 @@ #include <string> #include "ash/public/cpp/ash_public_export.h" +#include "base/time/time.h" namespace base { struct Feature; @@ -69,6 +70,10 @@ // Enables iconified text and inline icons in launcher search. ASH_PUBLIC_EXPORT extern const base::Feature kSearchResultInlineIcon; +// Enable shortened search result update animations when in progress animations +// are interrupted by search model updates. +ASH_PUBLIC_EXPORT extern const base::Feature kDynamicSearchUpdateAnimation; + ASH_PUBLIC_EXPORT bool IsAppRankerEnabled(); ASH_PUBLIC_EXPORT bool IsZeroStateAppsRankerEnabled(); ASH_PUBLIC_EXPORT bool IsQueryBasedMixedTypesRankerEnabled(); @@ -85,6 +90,8 @@ ASH_PUBLIC_EXPORT bool IsLauncherSearchNormalizationEnabled(); ASH_PUBLIC_EXPORT bool IsCategoricalSearchEnabled(); ASH_PUBLIC_EXPORT bool IsSearchResultInlineIconEnabled(); +ASH_PUBLIC_EXPORT bool IsDynamicSearchUpdateAnimationEnabled(); +ASH_PUBLIC_EXPORT base::TimeDelta DynamicSearchUpdateAnimationDuration(); ASH_PUBLIC_EXPORT std::string AnswerServerUrl(); ASH_PUBLIC_EXPORT std::string AnswerServerQuerySuffix();
diff --git a/ash/public/cpp/desks_templates_delegate.h b/ash/public/cpp/desks_templates_delegate.h index b4506ab3..3d5d4db 100644 --- a/ash/public/cpp/desks_templates_delegate.h +++ b/ash/public/cpp/desks_templates_delegate.h
@@ -96,6 +96,10 @@ // Called when the feedback button is pressed. virtual void OpenFeedbackDialog(const std::string& extra_diagnostics) = 0; + + // Return the readable app name for this app id (i.e. "madfksjfasdfkjasdkf" -> + // "Chrome"). + virtual std::string GetAppShortName(const std::string& app_id) = 0; }; } // namespace ash
diff --git a/ash/public/cpp/test/test_desks_templates_delegate.cc b/ash/public/cpp/test/test_desks_templates_delegate.cc index 889f534f..34ff8e3b 100644 --- a/ash/public/cpp/test/test_desks_templates_delegate.cc +++ b/ash/public/cpp/test/test_desks_templates_delegate.cc
@@ -61,4 +61,9 @@ void TestDesksTemplatesDelegate::OpenFeedbackDialog( const std::string& extra_diagnostics) {} +std::string TestDesksTemplatesDelegate::GetAppShortName( + const std::string& app_id) { + return std::string(); +} + } // namespace ash
diff --git a/ash/public/cpp/test/test_desks_templates_delegate.h b/ash/public/cpp/test/test_desks_templates_delegate.h index d5042e9..d7b490e9 100644 --- a/ash/public/cpp/test/test_desks_templates_delegate.h +++ b/ash/public/cpp/test/test_desks_templates_delegate.h
@@ -61,6 +61,7 @@ base::TimeDelta delay) override; bool IsWindowSupportedForDeskTemplate(aura::Window* window) const override; void OpenFeedbackDialog(const std::string& extra_diagnostics) override; + std::string GetAppShortName(const std::string& app_id) override; private: desks_storage::DeskModel* desk_model_ = nullptr;
diff --git a/ash/services/ime/ime_service_associated_unittest.cc b/ash/services/ime/ime_service_associated_unittest.cc index d8c6864f..bfbc43e 100644 --- a/ash/services/ime/ime_service_associated_unittest.cc +++ b/ash/services/ime/ime_service_associated_unittest.cc
@@ -203,8 +203,8 @@ void HandleAutocorrect(mojom::AutocorrectSpanPtr autocorrect_span) override {} void RequestSuggestions(mojom::SuggestionsRequestPtr request, RequestSuggestionsCallback callback) override {} - void DisplaySuggestions(const std::vector<::chromeos::ime::TextSuggestion>& - suggestions) override {} + void DisplaySuggestions( + const std::vector<TextSuggestion>& suggestions) override {} void UpdateCandidatesWindow(mojom::CandidatesWindowPtr window) override {} void RecordUkm(mojom::UkmEntryPtr entry) override {} void ReportKoreanAction(mojom::KoreanAction action) override {}
diff --git a/ash/services/ime/ime_service_unittest.cc b/ash/services/ime/ime_service_unittest.cc index 991b112..8b4c1da 100644 --- a/ash/services/ime/ime_service_unittest.cc +++ b/ash/services/ime/ime_service_unittest.cc
@@ -219,8 +219,8 @@ void HandleAutocorrect(mojom::AutocorrectSpanPtr autocorrect_span) override {} void RequestSuggestions(mojom::SuggestionsRequestPtr request, RequestSuggestionsCallback callback) override {} - void DisplaySuggestions(const std::vector<::chromeos::ime::TextSuggestion>& - suggestions) override {} + void DisplaySuggestions( + const std::vector<TextSuggestion>& suggestions) override {} void UpdateCandidatesWindow(mojom::CandidatesWindowPtr window) override {} void RecordUkm(mojom::UkmEntryPtr entry) override {} void ReportKoreanAction(mojom::KoreanAction action) override {}
diff --git a/ash/services/ime/public/cpp/rulebased/engine.cc b/ash/services/ime/public/cpp/rulebased/engine.cc index ec2fb5d8..14b1d0a9 100644 --- a/ash/services/ime/public/cpp/rulebased/engine.cc +++ b/ash/services/ime/public/cpp/rulebased/engine.cc
@@ -7,13 +7,10 @@ #include "ash/services/ime/public/cpp/rulebased/rules_data.h" #include "base/strings/utf_string_conversions.h" -namespace chromeos { +namespace ash { namespace ime { namespace rulebased { -// TODO(https://crbug.com/1164001): remove after migrating to ash. -namespace mojom = ::ash::ime::mojom; - Engine::Engine() = default; Engine::~Engine() = default; @@ -151,4 +148,4 @@ } // namespace rulebased } // namespace ime -} // namespace chromeos +} // namespace ash
diff --git a/ash/services/ime/public/cpp/rulebased/engine.h b/ash/services/ime/public/cpp/rulebased/engine.h index 596c3c4..0899816 100644 --- a/ash/services/ime/public/cpp/rulebased/engine.h +++ b/ash/services/ime/public/cpp/rulebased/engine.h
@@ -10,7 +10,7 @@ #include "ash/services/ime/public/mojom/input_method.mojom.h" -namespace chromeos { +namespace ash { namespace ime { namespace rulebased { @@ -42,8 +42,7 @@ void Activate(const std::string& id); void Reset(); - ProcessKeyResult ProcessKey(ash::ime::mojom::DomCode code, - uint8_t modifier_state); + ProcessKeyResult ProcessKey(mojom::DomCode code, uint8_t modifier_state); private: void ClearHistory(); @@ -70,6 +69,15 @@ } // namespace rulebased } // namespace ime -} // namespace chromeos +} // namespace ash + +// TODO(https://crbug.com/1164001): remove when the migration is finished. +namespace chromeos::ime::rulebased { +using ::ash::ime::rulebased::Engine; +using ::ash::ime::rulebased::MODIFIER_ALTGR; +using ::ash::ime::rulebased::MODIFIER_CAPSLOCK; +using ::ash::ime::rulebased::MODIFIER_SHIFT; +using ::ash::ime::rulebased::ProcessKeyResult; +} // namespace chromeos::ime::rulebased #endif // ASH_SERVICES_IME_PUBLIC_CPP_RULEBASED_ENGINE_H_
diff --git a/ash/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc b/ash/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc index 3b63488..e636c289 100644 --- a/ash/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc +++ b/ash/services/ime/public/cpp/rulebased/rulebased_fuzzer.cc
@@ -11,7 +11,7 @@ #include "ash/services/ime/public/cpp/rulebased/rules_data.h" #include "testing/libfuzzer/proto/lpm_interface.h" -namespace rulebased = chromeos::ime::rulebased; +namespace rulebased = ::ash::ime::rulebased; namespace mojom = ::ash::ime::mojom; namespace {
diff --git a/ash/services/ime/public/cpp/rulebased/rulebased_unittest.cc b/ash/services/ime/public/cpp/rulebased/rulebased_unittest.cc index 99ea83e..412c673 100644 --- a/ash/services/ime/public/cpp/rulebased/rulebased_unittest.cc +++ b/ash/services/ime/public/cpp/rulebased/rulebased_unittest.cc
@@ -10,12 +10,9 @@ #include "ash/services/ime/public/mojom/input_method.mojom-shared.h" #include "testing/gtest/include/gtest/gtest.h" -namespace chromeos { +namespace ash { namespace ime { -// TODO(https://crbug.com/1164001): remove after migrating to ash. -namespace mojom = ::ash::ime::mojom; - namespace { struct KeyVerifyEntry { @@ -244,4 +241,4 @@ } } // namespace ime -} // namespace chromeos +} // namespace ash
diff --git a/ash/services/ime/public/cpp/rulebased/rules_data.cc b/ash/services/ime/public/cpp/rulebased/rules_data.cc index dbabe72..13348c8 100644 --- a/ash/services/ime/public/cpp/rulebased/rules_data.cc +++ b/ash/services/ime/public/cpp/rulebased/rules_data.cc
@@ -42,15 +42,12 @@ #include "base/strings/utf_string_conversions.h" #include "third_party/re2/src/re2/re2.h" -namespace chromeos { +namespace ash { namespace ime { namespace rulebased { namespace { -// TODO(https://crbug.com/1164001): remove after migrating to ash. -namespace mojom = ::ash::ime::mojom; - struct RawDataEntry { const char*** key_map; bool is_102_keyboard; @@ -436,4 +433,4 @@ } // namespace rulebased } // namespace ime -} // namespace chromeos +} // namespace ash
diff --git a/ash/services/ime/public/cpp/rulebased/rules_data.h b/ash/services/ime/public/cpp/rulebased/rules_data.h index 7aedc57..21288ade 100644 --- a/ash/services/ime/public/cpp/rulebased/rules_data.h +++ b/ash/services/ime/public/cpp/rulebased/rules_data.h
@@ -16,11 +16,11 @@ class RE2; } // namespace re2 -namespace chromeos { +namespace ash { namespace ime { namespace rulebased { -using KeyMap = std::map<ash::ime::mojom::DomCode, const char*>; +using KeyMap = std::map<mojom::DomCode, const char*>; using TransformRule = std::pair<std::unique_ptr<re2::RE2>, std::string>; @@ -91,6 +91,6 @@ } // namespace rulebased } // namespace ime -} // namespace chromeos +} // namespace ash #endif // ASH_SERVICES_IME_PUBLIC_CPP_RULEBASED_RULES_DATA_H_
diff --git a/ash/services/ime/public/cpp/shared_lib/interfaces.h b/ash/services/ime/public/cpp/shared_lib/interfaces.h index e386b425..7f684ac 100644 --- a/ash/services/ime/public/cpp/shared_lib/interfaces.h +++ b/ash/services/ime/public/cpp/shared_lib/interfaces.h
@@ -62,7 +62,7 @@ // copy of the MojoSystemThunks struct definition. struct MojoSystemThunks; -namespace chromeos { +namespace ash { namespace ime { // A simple downloading callback with the downloading URL as return. @@ -174,7 +174,7 @@ }; } // namespace ime -} // namespace chromeos +} // namespace ash // ============================================================================ // [Proto + Mojo modes] [IME service container --> IME shared lib] @@ -206,7 +206,7 @@ // once. Client must call this function before any others. `platform` must // remain valid during the whole life of the IME shared lib. __attribute__((visibility("default"))) void ImeDecoderInitOnce( - chromeos::ime::ImeCrosPlatform* platform); + ash::ime::ImeCrosPlatform* platform); // Closes the IME shared lib and releases resources used by it. __attribute__((visibility("default"))) void ImeDecoderClose(); @@ -214,7 +214,7 @@ // Sets logger for the shared library. Releases the previous logger if there // was one. If the new logger is null, then no logger will be used. __attribute__((visibility("default"))) void SetImeEngineLogger( - chromeos::ime::ChromeLoggerFunc logger_func); + ash::ime::ChromeLoggerFunc logger_func); // **************************************************************************** // ***************************** PROTO MODE *********************************** @@ -230,7 +230,7 @@ // TODO(googleo): Remove this and pass `delegate` upon ImeDecoderInitOnce. __attribute__((visibility("default"))) bool ImeDecoderActivateIme( const char* ime_spec, - chromeos::ime::ImeClientDelegate* delegate); + ash::ime::ImeClientDelegate* delegate); // Processes IME events sent from client in serialised protobuf `data` which // should be invalidated by this IME shared lib soon after it's consumed. @@ -266,4 +266,13 @@ } // extern "C" +// TODO(https://crbug.com/1164001): remove when the migration is finished. +namespace chromeos::ime { +using ::ash::ime::ChromeLoggerFunc; +using ::ash::ime::ImeClientDelegate; +using ::ash::ime::ImeCrosPlatform; +using ::ash::ime::ImeSequencedTask; +using ::ash::ime::SimpleDownloadCallbackV2; +} // namespace chromeos::ime + #endif // ASH_SERVICES_IME_PUBLIC_CPP_SHARED_LIB_INTERFACES_H_
diff --git a/ash/services/ime/public/cpp/suggestions.h b/ash/services/ime/public/cpp/suggestions.h index 9cae129d..a590481b 100644 --- a/ash/services/ime/public/cpp/suggestions.h +++ b/ash/services/ime/public/cpp/suggestions.h
@@ -7,7 +7,7 @@ #include <string> -namespace chromeos { +namespace ash { namespace ime { enum class TextSuggestionMode { @@ -46,16 +46,11 @@ }; } // namespace ime -} // namespace chromeos - -// TODO(https://crbug.com/1164001): remove when moved to ash. -namespace ash { -namespace ime { -using ::chromeos::ime::TextCompletionCandidate; -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; -} // namespace ime } // namespace ash +// TODO(https://crbug.com/1164001): remove when the migration is finished. +namespace chromeos::ime { +using ::ash::ime::TextSuggestion; +} + #endif // ASH_SERVICES_IME_PUBLIC_CPP_SUGGESTIONS_H_
diff --git a/ash/shell.cc b/ash/shell.cc index f123131..463d9ef 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -1183,8 +1183,8 @@ tray_action_ = std::make_unique<TrayAction>(backlights_forced_off_setter_.get()); - lock_state_controller_ = - std::make_unique<LockStateController>(shutdown_controller_.get()); + lock_state_controller_ = std::make_unique<LockStateController>( + shutdown_controller_.get(), local_state_); power_button_controller_ = std::make_unique<PowerButtonController>( backlights_forced_off_setter_.get()); // Pass the initial display state to PowerButtonController.
diff --git a/ash/system/message_center/ash_notification_expand_button.cc b/ash/system/message_center/ash_notification_expand_button.cc index de66533a..4f560d7 100644 --- a/ash/system/message_center/ash_notification_expand_button.cc +++ b/ash/system/message_center/ash_notification_expand_button.cc
@@ -26,7 +26,7 @@ #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" -#include "ui/views/layout/flex_layout.h" +#include "ui/views/layout/box_layout.h" #include "ui/views/layout/layout_types.h" #include "ui/views/view_class_properties.h" @@ -38,8 +38,8 @@ AshNotificationExpandButton::AshNotificationExpandButton( PressedCallback callback) : Button(std::move(callback)) { - SetLayoutManager(std::make_unique<views::FlexLayout>()) - ->SetMainAxisAlignment(views::LayoutAlignment::kEnd); + SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal)); auto label = std::make_unique<views::Label>(); label->SetFontList(gfx::FontList({kGoogleSansFont}, gfx::Font::NORMAL, @@ -59,7 +59,8 @@ image_ = AddChildView(std::move(image)); views::InstallRoundRectHighlightPathGenerator( - this, gfx::Insets(), kNotificationExpandButtonCornerRadius); + this, kNotificationExpandButtonFocusInsets, + kNotificationExpandButtonCornerRadius); SetAccessibleName(l10n_util::GetStringUTF16( expanded_ ? IDS_ASH_NOTIFICATION_COLLAPSE_TOOLTIP
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc index 071d0b4..90eecce 100644 --- a/ash/system/message_center/ash_notification_view.cc +++ b/ash/system/message_center/ash_notification_view.cc
@@ -327,10 +327,9 @@ message_center_observer_.Observe(message_center::MessageCenter::Get()); // TODO(crbug/1232197): fix views and layout to match spec. // Instantiate view instances and define layout and view hierarchy. - SetLayoutManager(std::make_unique<views::FlexLayout>()) - ->SetOrientation(views::LayoutOrientation::kVertical) - .SetInteriorMargin(notification.group_child() ? gfx::Insets() - : kNotificationViewPadding); + SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical, + notification.group_child() ? gfx::Insets() : kNotificationViewPadding)); auto content_row_layout = std::make_unique<views::FlexLayout>(); content_row_layout->SetInteriorMargin(kMainRightViewChildPadding);
diff --git a/ash/system/message_center/message_center_constants.h b/ash/system/message_center/message_center_constants.h index 0ff00e8..1ec42e52 100644 --- a/ash/system/message_center/message_center_constants.h +++ b/ash/system/message_center/message_center_constants.h
@@ -40,6 +40,7 @@ // The width of notification that displayed inside the message center. constexpr int kNotificationInMessageCenterWidth = 344; +constexpr gfx::Insets kNotificationExpandButtonFocusInsets(2); constexpr gfx::Insets kNotificationExpandButtonImageInsets(4, 4); constexpr gfx::Insets kNotificationExpandButtonLabelInsets(0, 8, 0, 0); constexpr int kNotificationExpandButtonCornerRadius = 12;
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc index d6709f5..66c3319 100644 --- a/ash/system/status_area_widget.cc +++ b/ash/system/status_area_widget.cc
@@ -151,18 +151,18 @@ AddTrayButton(std::move(media_tray)); } - if (chromeos::features::IsPhoneHubEnabled()) { - auto phone_hub_tray = std::make_unique<PhoneHubTray>(shelf_); - phone_hub_tray_ = phone_hub_tray.get(); - AddTrayButton(std::move(phone_hub_tray)); - } - if (chromeos::features::IsEcheCustomWidgetEnabled()) { auto eche_tray = std::make_unique<EcheTray>(shelf_); eche_tray_ = eche_tray.get(); AddTrayButton(std::move(eche_tray)); } + if (chromeos::features::IsPhoneHubEnabled()) { + auto phone_hub_tray = std::make_unique<PhoneHubTray>(shelf_); + phone_hub_tray_ = phone_hub_tray.get(); + AddTrayButton(std::move(phone_hub_tray)); + } + auto unified_system_tray = std::make_unique<UnifiedSystemTray>(shelf_); unified_system_tray_ = unified_system_tray.get(); AddTrayButton(std::move(unified_system_tray));
diff --git a/ash/system/time/calendar_view_controller.cc b/ash/system/time/calendar_view_controller.cc index 3d01e6b..4e78941 100644 --- a/ash/system/time/calendar_view_controller.cc +++ b/ash/system/time/calendar_view_controller.cc
@@ -76,9 +76,11 @@ void CalendarViewController::UpdateMonth( const base::Time current_month_first_date) { base::Time::Exploded currently_shown_date_exploded = - calendar_utils::GetExplodedUTC(currently_shown_date_); + calendar_utils::GetExplodedUTC(currently_shown_date_ + + base::Minutes(time_difference_minutes_)); base::Time::Exploded current_month_first_date_exploded = - calendar_utils::GetExplodedUTC(current_month_first_date); + calendar_utils::GetExplodedUTC(current_month_first_date + + base::Minutes(time_difference_minutes_)); if (currently_shown_date_exploded.year == current_month_first_date_exploded.year && currently_shown_date_exploded.month ==
diff --git a/ash/system/time/calendar_view_unittest.cc b/ash/system/time/calendar_view_unittest.cc index 63a509b4..d563169 100644 --- a/ash/system/time/calendar_view_unittest.cc +++ b/ash/system/time/calendar_view_unittest.cc
@@ -736,8 +736,7 @@ } // Tests multiple scenarios that should record the metric when scrolling. -// TODO(crbug.com/1301872): Revive this test. -TEST_F(CalendarViewTest, DISABLED_RecordDwellTimeMetricWhenScrolling) { +TEST_F(CalendarViewTest, RecordDwellTimeMetricWhenScrolling) { base::HistogramTester histogram_tester; CreateCalendarView();
diff --git a/ash/webui/file_manager/untrusted_resources/files_media_content.js b/ash/webui/file_manager/untrusted_resources/files_media_content.js index 567d8ac2..7a09202 100644 --- a/ash/webui/file_manager/untrusted_resources/files_media_content.js +++ b/ash/webui/file_manager/untrusted_resources/files_media_content.js
@@ -9,6 +9,14 @@ const content = document.querySelector('#content'); let contentUrl; + /** + * Identifies every message to load an content. Used to check if the current + * load is still valid after an async operation. + * + * @type {number} + */ + let loadId = 0; + window.addEventListener('message', event => { if (event.origin !== FILES_APP_SWA_ORIGIN && event.origin !== LEGACY_FILES_APP_ORIGIN) { @@ -16,6 +24,12 @@ return; } + const currentLoadId = ++loadId; + + function isValidLoad() { + return currentLoadId === loadId; + } + // Release Object URLs generated with URL.createObjectURL. URL.revokeObjectURL(contentUrl); contentUrl = ''; @@ -46,16 +60,27 @@ contentChanged(null); fetch(contentUrl) .then((response) => { + if (!isValidLoad()) { + return; + } return response.text(); }) .then((text) => { + if (!isValidLoad()) { + return; + } content.textContent = text; contentChanged(text); }); break; case 'audio': case 'video': - content.onloadeddata = (e) => contentChanged(e.target.src); + content.onloadeddata = (e) => { + if (!isValidLoad()) { + return; + } + contentChanged(e.target.src); + }; content.src = contentUrl; break; case 'image': @@ -64,8 +89,11 @@ const image = new Image(); image.onload = (e) => { - contentChanged(e.target.src); document.body.appendChild(content); + if (!isValidLoad()) { + return; + } + contentChanged(e.target.src); content.src = e.target.src; }; @@ -76,7 +104,7 @@ image.src = contentUrl; break; default: - content.onload = (e) => contentChanged(e.target.src); + content.onload = (e) => isValidLoad() && contentChanged(e.target.src); content.src = contentUrl; break; }
diff --git a/ash/webui/media_app_ui/resources/mock/js/app_main.js b/ash/webui/media_app_ui/resources/mock/js/app_main.js index 12cb415..ab25be1 100644 --- a/ash/webui/media_app_ui/resources/mock/js/app_main.js +++ b/ash/webui/media_app_ui/resources/mock/js/app_main.js
@@ -183,9 +183,10 @@ this.replaceChild(newHandler, this.currentHandler); this.currentHandler = newHandler; - // Toggle 'shownav' indicating the navigation buttons are available. - // This emulates `setNavigationPossible()` in the real app. - this.currentHandler.toggleAttribute('shownav', this.files.length > 1); + // The presence of the 'filetraversalenabled' attribute emulates + // `setFileTraversalEnabled()` in the real app. + this.currentHandler.toggleAttribute( + 'filetraversalenabled', this.files.length > 1); } /** @override */ @@ -228,7 +229,7 @@ window.customElements.define('backlight-app', BacklightApp); // Element mimicking the image/video handler which is the parent of the -// `navigation-overlay`. +// `carousel-overlay`. class BacklightMediaHandler extends HTMLElement {} window.customElements.define('backlight-media-handler', BacklightMediaHandler);
diff --git a/ash/webui/personalization_app/resources/trusted/user/avatar_list_element.html b/ash/webui/personalization_app/resources/trusted/user/avatar_list_element.html index f21755cf..8e977863 100644 --- a/ash/webui/personalization_app/resources/trusted/user/avatar_list_element.html +++ b/ash/webui/personalization_app/resources/trusted/user/avatar_list_element.html
@@ -18,6 +18,9 @@ height: 62px; width: 62px; } + .image-container img:focus-visible { + outline: 2px solid var(--cros-focus-ring-color); + } .image-container img:hover { background-color: var(--cros-highlight-color-focus); } @@ -39,10 +42,21 @@ display: inline-block; height: 64px; line-height: 64px; + position: relative; text-align: center; vertical-align: middle; width: 64px; } + .folder-container:hover { + background-color: var(--cros-text-highlight-color); + } + .folder-container:focus-visible { + outline: 2px solid var(--cros-focus-ring-color); + } + .folder-container paper-ripple { + color: rgba(var(--cros-ripple-color-prominent-rgb), 1); + --paper-ripple-opacity: var(--cros-button-primary-ripple-opacity); + } #folderIcon { line-height: inherit; --iron-icon-height: 20px; @@ -73,6 +87,7 @@ </div> </template> <div class="folder-container"> + <paper-ripple class="circle"></paper-ripple> <iron-icon id="folderIcon" icon="personalization:folder" on-click="onSelectImageFromDisk_" on-keypress="onSelectImageFromDisk_"> </iron-icon>
diff --git a/ash/webui/projector_app/projector_xhr_sender.cc b/ash/webui/projector_app/projector_xhr_sender.cc index e421e7f..1f6b1a1 100644 --- a/ash/webui/projector_app/projector_xhr_sender.cc +++ b/ash/webui/projector_app/projector_xhr_sender.cc
@@ -21,6 +21,7 @@ namespace ash { namespace { + // Projector network traffic annotation tags. constexpr net::NetworkTrafficAnnotationTag kNetworkTrafficAnnotationTag = net::DefineNetworkTrafficAnnotation("projector_xhr_loader", R"( @@ -50,6 +51,11 @@ } return false; } + +// The maximum number of retries for the SimpleURLLoader requests. Three times +// is an arbitrary number to start with. +const int kMaxRetries = 3; + } // namespace ProjectorXhrSender::ProjectorXhrSender( @@ -133,7 +139,10 @@ if (!request_body.empty()) loader->AttachStringForUpload(request_body, "application/json"); - + loader->SetRetryOptions( + kMaxRetries, + network::SimpleURLLoader::RETRY_ON_5XX | + network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE); loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( url_loader_factory_, base::BindOnce(&ProjectorXhrSender::OnSimpleURLLoaderComplete,
diff --git a/ash/wm/desks/desk_action_context_menu.cc b/ash/wm/desks/desk_action_context_menu.cc new file mode 100644 index 0000000..2931afe --- /dev/null +++ b/ash/wm/desks/desk_action_context_menu.cc
@@ -0,0 +1,89 @@ +// 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 "ash/wm/desks/desk_action_context_menu.h" + +#include "ash/resources/vector_icons/vector_icons.h" +#include "ui/views/controls/menu/menu_runner.h" +#include "ui/views/view.h" + +namespace ash { + +namespace { + +// An enum with identifiers to link context menu items to their associated +// functions. +enum CommandId { + // Closes target desk and moves its windows to another desk. + kCombineDesks, + // Saves target desk in DesksController and gives user option to undo the + // desk before the desk is fully removed and its windows are closed. + kCloseAll, +}; + +} // namespace + +DeskActionContextMenu::DeskActionContextMenu( + base::RepeatingClosure combine_desks_callback, + base::RepeatingClosure close_all_callback, + base::RepeatingClosure on_context_menu_closed_callback) + : combine_desks_callback_(std::move(combine_desks_callback)), + close_all_callback_(std::move(close_all_callback)), + on_context_menu_closed_callback_( + std::move(on_context_menu_closed_callback)) {} + +DeskActionContextMenu::~DeskActionContextMenu() = default; + +void DeskActionContextMenu::ExecuteCommand(int command_id, int event_flags) { + switch (command_id) { + case CommandId::kCombineDesks: + combine_desks_callback_.Run(); + break; + case CommandId::kCloseAll: + close_all_callback_.Run(); + break; + default: + NOTREACHED(); + break; + } +} + +void DeskActionContextMenu::MenuClosed(ui::SimpleMenuModel* menu) { + on_context_menu_closed_callback_.Run(); +} + +ui::SimpleMenuModel* DeskActionContextMenu::BuildMenuModel() { + // TODO(crbug.com/1302030): Localize the strings here. + context_menu_model_ = std::make_unique<ui::SimpleMenuModel>(this); + context_menu_model_->AddItemWithIcon( + CommandId::kCombineDesks, u"Combine with ", + ui::ImageModel::FromVectorIcon(kCombineDesksIcon, + ui::kColorAshSystemUIMenuIcon)); + + context_menu_model_->AddItemWithIcon( + CommandId::kCloseAll, u"Close desk and windows", + ui::ImageModel::FromVectorIcon(kMediumOrLargeCloseButtonIcon, + ui::kColorAshSystemUIMenuIcon)); + + return context_menu_model_.get(); +} + +void DeskActionContextMenu::ShowContextMenuForViewImpl( + views::View* source, + const gfx::Point& point, + ui::MenuSourceType source_type) { + const int run_types = views::MenuRunner::USE_ASH_SYS_UI_LAYOUT | + views::MenuRunner::CONTEXT_MENU | + views::MenuRunner::FIXED_ANCHOR; + + context_menu_runner_ = + std::make_unique<views::MenuRunner>(BuildMenuModel(), run_types); + + context_menu_runner_->RunMenuAt( + source->GetWidget(), /*button_controller=*/nullptr, + /*bounds=*/gfx::Rect(point, gfx::Size()), + /*anchor=*/views::MenuAnchorPosition::kBubbleBottomRight, source_type); +} + +} // namespace ash \ No newline at end of file
diff --git a/ash/wm/desks/desk_action_context_menu.h b/ash/wm/desks/desk_action_context_menu.h new file mode 100644 index 0000000..09eed78c --- /dev/null +++ b/ash/wm/desks/desk_action_context_menu.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 ASH_WM_DESKS_DESK_ACTION_CONTEXT_MENU_H_ +#define ASH_WM_DESKS_DESK_ACTION_CONTEXT_MENU_H_ + +#include "ui/base/models/simple_menu_model.h" +#include "ui/views/context_menu_controller.h" + +namespace views { +class MenuRunner; +} // namespace views + +namespace ash { + +// A context menu controller that generates a context menu for a DeskMiniView +// with an option to combine desks and an option to close a desk and all of its +// windows. +class DeskActionContextMenu : public views::ContextMenuController, + public ui::SimpleMenuModel::Delegate { + public: + DeskActionContextMenu(base::RepeatingClosure combine_desks_callback, + base::RepeatingClosure close_all_callback, + base::RepeatingClosure on_context_menu_closed_callback); + DeskActionContextMenu(const DeskActionContextMenu&) = delete; + DeskActionContextMenu& operator=(const DeskActionContextMenu&) = delete; + ~DeskActionContextMenu() override; + + // ui::SimpleMenuModel::Delegate: + void ExecuteCommand(int command_id, int event_flags) override; + void MenuClosed(ui::SimpleMenuModel* menu) override; + + private: + ui::SimpleMenuModel* BuildMenuModel(); + + // views::ContextMenuController: + void ShowContextMenuForViewImpl(views::View* source, + const gfx::Point& point, + ui::MenuSourceType source_type) override; + + std::unique_ptr<ui::SimpleMenuModel> context_menu_model_; + std::unique_ptr<views::MenuRunner> context_menu_runner_; + + // Callbacks to run when the combine desks option is selected, when the close + // desk and windows option is selected, and when the menu is closed. + base::RepeatingClosure combine_desks_callback_; + base::RepeatingClosure close_all_callback_; + base::RepeatingClosure on_context_menu_closed_callback_; +}; + +} // namespace ash + +#endif \ No newline at end of file
diff --git a/ash/wm/desks/desk_action_view.cc b/ash/wm/desks/desk_action_view.cc new file mode 100644 index 0000000..0ebcbaa --- /dev/null +++ b/ash/wm/desks/desk_action_view.cc
@@ -0,0 +1,48 @@ +// 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 "ash/wm/desks/desk_action_view.h" + +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/style/ash_color_provider.h" +#include "ash/style/close_button.h" +#include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/views/background.h" + +namespace ash { + +namespace { + +constexpr int kButtonMargin = 2; +constexpr int kButtonSpacing = 4; +constexpr int kCornerRadius = 11; + +} // namespace + +DeskActionView::DeskActionView(base::RepeatingClosure combine_desks_callback, + base::RepeatingClosure close_all_callback) + : close_all_button_(AddChildView( + std::make_unique<CloseButton>(std::move(close_all_callback), + CloseButton::Type::kMediumFloating))), + combine_desks_button_(AddChildView( + std::make_unique<CloseButton>(std::move(combine_desks_callback), + CloseButton::Type::kMediumFloating))) { + SetOrientation(views::BoxLayout::Orientation::kHorizontal); + SetInsideBorderInsets(gfx::Insets(kButtonMargin)); + SetBetweenChildSpacing(kButtonSpacing); + SetBackground(views::CreateRoundedRectBackground( + AshColorProvider::Get()->GetBaseLayerColor( + AshColorProvider::BaseLayerType::kTransparent80), + kCornerRadius)); + + // TODO(crbug.com/1302030): Localize the strings here. + close_all_button_->SetTooltipText(u"Close desk and windows"); + combine_desks_button_->SetVectorIcon(kCombineDesksIcon); + combine_desks_button_->SetTooltipText(u"Combine with "); +} + +BEGIN_METADATA(DeskActionView, views::BoxLayoutView) +END_METADATA + +} // namespace ash \ No newline at end of file
diff --git a/ash/wm/desks/desk_action_view.h b/ash/wm/desks/desk_action_view.h new file mode 100644 index 0000000..629d877 --- /dev/null +++ b/ash/wm/desks/desk_action_view.h
@@ -0,0 +1,35 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WM_DESKS_DESK_ACTION_VIEW_H_ +#define ASH_WM_DESKS_DESK_ACTION_VIEW_H_ + +#include "ui/base/metadata/metadata_header_macros.h" +#include "ui/views/layout/box_layout_view.h" + +namespace ash { + +class CloseButton; + +// A view that holds buttons that act on a single DeskMiniView instance, such as +// combining two desks or closing a desk and all of its windows. +class DeskActionView : public views::BoxLayoutView { + public: + METADATA_HEADER(DeskActionView); + + DeskActionView(base::RepeatingClosure combine_desks_callback, + base::RepeatingClosure close_all_callback); + + CloseButton* close_all_button() { return close_all_button_; } + + CloseButton* combine_desks_button() { return combine_desks_button_; } + + private: + CloseButton* close_all_button_; + CloseButton* combine_desks_button_; +}; + +} // namespace ash + +#endif \ No newline at end of file
diff --git a/ash/wm/desks/templates/desks_templates_icon_view.cc b/ash/wm/desks/templates/desks_templates_icon_view.cc index 3f25bd56..15b0c3d 100644 --- a/ash/wm/desks/templates/desks_templates_icon_view.cc +++ b/ash/wm/desks/templates/desks_templates_icon_view.cc
@@ -21,6 +21,7 @@ #include "ui/gfx/image/image_skia_operations.h" #include "ui/native_theme/native_theme.h" #include "ui/resources/grit/ui_resources.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" #include "url/gurl.h" @@ -104,10 +105,22 @@ delegate->MaybeRetrieveIconForSpecialIdentifier( icon_identifier_, static_cast<DesksTemplatesIconContainer*>(parent()) ->incognito_window_color_provider()); + + icon_view_->GetViewAccessibility().OverrideRole(ax::mojom::Role::kImage); + + // PWAs (e.g. Messages) should use icon identifier as they share the same app + // id as Chrome and would return short name for app id as "Chromium" (see + // https://crbug.com/1281394). This is unlike Chrome browser apps which should + // use `app_id` as their icon identifiers have been stripped to avoid + // duplicate favicons (see https://crbug.com/1281391). if (chrome_icon.has_value()) { icon_view_->SetImage(CreateResizedImageToIconSize(chrome_icon.value())); + icon_view_->GetViewAccessibility().OverrideName( + delegate->GetAppShortName(app_id)); return; } + icon_view_->GetViewAccessibility().OverrideName( + delegate->GetAppShortName(icon_identifier_)); // It's not a special value so `icon_identifier_` is either a favicon or an // app id. If `icon_identifier_` is not a valid url then it's an app id.
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc index 81311db..8a5836931 100644 --- a/ash/wm/lock_state_controller.cc +++ b/ash/wm/lock_state_controller.cc
@@ -11,6 +11,7 @@ #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/cancel_mode.h" +#include "ash/constants/ash_pref_names.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/shutdown_controller.h" #include "ash/root_window_controller.h" @@ -26,13 +27,19 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h" +#include "base/json/values_util.h" #include "base/location.h" #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/strings/string_util.h" #include "base/system/sys_info.h" +#include "base/time/default_clock.h" +#include "base/time/time.h" #include "base/timer/timer.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" #include "ui/aura/window_tree_host.h" #include "ui/views/controls/menu/menu_controller.h" #include "ui/wm/core/compound_event_filter.h" @@ -76,18 +83,50 @@ SessionStateAnimator::SHELF; LockStateController::LockStateController( - ShutdownController* shutdown_controller) + ShutdownController* shutdown_controller, + PrefService* local_state) : animator_(new SessionStateAnimatorImpl()), shutdown_controller_(shutdown_controller), - scoped_session_observer_(this) { + scoped_session_observer_(this), + local_state_(local_state) { DCHECK(shutdown_controller_); Shell::GetPrimaryRootWindow()->GetHost()->AddObserver(this); + // |local_state_| could be null in tests. + if (local_state_) { + // If kLoginShutdownTimestampPrefName is registered, check the last recorded + // login shutdown timestamp in local state prefs, in case device was shut + // down using shelf button. + auto* login_shutdown_timestamp_pref = + local_state_->FindPreference(prefs::kLoginShutdownTimestampPrefName); + if (login_shutdown_timestamp_pref && + !login_shutdown_timestamp_pref->IsDefaultValue()) { + base::Time last_recorded_login_shutdown_timestamp = + base::ValueToTime(login_shutdown_timestamp_pref->GetValue()).value(); + base::TimeDelta duration = base::DefaultClock::GetInstance()->Now() - + last_recorded_login_shutdown_timestamp; + // Report time delta even if it exceeds histogram limit, to better + // understand fraction of users using the feature. + base::UmaHistogramLongTimes( + "Ash.Shelf.ShutdownConfirmationBubble.TimeToNextBoot." + "LoginShutdownToPowerUpDuration", + duration); + + // Reset to the default value after the value is recorded. + local_state_->ClearPref(prefs::kLoginShutdownTimestampPrefName); + } + } } LockStateController::~LockStateController() { Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this); } +// static +void LockStateController::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterTimePref(prefs::kLoginShutdownTimestampPrefName, + base::Time()); +} + void LockStateController::AddObserver(LockStateObserver* observer) { observers_.AddObserver(observer); } @@ -190,6 +229,12 @@ shutting_down_ = true; shutdown_reason_ = reason; + if (reason == ShutdownReason::LOGIN_SHUT_DOWN_BUTTON) { + base::Time now_timestamp = base::DefaultClock::GetInstance()->Now(); + local_state_->SetTime(prefs::kLoginShutdownTimestampPrefName, + now_timestamp); + } + ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager(); cursor_manager->HideCursor(); cursor_manager->LockCursor();
diff --git a/ash/wm/lock_state_controller.h b/ash/wm/lock_state_controller.h index 4719c48..f54d55b 100644 --- a/ash/wm/lock_state_controller.h +++ b/ash/wm/lock_state_controller.h
@@ -17,6 +17,8 @@ #include "base/observer_list.h" #include "base/timer/elapsed_timer.h" #include "base/timer/timer.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/aura/window_tree_host_observer.h" @@ -51,13 +53,16 @@ // pre-lock hiding animation. static const int kPreLockContainersMask; - explicit LockStateController(ShutdownController* shutdown_controller); + LockStateController(ShutdownController* shutdown_controller, + PrefService* local_state); LockStateController(const LockStateController&) = delete; LockStateController& operator=(const LockStateController&) = delete; ~LockStateController() override; + static void RegisterPrefs(PrefRegistrySimple* registry); + void AddObserver(LockStateObserver* observer); void RemoveObserver(LockStateObserver* observer); @@ -217,6 +222,9 @@ base::ObserverList<LockStateObserver>::Unchecked observers_; + // To access the pref kLoginShutdownTimestampPrefName + PrefService* local_state_; + base::WeakPtrFactory<LockStateController> weak_ptr_factory_{this}; };
diff --git a/ash/wm/lock_state_controller_unittest.cc b/ash/wm/lock_state_controller_unittest.cc index c87c392e..13e35a0 100644 --- a/ash/wm/lock_state_controller_unittest.cc +++ b/ash/wm/lock_state_controller_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "ash/constants/ash_pref_names.h" #include "ash/constants/ash_switches.h" #include "ash/public/cpp/shutdown_controller.h" #include "ash/root_window_controller.h" @@ -29,6 +30,7 @@ #include "base/command_line.h" #include "base/run_loop.h" #include "base/test/bind.h" +#include "base/test/metrics/histogram_tester.h" #include "base/time/time.h" #include "chromeos/dbus/power/fake_power_manager_client.h" #include "ui/display/fake/fake_display_snapshot.h" @@ -39,6 +41,10 @@ namespace ash { namespace { +constexpr char kShelfShutdownConfirmationHistogramName[] = + "Ash.Shelf.ShutdownConfirmationBubble.TimeToNextBoot." + "LoginShutdownToPowerUpDuration"; + // Shorthand for some long constants. constexpr power_manager::BacklightBrightnessChange_Cause kUserCause = power_manager::BacklightBrightnessChange_Cause_USER_REQUEST; @@ -100,6 +106,8 @@ test_shutdown_controller_ = std::make_unique<TestShutdownController>(); lock_state_test_api_->set_shutdown_controller( test_shutdown_controller_.get()); + + local_state_ = Shell::Get()->local_state(); } void TearDown() override { test_shutdown_controller_.reset(); @@ -305,10 +313,36 @@ lock_state_controller_->OnLockScreenHide(std::move(closure)); } + bool IsDefaultValueLoginShutdownTimestamp() { + auto* login_shutdown_timestamp_pref = + local_state_->FindPreference(prefs::kLoginShutdownTimestampPrefName); + + return login_shutdown_timestamp_pref->IsDefaultValue(); + } + + // To check if histogram of LockStateController is recorded correctly, we need + // to simulate the restart of a device as the metrics measures the time delta + // between a shutdown from login/lock screen and a following restart. By + // calling the constructor of LockStateController, the restart of a device is + // simulated and the call of UmaHistogramLongTimes is triggered if a previous + // shutdown was initiated with ShutdownReason::LOGIN_SHUT_DOWN_BUTTON. + void RestartDevice() { + LockStateController(test_shutdown_controller_.get(), local_state_); + } + + base::HistogramTester& histograms() { return histograms_; } + std::unique_ptr<ShutdownController::ScopedResetterForTest> shutdown_controller_resetter_; std::unique_ptr<TestShutdownController> test_shutdown_controller_; TestSessionStateAnimator* test_animator_ = nullptr; // not owned + + private: + // Histogram value verifier. + base::HistogramTester histograms_; + + // To access the pref kLoginShutdownTimestampPrefName + PrefService* local_state_ = nullptr; }; // Test the show menu and shutdown flow for non-Chrome-OS hardware that doesn't @@ -344,6 +378,8 @@ EXPECT_TRUE(lock_state_test_api_->real_shutdown_timer_is_running()); lock_state_test_api_->trigger_real_shutdown_timeout(); EXPECT_EQ(1, NumShutdownRequests()); + // Shutdown was not initiated with reason LOGIN_SHUT_DOWN_BUTTON + EXPECT_TRUE(IsDefaultValueLoginShutdownTimestamp()); } // Test that we ignore power button presses when the screen is turned off on an @@ -521,16 +557,21 @@ SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); GenerateMouseMoveEvent(); EXPECT_FALSE(cursor_visible()); + // Shutdown was not initiated with reason LOGIN_SHUT_DOWN_BUTTON + EXPECT_TRUE(IsDefaultValueLoginShutdownTimestamp()); } // Test that we display the fast-close animation and shut down when we get an // outside request to shut down (e.g. from the login or lock screen). TEST_P(LockStateControllerAnimationTest, RequestShutdownFromLoginScreen) { Initialize(ButtonType::NORMAL, LoginStatus::NOT_LOGGED_IN); + EXPECT_TRUE(IsDefaultValueLoginShutdownTimestamp()); lock_state_controller_->RequestShutdown( ShutdownReason::LOGIN_SHUT_DOWN_BUTTON); + // Shutdown was initiated with reason LOGIN_SHUT_DOWN_BUTTON + EXPECT_FALSE(IsDefaultValueLoginShutdownTimestamp()); ExpectShutdownAnimationStarted("1"); AdvanceOrAbort(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); @@ -550,10 +591,13 @@ AdvanceOrAbort(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); ExpectPostLockAnimationFinished("1"); + EXPECT_TRUE(IsDefaultValueLoginShutdownTimestamp()); lock_state_controller_->RequestShutdown( ShutdownReason::LOGIN_SHUT_DOWN_BUTTON); + // Shutdown was initiated with reason LOGIN_SHUT_DOWN_BUTTON + EXPECT_FALSE(IsDefaultValueLoginShutdownTimestamp()); ExpectShutdownAnimationStarted("2"); AdvanceOrAbort(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); @@ -566,6 +610,95 @@ EXPECT_EQ(1, NumShutdownRequests()); } +// Test that historgram of time delta was recorded if a previous shutdown was +// initiated from login/lock screen. +TEST_F(LockStateControllerTest, RequestShutdownFromLoginScreenThenRestart) { + Initialize(ButtonType::NORMAL, LoginStatus::NOT_LOGGED_IN); + EXPECT_TRUE(IsDefaultValueLoginShutdownTimestamp()); + + lock_state_controller_->RequestShutdown( + ShutdownReason::LOGIN_SHUT_DOWN_BUTTON); + + // Shutdown was initiated with reason LOGIN_SHUT_DOWN_BUTTON + EXPECT_FALSE(IsDefaultValueLoginShutdownTimestamp()); + + GenerateMouseMoveEvent(); + EXPECT_FALSE(cursor_visible()); + + EXPECT_EQ(0, NumShutdownRequests()); + EXPECT_TRUE(lock_state_test_api_->real_shutdown_timer_is_running()); + lock_state_test_api_->trigger_real_shutdown_timeout(); + EXPECT_EQ(1, NumShutdownRequests()); + + // Simulate restarting device + RestartDevice(); + histograms().ExpectTotalCount(kShelfShutdownConfirmationHistogramName, 1); +} + +TEST_F(LockStateControllerTest, RequestShutdownFromLockScreenThenRestart) { + Initialize(ButtonType::NORMAL, LoginStatus::USER); + + LockScreen(); + + EXPECT_TRUE(IsDefaultValueLoginShutdownTimestamp()); + + lock_state_controller_->RequestShutdown( + ShutdownReason::LOGIN_SHUT_DOWN_BUTTON); + + // Shutdown was initiated with reason LOGIN_SHUT_DOWN_BUTTON + EXPECT_FALSE(IsDefaultValueLoginShutdownTimestamp()); + + GenerateMouseMoveEvent(); + EXPECT_FALSE(cursor_visible()); + + EXPECT_EQ(0, NumShutdownRequests()); + EXPECT_TRUE(lock_state_test_api_->real_shutdown_timer_is_running()); + lock_state_test_api_->trigger_real_shutdown_timeout(); + EXPECT_EQ(1, NumShutdownRequests()); + + // Simulate restarting device + RestartDevice(); + histograms().ExpectTotalCount(kShelfShutdownConfirmationHistogramName, 1); +} + +// Test that historgram of time delta was not recorded if a previous shutdown +// was not initiated from login/lock screen. +TEST_F(LockStateControllerTest, LegacyShowMenuAndShutDownThenRestart) { + Initialize(ButtonType::LEGACY, LoginStatus::USER); + + ExpectUnlockedState("1"); + + // We should request that the screen be locked immediately after seeing the + // power button get pressed. + PressPowerButton(); + + EXPECT_TRUE(power_button_test_api_->IsMenuOpened()); + + // We shouldn't progress towards the shutdown state, however. + EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); + + ReleasePowerButton(); + + // Hold the button again and check that we start shutting down. + PressPowerButton(); + + ExpectShutdownAnimationStarted("2"); + + EXPECT_EQ(0, NumShutdownRequests()); + // Make sure a mouse move event won't show the cursor. + GenerateMouseMoveEvent(); + EXPECT_FALSE(cursor_visible()); + + EXPECT_TRUE(lock_state_test_api_->real_shutdown_timer_is_running()); + lock_state_test_api_->trigger_real_shutdown_timeout(); + EXPECT_EQ(1, NumShutdownRequests()); + // Shutdown was not initiated with reason LOGIN_SHUT_DOWN_BUTTON + EXPECT_TRUE(IsDefaultValueLoginShutdownTimestamp()); + + // Simulate restarting device + RestartDevice(); + histograms().ExpectTotalCount(kShelfShutdownConfirmationHistogramName, 0); +} // Test that hidden wallpaper appears and reverts correctly on lock/cancel. TEST_P(LockStateControllerAnimationTest, TestHiddenWallpaperLockCancel) { Initialize(ButtonType::NORMAL, LoginStatus::USER); @@ -720,6 +853,8 @@ // When the timeout fires, we should request a shutdown. lock_state_test_api_->trigger_real_shutdown_timeout(); EXPECT_EQ(1, NumShutdownRequests()); + // Shutdown was not initiated with reason LOGIN_SHUT_DOWN_BUTTON + EXPECT_TRUE(IsDefaultValueLoginShutdownTimestamp()); } TEST_P(LockStateControllerAnimationTest, CancelShouldResetWallpaperBlur) {
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc index 426a662..6e69d91 100644 --- a/ash/wm/splitview/split_view_controller.cc +++ b/ash/wm/splitview/split_view_controller.cc
@@ -1906,8 +1906,12 @@ return; } - // Get caret bounds. + // Get current active input field. auto* text_input_client = GetCurrentInputMethod()->GetTextInputClient(); + if (!text_input_client) + return; + + // Get caret bounds. const gfx::Rect caret_bounds = text_input_client->GetCaretBounds(); if (caret_bounds == gfx::Rect()) return;
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc index 165bdca9..01ddcf69 100644 --- a/ash/wm/splitview/split_view_controller_unittest.cc +++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -5836,4 +5836,47 @@ EXPECT_TRUE(split_view_controller()->split_view_divider()->IsAdjustable()); } +// Tests that when there is no activated input field in the bottom window, +// showing keyboard (on-screen keyboard) will not change the split view layout. +TEST_F(SplitViewKeyboardTest, NoInputField) { + UpdateDisplay("1200x800"); + int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); + display::DisplayManager* display_manager = Shell::Get()->display_manager(); + display::test::ScopedSetInternalDisplayId set_internal(display_manager, + display_id); + ScreenOrientationControllerTestApi test_api( + Shell::Get()->screen_orientation_controller()); + ASSERT_EQ(chromeos::OrientationType::kLandscapePrimary, + test_api.GetCurrentOrientation()); + + gfx::Rect bounds(0, 0, 400, 400); + std::unique_ptr<aura::Window> bottom_window(CreateWindow(bounds)); + + split_view_controller()->SnapWindow(bottom_window.get(), + SplitViewController::RIGHT); + + test_api.SetDisplayRotation(display::Display::ROTATE_270, + display::Display::RotationSource::ACTIVE); + EXPECT_EQ(chromeos::OrientationType::kPortraitPrimary, + test_api.GetCurrentOrientation()); + EXPECT_FALSE(split_view_controller()->IsPhysicalLeftOrTop( + SplitViewController::RIGHT, bottom_window.get())); + + const gfx::Rect orig_bottom_bounds = bottom_window->GetBoundsInScreen(); + const gfx::Rect orig_divider_bounds = split_view_controller() + ->split_view_divider() + ->divider_widget() + ->GetWindowBoundsInScreen(); + // Enable keyboard. The bottom window and divider will not move since there is + // no input field. + keyboard_controller()->ShowKeyboard(/*lock=*/false); + EXPECT_TRUE(keyboard_controller()->IsKeyboardVisible()); + EXPECT_EQ(orig_bottom_bounds, bottom_window->GetBoundsInScreen()); + EXPECT_EQ(orig_divider_bounds, split_view_controller() + ->split_view_divider() + ->divider_widget() + ->GetWindowBoundsInScreen()); + EXPECT_TRUE(split_view_controller()->split_view_divider()->IsAdjustable()); +} + } // namespace ash
diff --git a/base/metrics/metrics_hashes.cc b/base/metrics/metrics_hashes.cc index c400fc6..0303d20 100644 --- a/base/metrics/metrics_hashes.cc +++ b/base/metrics/metrics_hashes.cc
@@ -11,7 +11,6 @@ #include "base/sys_byteorder.h" namespace base { - namespace { // Converts the 8-byte prefix of an MD5 hash into a uint64_t value. @@ -50,4 +49,4 @@ return DigestToUInt32(digest); } -} // namespace metrics +} // namespace base
diff --git a/build/rust/tests/test_rust_static_library/src/lib.rs b/build/rust/tests/test_rust_static_library/src/lib.rs index 673a1a0..36e2c02b 100644 --- a/build/rust/tests/test_rust_static_library/src/lib.rs +++ b/build/rust/tests/test_rust_static_library/src/lib.rs
@@ -35,3 +35,10 @@ pub fn allocate_via_rust() -> Box<ffi::SomeStruct> { Box::new(ffi::SomeStruct { a: 43 }) } + +mod tests { + #[test] + fn test_in_mod() { + // Always passes; just to see if tests in modules are handled correctly. + } +}
diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn index 7915346..dec348e 100644 --- a/buildtools/third_party/libc++/BUILD.gn +++ b/buildtools/third_party/libc++/BUILD.gn
@@ -14,17 +14,17 @@ # libc++ wants to redefine the macros WIN32_LEAN_AND_MEAN and _CRT_RAND_S # in its implementation. "-Wno-macro-redefined", + ] + cflags_cc = [ # We want to use a uniform C++ version across all of chromium, but # upstream libc++ requires C++20 so we have to make an exception here. # No other target should override the default -std= flag. "-std:c++20", ] } else { - cflags += [ - "-fPIC", - "-std=c++20", - ] + cflags += [ "-fPIC" ] + cflags_cc = [ "-std=c++20" ] } defines = [ "_LIBCPP_BUILDING_LIBRARY" ] @@ -130,11 +130,13 @@ "//build/config/compiler:no_rtti", "//build/config/coverage:default_coverage", ] - if (is_android && libcxx_is_shared) { + if ((is_android || is_apple) && libcxx_is_shared) { # Use libc++_chrome to avoid conflicting with system libc++ - # See crbug.com/1076244#c11 for more detail. output_name = "libc++_chrome" - configs -= [ "//build/config/android:hide_all_but_jni_onload" ] + if (is_android) { + # See crbug.com/1076244#c11 for more detail. + configs -= [ "//build/config/android:hide_all_but_jni_onload" ] + } } configs += [ ":config",
diff --git a/cc/base/math_util.cc b/cc/base/math_util.cc index cf1eb357..c5393bc7 100644 --- a/cc/base/math_util.cc +++ b/cc/base/math_util.cc
@@ -953,10 +953,9 @@ const gfx::Transform& transform, base::trace_event::TracedValue* res) { res->BeginArray(name); - const skia::Matrix44& m = transform.matrix(); for (int row = 0; row < 4; ++row) { for (int col = 0; col < 4; ++col) - res->AppendDouble(m.rc(row, col)); + res->AppendDouble(transform.matrix().rc(row, col)); } res->EndArray(); }
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 4af959e1..1feb499 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -1680,17 +1680,15 @@ // a layer of size 10000px does not exceed 0.001px. static constexpr float kPixelErrorThreshold = 0.001f; static constexpr float kScaleErrorThreshold = kPixelErrorThreshold / 10000; - auto is_raster_scale = [this](const skia::Matrix44& matrix) -> bool { + auto is_raster_scale = [this](const gfx::Transform& transform) -> bool { // The matrix has the X scale at (0,0), and the Y scale at (1,1). - return std::abs(matrix.rc(0, 0) - raster_contents_scale_.x()) <= + return std::abs(transform.matrix().rc(0, 0) - raster_contents_scale_.x()) <= kScaleErrorThreshold && - std::abs(matrix.rc(1, 1) - raster_contents_scale_.y()) <= + std::abs(transform.matrix().rc(1, 1) - raster_contents_scale_.y()) <= kScaleErrorThreshold; }; - if (!is_raster_scale(screen_transform.matrix()) || - !is_raster_scale(draw_transform.matrix())) { + if (!is_raster_scale(screen_transform) || !is_raster_scale(draw_transform)) return false; - } // Extract the fractional part of layer origin in the screen space and in the // target space.
diff --git a/chrome/VERSION b/chrome/VERSION index 27a4e48..4623359 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=101 MINOR=0 -BUILD=4921 +BUILD=4922 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java index dcd6071e..1aa94e46 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java
@@ -16,6 +16,8 @@ import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager; import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutTab; import org.chromium.chrome.browser.compositor.overlays.strip.StripScrim; +import org.chromium.chrome.browser.flags.CachedFeatureFlags; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer; import org.chromium.chrome.browser.layouts.scene_layer.SceneOverlayLayer; import org.chromium.ui.base.LocalizationUtils; @@ -133,16 +135,28 @@ modelSelectorButton.getHeight() * mDpToPx, modelSelectorButton.isIncognito(), modelSelectorButtonVisible, resourceManager); - int leftFadeDrawable = modelSelectorButtonVisible && LocalizationUtils.isLayoutRtl() - ? R.drawable.tab_strip_fade_for_model_selector : R.drawable.tab_strip_fade; - int rightFadeDrawable = modelSelectorButtonVisible && !LocalizationUtils.isLayoutRtl() - ? R.drawable.tab_strip_fade_for_model_selector : R.drawable.tab_strip_fade; + boolean tabStripImprovementsEnabled = + CachedFeatureFlags.isEnabled(ChromeFeatureList.TAB_STRIP_IMPROVEMENTS); + boolean showLeftTabStripFade = + !tabStripImprovementsEnabled || LocalizationUtils.isLayoutRtl(); + boolean showRightTabStripFade = + !tabStripImprovementsEnabled || !LocalizationUtils.isLayoutRtl(); - TabStripSceneLayerJni.get().updateTabStripLeftFade(mNativePtr, TabStripSceneLayer.this, - leftFadeDrawable, layoutHelper.getLeftFadeOpacity(), resourceManager); + if (showLeftTabStripFade) { + int leftFadeDrawable = modelSelectorButtonVisible && LocalizationUtils.isLayoutRtl() + ? R.drawable.tab_strip_fade_for_model_selector + : R.drawable.tab_strip_fade; + TabStripSceneLayerJni.get().updateTabStripLeftFade(mNativePtr, TabStripSceneLayer.this, + leftFadeDrawable, layoutHelper.getLeftFadeOpacity(), resourceManager); + } - TabStripSceneLayerJni.get().updateTabStripRightFade(mNativePtr, TabStripSceneLayer.this, - rightFadeDrawable, layoutHelper.getRightFadeOpacity(), resourceManager); + if (showRightTabStripFade) { + int rightFadeDrawable = modelSelectorButtonVisible && !LocalizationUtils.isLayoutRtl() + ? R.drawable.tab_strip_fade_for_model_selector + : R.drawable.tab_strip_fade; + TabStripSceneLayerJni.get().updateTabStripRightFade(mNativePtr, TabStripSceneLayer.this, + rightFadeDrawable, layoutHelper.getRightFadeOpacity(), resourceManager); + } } private void pushStripTabs(StripLayoutHelperManager layoutHelper,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java index 0335b579..0bb12fd9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/ReturnToChromeExperimentsUtil.java
@@ -386,7 +386,10 @@ private static ChromeActivity getActivityPresentingOverviewWithOmnibox( String url, boolean skipOverviewCheck) { Activity activity = ApplicationStatus.getLastTrackedFocusedActivity(); - if (!isStartSurfaceEnabled(activity) || !(activity instanceof ChromeActivity)) return null; + if (activity == null || !isStartSurfaceEnabled(activity) + || !(activity instanceof ChromeActivity)) { + return null; + } ChromeActivity chromeActivity = (ChromeActivity) activity;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java index fc150e1..cc87d83 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediatorUnitTest.java
@@ -35,8 +35,10 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.chromium.base.ActivityState; import org.chromium.base.ContextUtils; import org.chromium.base.jank_tracker.DummyJankTracker; +import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.UiThreadTest; import org.chromium.base.test.util.Batch; @@ -48,6 +50,10 @@ import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteMediator.EditSessionState; import org.chromium.chrome.browser.omnibox.suggestions.header.HeaderProcessor; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelUtils; +import org.chromium.chrome.browser.tabmodel.TabWindowManager; import org.chromium.chrome.test.util.browser.Features; import org.chromium.components.metrics.OmniboxEventProtos.OmniboxEventProto.PageClassification; import org.chromium.components.omnibox.AutocompleteMatch; @@ -56,6 +62,7 @@ import org.chromium.content_public.browser.test.NativeLibraryTestUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.base.PageTransition; +import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.PropertyModel; @@ -187,6 +194,18 @@ Profile mProfile; @Mock + Tab mTab; + + @Mock + TabModel mTabModel; + + @Mock + TabWindowManager mTabManager; + + @Mock + WindowAndroid mMockWindowAndroid; + + @Mock OmniboxPedalDelegate mPedalDelegate; private ImmediatePostingHandler mHandler; @@ -194,6 +213,7 @@ private AutocompleteMediator mMediator; private List<AutocompleteMatch> mSuggestionsList; private ModelList mSuggestionModels; + private ObservableSupplierImpl<TabWindowManager> mTabWindowManagerSupplier; @Before public void setUp() { @@ -211,10 +231,12 @@ mListModel = new PropertyModel(SuggestionListProperties.ALL_KEYS); mListModel.set(SuggestionListProperties.SUGGESTION_MODELS, mSuggestionModels); + mTabWindowManagerSupplier = new ObservableSupplierImpl<>(); + mMediator = new AutocompleteMediator(ContextUtils.getApplicationContext(), mAutocompleteDelegate, mTextStateProvider, mListModel, mHandler, () -> mModalDialogManager, null, null, - mLocationBarDataProvider, tab -> {}, null, url -> false, new DummyJankTracker(), + mLocationBarDataProvider, tab -> {}, mTabWindowManagerSupplier, url -> false, new DummyJankTracker(), (pixelSize, callback) -> {}, mPedalDelegate); mMediator.setAutocompleteProfile(mProfile); }); @@ -717,4 +739,84 @@ mMediator.onUrlFocusChange(false); Assert.assertEquals(mMediator.getEditSessionStateForTest(), EditSessionState.INACTIVE); } + + @Test + @SmallTest + @UiThreadTest + public void switchToTab_noTargetTab() { + // There is no Tab to switch to. + doReturn(null).when(mAutocompleteController).getMatchingTabForSuggestion(anyInt()); + Assert.assertFalse(mMediator.maybeSwitchToTab(0)); + } + + @Test + @SmallTest + @UiThreadTest + public void switchToTab_noTabManager() { + // We have a tab, but no tab manager. + doReturn(mTab).when(mAutocompleteController).getMatchingTabForSuggestion(anyInt()); + Assert.assertFalse(mMediator.maybeSwitchToTab(0)); + } + + @Test + @SmallTest + @UiThreadTest + public void switchToTab_tabAttachedToStoppedActivity() { + // We have a tab, and tab manager. The tab is part of the stopped activity. + doReturn(mTab).when(mAutocompleteController).getMatchingTabForSuggestion(anyInt()); + mTabWindowManagerSupplier.set(mTabManager); + doReturn(mMockWindowAndroid).when(mTab).getWindowAndroid(); + doReturn(ActivityState.STOPPED).when(mMockWindowAndroid).getActivityState(); + Assert.assertTrue(mMediator.maybeSwitchToTab(0)); + } + + @Test + @SmallTest + @UiThreadTest + public void switchToTab_noTabModelForTab() { + // We have a tab, and tab manager. The tab is part of the running activity. + // The tab is not a part of the model though (eg. it has just been closed). + // https://crbug.com/1300447 + doReturn(mTab).when(mAutocompleteController).getMatchingTabForSuggestion(anyInt()); + mTabWindowManagerSupplier.set(mTabManager); + doReturn(mMockWindowAndroid).when(mTab).getWindowAndroid(); + doReturn(ActivityState.RESUMED).when(mMockWindowAndroid).getActivityState(); + doReturn(null).when(mTabManager).getTabModelForTab(any()); + Assert.assertFalse(mMediator.maybeSwitchToTab(0)); + } + + @Test + @SmallTest + @UiThreadTest + public void switchToTab_invalidTabModelAssociation() { + // We have a tab, and tab manager. The tab is part of the running activity. + // The tab reports association with an existing model, but the model thinks otherwise. + // https://crbug.com/1300447 + doReturn(mTab).when(mAutocompleteController).getMatchingTabForSuggestion(anyInt()); + mTabWindowManagerSupplier.set(mTabManager); + doReturn(mMockWindowAndroid).when(mTab).getWindowAndroid(); + doReturn(ActivityState.RESUMED).when(mMockWindowAndroid).getActivityState(); + doReturn(mTabModel).when(mTabManager).getTabModelForTab(any()); + + // Make sure that this indeed returns no association. + Assert.assertEquals( + TabModel.INVALID_TAB_INDEX, TabModelUtils.getTabIndexById(mTabModel, mTab.getId())); + Assert.assertFalse(mMediator.maybeSwitchToTab(0)); + } + + @Test + @SmallTest + @UiThreadTest + public void switchToTab_validTabModelAssociation() { + // We have a tab, and tab manager. The tab is part of the running activity. + // The tab reports association with an existing model; the model confirms this. + doReturn(mTab).when(mAutocompleteController).getMatchingTabForSuggestion(anyInt()); + mTabWindowManagerSupplier.set(mTabManager); + doReturn(mMockWindowAndroid).when(mTab).getWindowAndroid(); + doReturn(ActivityState.RESUMED).when(mMockWindowAndroid).getActivityState(); + doReturn(mTabModel).when(mTabManager).getTabModelForTab(any()); + doReturn(1).when(mTabModel).getCount(); + doReturn(mTab).when(mTabModel).getTabAt(anyInt()); + Assert.assertTrue(mMediator.maybeSwitchToTab(0)); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/AutomaticEmbargoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/AutomaticEmbargoTest.java index 4802301a..9152324e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/AutomaticEmbargoTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/AutomaticEmbargoTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.permissions; +import android.os.Build.VERSION_CODES; import android.support.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; @@ -14,7 +15,9 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; +import org.chromium.base.test.util.FlakyTest; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.permissions.PermissionTestRule.PermissionUpdateWaiter; import org.chromium.chrome.browser.tab.Tab; @@ -77,6 +80,10 @@ @Test @LargeTest @Feature({"Location"}) + @DisableIf. + Build(message = "Test is failing on Nexus 5X (64-bit) + Android M, see crbug.com/1111001.", + sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N, + supported_abis_includes = "arm64-v8a") public void testGeolocationEmbargo() throws Exception { LocationSettingsTestUtil.setSystemLocationSettingEnabled(true); LocationProviderOverrider.setLocationProviderImpl(new MockLocationProvider()); @@ -94,6 +101,7 @@ @Test @LargeTest @Feature({"MIDI"}) + @FlakyTest(message = "crbug.com/1232946") public void testMIDIEmbargo() throws Exception { runTest(MIDI_TEST_FILE, "", "fail", 0); } @@ -101,8 +109,11 @@ @Test @LargeTest @Feature({"MediaPermissions"}) + @DisableIf.Build(message = "Failing on Android P, see crbug.com/1251332.", + sdk_is_greater_than = VERSION_CODES.O_MR1) @CommandLineFlags.Add({ContentSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM}) - public void testCameraEmbargo() throws Exception { + public void + testCameraEmbargo() throws Exception { runTest(MEDIA_TEST_FILE, "initiate_getMicrophone()", "deny", 0); } @@ -110,15 +121,21 @@ @LargeTest @Feature({"MediaPermissions"}) @CommandLineFlags.Add({ContentSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM}) - public void testMicrophoneEmbargo() throws Exception { + @DisableIf.Build(message = "Failing on Android P, see crbug.com/1251332.", + sdk_is_greater_than = VERSION_CODES.O_MR1) + public void + testMicrophoneEmbargo() throws Exception { runTest(MEDIA_TEST_FILE, "initiate_getCamera()", "deny", 0); } @Test @LargeTest @Feature({"MediaPermissions"}) + @DisableIf.Build(message = "Failing on Android P, see crbug.com/1251332.", + sdk_is_greater_than = VERSION_CODES.O_MR1) @CommandLineFlags.Add({ContentSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM}) - public void testMicrophoneAndCameraEmbargo() throws Exception { + public void + testMicrophoneAndCameraEmbargo() throws Exception { runTest(MEDIA_TEST_FILE, "initiate_getCombined()", "deny", 0); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java index 9c5e4dd..ed51bd2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
@@ -14,7 +14,6 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.FlakyTest; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; @@ -55,14 +54,11 @@ @Test @MediumTest @Feature({"Permissions"}) - @FlakyTest(message = "https://crbug.com/1236419") public void testNavigationDismissesModalPermissionPrompt() throws Exception { mPermissionRule.setUpUrl(TEST_FILE); mPermissionRule.runJavaScriptCodeInCurrentTab("requestGeolocationPermission()"); mPermissionRule.waitForDialogShownState(true); - mPermissionRule.runJavaScriptCodeInCurrentTab("navigate()"); - Tab tab = mPermissionRule.getActivity().getActivityTab(); final CallbackHelper callbackHelper = new CallbackHelper(); EmptyTabObserver navigationWaiter = new EmptyTabObserver() { @@ -72,6 +68,9 @@ } }; TestThreadUtils.runOnUiThreadBlocking(() -> tab.addObserver(navigationWaiter)); + + mPermissionRule.runJavaScriptCodeInCurrentTab("navigate()"); + callbackHelper.waitForCallback(0); TestThreadUtils.runOnUiThreadBlocking(() -> tab.removeObserver(navigationWaiter));
diff --git a/chrome/app/app_management_strings.grdp b/chrome/app/app_management_strings.grdp index 79b5e425..4052859 100644 --- a/chrome/app/app_management_strings.grdp +++ b/chrome/app/app_management_strings.grdp
@@ -52,9 +52,6 @@ <message name="IDS_APP_MANAGEMENT_RUN_ON_OS_LOGIN" desc="Label for toggling running on OS Login mode."> Start app when you sign in </message> - <message name="IDS_APP_MANAGEMENT_FILE_HANDLING_HEADER" desc="Main text for toggling running on OS Login mode."> - Suggest app when opening files on your computer - </message> <message name="IDS_APP_MANAGEMENT_POLICY_APP_POLICY_STRING" desc="Tooltip label explaining that an app cannot be uninstalled as it has been installed by an adminstrator."> This app has been installed by your administrator. </message> @@ -124,4 +121,40 @@ <message name="IDS_APP_MANAGEMENT_APP_DETAILS_TYPE_SYSTEM" desc="Text for System app type"> System App </message> + + <!-- File Handling --> + <message name="IDS_APP_MANAGEMENT_FILE_HANDLING_HEADER" desc="Main text for toggling a web app's ability to use the File Handling API. This controls whether the app can appear in an 'Open With' list in a file's context menu."> + Suggest app when opening files on your computer + </message> + + <if expr="is_win"> + <message name="IDS_APP_MANAGEMENT_FILE_HANDLING_SET_DEFAULTS_LINK" desc="Further explanation of the File Handling API, including text describing the purpose of the toggle (referencing the Windows File Explorer) and a link to change Windows' default filetype associations."> + You can open and edit supported files with this app from the File Explorer or other apps. To control which files open in this app by default, go to <ph name="BEGIN_LINK"><a href="#"></ph>Windows settings<ph name="END_LINK"></a></ph>. + </message> + </if> + <if expr="chromeos"> + <message name="IDS_APP_MANAGEMENT_FILE_HANDLING_SET_DEFAULTS_LINK" desc="Further explanation of the File Handling API, including text describing the purpose of the toggle (referencing the Chrome OS Files app) and a link to a learn more link for default filetype associations."> + You can open and edit supported files with this app from the Files app or other apps. To control which files open this app by default, <ph name="BEGIN_LINK"><a href="#"></ph>learn how to set default apps on your device<ph name="END_LINK"></a></ph>. + </message> + </if> + <if expr="is_macosx"> + <message name="IDS_APP_MANAGEMENT_FILE_HANDLING_SET_DEFAULTS_LINK" desc="Further explanation of the File Handling API, including text describing the purpose of the toggle (referencing the Mac OS Finder app) and a link to a learn more link for default filetype associations."> + You can open and edit supported files with this app from Finder or other apps. To control which files open this app by default, <ph name="BEGIN_LINK"><a href="#"></ph>learn how to set default apps on your device<ph name="END_LINK"></a></ph>. + </message> + </if> + <if expr="is_fuchsia or desktop_linux"> + <message name="IDS_APP_MANAGEMENT_FILE_HANDLING_SET_DEFAULTS_LINK" desc="Further explanation of the File Handling API, including text describing the purpose of the toggle (referencing a generic Linux file browser app) and a link to a learn more link for default filetype associations."> + You can open and edit supported files with this app from your file browser or other apps. To control which files open this app by default, <ph name="BEGIN_LINK"><a href="#"></ph>learn how to set default apps on your device<ph name="END_LINK"></a></ph>. + </message> + </if> + + <message name="IDS_APP_MANAGEMENT_FILE_HANDLING_TYPES" desc="A label describing the file types (extensions) that an app has advertised the ability to open. If there are 1-4 file types, all will be shown. If there are more than 4, the extras will be truncated and a link will be added which, when clicked, shows the elided extensions. [ICU_Syntax]"> + {FILE_TYPE_COUNT, plural, + =1 {Supported file type: <ph name="FILE_TYPE1">{FILE_TYPE1}<ex>TXT</ex></ph>} + =2 {Supported file types: <ph name="FILE_TYPE1">{FILE_TYPE1}<ex>TXT</ex></ph>, <ph name="FILE_TYPE2">{FILE_TYPE2}<ex>CSV</ex></ph>} + =3 {Supported file types: <ph name="FILE_TYPE1">{FILE_TYPE1}<ex>TXT</ex></ph>, <ph name="FILE_TYPE2">{FILE_TYPE2}<ex>CSV</ex></ph>, <ph name="FILE_TYPE3">{FILE_TYPE3}<ex>DOC</ex></ph>} + =4 {Supported file types: <ph name="FILE_TYPE1">{FILE_TYPE1}<ex>TXT</ex></ph>, <ph name="FILE_TYPE2">{FILE_TYPE2}<ex>CSV</ex></ph>, <ph name="FILE_TYPE3">{FILE_TYPE3}<ex>DOC</ex></ph>, <ph name="FILE_TYPE4">{FILE_TYPE4}<ex>DOCX</ex></ph>} + other {Supported file types: <ph name="FILE_TYPE1">{FILE_TYPE1}<ex>TXT</ex></ph>, <ph name="FILE_TYPE2">{FILE_TYPE2}<ex>CSV</ex></ph>, <ph name="FILE_TYPE3">{FILE_TYPE3}<ex>DOC</ex></ph>, <ph name="FILE_TYPE4">{FILE_TYPE4}<ex>DOCX</ex></ph> (<ph name="LINK"><a href="{LINK}"></ph>and {OVERFLOW_COUNT} more<ph name="END_LINK"></a></ph>)} + } + </message> </grit-part>
diff --git a/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_HEADER.png.sha1 b/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_HEADER.png.sha1 new file mode 100644 index 0000000..feed3237 --- /dev/null +++ b/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_HEADER.png.sha1
@@ -0,0 +1 @@ +117d6fc647df485427d283ad4ce42cc07ec041fe \ No newline at end of file
diff --git a/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_SET_DEFAULTS_LINK.png.sha1 b/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_SET_DEFAULTS_LINK.png.sha1 new file mode 100644 index 0000000..feed3237 --- /dev/null +++ b/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_SET_DEFAULTS_LINK.png.sha1
@@ -0,0 +1 @@ +117d6fc647df485427d283ad4ce42cc07ec041fe \ No newline at end of file
diff --git a/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_TYPES.png.sha1 b/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_TYPES.png.sha1 new file mode 100644 index 0000000..feed3237 --- /dev/null +++ b/chrome/app/app_management_strings_grdp/IDS_APP_MANAGEMENT_FILE_HANDLING_TYPES.png.sha1
@@ -0,0 +1 @@ +117d6fc647df485427d283ad4ce42cc07ec041fe \ No newline at end of file
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index bf67ab98..dc91eb7 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -5794,6 +5794,9 @@ <message name="IDS_BOREALIS_APP_NAME" desc="" translateable="false"> Steam </message> + <message name="IDS_BOREALIS_CREDITS_PLACEHOLDER" desc="Shown to users who navigate to about://borealis-credits when the real credits file can't be shown (e.g. because borealis is not running)" translateable="false"> + Borealis is either not installed or not running. Please run Borealis to view credits. + </message> <message name="IDS_BOREALIS_INSTALLER_CONFIRMATION_TITLE" desc="" translateable="false"> Set up <ph name="APP_NAME">$1<ex>BOREALIS</ex></ph> </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_BOREALIS_CREDITS_PLACEHOLDER.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_BOREALIS_CREDITS_PLACEHOLDER.png.sha1 new file mode 100644 index 0000000..c45c159cd --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_BOREALIS_CREDITS_PLACEHOLDER.png.sha1
@@ -0,0 +1 @@ +d43f02cad61ae65be3a15fd47e8f101f74253fec \ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index 890cf7bf..58f2aa66 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -1385,7 +1385,7 @@ Assign 1 more switch </message> <message name="IDS_SETTINGS_SWITCH_ACCESS_SETUP_CHOOSE_2_SWITCHES_DESCRIPTION" desc="The description for the option to use two switches (with one already assigned), within the Switch Access setup guide. It details that the second switch will be 'next' and move focus to the next item onscreen. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> - Use “Next” to move forward on the screen + Use “Next” to move your focus forward on the screen </message> <message name="IDS_SETTINGS_SWITCH_ACCESS_SETUP_CHOOSE_3_SWITCHES" desc="The label for the option to use three switches (with one already assigned), within the Switch Access setup guide. Switch Access is an alternative input method designed for users with limited mobility, where the user has as little as one switch (for example, a button) to control the computer."> Assign 2 more switches
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_SETUP_CHOOSE_2_SWITCHES_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_SETUP_CHOOSE_2_SWITCHES_DESCRIPTION.png.sha1 index 63c9867..cfe5690 100644 --- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_SETUP_CHOOSE_2_SWITCHES_DESCRIPTION.png.sha1 +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SWITCH_ACCESS_SETUP_CHOOSE_2_SWITCHES_DESCRIPTION.png.sha1
@@ -1 +1 @@ -525d3016e4561003b44e60f3521d16326eb86db6 \ No newline at end of file +a894876e85b51f7b1ede422b773966a070b8b81c \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index ed48d8c..bde4bc5e 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -6329,6 +6329,12 @@ "//printing/backend", ] + if (!is_android) { + sources += [ + "printing/print_error_dialog.cc", + "printing/print_error_dialog.h", + ] + } if (is_win) { sources += [ "printing/pdf_to_emf_converter.cc", @@ -6375,8 +6381,6 @@ "printing/pdf_nup_converter_client.h", "printing/prefs_util.cc", "printing/prefs_util.h", - "printing/print_error_dialog.cc", - "printing/print_error_dialog.h", "printing/print_preview_context_menu_observer.cc", "printing/print_preview_context_menu_observer.h", "printing/print_preview_data_service.cc", @@ -6917,8 +6921,6 @@ if (enable_plugins) { sources += [ - "metrics/plugin_metrics_provider.cc", - "metrics/plugin_metrics_provider.h", "plugins/chrome_content_browser_client_plugins_part.cc", "plugins/chrome_content_browser_client_plugins_part.h", "plugins/chrome_plugin_service_filter.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 1362421..a9db4013 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -780,6 +780,23 @@ }; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_CHROMEOS_ASH) +const FeatureEntry::FeatureParam kDynamicSearchUpdateAnimationDuration_50[] = { + {"search_result_translation_duration", "50"}}; +const FeatureEntry::FeatureParam kDynamicSearchUpdateAnimationDuration_100[] = { + {"search_result_translation_duration", "100"}}; +const FeatureEntry::FeatureParam kDynamicSearchUpdateAnimationDuration_150[] = { + {"search_result_translation_duration", "150"}}; + +const FeatureEntry::FeatureVariation kDynamicSearchUpdateAnimationVariations[] = + {{"50ms", kDynamicSearchUpdateAnimationDuration_50, + std::size(kDynamicSearchUpdateAnimationDuration_50), nullptr}, + {"100ms", kDynamicSearchUpdateAnimationDuration_100, + std::size(kDynamicSearchUpdateAnimationDuration_100), nullptr}, + {"150ms", kDynamicSearchUpdateAnimationDuration_150, + std::size(kDynamicSearchUpdateAnimationDuration_150), nullptr}}; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + #if BUILDFLAG(ENABLE_NACL) // Note: This needs to be kept in sync with parsing in // content/common/zygote/zygote_communication_linux.cc @@ -6893,6 +6910,14 @@ flag_descriptions::kSearchResultInlineIconDescription, kOsCrOS, FEATURE_VALUE_TYPE(app_list_features::kSearchResultInlineIcon)}, + {"dynamic-search-update-animation", + flag_descriptions::kDynamicSearchUpdateAnimationName, + flag_descriptions::kDynamicSearchUpdateAnimationDescription, kOsCrOS, + FEATURE_WITH_PARAMS_VALUE_TYPE( + app_list_features::kDynamicSearchUpdateAnimation, + kDynamicSearchUpdateAnimationVariations, + "LauncherDynamicAnimations")}, + {"app-discovery-remote-url-search", flag_descriptions::kAppDiscoveryRemoteUrlSearchName, flag_descriptions::kAppDiscoveryRemoteUrlSearchDescription, kOsCrOS,
diff --git a/chrome/browser/android/bottombar/overlay_panel_content.cc b/chrome/browser/android/bottombar/overlay_panel_content.cc index 92e613c7..34dffd9 100644 --- a/chrome/browser/android/bottombar/overlay_panel_content.cc +++ b/chrome/browser/android/bottombar/overlay_panel_content.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/memory/weak_ptr.h" +#include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "cc/input/browser_controls_state.h" #include "chrome/android/chrome_jni_headers/OverlayPanelContent_jni.h" @@ -125,7 +126,12 @@ JNIEnv* env, const JavaParamRef<jobject>& jobj) { DCHECK(web_contents_.get()); - web_contents_.reset(); + // At the time this is called we may be deeply nested in a callback from + // WebContents. WebContents does not support being deleted from a callback + // (crashes). To avoid this problem DeleteSoon() is used. See + // https://crbug.com/1262098. + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, + web_contents_.release()); // |web_contents_delegate_| may already be NULL at this point. web_contents_delegate_.reset(); }
diff --git a/chrome/browser/apps/app_service/webapk/webapk_install_task_unittest.cc b/chrome/browser/apps/app_service/webapk/webapk_install_task_unittest.cc index fba00c95..035539d 100644 --- a/chrome/browser/apps/app_service/webapk/webapk_install_task_unittest.cc +++ b/chrome/browser/apps/app_service/webapk/webapk_install_task_unittest.cc
@@ -213,7 +213,7 @@ ASSERT_EQ(fake_webapk_instance()->handled_packages().size(), 1u); ASSERT_EQ(fake_webapk_instance()->handled_packages().count( "org.chromium.webapk.some_package"), - 1); + 1u); ASSERT_THAT(apps::webapk_prefs::GetWebApkAppIds(profile()), testing::ElementsAre(app_id)); @@ -256,9 +256,9 @@ EXPECT_EQ(manifest.share_targets(0).params().url(), "share_url"); EXPECT_FALSE(manifest.share_targets(0).params().has_title()); EXPECT_EQ(manifest.share_targets(0).params().files(0).name(), "images"); - EXPECT_EQ(manifest.share_targets(0).params().files(0).accept_size(), 1u); + EXPECT_EQ(manifest.share_targets(0).params().files(0).accept_size(), 1); EXPECT_EQ(manifest.share_targets(0).params().files(0).accept(0), "image/*"); - EXPECT_EQ(manifest.share_targets(0).params().files(1).accept_size(), 2u); + EXPECT_EQ(manifest.share_targets(0).params().files(1).accept_size(), 2); } TEST_F(WebApkInstallTaskTest, NoIconInManifest) { @@ -303,7 +303,7 @@ ASSERT_FALSE(InstallWebApk(app_id)); ASSERT_EQ(fake_webapk_instance()->handled_packages().count( "org.chromium.webapk.some_package"), - 1); + 1u); ASSERT_EQ(apps::webapk_prefs::GetWebApkAppIds(profile()).size(), 0u); histograms.ExpectBucketCount(apps::kWebApkInstallResultHistogram, apps::WebApkInstallStatus::kGooglePlayError, 1);
diff --git a/chrome/browser/ash/accessibility/dictation_browsertest.cc b/chrome/browser/ash/accessibility/dictation_browsertest.cc index f278bc2..51e76bca 100644 --- a/chrome/browser/ash/accessibility/dictation_browsertest.cc +++ b/chrome/browser/ash/accessibility/dictation_browsertest.cc
@@ -1121,19 +1121,6 @@ return base::UTF16ToUTF8(text); } - void WaitForHelpUrlVisible() { - std::string error_message = "Still waiting for help URL to be visible"; - SuccessWaiter(base::BindLambdaForTesting([&]() { - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - return web_contents->GetVisibleURL().spec().rfind( - "https://support.google.com/chromebook", - /*pos=*/0) != 0; - }), - error_message) - .Wait(); - } - private: base::test::ScopedFeatureList scoped_feature_list_; }; @@ -1263,17 +1250,20 @@ /*expected_bucket_count=*/1); } -// TODO(1266696): DictationCommandsExtensionTest.Help is flaky. -// According to the flake occurrences tool, the OnDevice variant is the flaky -// one; the Network variant passes consistently. -#if BUILDFLAG(IS_CHROMEOS) -#define MAYBE_Help DISABLED_Help -#else -#define MAYBE_Help Help -#endif -IN_PROC_BROWSER_TEST_P(DictationCommandsExtensionTest, MAYBE_Help) { +IN_PROC_BROWSER_TEST_P(DictationCommandsExtensionTest, Help) { SendFinalResultAndWait("help"); - WaitForHelpUrlVisible(); + + // Wait for the help URL to load. + SuccessWaiter( + base::BindLambdaForTesting([&]() { + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + return web_contents->GetVisibleURL() == + "https://support.google.com/chromebook?p=text_dictation_m100"; + }), + "Still waiting for help URL to load") + .Wait(); + // Opening a new tab with the help center article toggles Dictation off. WaitForRecognitionStopped(); }
diff --git a/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner.cc b/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner.cc index a3b4b5e..878aede 100644 --- a/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner.cc +++ b/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner.cc
@@ -207,13 +207,54 @@ return; } auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service_->file_system(), OpenFileToWrite); + arc_bridge_service_->file_system(), DEPRECATED_OpenFileToWrite); if (!file_system_instance) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), mojo::ScopedHandle())); return; } - file_system_instance->OpenFileToWrite(url.spec(), std::move(callback)); + file_system_instance->DEPRECATED_OpenFileToWrite(url.spec(), + std::move(callback)); +} + +void ArcFileSystemOperationRunner::CloseFileSession( + const std::string& url_id, + const std::string& error_message) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (should_defer_) { + deferred_operations_.emplace_back( + base::BindOnce(&ArcFileSystemOperationRunner::CloseFileSession, + weak_ptr_factory_.GetWeakPtr(), url_id, error_message)); + return; + } + auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( + arc_bridge_service_->file_system(), CloseFileSession); + if (!file_system_instance) { + LOG(WARNING) << "Failed to call CloseFileSession."; + return; + } + file_system_instance->CloseFileSession(url_id, error_message); +} + +void ArcFileSystemOperationRunner::OpenFileSessionToWrite( + const GURL& url, + OpenFileSessionToWriteCallback callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (should_defer_) { + deferred_operations_.emplace_back(base::BindOnce( + &ArcFileSystemOperationRunner::OpenFileSessionToWrite, + weak_ptr_factory_.GetWeakPtr(), url, std::move(callback))); + return; + } + auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( + arc_bridge_service_->file_system(), OpenFileSessionToWrite); + if (!file_system_instance) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), mojom::FileSessionPtr())); + return; + } + file_system_instance->OpenFileSessionToWrite(url, std::move(callback)); } void ArcFileSystemOperationRunner::GetDocument(const std::string& authority,
diff --git a/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner.h b/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner.h index 4f6d9f9..53fce8bf 100644 --- a/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner.h +++ b/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner.h
@@ -73,7 +73,9 @@ using OpenThumbnailCallback = mojom::FileSystemInstance::OpenThumbnailCallback; using OpenFileToWriteCallback = - mojom::FileSystemInstance::OpenFileToWriteCallback; + mojom::FileSystemInstance::DEPRECATED_OpenFileToWriteCallback; + using OpenFileSessionToWriteCallback = + mojom::FileSystemInstance::OpenFileSessionToWriteCallback; using GetDocumentCallback = mojom::FileSystemInstance::GetDocumentCallback; using GetChildDocumentsCallback = mojom::FileSystemInstance::GetChildDocumentsCallback; @@ -142,7 +144,12 @@ void OpenThumbnail(const GURL& url, const gfx::Size& size, OpenThumbnailCallback callback); + // TODO(b/220547241): Remove DEPRECATED function from file_system.mojom. void OpenFileToWrite(const GURL& url, OpenFileToWriteCallback callback); + void CloseFileSession(const std::string& session_id, + const std::string& error_message); + void OpenFileSessionToWrite(const GURL& url, + OpenFileSessionToWriteCallback callback); void GetDocument(const std::string& authority, const std::string& document_id, GetDocumentCallback callback);
diff --git a/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner_unittest.cc b/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner_unittest.cc index 4f3a5db9..bcfb145d 100644 --- a/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner_unittest.cc +++ b/chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner_unittest.cc
@@ -30,6 +30,7 @@ constexpr char kDocumentId[] = "document_id"; constexpr char kRootId[] = "root_id"; constexpr char kUrl[] = "content://test"; +constexpr char kUrlId[] = "url_id"; } // namespace @@ -132,6 +133,12 @@ base::BindOnce( [](int* counter, mojo::ScopedHandle handle) { ++*counter; }, counter)); + runner_->OpenFileSessionToWrite( + GURL(kUrl), + base::BindOnce([](int* counter, + mojom::FileSessionPtr file_session) { ++*counter; }, + counter)); + runner_->CloseFileSession(kUrlId, /*error_message=*/std::string()); // RemoveWatcher() is never deferred. runner_->RemoveWatcher( @@ -154,7 +161,7 @@ CallSetShouldDefer(false); CallAllFunctions(&counter); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(11, counter); + EXPECT_EQ(12, counter); } TEST_F(ArcFileSystemOperationRunnerTest, DeferAndRun) { @@ -166,7 +173,7 @@ CallSetShouldDefer(false); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(11, counter); + EXPECT_EQ(12, counter); } // TODO(nya,hidehiko): Check if we should keep this test. @@ -191,7 +198,7 @@ CallSetShouldDefer(false); CallAllFunctions(&counter); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(11, counter); + EXPECT_EQ(12, counter); } } // namespace arc
diff --git a/chrome/browser/ash/arc/nearby_share/nearby_share_session_impl.cc b/chrome/browser/ash/arc/nearby_share/nearby_share_session_impl.cc index 6fda436..5a6d791 100644 --- a/chrome/browser/ash/arc/nearby_share/nearby_share_session_impl.cc +++ b/chrome/browser/ash/arc/nearby_share/nearby_share_session_impl.cc
@@ -261,7 +261,7 @@ void NearbyShareSessionImpl::OnPreparedDirectory(base::File::Error result) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(arc_window_); - DCHECK_GT(file_handler_->GetTotalSizeOfFiles(), 0); + DCHECK_GT(file_handler_->GetTotalSizeOfFiles(), 0u); DVLOG(1) << __func__; if (result == base::File::FILE_ERROR_NO_SPACE) {
diff --git a/chrome/browser/ash/arc/nearby_share/share_info_file_stream_adapter.cc b/chrome/browser/ash/arc/nearby_share/share_info_file_stream_adapter.cc index 18be7ef4..75d58e1 100644 --- a/chrome/browser/ash/arc/nearby_share/share_info_file_stream_adapter.cc +++ b/chrome/browser/ash/arc/nearby_share/share_info_file_stream_adapter.cc
@@ -187,7 +187,7 @@ void ShareInfoFileStreamAdapter::WriteToPipe() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK(producer_stream_.is_valid()); - DCHECK_NE(pipe_write_size_, 0); + DCHECK_NE(pipe_write_size_, 0u); while (true) { uint32_t bytes_to_write = pipe_write_size_ - pipe_write_offset_;
diff --git a/chrome/browser/ash/borealis/borealis_credits.cc b/chrome/browser/ash/borealis/borealis_credits.cc new file mode 100644 index 0000000..c0f057ee --- /dev/null +++ b/chrome/browser/ash/borealis/borealis_credits.cc
@@ -0,0 +1,67 @@ +// 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/ash/borealis/borealis_credits.h" + +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/task/thread_pool.h" +#include "chrome/browser/ash/borealis/borealis_features.h" +#include "chrome/browser/ash/borealis/borealis_service.h" +#include "chrome/browser/ash/borealis/borealis_util.h" +#include "chromeos/dbus/dlcservice/dlcservice.pb.h" +#include "chromeos/dbus/dlcservice/dlcservice_client.h" +#include "third_party/cros_system_api/dbus/dlcservice/dbus-constants.h" + +namespace borealis { + +namespace { + +const char kBorealisCreditsDlcSubpath[] = "credits.html"; + +std::string LoadCreditsFileBlocking(std::string dlc_root_path) { + std::string contents; + base::FilePath path = + base::FilePath(dlc_root_path).Append(kBorealisCreditsDlcSubpath); + if (!base::ReadFileToString(path, &contents)) { + LOG(ERROR) << "Failed to load credits file: Failed to read " << path; + return ""; + } + return contents; +} + +void OnStateQueried(base::OnceCallback<void(std::string)> callback, + const std::string& err, + const dlcservice::DlcState& state) { + if (err != dlcservice::kErrorNone) { + LOG(ERROR) << "Failed to load credits file: DLC error: " << err; + std::move(callback).Run(""); + return; + } + if (state.state() != dlcservice::DlcState_State::DlcState_State_INSTALLED) { + VLOG(1) << "Can't load credits file: DLC not available"; + std::move(callback).Run(""); + return; + } + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&LoadCreditsFileBlocking, state.root_path()), + std::move(callback)); +} + +} // namespace + +void LoadBorealisCredits(Profile* profile, + base::OnceCallback<void(std::string)> callback) { + if (!BorealisService::GetForProfile(profile)->Features().IsEnabled()) { + VLOG(1) << "Can't load credits file: Borealis not installed"; + std::move(callback).Run(""); + return; + } + chromeos::DlcserviceClient::Get()->GetDlcState( + kBorealisDlcName, base::BindOnce(&OnStateQueried, std::move(callback))); +} + +} // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_credits.h b/chrome/browser/ash/borealis/borealis_credits.h new file mode 100644 index 0000000..bfe94d0 --- /dev/null +++ b/chrome/browser/ash/borealis/borealis_credits.h
@@ -0,0 +1,24 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ASH_BOREALIS_BOREALIS_CREDITS_H_ +#define CHROME_BROWSER_ASH_BOREALIS_BOREALIS_CREDITS_H_ + +#include <string> + +#include "base/callback_forward.h" + +class Profile; + +namespace borealis { + +// Loads the borealis credits file from the DLC, invoking |callback| with the +// HTML contents in a string. If the credits can not be loaded, the empty string +// will be used instead. +void LoadBorealisCredits(Profile* profile, + base::OnceCallback<void(std::string)> callback); + +} // namespace borealis + +#endif // CHROME_BROWSER_ASH_BOREALIS_BOREALIS_CREDITS_H_
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager_impl.cc b/chrome/browser/ash/borealis/borealis_disk_manager_impl.cc index 7103ab972..a2287ba 100644 --- a/chrome/browser/ash/borealis/borealis_disk_manager_impl.cc +++ b/chrome/browser/ash/borealis/borealis_disk_manager_impl.cc
@@ -471,6 +471,19 @@ Expected<std::unique_ptr<std::pair<BorealisDiskInfo, BorealisDiskInfo>>, Described<BorealisResizeDiskResult>> disk_info_or_error) { if (!disk_info_or_error) { + // Sometimes the disk size can get out of sync, so that btrfs reports that + // the minimum size of the disk is larger than the actual disk size. In + // this case we will get a kViolatesMinimumSize from trying to resize the + // disk. We don't want to block the startup process because of this error + // so we special case it as a success. + if (disk_info_or_error.Error().error() == + BorealisResizeDiskResult::kViolatesMinimumSize) { + LOG(WARNING) << "disk was unable to be shrunk due to the disk " + "already being smaller than the minimum size"; + Succeed(std::make_unique<BorealisSyncDiskSizeResult>( + BorealisSyncDiskSizeResult::kDiskSizeSmallerThanMin)); + return; + } Fail(Described<BorealisSyncDiskSizeResult>( BorealisSyncDiskSizeResult::kResizeFailed, "resize failed: " + disk_info_or_error.Error().description()));
diff --git a/chrome/browser/ash/borealis/borealis_disk_manager_unittest.cc b/chrome/browser/ash/borealis/borealis_disk_manager_unittest.cc index 01dbd3f..0a18bed 100644 --- a/chrome/browser/ash/borealis/borealis_disk_manager_unittest.cc +++ b/chrome/browser/ash/borealis/borealis_disk_manager_unittest.cc
@@ -1099,7 +1099,7 @@ [](Expected<uint64_t, Described<BorealisResizeDiskResult>> response_or_error) { EXPECT_TRUE(response_or_error); - EXPECT_EQ(response_or_error.Value(), 0); + EXPECT_EQ(response_or_error.Value(), 0u); })); disk_manager_->ReleaseSpace(1 * kGiB, callback_factory.BindOnce()); run_loop()->RunUntilIdle(); @@ -1422,6 +1422,39 @@ BorealisSyncDiskSizeResult::kResizeFailed, 1); } +TEST_F(BorealisDiskManagerTest, + SyncDiskSizeSucceedsIfDiskBelowMinSizeDuringShrink) { + // This object forces all EXPECT_CALLs to occur in the order they are + // declared. + testing::InSequence sequence; + + EXPECT_CALL(*free_space_provider_, Get(_)) + .Times(2) + .WillRepeatedly( + testing::Invoke([this](base::OnceCallback<void(int64_t)> callback) { + auto response = BuildValidListVmDisksResponse( + /*min_size=*/6 * kGiB, /*size=*/5 * kGiB, + /*available_space=*/3 * kGiB); + FakeConciergeClient()->set_list_vm_disks_response(response); + std::move(callback).Run(5 * kGiB); + })); + + SyncDiskCallbackFactory callback_factory; + EXPECT_CALL(callback_factory, Call(_)) + .WillOnce(testing::Invoke( + [](Expected<BorealisSyncDiskSizeResult, + Described<BorealisSyncDiskSizeResult>> result) { + EXPECT_TRUE(result); + EXPECT_EQ(result.Value(), + BorealisSyncDiskSizeResult::kDiskSizeSmallerThanMin); + })); + disk_manager_->SyncDiskSize(callback_factory.BindOnce()); + run_loop()->RunUntilIdle(); + histogram_tester_.ExpectUniqueSample( + kBorealisDiskStartupResultHistogram, + BorealisSyncDiskSizeResult::kDiskSizeSmallerThanMin, 1); +} + TEST_F(BorealisDiskManagerTest, SyncDiskSizePartialResizeSucceeds) { // This is considered "partial" as it should log a warning. There is not // enough space on the device to fully rebuild the buffer to 2GB, but it will
diff --git a/chrome/browser/ash/borealis/borealis_installer_unittest.cc b/chrome/browser/ash/borealis/borealis_installer_unittest.cc index 432503e..2a86621 100644 --- a/chrome/browser/ash/borealis/borealis_installer_unittest.cc +++ b/chrome/browser/ash/borealis/borealis_installer_unittest.cc
@@ -90,7 +90,7 @@ installer_->AddObserver(observer_.get()); UpdateCurrentDlcs(); - ASSERT_EQ(current_dlcs_.dlc_infos_size(), 0u); + ASSERT_EQ(current_dlcs_.dlc_infos_size(), 0); ASSERT_FALSE( BorealisService::GetForProfile(&profile_)->Features().IsEnabled()); } @@ -165,7 +165,7 @@ StartAndRunToCompletion(); UpdateCurrentDlcs(); - ASSERT_EQ(current_dlcs_.dlc_infos_size(), 0u); + ASSERT_EQ(current_dlcs_.dlc_infos_size(), 0); EXPECT_FALSE( BorealisService::GetForProfile(&profile_)->Features().IsEnabled()); } @@ -181,7 +181,7 @@ StartAndRunToCompletion(); UpdateCurrentDlcs(); - ASSERT_EQ(current_dlcs_.dlc_infos_size(), 0u); + ASSERT_EQ(current_dlcs_.dlc_infos_size(), 0); EXPECT_FALSE( BorealisService::GetForProfile(&profile_)->Features().IsEnabled()); } @@ -193,7 +193,7 @@ StartAndRunToCompletion(); UpdateCurrentDlcs(); - ASSERT_EQ(current_dlcs_.dlc_infos_size(), 1u); + ASSERT_EQ(current_dlcs_.dlc_infos_size(), 1); EXPECT_EQ(current_dlcs_.dlc_infos(0).id(), borealis::kBorealisDlcName); EXPECT_TRUE( BorealisService::GetForProfile(&profile_)->Features().IsEnabled()); @@ -235,7 +235,7 @@ task_environment_.RunUntilIdle(); UpdateCurrentDlcs(); - ASSERT_EQ(current_dlcs_.dlc_infos_size(), 1u); + ASSERT_EQ(current_dlcs_.dlc_infos_size(), 1); EXPECT_EQ(current_dlcs_.dlc_infos(0).id(), borealis::kBorealisDlcName); EXPECT_FALSE( BorealisService::GetForProfile(&profile_)->Features().IsEnabled()); @@ -254,7 +254,7 @@ task_environment_.RunUntilIdle(); UpdateCurrentDlcs(); - ASSERT_EQ(current_dlcs_.dlc_infos_size(), 1u); + ASSERT_EQ(current_dlcs_.dlc_infos_size(), 1); EXPECT_EQ(current_dlcs_.dlc_infos(0).id(), borealis::kBorealisDlcName); EXPECT_TRUE( BorealisService::GetForProfile(&profile_)->Features().IsEnabled()); @@ -269,7 +269,7 @@ task_environment_.RunUntilIdle(); UpdateCurrentDlcs(); - ASSERT_EQ(current_dlcs_.dlc_infos_size(), 0u); + ASSERT_EQ(current_dlcs_.dlc_infos_size(), 0); EXPECT_FALSE( BorealisService::GetForProfile(&profile_)->Features().IsEnabled()); @@ -279,7 +279,7 @@ task_environment_.RunUntilIdle(); UpdateCurrentDlcs(); - ASSERT_EQ(current_dlcs_.dlc_infos_size(), 1u); + ASSERT_EQ(current_dlcs_.dlc_infos_size(), 1); EXPECT_EQ(current_dlcs_.dlc_infos(0).id(), borealis::kBorealisDlcName); EXPECT_TRUE( BorealisService::GetForProfile(&profile_)->Features().IsEnabled()); @@ -474,7 +474,7 @@ // The DLC should remain because the disk was not removed. UpdateCurrentDlcs(); - EXPECT_EQ(current_dlcs_.dlc_infos_size(), 1u); + EXPECT_EQ(current_dlcs_.dlc_infos_size(), 1); // Borealis is still "installed" according to the prefs. EXPECT_TRUE( @@ -542,7 +542,7 @@ // Borealis's DLC is not installed UpdateCurrentDlcs(); - EXPECT_EQ(current_dlcs_.dlc_infos_size(), 0u); + EXPECT_EQ(current_dlcs_.dlc_infos_size(), 0); } TEST_F(BorealisUninstallerTest, UninstallationIsIdempotent) {
diff --git a/chrome/browser/ash/borealis/borealis_metrics.h b/chrome/browser/ash/borealis/borealis_metrics.h index e8696bd..29e4169 100644 --- a/chrome/browser/ash/borealis/borealis_metrics.h +++ b/chrome/browser/ash/borealis/borealis_metrics.h
@@ -119,7 +119,8 @@ kAlreadyInProgress = 5, kFailedToGetDiskInfo = 6, kResizeFailed = 7, - kMaxValue = kResizeFailed, + kDiskSizeSmallerThanMin = 8, + kMaxValue = kDiskSizeSmallerThanMin, }; // These values are persisted to logs. Entries should not be renumbered and
diff --git a/chrome/browser/ash/borealis/borealis_util.cc b/chrome/browser/ash/borealis/borealis_util.cc index ac61674..d62add2 100644 --- a/chrome/browser/ash/borealis/borealis_util.cc +++ b/chrome/browser/ash/borealis/borealis_util.cc
@@ -242,4 +242,25 @@ return version_info; } +void OnGetDlcState(base::OnceCallback<void(const std::string& path)> callback, + const std::string& err, + const dlcservice::DlcState& dlc_state) { + if (err != dlcservice::kErrorNone) { + LOG(ERROR) << "Failed to get dlc state with error: " << err; + } + + // TODO(b/220799106): Add user visible error. + if (!dlc_state.INSTALLED) { + LOG(ERROR) << "Borealis dlc is not installed"; + return; + } + // std::string path = dlc_state.root_path().get*; + std::move(callback).Run(dlc_state.root_path()); +} + +void GetDlcPath(base::OnceCallback<void(const std::string& path)> callback) { + chromeos::DlcserviceClient::Get()->GetDlcState( + kBorealisDlcName, base::BindOnce(&OnGetDlcState, std::move(callback))); +} + } // namespace borealis
diff --git a/chrome/browser/ash/borealis/borealis_util.h b/chrome/browser/ash/borealis/borealis_util.h index 2a2bd51..4d02300 100644 --- a/chrome/browser/ash/borealis/borealis_util.h +++ b/chrome/browser/ash/borealis/borealis_util.h
@@ -9,6 +9,7 @@ #include "base/callback_forward.h" #include "base/strings/string_piece.h" +#include "chromeos/dbus/dlcservice/dlcservice_client.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/views/widget/widget.h" @@ -80,6 +81,10 @@ ProtonVersionInfo ParseProtonVersionInfo(absl::optional<int> game_id, const std::string& output); +// Used in the splash screen to get the dlc path as dlcservice could not be +// imported directly. +void GetDlcPath(base::OnceCallback<void(const std::string& path)> callback); + } // namespace borealis #endif // CHROME_BROWSER_ASH_BOREALIS_BOREALIS_UTIL_H_
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc index feb24740..04dc9d6a 100644 --- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc +++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -1216,7 +1216,8 @@ std::make_unique<device_activity::DeviceActivityController>(); device_activity_controller_->Start( - device_activity::Trigger::kNetwork, g_browser_process->local_state(), + device_activity::Trigger::kNetwork, chrome::GetChannel(), + g_browser_process->local_state(), g_browser_process->system_network_context_manager() ->GetSharedURLLoaderFactory()); }
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator.cc b/chrome/browser/ash/crosapi/browser_data_migrator.cc index 1a6ef0f..f65db69 100644 --- a/chrome/browser/ash/crosapi/browser_data_migrator.cc +++ b/chrome/browser/ash/crosapi/browser_data_migrator.cc
@@ -53,9 +53,6 @@ const AccountId& account_id, const std::string& user_id_hash) { LOG(WARNING) << "MaybeForceResumeMoveMigration() is called."; - // TODO(crbug.com/1261730): Set a max number of force resume and if that - // number is reached, do not attempt a resume and simply mark move migration - // && migration as completed. if (!MoveMigrator::ResumeRequired(local_state, user_id_hash)) return false; @@ -146,6 +143,9 @@ user_id_hash); crosapi::browser_util::ClearProfileMigrationCompletedForUser( g_browser_process->local_state(), user_id_hash); + // TODO(ythjkt): Also clear move migration resume step here. + MoveMigrator::ClearResumeAttemptCountForUser( + g_browser_process->local_state(), user_id_hash); return false; }
diff --git a/chrome/browser/ash/crosapi/field_trial_service_ash_unittest.cc b/chrome/browser/ash/crosapi/field_trial_service_ash_unittest.cc index bfbf262..1e3ee31 100644 --- a/chrome/browser/ash/crosapi/field_trial_service_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/field_trial_service_ash_unittest.cc
@@ -92,7 +92,7 @@ base::RunLoop run_loop2; observer_.set_on_activate(base::BindLambdaForTesting( [&](const std::vector<mojom::FieldTrialGroupInfoPtr>& infos) { - EXPECT_EQ(1, infos.size()); + EXPECT_EQ(1u, infos.size()); VerifyFieldTrial(infos[0], kTrialName3, kGroupName); run_loop2.Quit(); // Test won't exit until this is called. @@ -109,7 +109,7 @@ base::RunLoop run_loop; observer_.set_on_activate(base::BindLambdaForTesting( [&](const std::vector<mojom::FieldTrialGroupInfoPtr>& infos) { - EXPECT_EQ(0, infos.size()); + EXPECT_EQ(0u, infos.size()); run_loop.Quit(); // Test won't exit until this is called. }));
diff --git a/chrome/browser/ash/crosapi/move_migrator.cc b/chrome/browser/ash/crosapi/move_migrator.cc index 99fb396..da729e5 100644 --- a/chrome/browser/ash/crosapi/move_migrator.cc +++ b/chrome/browser/ash/crosapi/move_migrator.cc
@@ -49,6 +49,17 @@ void MoveMigrator::Migrate() { ResumeStep resume_step = GetResumeStep(local_state_, user_id_hash_); + if (IsResumeStep(resume_step)) { + const int resume_count = + UpdateResumeAttemptCountForUser(local_state_, user_id_hash_); + if (resume_count > kMoveMigrationResumeCountLimit) { + LOG(ERROR) << "The number of resume attempt limit has reached. Marking " + "move migration as completed."; + SetResumeStep(local_state_, user_id_hash_, ResumeStep::kCompleted); + resume_step = ResumeStep::kCompleted; + } + } + // Start or resume migration. switch (resume_step) { case ResumeStep::kStart: @@ -101,6 +112,10 @@ const std::string& user_id_hash) { ResumeStep resume_step = GetResumeStep(local_state, user_id_hash); + return IsResumeStep(resume_step); +} + +bool MoveMigrator::IsResumeStep(ResumeStep resume_step) { switch (resume_step) { case ResumeStep::kStart: return false; @@ -117,6 +132,8 @@ void MoveMigrator::RegisterLocalStatePrefs(PrefRegistrySimple* registry) { registry->RegisterDictionaryPref(kMoveMigrationResumeStepPref, base::DictionaryValue()); + registry->RegisterDictionaryPref(kMoveMigrationResumeCountPref, + base::DictionaryValue()); } // static @@ -139,6 +156,27 @@ local_state->CommitPendingWrite(); } +int MoveMigrator::UpdateResumeAttemptCountForUser( + PrefService* local_state, + const std::string& user_id_hash) { + int count = local_state->GetDictionary(kMoveMigrationResumeCountPref) + ->FindIntPath(user_id_hash) + .value_or(0); + count += 1; + DictionaryPrefUpdate update(local_state, kMoveMigrationResumeCountPref); + base::Value* dict = update.Get(); + dict->SetIntKey(user_id_hash, count); + return count; +} + +void MoveMigrator::ClearResumeAttemptCountForUser( + PrefService* local_state, + const std::string& user_id_hash) { + DictionaryPrefUpdate update(local_state, kMoveMigrationResumeCountPref); + base::Value* dict = update.Get(); + dict->RemoveKey(user_id_hash); +} + // static MoveMigrator::PreMigrationCleanUpResult MoveMigrator::PreMigrationCleanUp( const base::FilePath& original_profile_dir) {
diff --git a/chrome/browser/ash/crosapi/move_migrator.h b/chrome/browser/ash/crosapi/move_migrator.h index 234d35dc..20ecdb9 100644 --- a/chrome/browser/ash/crosapi/move_migrator.h +++ b/chrome/browser/ash/crosapi/move_migrator.h
@@ -30,6 +30,16 @@ constexpr char kMoveMigrationResumeStepPref[] = "ash.browser_data_migrator.move_migration_resume_step"; +// Dictionary pref storing user id hash as key and number of resumes in int as +// value. +constexpr char kMoveMigrationResumeCountPref[] = + "ash.browser_data_migrator.move_migration_resume_count"; + +// The number of maximum resume tries for `MoveMigrator`. If the limit is +// reached then move migration is marked as completed without actually +// completing the migration. +constexpr int kMoveMigrationResumeCountLimit = 5; + // This class "moves" Lacros data from Ash to Lacros. It migrates user data from // `original_profile_dir` (/home/user/<hash>/), denoted as <Ash PDD> from here // forward, to the new profile data directory @@ -81,12 +91,16 @@ // BrowserDataMigratorImpl::MigratorDelegate override. void Migrate() override; - // Returns true if the `ResumeStep` stored in `local_state` for the user - // indicates that the migration had been left unfinished in the previous - // attempt and that it must be resumed before user profile is created. + // Gets the `ResumeStep` for the user stored in `local_state` and checks if + // move migration has to be resumed by calling `IsResumeStep()`. static bool ResumeRequired(PrefService* local_state, const std::string& user_id_hash); + // Resets the number of resume attempts for the user stored in + // `kMoveMigrationResumeCountPref. + static void ClearResumeAttemptCountForUser(PrefService* local_state, + const std::string& user_id_hash); + static void RegisterLocalStatePrefs(PrefRegistrySimple* registry); private: @@ -114,6 +128,17 @@ const std::string& user_id_hash, const ResumeStep step); + // Returns true if `resume_step` indicates that the migration had been left + // unfinished in the previous attempt and that it must be resumed before user + // profile is created. + static bool IsResumeStep(ResumeStep resume_step); + + // Increments the resume attempt count stored in + // `kMoveMigrationResumeCountPref` by 1 for the user identified by + // `user_id_hash`. Returns the updated resume count. + int UpdateResumeAttemptCountForUser(PrefService* local_state, + const std::string& user_id_hash); + // Deletes lacros user directory and `kMoveTmpDir` if they exist. Set // `PreMigrationCleanUpResult::success` to true if the deletion of those // directories are successful. If the deletion is successful then it also
diff --git a/chrome/browser/ash/drive/drive_integration_service_browsertest.cc b/chrome/browser/ash/drive/drive_integration_service_browsertest.cc index 5997639..d0340e2f 100644 --- a/chrome/browser/ash/drive/drive_integration_service_browsertest.cc +++ b/chrome/browser/ash/drive/drive_integration_service_browsertest.cc
@@ -253,9 +253,9 @@ CHECK(mount_path.AppendRelativePath(path, &some_other_file)); fake->SetMetadata(some_file, "text/plain", some_file.BaseName().value(), - false, false, {}, {}, "abc123"); + false, false, {}, {}, "abc123", ""); fake->SetMetadata(some_other_file, "text/plain", some_file.BaseName().value(), - false, false, {}, {}, "qwertyqwerty"); + false, false, {}, {}, "qwertyqwerty", ""); { base::RunLoop run_loop;
diff --git a/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_utils_unittest.cc b/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_utils_unittest.cc index b265590..5d0fca9c 100644 --- a/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_utils_unittest.cc +++ b/chrome/browser/ash/enhanced_network_tts/enhanced_network_tts_utils_unittest.cc
@@ -163,7 +163,7 @@ EXPECT_TRUE(result->is_data()); EXPECT_EQ(result->get_data()->audio, std::vector<uint8_t>({1, 2, 5})); EXPECT_TRUE(result->get_data()->last_data); - EXPECT_EQ(result->get_data()->time_info[0]->text_offset, 4); + EXPECT_EQ(result->get_data()->time_info[0]->text_offset, 4u); result = UnpackJsonResponse(*json, 4 /* start_index */, false /* is_last_request */); @@ -171,7 +171,7 @@ EXPECT_TRUE(result->is_data()); EXPECT_EQ(result->get_data()->audio, std::vector<uint8_t>({1, 2, 5})); EXPECT_FALSE(result->get_data()->last_data); - EXPECT_EQ(result->get_data()->time_info[0]->text_offset, 4); + EXPECT_EQ(result->get_data()->time_info[0]->text_offset, 4u); } TEST_F(EnhancedNetworkTtsUtilsTest,
diff --git a/chrome/browser/ash/events/event_rewriter_unittest.cc b/chrome/browser/ash/events/event_rewriter_unittest.cc index 416d46d..53ea08c 100644 --- a/chrome/browser/ash/events/event_rewriter_unittest.cc +++ b/chrome/browser/ash/events/event_rewriter_unittest.cc
@@ -4029,7 +4029,7 @@ TEST_F(EventRewriterTest, DontRewriteIfNotRewritten_AltClickIsRightClick) { DontRewriteIfNotRewritten(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN); - EXPECT_EQ(message_center_.NotificationCount(), 0); + EXPECT_EQ(message_center_.NotificationCount(), 0u); } TEST_F(EventRewriterTest, DontRewriteIfNotRewritten_AltClickIsRightClick_New) { @@ -4038,14 +4038,14 @@ scoped_feature_list_.InitAndEnableFeature( ::features::kImprovedKeyboardShortcuts); DontRewriteIfNotRewritten(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN); - EXPECT_EQ(message_center_.NotificationCount(), 0); + EXPECT_EQ(message_center_.NotificationCount(), 0u); } TEST_F(EventRewriterTest, DontRewriteIfNotRewritten_SearchClickIsRightClick) { scoped_feature_list_.InitAndEnableFeature( features::kUseSearchClickForRightClick); DontRewriteIfNotRewritten(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_COMMAND_DOWN); - EXPECT_EQ(message_center_.NotificationCount(), 0); + EXPECT_EQ(message_center_.NotificationCount(), 0u); } TEST_F(EventRewriterTest, DontRewriteIfNotRewritten_AltClickDeprecated) { @@ -4053,7 +4053,7 @@ // generate a notification. scoped_feature_list_.InitAndEnableFeature(::features::kDeprecateAltClick); DontRewriteIfNotRewritten(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_COMMAND_DOWN); - EXPECT_EQ(message_center_.NotificationCount(), 0); + EXPECT_EQ(message_center_.NotificationCount(), 0u); } TEST_F(EventRewriterTest, DeprecatedAltClickGeneratesNotification) { @@ -4090,7 +4090,7 @@ EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result.changed_button_flags()); // Expect a deprecation notification. - EXPECT_EQ(message_center_.NotificationCount(), 1); + EXPECT_EQ(message_center_.NotificationCount(), 1u); ClearNotifications(); } { @@ -4106,7 +4106,7 @@ EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result.changed_button_flags()); // Don't expect a new notification on release. - EXPECT_EQ(message_center_.NotificationCount(), 0); + EXPECT_EQ(message_center_.NotificationCount(), 0u); } // No rewrite or notification for non-touchpad devices. @@ -4123,7 +4123,7 @@ EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result.changed_button_flags()); // No notification expected for this case. - EXPECT_EQ(message_center_.NotificationCount(), 0); + EXPECT_EQ(message_center_.NotificationCount(), 0u); } { ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), @@ -4136,7 +4136,7 @@ EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result.changed_button_flags()); // No notification expected for this case. - EXPECT_EQ(message_center_.NotificationCount(), 0); + EXPECT_EQ(message_center_.NotificationCount(), 0u); } } @@ -4233,7 +4233,7 @@ EXPECT_EQ(out_layout, ui::EventRewriterChromeOS::kKbdTopRowLayoutCustom); // Basic inspection to match kKbdDefaultCustomTopRowLayout - EXPECT_EQ(15, scan_code_map.size()); + EXPECT_EQ(15u, scan_code_map.size()); ASSERT_TRUE(scan_code_map.contains(1)); EXPECT_EQ(ui::VKEY_F1, scan_code_map[1].key_code);
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc index 21c5cee..0a6064c 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -521,21 +521,34 @@ // TODO(crbug.com/1236842): Remove flakiness and enable this test. #if !defined(ADDRESS_SANITIZER) && defined(NDEBUG) TestCase("keyboardFocusOutlineVisible"), + TestCase("keyboardFocusOutlineVisible").FilesSwa(), TestCase("keyboardFocusOutlineVisible").EnableTrash(), + TestCase("keyboardFocusOutlineVisible").EnableTrash().FilesSwa(), TestCase("keyboardFocusOutlineVisibleMouse"), + TestCase("keyboardFocusOutlineVisibleMouse").FilesSwa(), TestCase("keyboardFocusOutlineVisibleMouse").EnableTrash(), + TestCase("keyboardFocusOutlineVisibleMouse").EnableTrash().FilesSwa(), #endif TestCase("keyboardSelectDriveDirectoryTree"), + TestCase("keyboardSelectDriveDirectoryTree").FilesSwa(), TestCase("keyboardDisableCopyWhenDialogDisplayed"), + TestCase("keyboardDisableCopyWhenDialogDisplayed").FilesSwa(), TestCase("keyboardOpenNewWindow"), - TestCase("keyboardOpenNewWindow").InGuestMode(), TestCase("keyboardOpenNewWindow").FilesSwa(), - TestCase("renameFileDownloads").InGuestMode(), + TestCase("keyboardOpenNewWindow").InGuestMode(), + TestCase("keyboardOpenNewWindow").InGuestMode().FilesSwa(), TestCase("renameFileDownloads"), + TestCase("renameFileDownloads").FilesSwa(), + TestCase("renameFileDownloads").InGuestMode(), + TestCase("renameFileDownloads").InGuestMode().FilesSwa(), TestCase("renameFileDrive"), - TestCase("renameNewFolderDownloads").InGuestMode(), + TestCase("renameFileDrive").FilesSwa(), TestCase("renameNewFolderDownloads"), - TestCase("renameRemovableWithKeyboardOnFileList"))); + TestCase("renameNewFolderDownloads").FilesSwa(), + TestCase("renameNewFolderDownloads").InGuestMode(), + TestCase("renameNewFolderDownloads").InGuestMode().FilesSwa(), + TestCase("renameRemovableWithKeyboardOnFileList"), + TestCase("renameRemovableWithKeyboardOnFileList").FilesSwa())); WRAPPED_INSTANTIATE_TEST_SUITE_P( ContextMenu, /* context_menu.js for file list */ @@ -1595,8 +1608,16 @@ TestCase("openOfficeFile").EnableWebDriveOffice().FilesSwa(), TestCase("openOfficeFromMyFiles").EnableWebDriveOffice(), TestCase("openOfficeFromMyFiles").EnableWebDriveOffice().FilesSwa(), + TestCase("openMultipleOfficeFromDrive").EnableWebDriveOffice(), + TestCase("openMultipleOfficeFromDrive") + .EnableWebDriveOffice() + .FilesSwa(), TestCase("openOfficeFromDrive").EnableWebDriveOffice(), TestCase("openOfficeFromDrive").EnableWebDriveOffice().FilesSwa(), + TestCase("openOfficeFromDriveNotSynced").EnableWebDriveOffice(), + TestCase("openOfficeFromDriveNotSynced") + .EnableWebDriveOffice() + .FilesSwa(), TestCase("openOfficeFromDriveOffline").EnableWebDriveOffice().Offline(), TestCase("openOfficeFromDriveOffline") .EnableWebDriveOffice()
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc index 91953a8..840812d 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -36,6 +36,7 @@ #include "base/json/json_reader.h" #include "base/json/json_value_converter.h" #include "base/json/json_writer.h" +#include "base/json/values_util.h" #include "base/no_destructor.h" #include "base/path_service.h" #include "base/ranges/algorithm.h" @@ -49,6 +50,7 @@ #include "base/test/bind.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" +#include "base/value_iterators.h" #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" @@ -397,6 +399,7 @@ EntryCapabilities capabilities; // Entry permissions. EntryFolderFeature folder_feature; // Entry folder feature. bool pinned = false; // Whether the file should be pinned. + std::string alternate_url; // Entry's alternate URL on Drive. TestEntryInfo& SetSharedOption(SharedOption option) { shared_option = option; @@ -445,6 +448,11 @@ return *this; } + TestEntryInfo& SetAlternateUrl(const std::string& new_alternate_url) { + alternate_url = new_alternate_url; + return *this; + } + // Registers the member information to the given converter. static void RegisterJSONConverter( base::JSONValueConverter<TestEntryInfo>* converter) { @@ -472,6 +480,8 @@ converter->RegisterNestedField("folderFeature", &TestEntryInfo::folder_feature); converter->RegisterBoolField("pinned", &TestEntryInfo::pinned); + converter->RegisterStringField("alternateUrl", + &TestEntryInfo::alternate_url); } // Maps |value| to an EntryType. Returns true on success. @@ -1238,7 +1248,7 @@ {entry.folder_feature.is_machine_root, entry.folder_feature.is_arbitrary_sync_folder, entry.folder_feature.is_external_media}, - ""); + "", entry.alternate_url); ASSERT_TRUE(UpdateModifiedTime(entry)); } @@ -1922,14 +1932,6 @@ base::BindRepeating(&FileManagerBrowserTestBase::MaybeMountCrostini, base::Unretained(this))); - if (options.enable_guest_os_files) { - // Create some mocks, that show up by default, - auto* registry = guest_os::GuestOsService::GetForProfile(profile()) - ->MountProviderRegistry(); - registry->Register(std::make_unique<MockGuestOsMountProvider>("Jemima")); - registry->Register(std::make_unique<MockGuestOsMountProvider>("Electra")); - } - if (arc::IsArcAvailable()) { // When ARC is available, create and register a fake FileSystemInstance // so ARC-related services work without a real ARC container. @@ -2996,9 +2998,40 @@ return; } + if (HandleGuestOsCommands(name, value, output)) { + return; + } + FAIL() << "Unknown test message: " << name; } +bool FileManagerBrowserTestBase::HandleGuestOsCommands( + const std::string& name, + const base::DictionaryValue& value, + std::string* output) { + if (name == "registerMountableGuest") { + const std::string* displayName = value.GetDict().FindString("displayName"); + CHECK(displayName != nullptr); + auto* registry = guest_os::GuestOsService::GetForProfile(profile()) + ->MountProviderRegistry(); + auto id = registry->Register( + std::make_unique<MockGuestOsMountProvider>(*displayName)); + base::JSONWriter::Write(base::Value(id), output); + return true; + } + if (name == "unregisterMountableGuest") { + int id; + auto* str = value.GetDict().FindString("guestId"); + CHECK(str != nullptr); + CHECK(base::StringToInt(*str, &id)); + auto* registry = guest_os::GuestOsService::GetForProfile(profile()) + ->MountProviderRegistry(); + registry->Unregister(id); + return true; + } + return false; +} + drive::DriveIntegrationService* FileManagerBrowserTestBase::CreateDriveIntegrationService(Profile* profile) { const Options options = GetOptions();
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h index 795c38f..cf6fc16 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -179,6 +179,12 @@ const base::DictionaryValue& value, std::string* output); + // Checks if the command is a GuestOs one. If so, handles it and returns + // true, otherwise it returns false. + bool HandleGuestOsCommands(const std::string& name, + const base::DictionaryValue& value, + std::string* output); + // Called during setup if needed, to create a drive integration service for // the given |profile|. Caller owns the return result. drive::DriveIntegrationService* CreateDriveIntegrationService(
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc index 0cb2709..775456f5 100644 --- a/chrome/browser/ash/file_manager/file_tasks.cc +++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -29,6 +29,7 @@ #include "chrome/browser/apps/app_service/metrics/app_platform_metrics.h" #include "chrome/browser/apps/app_service/metrics/app_service_metrics.h" #include "chrome/browser/ash/crostini/crostini_features.h" +#include "chrome/browser/ash/drive/drive_integration_service.h" #include "chrome/browser/ash/drive/file_system_util.h" #include "chrome/browser/ash/file_manager/app_id.h" #include "chrome/browser/ash/file_manager/app_service_file_tasks.h" @@ -70,6 +71,7 @@ #include "extensions/common/extension_set.h" #include "net/base/mime_util.h" #include "pdf/buildflags.h" +#include "storage/browser/file_system/file_system_context.h" #include "storage/browser/file_system/file_system_url.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/mime_util/mime_util.h" @@ -88,6 +90,7 @@ const char kActionIdView[] = "view"; const char kActionIdSend[] = "send"; const char kActionIdSendMultiple[] = "send_multiple"; +const char kActionIdWebDriveOffice[] = "open-web-drive-office"; namespace { @@ -154,6 +157,155 @@ tasks->swap(filtered); } +// Ends the recursion that determines whether or not the Web Drive Office action +// is available. +void EndAdjustTasksForWebDriveOffice( + Profile* profile, + const std::vector<extensions::EntryInfo>& entries, + const std::set<std::string>& disabled_actions, + FindTasksCallback callback, + std::unique_ptr<std::vector<FullTaskDescriptor>> result_list) { + if (!disabled_actions.empty()) + RemoveFileManagerInternalActions(disabled_actions, result_list.get()); + + ChooseAndSetDefaultTask(*profile->GetPrefs(), entries, result_list.get()); + std::move(callback).Run(std::move(result_list)); +} + +// Forward declaration. +void ProcessNextEntryForWebDriveOffice( + Profile* profile, + const std::vector<extensions::EntryInfo>& entries, + size_t entry_index, + std::set<std::string> disabled_actions, + FindTasksCallback callback, + std::unique_ptr<std::vector<FullTaskDescriptor>> result_list); + +// Checks whether the Web Drive Office task should be disabled based on the +// entry's alternate URL. +void OnGetDriveFsMetadataForWebDriveOffice( + Profile* profile, + const std::vector<extensions::EntryInfo> entries, + size_t entry_index, + std::set<std::string> disabled_actions, + FindTasksCallback callback, + std::unique_ptr<std::vector<FullTaskDescriptor>> result_list, + drive::FileError error, + drivefs::mojom::FileMetadataPtr metadata) { + if (error != drive::FILE_ERROR_OK) { + disabled_actions.emplace(kActionIdWebDriveOffice); + EndAdjustTasksForWebDriveOffice(profile, entries, disabled_actions, + std::move(callback), + std::move(result_list)); + return; + } + + GURL hosted_url(metadata->alternate_url); + // URLs for editing Office files in Web Drive all have a "docs.google.com" + // host. + if (!hosted_url.is_valid() || hosted_url.host() != "docs.google.com") { + disabled_actions.emplace(kActionIdWebDriveOffice); + EndAdjustTasksForWebDriveOffice(profile, entries, disabled_actions, + std::move(callback), + std::move(result_list)); + return; + } + + // Check alternate URL for next entry. + ProcessNextEntryForWebDriveOffice( + profile, entries, ++entry_index, std::move(disabled_actions), + std::move(callback), std::move(result_list)); +} + +// Checks whether an entry is potentially available to be opened and edited in +// Web Drive, and query its DriveFS metadata. +void ProcessNextEntryForWebDriveOffice( + Profile* profile, + const std::vector<extensions::EntryInfo>& entries, + size_t entry_index, + std::set<std::string> disabled_actions, + FindTasksCallback callback, + std::unique_ptr<std::vector<FullTaskDescriptor>> result_list) { + // Web Drive Office is available for all the selected entries. + if (entry_index == entries.size()) { + EndAdjustTasksForWebDriveOffice(profile, entries, disabled_actions, + std::move(callback), + std::move(result_list)); + return; + } + // Check whether the entry is on Drive. + if (!::file_manager::util::IsDriveLocalPath(profile, + entries[entry_index].path)) { + disabled_actions.emplace(kActionIdWebDriveOffice); + EndAdjustTasksForWebDriveOffice(profile, entries, disabled_actions, + std::move(callback), + std::move(result_list)); + return; + } + + // Check whether the DriveIntegrationService is available. + drive::DriveIntegrationService* integration_service = + drive::DriveIntegrationServiceFactory::FindForProfile(profile); + base::FilePath relative_drive_path; + if (!(integration_service && integration_service->IsMounted() && + integration_service->GetDriveFsInterface() && + integration_service->GetRelativeDrivePath(entries[entry_index].path, + &relative_drive_path))) { + disabled_actions.emplace(kActionIdWebDriveOffice); + EndAdjustTasksForWebDriveOffice(profile, entries, disabled_actions, + std::move(callback), + std::move(result_list)); + return; + } + + // Get Office file's metadata. + integration_service->GetDriveFsInterface()->GetMetadata( + relative_drive_path, + base::BindOnce(&OnGetDriveFsMetadataForWebDriveOffice, profile, + std::move(entries), entry_index, + std::move(disabled_actions), std::move(callback), + std::move(result_list))); +} + +// Starts processing entries to determine whether the Web Drive Office action +// should be disabled or not. +void AdjustTasksForWebDriveOffice( + Profile* profile, + const std::vector<extensions::EntryInfo>& entries, + std::set<std::string>& disabled_actions, + FindTasksCallback callback, + std::unique_ptr<std::vector<FullTaskDescriptor>> result_list) { + // No checks to perform if the Web Drive Office task has not been selected. + const auto web_drive_office_task = std::find_if( + result_list->begin(), result_list->end(), [&](const auto& task) { + return isFilesAppId(task.task_descriptor.app_id) && + parseFilesAppActionId(task.task_descriptor.action_id) == + kActionIdWebDriveOffice; + }); + if (web_drive_office_task == result_list->end()) { + EndAdjustTasksForWebDriveOffice(profile, entries, disabled_actions, + std::move(callback), + std::move(result_list)); + return; + } + + // Remove Web Drive Office action if Web Drive Office is disabled or if Drive + // is Offline. + if (!base::FeatureList::IsEnabled(ash::features::kFilesWebDriveOffice) || + drive::util::GetDriveConnectionStatus(profile) != + drive::util::DRIVE_CONNECTED) { + disabled_actions.emplace(kActionIdWebDriveOffice); + EndAdjustTasksForWebDriveOffice(profile, entries, disabled_actions, + std::move(callback), + std::move(result_list)); + return; + } + + ProcessNextEntryForWebDriveOffice(profile, entries, 0, disabled_actions, + std::move(callback), + std::move(result_list)); +} + // Adjusts |tasks| to reflect the product decision that chrome://media-app // should behave more like a user-installed app than a fallback handler. // Specifically, only apps set as the default in user prefs should be preferred @@ -285,6 +437,8 @@ const std::vector<extensions::EntryInfo>& entries, FindTasksCallback callback, std::unique_ptr<std::vector<FullTaskDescriptor>> result_list) { + AdjustTasksForMediaApp(entries, result_list.get()); + // Google documents can only be handled by internal handlers. if (ContainsGoogleDocument(entries)) KeepOnlyFileManagerInternalTasks(result_list.get()); @@ -338,31 +492,12 @@ } } - if (!base::FeatureList::IsEnabled(ash::features::kFilesWebDriveOffice) || - drive::util::GetDriveConnectionStatus(profile) != - drive::util::DRIVE_CONNECTED) { - disabled_actions.emplace("open-web-drive-office"); - } else { - for (const auto& entry : entries) { - // Allow the Web Drive Office task only if the entries are on Drive. - if (!::file_manager::util::IsDriveLocalPath(profile, entry.path)) { - disabled_actions.emplace("open-web-drive-office"); - break; - } - } - } - #if !BUILDFLAG(ENABLE_PDF) disabled_actions.emplace("view-pdf"); #endif // !BUILDFLAG(ENABLE_PDF) - if (!disabled_actions.empty()) - RemoveFileManagerInternalActions(disabled_actions, result_list.get()); - - AdjustTasksForMediaApp(entries, result_list.get()); - - ChooseAndSetDefaultTask(*profile->GetPrefs(), entries, result_list.get()); - std::move(callback).Run(std::move(result_list)); + AdjustTasksForWebDriveOffice(profile, entries, disabled_actions, + std::move(callback), std::move(result_list)); } // Returns true if |extension_id| and |action_id| indicate that the file @@ -376,7 +511,7 @@ action_id == "open-hosted-gdoc" || action_id == "open-hosted-gsheet" || action_id == "open-hosted-gslides" || - action_id == "open-web-drive-office"); + action_id == kActionIdWebDriveOffice); } // Opens the files specified by |file_urls| with the browser for |profile|. @@ -772,7 +907,7 @@ for (FullTaskDescriptor& task : *tasks) { if (isFilesAppId(task.task_descriptor.app_id) && parseFilesAppActionId(task.task_descriptor.action_id) == - "open-web-drive-office") { + kActionIdWebDriveOffice) { task.is_default = true; return; }
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h index 93c06fb..2eeec1d9 100644 --- a/chrome/browser/ash/file_manager/file_tasks.h +++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -120,6 +120,7 @@ extern const char kActionIdView[]; extern const char kActionIdSend[]; extern const char kActionIdSendMultiple[]; +extern const char kActionIdWebDriveOffice[]; // Task types as explained in the comment above. Search for <task-type>. enum TaskType {
diff --git a/chrome/browser/ash/file_manager/open_with_browser.cc b/chrome/browser/ash/file_manager/open_with_browser.cc index fe03662..cfab3c5 100644 --- a/chrome/browser/ash/file_manager/open_with_browser.cc +++ b/chrome/browser/ash/file_manager/open_with_browser.cc
@@ -16,6 +16,7 @@ #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "chrome/browser/ash/drive/drive_integration_service.h" +#include "chrome/browser/ash/file_manager/file_tasks.h" #include "chrome/browser/ash/file_manager/filesystem_api_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/fileapi/external_file_url_util.h" @@ -166,7 +167,7 @@ return true; } - if (action_id == "open-web-drive-office") { + if (action_id == ::file_manager::file_tasks::kActionIdWebDriveOffice) { drive::DriveIntegrationService* integration_service = drive::DriveIntegrationServiceFactory::FindForProfile(profile); base::FilePath path;
diff --git a/chrome/browser/ash/file_manager/volume_manager_unittest.cc b/chrome/browser/ash/file_manager/volume_manager_unittest.cc index d8603b2..54ebc54 100644 --- a/chrome/browser/ash/file_manager/volume_manager_unittest.cc +++ b/chrome/browser/ash/file_manager/volume_manager_unittest.cc
@@ -1008,7 +1008,7 @@ volume_manager()->Initialize(); // Adds "Downloads" std::vector<base::WeakPtr<Volume>> volume_list = volume_manager()->GetVolumeList(); - ASSERT_GT(volume_list.size(), 0); + ASSERT_GT(volume_list.size(), 0u); auto volume = base::ranges::find_if(volume_list, [](auto& v) { return v->volume_id() == "downloads:MyFiles"; });
diff --git a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.cc b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.cc index 893b30c..030b9a8 100644 --- a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.cc +++ b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.cc
@@ -35,15 +35,17 @@ return pos->second.get(); } -void GuestOsMountProviderRegistry::Register( +GuestOsMountProviderRegistry::Id GuestOsMountProviderRegistry::Register( std::unique_ptr<GuestOsMountProvider> provider) { - // We use the rang 0->INT_MAX because these IDs can get serialised into + // We use the range 0->INT_MAX because these IDs can get serialised into // base::Value, and that's the range they support. CHECK(next_id_ < INT_MAX); - providers_[next_id_++] = std::move(provider); + Id id = next_id_++; + providers_[id] = std::move(provider); for (auto& observer : observers_) { - observer.OnRegistered(next_id_ - 1, provider.get()); + observer.OnRegistered(id, provider.get()); } + return id; } std::unique_ptr<GuestOsMountProvider> GuestOsMountProviderRegistry::Unregister(
diff --git a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.h b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.h index d30f565..95de752 100644 --- a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.h +++ b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.h
@@ -44,8 +44,9 @@ GuestOsMountProvider* Get(Id id) const; // Registers a new provider with the registry. The registry takes ownership of - // the provider, holding on to it until it's unregistered. - void Register(std::unique_ptr<GuestOsMountProvider> provider); + // the provider, holding on to it until it's unregistered. Returns the id of + // the newly-registered provider. + Id Register(std::unique_ptr<GuestOsMountProvider> provider); // Removes a provider from the registry, returning the provider. The specified // provider must be in the registry.
diff --git a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry_unittest.cc b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry_unittest.cc index 53486d02..450ce7a 100644 --- a/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry_unittest.cc +++ b/chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry_unittest.cc
@@ -43,14 +43,14 @@ auto provider2 = std::make_unique<MockProvider>(); auto* p2 = provider2.get(); GuestOsMountProviderRegistry registry; - registry.Register(std::move(provider1)); - registry.Register(std::move(provider2)); + auto id1 = registry.Register(std::move(provider1)); + auto id2 = registry.Register(std::move(provider2)); std::vector<Id> expected = std::vector<Id>{0, 1}; ASSERT_EQ(registry.List(), expected); - ASSERT_EQ(p1, registry.Get(0)); - ASSERT_EQ(p2, registry.Get(1)); + ASSERT_EQ(p1, registry.Get(id1)); + ASSERT_EQ(p2, registry.Get(id2)); } // Test that we can register, list and get providers
diff --git a/chrome/browser/ash/input_method/assistive_suggester.cc b/chrome/browser/ash/input_method/assistive_suggester.cc index c4389a9..cb31d7d9 100644 --- a/chrome/browser/ash/input_method/assistive_suggester.cc +++ b/chrome/browser/ash/input_method/assistive_suggester.cc
@@ -31,9 +31,9 @@ namespace { -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; const char kMaxTextBeforeCursorLength = 50;
diff --git a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc index a4c03ad1..b6a904b3 100644 --- a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc +++ b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
@@ -25,9 +25,9 @@ namespace input_method { namespace { -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; const char kEmojiData[] = "happy,😀;😃;😄"; const char kUsEnglishEngineId[] = "xkb:us::eng";
diff --git a/chrome/browser/ash/input_method/emoji_suggester.cc b/chrome/browser/ash/input_method/emoji_suggester.cc index c44f5404..0d5e4af 100644 --- a/chrome/browser/ash/input_method/emoji_suggester.cc +++ b/chrome/browser/ash/input_method/emoji_suggester.cc
@@ -33,9 +33,9 @@ namespace { -using TextSuggestion = ::chromeos::ime::TextSuggestion; -using TextSuggestionMode = ::chromeos::ime::TextSuggestionMode; -using TextSuggestionType = ::chromeos::ime::TextSuggestionType; +using TextSuggestion = ime::TextSuggestion; +using TextSuggestionMode = ime::TextSuggestionMode; +using TextSuggestionType = ime::TextSuggestionType; constexpr char kEmojiSuggesterShowSettingCount[] = "emoji_suggester.show_setting_count";
diff --git a/chrome/browser/ash/input_method/emoji_suggester_unittest.cc b/chrome/browser/ash/input_method/emoji_suggester_unittest.cc index f4f242c..54d91602 100644 --- a/chrome/browser/ash/input_method/emoji_suggester_unittest.cc +++ b/chrome/browser/ash/input_method/emoji_suggester_unittest.cc
@@ -18,9 +18,9 @@ namespace input_method { namespace { -using TextSuggestion = ::chromeos::ime::TextSuggestion; -using TextSuggestionMode = ::chromeos::ime::TextSuggestionMode; -using TextSuggestionType = ::chromeos::ime::TextSuggestionType; +using TextSuggestion = ime::TextSuggestion; +using TextSuggestionMode = ime::TextSuggestionMode; +using TextSuggestionType = ime::TextSuggestionType; } // namespace
diff --git a/chrome/browser/ash/input_method/multi_word_suggester.cc b/chrome/browser/ash/input_method/multi_word_suggester.cc index 97541b8..a935c94 100644 --- a/chrome/browser/ash/input_method/multi_word_suggester.cc +++ b/chrome/browser/ash/input_method/multi_word_suggester.cc
@@ -21,9 +21,9 @@ namespace input_method { namespace { -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; constexpr char kMultiWordFirstAcceptTimeDays[] = "multi_word_first_accept"; constexpr char16_t kSuggestionShownMessage[] =
diff --git a/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc b/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc index 061d535..32b2264 100644 --- a/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc +++ b/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
@@ -24,9 +24,9 @@ namespace input_method { namespace { -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; constexpr int kFocusedContextId = 5; @@ -785,7 +785,7 @@ suggester_->OnSurroundingTextChanged(u"why aren't", 10, 10); suggester_->Suggest(u"why aren't", 10, 10); - ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 0); + ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 0u); } TEST_F(MultiWordSuggesterTest, ShowingSuggestionsTriggersAnnouncement) { @@ -800,7 +800,7 @@ suggester_->Suggest(u"why are", 7, 7); suggester_->OnExternalSuggestionsUpdated(suggestions); - ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 1); + ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 1u); EXPECT_EQ(suggestion_handler_.GetAnnouncements().back(), u"predictive writing candidate shown, press tab to accept"); } @@ -824,7 +824,7 @@ suggester_->OnSurroundingTextChanged(u"why aren't", 10, 10); suggester_->Suggest(u"why aren't", 10, 10); - ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 1); + ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 1u); EXPECT_EQ(suggestion_handler_.GetAnnouncements().back(), u"predictive writing candidate shown, press tab to accept"); } @@ -842,7 +842,7 @@ suggester_->OnExternalSuggestionsUpdated(suggestions); SendKeyEvent(suggester_.get(), ui::DomCode::TAB); - ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2); + ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2u); EXPECT_EQ(suggestion_handler_.GetAnnouncements().back(), u"predictive writing candidate inserted"); } @@ -863,7 +863,7 @@ suggester_->OnSurroundingTextChanged(u"why aren", 8, 8); suggester_->Suggest(u"why aren", 8, 8); - ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2); + ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2u); } TEST_F(MultiWordSuggesterTest, DismissingSuggestionTriggersAnnouncement) { @@ -879,7 +879,7 @@ suggester_->OnExternalSuggestionsUpdated(suggestions); suggester_->DismissSuggestion(); - ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2); + ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2u); EXPECT_EQ(suggestion_handler_.GetAnnouncements().back(), u"predictive writing candidate dismissed"); } @@ -900,7 +900,7 @@ suggester_->OnSurroundingTextChanged(u"why aren", 8, 8); suggester_->Suggest(u"why aren", 8, 8); - ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2); + ASSERT_EQ(suggestion_handler_.GetAnnouncements().size(), 2u); } } // namespace input_method
diff --git a/chrome/browser/ash/input_method/personal_info_suggester.cc b/chrome/browser/ash/input_method/personal_info_suggester.cc index aefff94d..4e6eb49 100644 --- a/chrome/browser/ash/input_method/personal_info_suggester.cc +++ b/chrome/browser/ash/input_method/personal_info_suggester.cc
@@ -33,9 +33,9 @@ namespace { -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; const size_t kMaxConfirmedTextLength = 10; constexpr size_t kMaxTextBeforeCursorLength = 50;
diff --git a/chrome/browser/ash/input_method/personal_info_suggester_unittest.cc b/chrome/browser/ash/input_method/personal_info_suggester_unittest.cc index 21dc536d..ba8c46d 100644 --- a/chrome/browser/ash/input_method/personal_info_suggester_unittest.cc +++ b/chrome/browser/ash/input_method/personal_info_suggester_unittest.cc
@@ -28,9 +28,9 @@ namespace input_method { namespace { -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; // TODO(crbug/1201529): Update this unit test to use `FakeSuggestionHandler` // instead.
diff --git a/chrome/browser/ash/input_method/suggestions_collector.cc b/chrome/browser/ash/input_method/suggestions_collector.cc index 5896fd2b..8d026f9 100644 --- a/chrome/browser/ash/input_method/suggestions_collector.cc +++ b/chrome/browser/ash/input_method/suggestions_collector.cc
@@ -12,8 +12,8 @@ namespace input_method { namespace { -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; +using ime::TextSuggestion; +using ime::TextSuggestionMode; std::vector<TextSuggestion> CombineResults( const std::vector<TextSuggestion>& first,
diff --git a/chrome/browser/ash/input_method/suggestions_collector_unittest.cc b/chrome/browser/ash/input_method/suggestions_collector_unittest.cc index c0a63eb..70e05e50 100644 --- a/chrome/browser/ash/input_method/suggestions_collector_unittest.cc +++ b/chrome/browser/ash/input_method/suggestions_collector_unittest.cc
@@ -17,10 +17,10 @@ namespace input_method { namespace { -using ::chromeos::ime::TextCompletionCandidate; -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; +using ime::TextCompletionCandidate; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; class FakeAssistiveSuggester : public SuggestionsSource { public:
diff --git a/chrome/browser/ash/input_method/suggestions_service_client.cc b/chrome/browser/ash/input_method/suggestions_service_client.cc index 08fea08a..cd38154 100644 --- a/chrome/browser/ash/input_method/suggestions_service_client.cc +++ b/chrome/browser/ash/input_method/suggestions_service_client.cc
@@ -15,15 +15,15 @@ namespace input_method { namespace { -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; using ::chromeos::machine_learning::mojom::MultiWordExperimentGroup; using ::chromeos::machine_learning::mojom::NextWordCompletionCandidate; using ::chromeos::machine_learning::mojom::TextSuggesterQuery; using ::chromeos::machine_learning::mojom::TextSuggesterResultPtr; using ::chromeos::machine_learning::mojom::TextSuggesterSpec; using ::chromeos::machine_learning::mojom::TextSuggestionCandidatePtr; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; constexpr size_t kMaxNumberCharsSent = 100;
diff --git a/chrome/browser/ash/input_method/suggestions_service_client_unittest.cc b/chrome/browser/ash/input_method/suggestions_service_client_unittest.cc index 1aac37a..b82b8b2 100644 --- a/chrome/browser/ash/input_method/suggestions_service_client_unittest.cc +++ b/chrome/browser/ash/input_method/suggestions_service_client_unittest.cc
@@ -18,10 +18,10 @@ namespace machine_learning = ::chromeos::machine_learning; -using ::chromeos::ime::TextCompletionCandidate; -using ::chromeos::ime::TextSuggestion; -using ::chromeos::ime::TextSuggestionMode; -using ::chromeos::ime::TextSuggestionType; +using ime::TextCompletionCandidate; +using ime::TextSuggestion; +using ime::TextSuggestionMode; +using ime::TextSuggestionType; class SuggestionsServiceClientTest : public testing::Test { public:
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/usb/usb_events_observer_unittest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/usb/usb_events_observer_unittest.cc index 0fe061a..a887c19 100644 --- a/chrome/browser/ash/policy/reporting/metrics_reporting/usb/usb_events_observer_unittest.cc +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/usb/usb_events_observer_unittest.cc
@@ -94,7 +94,8 @@ EXPECT_THAT(usb_telemetry.vendor(), StrEq(kTestVendor)); EXPECT_THAT(usb_telemetry.vid(), Eq(kTestVid)); EXPECT_EQ(metric_data.event_data().type(), MetricEventType::USB_REMOVED); - ASSERT_EQ(usb_telemetry.categories().size(), kTestCategories.size()); + ASSERT_EQ(static_cast<size_t>(usb_telemetry.categories().size()), + kTestCategories.size()); for (size_t i = 0; i < kTestCategories.size(); ++i) { EXPECT_THAT(usb_telemetry.categories()[i], StrEq(kTestCategories[i])); @@ -132,7 +133,8 @@ EXPECT_THAT(usb_telemetry.vendor(), StrEq(kTestVendor)); EXPECT_THAT(usb_telemetry.vid(), Eq(kTestVid)); EXPECT_EQ(metric_data.event_data().type(), MetricEventType::USB_ADDED); - ASSERT_THAT(usb_telemetry.categories().size(), Eq(kTestCategories.size())); + ASSERT_EQ(static_cast<size_t>(usb_telemetry.categories().size()), + kTestCategories.size()); for (size_t i = 0; i < kTestCategories.size(); ++i) { EXPECT_THAT(usb_telemetry.categories()[i], StrEq(kTestCategories[i]));
diff --git a/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc b/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc index 81879f5..d724d9c8 100644 --- a/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc +++ b/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc
@@ -565,7 +565,7 @@ WaitForResult(); ASSERT_TRUE(scanner_capabilities()); const auto caps = scanner_capabilities().value(); - ASSERT_EQ(caps.resolutions_size(), 1u); + ASSERT_EQ(caps.resolutions_size(), 1); EXPECT_EQ(caps.resolutions()[0], 300u); EXPECT_EQ(caps.sources_size(), 0u); ASSERT_EQ(caps.color_modes_size(), 1u);
diff --git a/chrome/browser/ash/scanning/scan_service_unittest.cc b/chrome/browser/ash/scanning/scan_service_unittest.cc index fc49c2a0..306727b 100644 --- a/chrome/browser/ash/scanning/scan_service_unittest.cc +++ b/chrome/browser/ash/scanning/scan_service_unittest.cc
@@ -961,7 +961,7 @@ const std::vector<std::string> scanned_images = scan_service_->GetScannedImagesForTesting(); - EXPECT_EQ(1, scanned_images.size()); + EXPECT_EQ(1u, scanned_images.size()); EXPECT_EQ(second_scanned_image, scanned_images[0]); // Expect 1 record of the Scanning.NumPagesScanned metric in the 1 pages
diff --git a/chrome/browser/ash/system_extensions/api/window_management/window_management_impl.cc b/chrome/browser/ash/system_extensions/api/window_management/window_management_impl.cc index 395f8c201..cf753e7 100644 --- a/chrome/browser/ash/system_extensions/api/window_management/window_management_impl.cc +++ b/chrome/browser/ash/system_extensions/api/window_management/window_management_impl.cc
@@ -66,11 +66,9 @@ aura::Window* target = nullptr; apps::AppServiceProxy* proxy = apps::AppServiceProxyFactory::GetForProfile( Profile::FromBrowserContext(browser_context_)); - proxy->InstanceRegistry().ForEachInstance( - [&target, &id](const apps::InstanceUpdate& update) { - if (id == update.InstanceId()) { - target = update.Window(); - } + proxy->InstanceRegistry().ForOneInstance( + id, [&target](const apps::InstanceUpdate& update) { + target = update.Window(); }); return target;
diff --git a/chrome/browser/ash/web_applications/file_manager_web_app_info.cc b/chrome/browser/ash/web_applications/file_manager_web_app_info.cc index 655c1ae..572483ce 100644 --- a/chrome/browser/ash/web_applications/file_manager_web_app_info.cc +++ b/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
@@ -11,6 +11,7 @@ #include "ash/webui/file_manager/resources/grit/file_manager_swa_resources.h" #include "ash/webui/file_manager/url_constants.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ash/file_manager/file_tasks.h" #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h" #include "chrome/browser/web_applications/web_app_constants.h" #include "chrome/browser/web_applications/web_app_install_info.h" @@ -92,7 +93,7 @@ AppendFileHandler(*info, "open-hosted-gslides", {"gslides"}); // Drive & Office Docs: - AppendFileHandler(*info, "open-web-drive-office", + AppendFileHandler(*info, ::file_manager::file_tasks::kActionIdWebDriveOffice, {"doc", "docx", "xls", "xlsx", "ppt", "pptx"}); // View in the browser (with mime-type):
diff --git a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc index c86351c..d843863 100644 --- a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc +++ b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
@@ -268,14 +268,14 @@ return result; } -// Waits for the "shownav" attribute to show up in the MediaApp's current -// handler. Also checks the panel isn't open indicating an edit is not in -// progress. This prevents trying to traverse a directory before other files are -// available / while editing. +// Waits for the "filetraversalenabled" attribute to show up in the MediaApp's +// current handler. Also checks the panel isn't open indicating an edit is not +// in progress. This prevents trying to traverse a directory before other files +// are available / while editing. content::EvalJsResult WaitForNavigable(content::WebContents* web_ui) { constexpr char kScript[] = R"( (async function waitForNavigable() { - await waitForNode(':not([panelopen])[shownav]'); + await waitForNode(':not([panelopen])[filetraversalenabled]'); })(); )"; @@ -1189,7 +1189,7 @@ EXPECT_EQ(u"Gallery", observer.source_title); } -// Test that the MediaApp can navigate other files in the directory of a file +// Test that the MediaApp can traverse other files in the directory of a file // that was opened, even if those files have changed since launch. IN_PROC_BROWSER_TEST_P(MediaAppIntegrationWithFilesAppAllProfilesTest, FileOpenCanTraverseDirectory) {
diff --git a/chrome/browser/cart/cart_handler.cc b/chrome/browser/cart/cart_handler.cc index 0904477..3b0de0e 100644 --- a/chrome/browser/cart/cart_handler.cc +++ b/chrome/browser/cart/cart_handler.cc
@@ -120,6 +120,10 @@ cart_service_->AcknowledgeDiscountConsent(accept); } +void CartHandler::OnDiscountConsentDismissed() { + cart_service_->DismissedDiscountConsent(); +} + void CartHandler::GetDiscountEnabled(GetDiscountEnabledCallback callback) { std::move(callback).Run(cart_service_->IsCartDiscountEnabled()); }
diff --git a/chrome/browser/cart/cart_handler.h b/chrome/browser/cart/cart_handler.h index 3acd45c0..268be4f 100644 --- a/chrome/browser/cart/cart_handler.h +++ b/chrome/browser/cart/cart_handler.h
@@ -36,6 +36,7 @@ void GetDiscountConsentCardVisible( GetDiscountConsentCardVisibleCallback callback) override; void OnDiscountConsentAcknowledged(bool accept) override; + void OnDiscountConsentDismissed() override; void GetDiscountEnabled(GetDiscountEnabledCallback callback) override; void SetDiscountEnabled(bool enabled) override; void PrepareForNavigation(const GURL& cart_url, bool is_navigating) override;
diff --git a/chrome/browser/cart/cart_handler_unittest.cc b/chrome/browser/cart/cart_handler_unittest.cc index 369dc560..b677c6d 100644 --- a/chrome/browser/cart/cart_handler_unittest.cc +++ b/chrome/browser/cart/cart_handler_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/persisted_state_db/profile_proto_db.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_profile.h" +#include "components/commerce/core/commerce_feature_list.h" #include "components/prefs/pref_service.h" #include "components/search/ntp_features.h" #include "content/public/test/browser_task_environment.h" @@ -670,3 +671,59 @@ run_loop.QuitClosure(), false, "")); run_loop.Run(); } + +class CartHandlerNtpModuleDiscountConsentV2Test : public CartHandlerTest { + public: + CartHandlerNtpModuleDiscountConsentV2Test() { + std::vector<base::test::ScopedFeatureList::FeatureAndParams> + enabled_features; + base::FieldTrialParams consent_v2_params, cart_params; + cart_params["NtpChromeCartModuleAbandonedCartDiscountParam"] = "true"; + cart_params["partner-merchant-pattern"] = "(foo.com)"; + enabled_features.emplace_back(ntp_features::kNtpChromeCartModule, + cart_params); + consent_v2_params["discount-consent-ntp-reshow-time"] = "1m"; + consent_v2_params["discount-consent-ntp-max-dismiss-count"] = "2"; + enabled_features.emplace_back(commerce::kDiscountConsentV2, + consent_v2_params); + feature_list_.InitWithFeaturesAndParameters(enabled_features, + /*disabled_features*/ {}); + } + + void SetUp() override { + CartHandlerTest::SetUp(); + // Simulate that the welcome surface has been shown. + profile_->GetPrefs()->SetInteger(prefs::kCartModuleWelcomeSurfaceShownTimes, + CartService::kWelcomSurfaceShowLimit); + } +}; + +TEST_F(CartHandlerNtpModuleDiscountConsentV2Test, + TestOnDiscountConsentDismissed) { + CartDB* cart_db = service_->GetDB(); + { + base::RunLoop run_loop; + // Add a partner cart. + cart_db->AddCart( + kFakeMerchant, kFakeProto, + base::BindOnce(&CartHandlerTest::OperationEvaluation, + base::Unretained(this), run_loop.QuitClosure(), true)); + run_loop.Run(); + } + { + base::RunLoop run_loop; + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), true)); + run_loop.Run(); + } + + handler_->OnDiscountConsentDismissed(); + { + base::RunLoop run_loop; + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartHandlerTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), false)); + run_loop.Run(); + } +}
diff --git a/chrome/browser/cart/cart_service.cc b/chrome/browser/cart/cart_service.cc index 96f3d71d..796a98c4 100644 --- a/chrome/browser/cart/cart_service.cc +++ b/chrome/browser/cart/cart_service.cc
@@ -163,6 +163,9 @@ registry->RegisterDictionaryPref(prefs::kCartUsedDiscounts); registry->RegisterTimePref(prefs::kCartDiscountLastFetchedTime, base::Time()); registry->RegisterBooleanPref(prefs::kCartDiscountConsentShown, false); + registry->RegisterTimePref(prefs::kDiscountConsentLastDimissedTime, + base::Time()); + registry->RegisterIntegerPref(prefs::kDiscountConsentPastDismissedCount, 0); } GURL CartService::AppendUTM(const GURL& base_url, bool is_discount_enabled) { @@ -282,6 +285,18 @@ } } +void CartService::DismissedDiscountConsent() { + if (cart_features::IsFakeDataEnabled()) { + return; + } + profile_->GetPrefs()->SetTime(prefs::kDiscountConsentLastDimissedTime, + base::Time::Now()); + int past_dimissed_count = profile_->GetPrefs()->GetInteger( + prefs::kDiscountConsentPastDismissedCount); + profile_->GetPrefs()->SetInteger(prefs::kDiscountConsentPastDismissedCount, + past_dimissed_count + 1); +} + void CartService::ShouldShowDiscountConsent( base::OnceCallback<void(bool)> callback) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); @@ -334,6 +349,23 @@ CartDiscountMetricCollector::RecordDiscountConsentStatus( CartDiscountMetricCollector::DiscountConsentStatus::IGNORED); } + + if (base::FeatureList::IsEnabled(commerce::kDiscountConsentV2)) { + base::Time last_dismissed_time = + profile_->GetPrefs()->GetTime(prefs::kDiscountConsentLastDimissedTime); + base::TimeDelta reshow_time_delta = + ntp_features::kNtpChromeCartModuleDiscountConsentReshowTime.Get() - + (base::Time::Now() - last_dismissed_time); + int last_dismissed_count = profile_->GetPrefs()->GetInteger( + prefs::kDiscountConsentPastDismissedCount); + should_show &= + (last_dismissed_time == base::Time() || + reshow_time_delta.is_negative()) && + last_dismissed_count < + ntp_features::kNtpChromeCartModuleDiscountConsentMaxDismissalCount + .Get(); + } + std::move(callback).Run(should_show); }
diff --git a/chrome/browser/cart/cart_service.h b/chrome/browser/cart/cart_service.h index e0abec1..7181fd17 100644 --- a/chrome/browser/cart/cart_service.h +++ b/chrome/browser/cart/cart_service.h
@@ -94,6 +94,8 @@ // shouldEnable indicates whether user has chosen to opt-in or opt-out the // feature. void AcknowledgeDiscountConsent(bool should_enable); + // Gets called when user has dismissed the discount consent in cart module. + void DismissedDiscountConsent(); // Decides whether to show the consent card in module for rule-based discount, // and returns it in the callback. void ShouldShowDiscountConsent(base::OnceCallback<void(bool)> callback);
diff --git a/chrome/browser/cart/cart_service_unittest.cc b/chrome/browser/cart/cart_service_unittest.cc index 9eb3ffb8..66fca8d 100644 --- a/chrome/browser/cart/cart_service_unittest.cc +++ b/chrome/browser/cart/cart_service_unittest.cc
@@ -2116,3 +2116,121 @@ service_->Hide(); ASSERT_FALSE(service_->IsHidden()); } + +class CartServiceDiscountConsentV2Test : public CartServiceTest { + public: + // Features need to be initialized before CartServiceTest::SetUp runs, in + // order to avoid tsan data race error on FeatureList. + CartServiceDiscountConsentV2Test() { + std::vector<base::test::ScopedFeatureList::FeatureAndParams> + enabled_features; + base::FieldTrialParams consent_v2_params, cart_params; + cart_params["NtpChromeCartModuleAbandonedCartDiscountParam"] = "true"; + cart_params["partner-merchant-pattern"] = "(foo.com)"; + enabled_features.emplace_back(ntp_features::kNtpChromeCartModule, + cart_params); + consent_v2_params["discount-consent-ntp-reshow-time"] = "1m"; + consent_v2_params["discount-consent-ntp-max-dismiss-count"] = "2"; + enabled_features.emplace_back(commerce::kDiscountConsentV2, + consent_v2_params); + features_.InitWithFeaturesAndParameters(enabled_features, + /*disabled_features*/ {}); + } + + void SetUp() override { + CartServiceTest::SetUp(); + + // Add a partner merchant cart. + service_->AddCart(kMockMerchantA, absl::nullopt, kMockProtoA); + task_environment_.RunUntilIdle(); + // Simulate that the welcome surface is not showing, the discount feature is + // disabled and there is no partner merchant carts. + profile_->GetPrefs()->SetInteger(prefs::kCartModuleWelcomeSurfaceShownTimes, + CartService::kWelcomSurfaceShowLimit); + } + + void TearDown() override { + profile_->GetPrefs()->SetInteger(prefs::kDiscountConsentPastDismissedCount, + 0); + profile_->GetPrefs()->SetInteger(prefs::kCartModuleWelcomeSurfaceShownTimes, + 0); + } +}; + +// Tests discount consent doesn't show after dismiss count reach the max +// allowance. +TEST_F(CartServiceDiscountConsentV2Test, TestNoConsentAfterDimissAllowance) { + // Simulate that use has dismissed the consent once. + profile_->GetPrefs()->SetInteger(prefs::kDiscountConsentPastDismissedCount, + 1); + { + base::RunLoop run_loop; + + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartServiceTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), true)); + run_loop.Run(); + } + + service_->DismissedDiscountConsent(); + { + base::RunLoop run_loop; + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartServiceTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), false)); + run_loop.Run(); + } +} + +// Tests discount consent doesn't show if reshow time threshold does not meet. +TEST_F(CartServiceDiscountConsentV2Test, + TestNoConsentBeforeReshowTimeThreshold) { + { + base::RunLoop run_loop; + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartServiceTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), true)); + run_loop.Run(); + } + + service_->DismissedDiscountConsent(); + { + base::RunLoop run_loop; + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartServiceTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), false)); + run_loop.Run(); + } +} + +// Tests discount consent reshow after the reshow time threshold. +TEST_F(CartServiceDiscountConsentV2Test, + TestReshowConsentAfterReshowTimeThreshold) { + { + base::RunLoop run_loop; + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartServiceTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), true)); + run_loop.Run(); + } + + service_->DismissedDiscountConsent(); + + { + base::RunLoop run_loop; + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartServiceTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), false)); + run_loop.Run(); + } + + task_environment_.FastForwardBy(base::Minutes(2)); + + { + base::RunLoop run_loop; + service_->ShouldShowDiscountConsent( + base::BindOnce(&CartServiceTest::GetEvaluationBoolResult, + base::Unretained(this), run_loop.QuitClosure(), true)); + run_loop.Run(); + } +}
diff --git a/chrome/browser/cart/chrome_cart.mojom b/chrome/browser/cart/chrome_cart.mojom index 58b57cd4..e367f0f 100644 --- a/chrome/browser/cart/chrome_cart.mojom +++ b/chrome/browser/cart/chrome_cart.mojom
@@ -44,10 +44,14 @@ GetDiscountURL(url.mojom.Url cart_url) => (url.mojom.Url discount_url); // Returns whether to show discount consent card in the module. GetDiscountConsentCardVisible() => (bool consent_visible); + // TODO(crbug.com/1298116): Merge OnDiscountConsentAcknowledged and + // OnDiscountConsentDismissed. // Stores in profile prefs that user has acknowledged // discount consent and whether user has opted-in or opted-out // the feature. OnDiscountConsentAcknowledged(bool accept); + // Stores in profile prefs that user has dismissed the consent. + OnDiscountConsentDismissed(); // Returns whether the rule-based discount feature is enabled. GetDiscountEnabled() => (bool enabled); // Sets whether the rule-based discount feature is enabled.
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index d5bab27..53995289 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1132,6 +1132,8 @@ "../ash/borealis/borealis_context_manager.h", "../ash/borealis/borealis_context_manager_impl.cc", "../ash/borealis/borealis_context_manager_impl.h", + "../ash/borealis/borealis_credits.cc", + "../ash/borealis/borealis_credits.h", "../ash/borealis/borealis_disk_manager.h", "../ash/borealis/borealis_disk_manager_dispatcher.cc", "../ash/borealis/borealis_disk_manager_dispatcher.h",
diff --git a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager_unittest.cc index d8f4fd5..4f2b4431 100644 --- a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager_unittest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager_unittest.cc
@@ -1169,7 +1169,7 @@ notification_manager->HandleIOTaskProgress(status); // Check: We have the 1 notification. - ASSERT_EQ(1, GetNotificationCount()); + ASSERT_EQ(1u, GetNotificationCount()); TestNotificationStrings notification_strings = notification_platform_bridge->GetNotificationStringsById( @@ -1185,7 +1185,7 @@ notification_manager->HandleIOTaskProgress(status); // Check: We have the same notification. - ASSERT_EQ(1, GetNotificationCount()); + ASSERT_EQ(1u, GetNotificationCount()); notification_strings = notification_platform_bridge->GetNotificationStringsById( "swa-file-operation-1"); @@ -1198,7 +1198,7 @@ notification_manager->HandleIOTaskProgress(status); // Notification should disappear. - ASSERT_EQ(0, GetNotificationCount()); + ASSERT_EQ(0u, GetNotificationCount()); } TEST_F(SystemNotificationManagerTest, CancelButtonIOTask) { @@ -1223,14 +1223,14 @@ const io_task::IOTaskId task_id = io_task_controller.Add(std::move(task)); // Check: We have the 1 notification. - ASSERT_EQ(1, GetNotificationCount()); + ASSERT_EQ(1u, GetNotificationCount()); // Click on the cancel button. notification_platform_bridge->ClickButtonIndexById("swa-file-operation-1", /*button_index=*/0); // Notification should disappear. - ASSERT_EQ(0, GetNotificationCount()); + ASSERT_EQ(0u, GetNotificationCount()); // The last status observed should be Cancelled. ASSERT_EQ(io_task::State::kCancelled, task_statuses[task_id].back());
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/linux_key_rotation_command.cc b/chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/linux_key_rotation_command.cc index c4c34e1e..fb90e1e3 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/linux_key_rotation_command.cc +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/linux_key_rotation_command.cc
@@ -111,8 +111,11 @@ channel.PrepareToPassRemoteEndpoint(&options, &command_line); base::Process process = launch_callback.Run(command_line, options); - if (!process.IsValid()) + if (!process.IsValid()) { + SYSLOG(ERROR) << "Device trust key rotation failed. Could not " + "launch the ChromeManagementService process."; return KeyRotationCommand::Status::FAILED; + } channel.RemoteProcessLaunchAttempted(); mojo::OutgoingInvitation::Send(std::move(invitation), @@ -126,27 +129,12 @@ return KeyRotationCommand::Status::TIMED_OUT; } - switch (exit_code) { - case chrome_management_service::kSuccess: - return KeyRotationCommand::Status::SUCCEEDED; - - case chrome_management_service::kStoreKeyFailure: - SYSLOG(ERROR) << "Device trust key rotation failed. Could not " - "write to signing key storage."; - break; - case chrome_management_service::kUploadKeyFailure: - SYSLOG(ERROR) << "Device trust key rotation failed. Could not " - "send public key to DM server."; - break; - case chrome_management_service::kInstanceAlreadyRunning: - SYSLOG(ERROR) << "Device trust key rotation failed. Another " - "instance of the " - "ChromeManagementService is running."; - break; - default: - SYSLOG(ERROR) - << "Device trust key rotation failed with exit code: " - << exit_code; + if (exit_code == chrome_management_service::kSuccess) { + return KeyRotationCommand::Status::SUCCEEDED; + } else if (exit_code != chrome_management_service::kFailure) { + SYSLOG(ERROR) + << "Device trust key rotation failed with exit code: " + << exit_code; } return KeyRotationCommand::Status::FAILED; },
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/linux_key_rotation_command_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/linux_key_rotation_command_unittest.cc index 5d7b514..44f13eb 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/linux_key_rotation_command_unittest.cc +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/browser/commands/linux_key_rotation_command_unittest.cc
@@ -157,8 +157,7 @@ StartTestRotation("MojoInvitation", KeyRotationCommand::Status::SUCCEEDED); } -// Tests for a key rotation failure when the chrome management service failed -// to store the signing key to persistence storage. +// Tests for a key rotation when the chrome management service succeeded. MULTIPROCESS_TEST_MAIN(Success) { return chrome_management_service::kSuccess; } @@ -167,56 +166,23 @@ StartTestRotation("Success", KeyRotationCommand::Status::SUCCEEDED); } -// Tests for a key rotation failure when the chrome management service failed -// to store the signing key to persistence storage. -MULTIPROCESS_TEST_MAIN(FailureToWrite) { - return chrome_management_service::kStoreKeyFailure; +// Tests for a key rotation failure when the chrome management service failed. +MULTIPROCESS_TEST_MAIN(Failure) { + return chrome_management_service::kFailure; } -TEST_F(LinuxKeyRotationCommandTest, RotateFailureToWriteToSigningKeyStorage) { - StartTestRotation("FailureToWrite", KeyRotationCommand::Status::FAILED); +TEST_F(LinuxKeyRotationCommandTest, RotateFailure) { + StartTestRotation("Failure", KeyRotationCommand::Status::FAILED); } // Tests for a key rotation failure when the chrome management service failed -// to upload the key to the dm server. -MULTIPROCESS_TEST_MAIN(FailureToSendKey) { - return chrome_management_service::kUploadKeyFailure; +// with an unknown error. +MULTIPROCESS_TEST_MAIN(UnknownFailure) { + return 3; } -TEST_F(LinuxKeyRotationCommandTest, RotateFailureUploadFailure) { - StartTestRotation("FailureToSendKey", KeyRotationCommand::Status::FAILED); -} - -// Tests for a key rotation failure when the chrome management service was -// already running and a another rotate request occurred. -MULTIPROCESS_TEST_MAIN(DuplicateProcess) { - return chrome_management_service::kInstanceAlreadyRunning; -} - -TEST_F(LinuxKeyRotationCommandTest, RotateFailureAnotherInstanceRunning) { - StartTestRotation("DuplicateProcess", KeyRotationCommand::Status::FAILED); -} - -// Tests for a key rotation failure when the chrome management service exited -// with an unknown positive error code. -MULTIPROCESS_TEST_MAIN(UnkownFailurePositiveErrorCode) { - return 5; -} - -TEST_F(LinuxKeyRotationCommandTest, RotateFailureUnknownPositiveErrorCode) { - StartTestRotation("UnkownFailurePositiveErrorCode", - KeyRotationCommand::Status::FAILED); -} - -// Tests for a key rotation failure when the chrome management service exited -// with an unknown negative error code. -MULTIPROCESS_TEST_MAIN(UnkownFailureNegativeErrorCode) { - return -1; -} - -TEST_F(LinuxKeyRotationCommandTest, RotateFailureUnknownNegativeErrorCode) { - StartTestRotation("UnkownFailureNegativeErrorCode", - KeyRotationCommand::Status::FAILED); +TEST_F(LinuxKeyRotationCommandTest, RotateFailure_UnknownError) { + StartTestRotation("UnknownFailure", KeyRotationCommand::Status::FAILED); } // Tests for a key rotation failure when an invalid process was launched.
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/common/chrome_management_service_constants.h b/chrome/browser/enterprise/connectors/device_trust/key_management/common/chrome_management_service_constants.h index afa205d..1ae8387 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/common/chrome_management_service_constants.h +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/common/chrome_management_service_constants.h
@@ -11,12 +11,8 @@ // Process exit codes of the chrome management service executable. enum Status { - kSuccess = 0, // Successfully executed the key rotation. - kStoreKeyFailure = 1, // Writing to signing key storage failed. - kUploadKeyFailure = 2, // Sending the public key to the DM server failed. - kInstanceAlreadyRunning = 3, // Another instance of service is running. - kInvalidHostName = 4, // The hostname for dm_server_url on a stable channel - // is not a prod hostname. + kSuccess = 0, + kFailure = 1, }; namespace switches {
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/BUILD.gn b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/BUILD.gn index 294349b0..3e7f56e6 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/BUILD.gn +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/BUILD.gn
@@ -3,12 +3,16 @@ # found in the LICENSE file. source_set("elevated_rotation") { - public = [ "key_rotation_manager.h" ] + public = [ + "key_rotation_manager.h", + "metrics_util.h", + ] sources = [ "key_rotation_manager.cc", "key_rotation_manager_impl.cc", "key_rotation_manager_impl.h", + "metrics_util.cc", ] deps = [
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager.h b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager.h index ddcf4ce..4b7a16e 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager.h +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager.h
@@ -19,21 +19,6 @@ // installer. class KeyRotationManager { public: - // Status of rotation attempts made with RotateWithAdminRights(). - // Must be kept in sync with the DeviceTrustKeyRotationStatus UMA enum. - // Making this public here to access from tests. - enum class RotationStatus { - SUCCESS, - FAILURE_CANNOT_GENERATE_NEW_KEY, - FAILURE_CANNOT_STORE_KEY, - FAILURE_CANNOT_BUILD_REQUEST, - FAILURE_CANNOT_UPLOAD_KEY, - FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED, - FAILURE_CANNOT_UPLOAD_KEY_RESTORE_FAILED, - FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED_RESTORE_FAILED, - kMaxValue = FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED_RESTORE_FAILED, - }; - virtual ~KeyRotationManager() = default; static std::unique_ptr<KeyRotationManager> Create(
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager_impl.cc b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager_impl.cc index 84c15884..66ffb6f 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager_impl.cc +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager_impl.cc
@@ -9,11 +9,12 @@ #include <utility> #include "base/check.h" -#include "base/metrics/histogram_functions.h" +#include "base/syslog_logging.h" #include "base/threading/platform_thread.h" #include "chrome/browser/enterprise/connectors/device_trust/key_management/core/ec_signing_key.h" #include "chrome/browser/enterprise/connectors/device_trust/key_management/core/network/key_network_delegate.h" #include "chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence/key_persistence_delegate.h" +#include "chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.h" #include "crypto/unexportable_key.h" #include "url/gurl.h" @@ -42,29 +43,6 @@ } } -void RecordRotationStatus(const std::string& nonce, - KeyRotationManager::RotationStatus status) { - if (nonce.empty()) { - base::UmaHistogramEnumeration( - "Enterprise.DeviceTrust.RotateSigningKey.NoNonce.Status", status); - } else { - base::UmaHistogramEnumeration( - "Enterprise.DeviceTrust.RotateSigningKey.WithNonce.Status", status); - } -} - -void RecordUploadCode(const std::string& nonce, int status_code) { - if (nonce.empty()) { - base::UmaHistogramSparse( - "Enterprise.DeviceTrust.RotateSigningKey.NoNonce.UploadCode", - status_code); - } else { - base::UmaHistogramSparse( - "Enterprise.DeviceTrust.RotateSigningKey.WithNonce.UploadCode", - status_code); - } -} - } // namespace KeyRotationManagerImpl::KeyRotationManagerImpl( @@ -107,12 +85,16 @@ if (!new_key_pair) { RecordRotationStatus(nonce, RotationStatus::FAILURE_CANNOT_GENERATE_NEW_KEY); + SYSLOG(ERROR) << "Device trust key rotation failed. Could not generate a " + "new signing key."; return false; } if (!persistence_delegate_->StoreKeyPair(new_trust_level, new_key_pair->GetWrappedKey())) { RecordRotationStatus(nonce, RotationStatus::FAILURE_CANNOT_STORE_KEY); + SYSLOG(ERROR) << "Device trust key rotation failed. Could not write to " + "signing key storage."; return false; } @@ -121,6 +103,8 @@ new_trust_level, new_key_pair, nonce, request.mutable_browser_public_key_upload_request())) { RecordRotationStatus(nonce, RotationStatus::FAILURE_CANNOT_BUILD_REQUEST); + SYSLOG(ERROR) << "Device trust key rotation failed. Could not build the " + "upload key request."; return false; } @@ -168,6 +152,8 @@ FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED_RESTORE_FAILED : RotationStatus::FAILURE_CANNOT_UPLOAD_KEY_RESTORE_FAILED); RecordRotationStatus(nonce, status); + SYSLOG(ERROR) << "Device trust key rotation failed. Could not send public " + "key to DM server."; return false; }
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager_unittest.cc b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager_unittest.cc index 364fe58a..07adadb 100644 --- a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager_unittest.cc +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager_unittest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence/key_persistence_delegate.h" #include "chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence/mock_key_persistence_delegate.h" #include "chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence/scoped_key_persistence_delegate_factory.h" +#include "chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.h" #include "components/policy/proto/device_management_backend.pb.h" #include "crypto/unexportable_key.h" #include "testing/gmock/include/gmock/gmock.h" @@ -129,8 +130,8 @@ EXPECT_FALSE(upload_key_request.signature().empty()); // Should expect one successful attempt to rotate a key. - histogram_tester.ExpectUniqueSample( - status_histogram_name(), KeyRotationManager::RotationStatus::SUCCESS, 1); + histogram_tester.ExpectUniqueSample(status_histogram_name(), + RotationStatus::SUCCESS, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); histogram_tester.ExpectUniqueSample(http_code_histogram_name(), kSuccessCode, 1); @@ -163,10 +164,9 @@ std::move(mock_network_delegate), std::move(mock_persistence_delegate)); EXPECT_TRUE(manager->RotateWithAdminRights(dm_server_url, kDmToken, nonce())); - // Should expect one successful attempt to rotate a key. - histogram_tester.ExpectUniqueSample( - status_histogram_name(), KeyRotationManager::RotationStatus::SUCCESS, 1); + histogram_tester.ExpectUniqueSample(status_histogram_name(), + RotationStatus::SUCCESS, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); } @@ -196,8 +196,8 @@ EXPECT_TRUE(manager->RotateWithAdminRights(dm_server_url, kDmToken, nonce())); // Should expect one successful attempt to rotate a key. - histogram_tester.ExpectUniqueSample( - status_histogram_name(), KeyRotationManager::RotationStatus::SUCCESS, 1); + histogram_tester.ExpectUniqueSample(status_histogram_name(), + RotationStatus::SUCCESS, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); } @@ -242,8 +242,7 @@ // Should expect one failed attempt to rotate a key on first try. histogram_tester.ExpectUniqueSample( - status_histogram_name(), - KeyRotationManager::RotationStatus::FAILURE_CANNOT_UPLOAD_KEY, 1); + status_histogram_name(), RotationStatus::FAILURE_CANNOT_UPLOAD_KEY, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); histogram_tester.ExpectUniqueSample(http_code_histogram_name(), kHardFailureCode, 1); @@ -292,9 +291,7 @@ // Should expect one failed attempt to rotate a key with max tries. histogram_tester.ExpectUniqueSample( status_histogram_name(), - KeyRotationManager::RotationStatus:: - FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED, - 1); + RotationStatus::FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); histogram_tester.ExpectUniqueSample(http_code_histogram_name(), kTransientFailureCode, 1); @@ -325,8 +322,8 @@ EXPECT_TRUE(manager->RotateWithAdminRights(dm_server_url, kDmToken, nonce())); // Should expect one successful attempt to rotate a key. - histogram_tester.ExpectUniqueSample( - status_histogram_name(), KeyRotationManager::RotationStatus::SUCCESS, 1); + histogram_tester.ExpectUniqueSample(status_histogram_name(), + RotationStatus::SUCCESS, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); } @@ -358,8 +355,7 @@ // Should expect one failed attempt to rotate a key. histogram_tester.ExpectUniqueSample( - status_histogram_name(), - KeyRotationManager::RotationStatus::FAILURE_CANNOT_STORE_KEY, 1); + status_histogram_name(), RotationStatus::FAILURE_CANNOT_STORE_KEY, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); } @@ -397,9 +393,7 @@ // Should expect one failed attempt to rotate a key on first try. histogram_tester.ExpectUniqueSample( status_histogram_name(), - KeyRotationManager::RotationStatus:: - FAILURE_CANNOT_UPLOAD_KEY_RESTORE_FAILED, - 1); + RotationStatus::FAILURE_CANNOT_UPLOAD_KEY_RESTORE_FAILED, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); } @@ -441,9 +435,7 @@ // Should expect one failed attempt to rotate a key with max tries. histogram_tester.ExpectUniqueSample( status_histogram_name(), - KeyRotationManager::RotationStatus:: - FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED, - 1); + RotationStatus::FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED, 1); histogram_tester.ExpectTotalCount(opposite_status_histogram_name(), 0); }
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.cc b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.cc new file mode 100644 index 0000000..7a6f9f5d --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.cc
@@ -0,0 +1,35 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.h" + +#include <string> + +#include "base/metrics/histogram_functions.h" + +namespace enterprise_connectors { + +void RecordRotationStatus(const std::string& nonce, RotationStatus status) { + if (nonce.empty()) { + base::UmaHistogramEnumeration( + "Enterprise.DeviceTrust.RotateSigningKey.NoNonce.Status", status); + } else { + base::UmaHistogramEnumeration( + "Enterprise.DeviceTrust.RotateSigningKey.WithNonce.Status", status); + } +} + +void RecordUploadCode(const std::string& nonce, int status_code) { + if (nonce.empty()) { + base::UmaHistogramSparse( + "Enterprise.DeviceTrust.RotateSigningKey.NoNonce.UploadCode", + status_code); + } else { + base::UmaHistogramSparse( + "Enterprise.DeviceTrust.RotateSigningKey.WithNonce.UploadCode", + status_code); + } +} + +} // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.h b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.h new file mode 100644 index 0000000..97b82126 --- /dev/null +++ b/chrome/browser/enterprise/connectors/device_trust/key_management/installer/metrics_util.h
@@ -0,0 +1,38 @@ +// 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_ENTERPRISE_CONNECTORS_DEVICE_TRUST_KEY_MANAGEMENT_INSTALLER_METRICS_UTIL_H_ +#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_KEY_MANAGEMENT_INSTALLER_METRICS_UTIL_H_ + +#include <string> + +namespace enterprise_connectors { + +// Status of rotation attempts made with RotateWithAdminRights(). +// Must be kept in sync with the DeviceTrustKeyRotationStatus UMA enum. +enum class RotationStatus { + SUCCESS, + FAILURE_CANNOT_GENERATE_NEW_KEY, + FAILURE_CANNOT_STORE_KEY, + FAILURE_CANNOT_BUILD_REQUEST, + FAILURE_CANNOT_UPLOAD_KEY, + FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED, + FAILURE_CANNOT_UPLOAD_KEY_RESTORE_FAILED, + FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED_RESTORE_FAILED, + kMaxValue = FAILURE_CANNOT_UPLOAD_KEY_TRIES_EXHAUSTED_RESTORE_FAILED, +}; + +// Metrics for the RotateWithAdminRights() result. `nonce` is the +// nonce from the rotate attempt and `status` is the status of the +// rotation. +void RecordRotationStatus(const std::string& nonce, RotationStatus status); + +// Metrics for the network delegates upload key result. `nonce` is +// the nonce from the rotate attempt and `status_code` is the HTTP +// response code from the upload key request. +void RecordUploadCode(const std::string& nonce, int status_code); + +} // namespace enterprise_connectors + +#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_DEVICE_TRUST_KEY_MANAGEMENT_INSTALLER_METRICS_UTIL_H_
diff --git a/chrome/browser/extensions/api/runtime/runtime_apitest.cc b/chrome/browser/extensions/api/runtime/runtime_apitest.cc index 485568c0..e3dfae99 100644 --- a/chrome/browser/extensions/api/runtime/runtime_apitest.cc +++ b/chrome/browser/extensions/api/runtime/runtime_apitest.cc
@@ -4,6 +4,7 @@ #include <memory> +#include "base/json/json_reader.h" #include "base/run_loop.h" #include "chrome/browser/apps/platform_apps/app_browsertest_util.h" #include "chrome/browser/extensions/extension_apitest.h" @@ -12,6 +13,7 @@ #include "chrome/test/base/ui_test_utils.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" #include "extensions/browser/api/runtime/runtime_api.h" #include "extensions/browser/blocklist_extension_prefs.h" #include "extensions/browser/blocklist_state.h" @@ -453,4 +455,66 @@ EXPECT_EQ(url::kAboutBlankURL, GetActiveUrl(browser())); } +// Used for tests that only make sense with a background page. +using BackgroundPageOnlyRuntimeApiTest = RuntimeApiTest; +INSTANTIATE_TEST_SUITE_P(All, + BackgroundPageOnlyRuntimeApiTest, + testing::Values(ContextType::kPersistentBackground)); + +// Regression test for https://crbug.com/1298195 - whether a tab opened +// from the background page (via `window.open(...)`) will be correctly +// marked as `mojom::ViewType::kTabContents`. +// +// This test is a BackgroundPageOnlyRuntimeApiTest, because service workers +// can call neither 1) window.open nor 2) chrome.extension.getViews. +IN_PROC_BROWSER_TEST_P(BackgroundPageOnlyRuntimeApiTest, + GetViewsOfWindowOpenedFromBackgroundPage) { + ASSERT_EQ(GetParam(), ContextType::kPersistentBackground); + static constexpr char kManifest[] = R"( + { + "name": "test", + "version": "1.0", + "background": {"scripts": ["background.js"]}, + "manifest_version": 2 + })"; + TestExtensionDir dir; + dir.WriteManifest(kManifest); + dir.WriteFile(FILE_PATH_LITERAL("background.js"), ""); + dir.WriteFile(FILE_PATH_LITERAL("index.htm"), ""); + + const Extension* extension = LoadExtension(dir.UnpackedPath()); + ASSERT_TRUE(extension); + + GURL new_tab_url = extension->GetResourceURL("/index.htm"); + { + content::TestNavigationObserver nav_observer(new_tab_url); + nav_observer.StartWatchingNewWebContents(); + ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait( + browser()->profile(), extension->id(), + R"( window.open('/index.htm', ''); )")); + nav_observer.Wait(); + } + + { + content::DOMMessageQueue message_queue; + static constexpr char kScript[] = R"( + const foundWindows = chrome.extension.getViews({type: 'tab'}); + domAutomationController.send(foundWindows.length); + domAutomationController.send(foundWindows[0].location.href); + )"; + ASSERT_TRUE(browsertest_util::ExecuteScriptInBackgroundPageNoWait( + browser()->profile(), extension->id(), kScript)); + + std::string json; + ASSERT_TRUE(message_queue.WaitForMessage(&json)); + ASSERT_EQ("1", json); + + ASSERT_TRUE(message_queue.WaitForMessage(&json)); + absl::optional<base::Value> url = + base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS); + ASSERT_TRUE(url->is_string()); + ASSERT_EQ(new_tab_url.spec(), url->GetString()); + } +} + } // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 204c529..915c681 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1446,6 +1446,11 @@ "expiry_milestone": 90 }, { + "name": "dynamic-search-update-animation", + "owners": ["yulunwu"], + "expiry_milestone": 103 + }, + { "name": "eche-custom-widget", "owners": [ "nayebi" ], "expiry_milestone": 106
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 744d3d4..910d662 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2260,6 +2260,13 @@ "Show iconified text and vector icons " "in launcher search results."; +extern const char kDynamicSearchUpdateAnimationName[] = + "Dynamic Search Result Update Animation"; +extern const char kDynamicSearchUpdateAnimationDescription[] = + "Dynamically adjust the search result update animation when those update " + "animations are preempted. Shortened animation durations configurable " + "(unit: milliseconds)."; + const char kSecurePaymentConfirmationDebugName[] = "Secure Payment Confirmation Debug Mode"; const char kSecurePaymentConfirmationDebugDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 6ad9f26d..08f5a6ad 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1283,6 +1283,9 @@ extern const char kSearchResultInlineIconName[]; extern const char kSearchResultInlineIconDescription[]; +extern const char kDynamicSearchUpdateAnimationName[]; +extern const char kDynamicSearchUpdateAnimationDescription[]; + extern const char kSecurePaymentConfirmationDebugName[]; extern const char kSecurePaymentConfirmationDebugDescription[];
diff --git a/chrome/browser/media/media_engagement_score.cc b/chrome/browser/media/media_engagement_score.cc index c2d856cb..412062e 100644 --- a/chrome/browser/media/media_engagement_score.cc +++ b/chrome/browser/media/media_engagement_score.cc
@@ -26,6 +26,8 @@ const char MediaEngagementScore::kHighScoreUpperThresholdParamName[] = "upper_threshold"; +base::TimeDelta kScoreExpirationDuration = base::Days(30); + namespace { const int kScoreMinVisitsParamDefault = 20; @@ -156,9 +158,12 @@ if (!UpdateScoreDict()) return; + content_settings::ContentSettingConstraints constraints = { + base::Time::Now() + kScoreExpirationDuration}; settings_map_->SetWebsiteSettingDefaultScope( origin_.GetURL(), GURL(), ContentSettingsType::MEDIA_ENGAGEMENT, - content_settings::FromNullableUniquePtrValue(std::move(score_dict_))); + content_settings::FromNullableUniquePtrValue(std::move(score_dict_)), + constraints); } void MediaEngagementScore::IncrementMediaPlaybacks() {
diff --git a/chrome/browser/metrics/antivirus_metrics_provider_win.h b/chrome/browser/metrics/antivirus_metrics_provider_win.h index bfbacf9..9c95d6e 100644 --- a/chrome/browser/metrics/antivirus_metrics_provider_win.h +++ b/chrome/browser/metrics/antivirus_metrics_provider_win.h
@@ -30,7 +30,7 @@ ~AntiVirusMetricsProvider() override; - // metrics::MetricsDataProvider: + // metrics::MetricsProvider: void AsyncInit(base::OnceClosure done_callback) override; void ProvideSystemProfileMetrics( metrics::SystemProfileProto* system_profile_proto) override;
diff --git a/chrome/browser/metrics/cached_metrics_profile.cc b/chrome/browser/metrics/cached_metrics_profile.cc index 4dfb856..e686cc5 100644 --- a/chrome/browser/metrics/cached_metrics_profile.cc +++ b/chrome/browser/metrics/cached_metrics_profile.cc
@@ -16,7 +16,6 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) namespace metrics { - namespace { #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc index 70dd329..37b2805 100644 --- a/chrome/browser/metrics/chrome_metrics_service_client.cc +++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -139,10 +139,6 @@ #include "extensions/common/extension.h" #endif -#if BUILDFLAG(ENABLE_PLUGINS) -#include "chrome/browser/metrics/plugin_metrics_provider.h" -#endif - #if BUILDFLAG(IS_CHROMEOS_LACROS) #include "chrome/browser/metrics/lacros_metrics_provider.h" #endif @@ -522,10 +518,6 @@ ChromeAndroidMetricsProvider::RegisterPrefs(registry); #endif // BUILDFLAG(IS_ANDROID) -#if BUILDFLAG(ENABLE_PLUGINS) - PluginMetricsProvider::RegisterPrefs(registry); -#endif // BUILDFLAG(ENABLE_PLUGINS) - #if BUILDFLAG(IS_CHROMEOS_ASH) metrics::PerUserStateManagerChromeOS::RegisterPrefs(registry); #endif // BUILDFLAG(IS_CHROMEOS_ASH) @@ -629,15 +621,6 @@ return metrics::GetUploadInterval(metrics::ShouldUseCellularUploadInterval()); } -void ChromeMetricsServiceClient::OnPluginLoadingError( - const base::FilePath& plugin_path) { -#if BUILDFLAG(ENABLE_PLUGINS) - plugin_metrics_provider_->LogPluginLoadingError(plugin_path); -#else - NOTREACHED(); -#endif // BUILDFLAG(ENABLE_PLUGINS) -} - bool ChromeMetricsServiceClient::IsReportingPolicyManaged() { return IsMetricsReportingPolicyManaged(); } @@ -784,12 +767,6 @@ #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_LINUX) || // BUILDFLAG(IS_CHROMEOS_LACROS)) -#if BUILDFLAG(ENABLE_PLUGINS) - plugin_metrics_provider_ = new PluginMetricsProvider(local_state); - metrics_service_->RegisterMetricsProvider( - std::unique_ptr<metrics::MetricsProvider>(plugin_metrics_provider_)); -#endif // BUILDFLAG(ENABLE_PLUGINS) - #if BUILDFLAG(IS_CHROMEOS_LACROS) metrics_service_->RegisterMetricsProvider( std::make_unique<LacrosMetricsProvider>());
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.h b/chrome/browser/metrics/chrome_metrics_service_client.h index 9f67a99..7b9dc1d6 100644 --- a/chrome/browser/metrics/chrome_metrics_service_client.h +++ b/chrome/browser/metrics/chrome_metrics_service_client.h
@@ -37,7 +37,6 @@ #endif class BrowserActivityWatcher; -class PluginMetricsProvider; class Profile; class PrefRegistrySimple; @@ -97,7 +96,6 @@ override; base::TimeDelta GetStandardUploadInterval() override; void LoadingStateChanged(bool is_loading) override; - void OnPluginLoadingError(const base::FilePath& plugin_path) override; bool IsReportingPolicyManaged() override; metrics::EnableMetricsDefault GetMetricsReportingDefaultState() override; bool IsUMACellularUploadLogicEnabled() override; @@ -220,12 +218,6 @@ // Number of async histogram fetch requests in progress. int num_async_histogram_fetches_in_progress_ = 0; -#if BUILDFLAG(ENABLE_PLUGINS) - // The PluginMetricsProvider instance that was registered with - // MetricsService. Has the same lifetime as |metrics_service_|. - raw_ptr<PluginMetricsProvider> plugin_metrics_provider_ = nullptr; -#endif - // Subscription for receiving callbacks that a URL was opened from the // omnibox. base::CallbackListSubscription omnibox_url_opened_subscription_;
diff --git a/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc b/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc index 8c4d765..e69abf8 100644 --- a/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc +++ b/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc
@@ -179,11 +179,6 @@ expected_providers += 2; #endif // BUILDFLAG(IS_WIN) -#if BUILDFLAG(ENABLE_PLUGINS) - // PluginMetricsProvider. - expected_providers++; -#endif // BUILDFLAG(ENABLE_PLUGINS) - #if BUILDFLAG(IS_CHROMEOS_LACROS) // LacrosMetricsProvider. expected_providers++;
diff --git a/chrome/browser/metrics/perf/metric_provider.cc b/chrome/browser/metrics/perf/metric_provider.cc index 21e66c66e..f778c81 100644 --- a/chrome/browser/metrics/perf/metric_provider.cc +++ b/chrome/browser/metrics/perf/metric_provider.cc
@@ -20,7 +20,6 @@ #include "third_party/metrics_proto/sampled_profile.pb.h" namespace metrics { - namespace { // Name prefix of the histogram that counts the number of reports uploaded by a
diff --git a/chrome/browser/metrics/plugin_metrics_provider.cc b/chrome/browser/metrics/plugin_metrics_provider.cc deleted file mode 100644 index 06beab27..0000000 --- a/chrome/browser/metrics/plugin_metrics_provider.cc +++ /dev/null
@@ -1,333 +0,0 @@ -// Copyright 2014 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/metrics/plugin_metrics_provider.h" - -#include <stddef.h> - -#include <memory> -#include <string> -#include <utility> - -#include "base/bind.h" -#include "base/containers/contains.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/plugins/plugin_prefs.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/common/pref_names.h" -#include "components/metrics/stability_metrics_helper.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" -#include "components/prefs/scoped_user_pref_update.h" -#include "content/public/browser/child_process_data.h" -#include "content/public/browser/plugin_service.h" -#include "content/public/common/process_type.h" -#include "content/public/common/webplugininfo.h" -#include "third_party/metrics_proto/system_profile.pb.h" - -namespace { - -// Delay for RecordCurrentState execution. -constexpr base::TimeDelta kRecordStateDelay = base::Seconds(15); - -// Returns the plugin preferences corresponding for this user, if available. -// If multiple user profiles are loaded, returns the preferences corresponding -// to an arbitrary one of the profiles. -PluginPrefs* GetPluginPrefs() { - ProfileManager* profile_manager = g_browser_process->profile_manager(); - - if (!profile_manager) { - // The profile manager can be NULL when testing. - return NULL; - } - - std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles(); - if (profiles.empty()) - return NULL; - - return PluginPrefs::GetForProfile(profiles.front()).get(); -} - -// Fills |plugin| with the info contained in |plugin_info| and |plugin_prefs|. -void SetPluginInfo(const content::WebPluginInfo& plugin_info, - const PluginPrefs* plugin_prefs, - metrics::SystemProfileProto::Plugin* plugin) { - plugin->set_name(base::UTF16ToUTF8(plugin_info.name)); - plugin->set_filename(plugin_info.path.BaseName().AsUTF8Unsafe()); - plugin->set_version(base::UTF16ToUTF8(plugin_info.version)); - plugin->set_is_pepper(plugin_info.is_pepper_plugin()); - if (plugin_prefs) - plugin->set_is_disabled(!plugin_prefs->IsPluginEnabled(plugin_info)); -} - -} // namespace - -// This is used to quickly log stats from child process related notifications in -// PluginMetricsProvider::child_stats_buffer_. The buffer's contents are -// transferred out when Local State is periodically saved. The information is -// then reported to the UMA server on next launch. -struct PluginMetricsProvider::ChildProcessStats { - public: - explicit ChildProcessStats(int process_type) - : process_crashes(0), process_type(process_type) {} - - // This constructor is only used by the map to return some default value for - // an index for which no value has been assigned. - ChildProcessStats() - : process_crashes(0), process_type(content::PROCESS_TYPE_UNKNOWN) {} - - // The number of times that the given child process has crashed - int process_crashes; - - int process_type; -}; - -PluginMetricsProvider::PluginMetricsProvider(PrefService* local_state) - : local_state_(local_state) { - DCHECK(local_state_); - - BrowserChildProcessObserver::Add(this); -} - -PluginMetricsProvider::~PluginMetricsProvider() { - BrowserChildProcessObserver::Remove(this); -} - -void PluginMetricsProvider::AsyncInit(base::OnceClosure done_callback) { - content::PluginService::GetInstance()->GetPlugins( - base::BindOnce(&PluginMetricsProvider::OnGotPlugins, - weak_ptr_factory_.GetWeakPtr(), std::move(done_callback))); -} - -void PluginMetricsProvider::ProvideSystemProfileMetrics( - metrics::SystemProfileProto* system_profile_proto) { - PluginPrefs* plugin_prefs = GetPluginPrefs(); - for (size_t i = 0; i < plugins_.size(); ++i) { - SetPluginInfo(plugins_[i], plugin_prefs, - system_profile_proto->add_plugin()); - } -} - -void PluginMetricsProvider::ProvideStabilityMetrics( - metrics::SystemProfileProto* system_profile_proto) { - RecordCurrentStateIfPending(); - const base::Value* plugin_stats_list = - local_state_->GetList(prefs::kStabilityPluginStats); - if (!plugin_stats_list) - return; - - metrics::SystemProfileProto::Stability* stability = - system_profile_proto->mutable_stability(); - for (const auto& value : plugin_stats_list->GetListDeprecated()) { - const base::DictionaryValue* plugin_dict; - if (!value.GetAsDictionary(&plugin_dict)) { - NOTREACHED(); - continue; - } - - // Note that this search is potentially a quadratic operation, but given the - // low number of plugins installed on a "reasonable" setup, this should be - // fine. - // TODO(isherman): Verify that this does not show up as a hotspot in - // profiler runs. - const metrics::SystemProfileProto::Plugin* system_profile_plugin = NULL; - std::string plugin_name; - if (const std::string* ptr = - plugin_dict->FindStringKey(prefs::kStabilityPluginName)) - plugin_name = *ptr; - for (int i = 0; i < system_profile_proto->plugin_size(); ++i) { - if (system_profile_proto->plugin(i).name() == plugin_name) { - system_profile_plugin = &system_profile_proto->plugin(i); - break; - } - } - - if (!system_profile_plugin) { - continue; - } - - metrics::SystemProfileProto::Stability::PluginStability* plugin_stability = - stability->add_plugin_stability(); - *plugin_stability->mutable_plugin() = *system_profile_plugin; - - int crashes = - plugin_dict->FindIntKey(prefs::kStabilityPluginCrashes).value_or(0); - if (crashes > 0) - plugin_stability->set_crash_count(crashes); - } - - ClearSavedStabilityMetrics(); -} - -void PluginMetricsProvider::ClearSavedStabilityMetrics() { - local_state_->ClearPref(prefs::kStabilityPluginStats); -} - -// Saves plugin-related updates from the in-object buffer to Local State -// for retrieval next time we send a Profile log (generally next launch). -void PluginMetricsProvider::RecordCurrentState() { - ListPrefUpdate update(local_state_, prefs::kStabilityPluginStats); - base::Value* plugins = update.Get(); - DCHECK(plugins); - - for (auto& value : plugins->GetListDeprecated()) { - base::DictionaryValue* plugin_dict; - if (!value.GetAsDictionary(&plugin_dict)) { - NOTREACHED(); - continue; - } - - std::u16string plugin_name; - if (const std::string* ptr = - plugin_dict->FindStringKey(prefs::kStabilityPluginName)) { - plugin_name = base::UTF8ToUTF16(*ptr); - } - if (plugin_name.empty()) { - NOTREACHED(); - continue; - } - - if (child_process_stats_buffer_.find(plugin_name) == - child_process_stats_buffer_.end()) { - continue; - } - - ChildProcessStats stats = child_process_stats_buffer_[plugin_name]; - if (stats.process_crashes) { - int crashes = - plugin_dict->FindIntKey(prefs::kStabilityPluginCrashes).value_or(0); - crashes += stats.process_crashes; - plugin_dict->SetIntKey(prefs::kStabilityPluginCrashes, crashes); - } - - child_process_stats_buffer_.erase(plugin_name); - } - - // Now go through and add dictionaries for plugins that didn't already have - // reports in Local State. - for (auto cache_iter = child_process_stats_buffer_.begin(); - cache_iter != child_process_stats_buffer_.end(); ++cache_iter) { - ChildProcessStats stats = cache_iter->second; - - // Insert only plugins information into the plugins list. - if (!IsPluginProcess(stats.process_type)) - continue; - - base::Value plugin_dict(base::Value::Type::DICTIONARY); - - plugin_dict.SetStringKey(prefs::kStabilityPluginName, cache_iter->first); - plugin_dict.SetIntKey(prefs::kStabilityPluginCrashes, - stats.process_crashes); - plugins->Append(std::move(plugin_dict)); - } - child_process_stats_buffer_.clear(); -} - -void PluginMetricsProvider::LogPluginLoadingError( - const base::FilePath& plugin_path) { - content::WebPluginInfo plugin; - bool success = - content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path, - &plugin); - DCHECK(success); - ChildProcessStats& stats = child_process_stats_buffer_[plugin.name]; - // Initialize the type if this entry is new. - if (stats.process_type == content::PROCESS_TYPE_UNKNOWN) { - // The plugin process might not actually be of type PPAPI_PLUGIN, but we - // only care that it is *a* plugin process. - stats.process_type = content::PROCESS_TYPE_PPAPI_PLUGIN; - } else { - DCHECK(IsPluginProcess(stats.process_type)); - } - RecordCurrentStateWithDelay(); -} - -void PluginMetricsProvider::SetPluginsForTesting( - const std::vector<content::WebPluginInfo>& plugins) { - plugins_ = plugins; -} - -// static -bool PluginMetricsProvider::IsPluginProcess(int process_type) { - return (process_type == content::PROCESS_TYPE_PPAPI_PLUGIN || - process_type == content::PROCESS_TYPE_PPAPI_BROKER); -} - -// static -void PluginMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) { - registry->RegisterListPref(prefs::kStabilityPluginStats); -} - -void PluginMetricsProvider::OnGotPlugins( - base::OnceClosure done_callback, - const std::vector<content::WebPluginInfo>& plugins) { - plugins_ = plugins; - std::move(done_callback).Run(); -} - -PluginMetricsProvider::ChildProcessStats& -PluginMetricsProvider::GetChildProcessStats( - const content::ChildProcessData& data) { - const std::u16string& child_name = data.name; - if (!base::Contains(child_process_stats_buffer_, child_name)) { - child_process_stats_buffer_[child_name] = - ChildProcessStats(data.process_type); - } - return child_process_stats_buffer_[child_name]; -} - -void PluginMetricsProvider::BrowserChildProcessLaunchedAndConnected( - const content::ChildProcessData& data) { - RecordCurrentStateWithDelay(); -} - -void PluginMetricsProvider::BrowserChildProcessCrashed( - const content::ChildProcessData& data, - const content::ChildProcessTerminationInfo& info) { - GetChildProcessStats(data).process_crashes++; - metrics::StabilityMetricsHelper::RecordStabilityEvent( - metrics::StabilityEventType::kPluginCrash); - RecordCurrentStateWithDelay(); -} - -void PluginMetricsProvider::BrowserChildProcessKilled( - const content::ChildProcessData& data, - const content::ChildProcessTerminationInfo& info) { - // Treat a kill as a crash, since Flash returns STATUS_DEBUGGER_INACTIVE for - // actual crashes, which is treated as a kill rather than a crash by - // base::GetTerminationStatus - GetChildProcessStats(data).process_crashes++; - metrics::StabilityMetricsHelper::RecordStabilityEvent( - metrics::StabilityEventType::kPluginCrash); - RecordCurrentStateWithDelay(); -} - -bool PluginMetricsProvider::RecordCurrentStateWithDelay() { - if (weak_ptr_factory_.HasWeakPtrs()) - return false; - - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&PluginMetricsProvider::RecordCurrentState, - weak_ptr_factory_.GetWeakPtr()), - kRecordStateDelay); - return true; -} - -bool PluginMetricsProvider::RecordCurrentStateIfPending() { - if (!weak_ptr_factory_.HasWeakPtrs()) - return false; - - weak_ptr_factory_.InvalidateWeakPtrs(); - RecordCurrentState(); - return true; -} - -// static -base::TimeDelta PluginMetricsProvider::GetRecordStateDelay() { - return kRecordStateDelay; -}
diff --git a/chrome/browser/metrics/plugin_metrics_provider.h b/chrome/browser/metrics/plugin_metrics_provider.h deleted file mode 100644 index d05f034..0000000 --- a/chrome/browser/metrics/plugin_metrics_provider.h +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright 2014 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_METRICS_PLUGIN_METRICS_PROVIDER_H_ -#define CHROME_BROWSER_METRICS_PLUGIN_METRICS_PROVIDER_H_ - -#include <map> -#include <string> -#include <vector> - -#include "base/callback_forward.h" -#include "base/gtest_prod_util.h" -#include "base/memory/raw_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" -#include "components/metrics/metrics_provider.h" -#include "content/public/browser/browser_child_process_observer.h" - -namespace base { -class FilePath; -} - -namespace content { -struct WebPluginInfo; -} - -class PrefRegistrySimple; -class PrefService; - -// PluginMetricsProvider is responsible for adding out plugin information to -// the UMA proto. -class PluginMetricsProvider : public metrics::MetricsProvider, - public content::BrowserChildProcessObserver { - public: - explicit PluginMetricsProvider(PrefService* local_state); - - PluginMetricsProvider(const PluginMetricsProvider&) = delete; - PluginMetricsProvider& operator=(const PluginMetricsProvider&) = delete; - - ~PluginMetricsProvider() override; - - // metrics::MetricsDataProvider: - void AsyncInit(base::OnceClosure done_callback) override; - void ProvideSystemProfileMetrics( - metrics::SystemProfileProto* system_profile_proto) override; - void ProvideStabilityMetrics( - metrics::SystemProfileProto* system_profile_proto) override; - void ClearSavedStabilityMetrics() override; - - // Notifies the provider about an error loading the plugin at |plugin_path|. - void LogPluginLoadingError(const base::FilePath& plugin_path); - - // Sets this provider's list of plugins, exposed for testing. - void SetPluginsForTesting(const std::vector<content::WebPluginInfo>& plugins); - - // Returns true if process of type |type| should be counted as a plugin - // process, and false otherwise. - static bool IsPluginProcess(int process_type); - - // Registers local state prefs used by this class. - static void RegisterPrefs(PrefRegistrySimple* registry); - - private: - FRIEND_TEST_ALL_PREFIXES(PluginMetricsProviderTest, - RecordCurrentStateWithDelay); - FRIEND_TEST_ALL_PREFIXES(PluginMetricsProviderTest, - RecordCurrentStateIfPending); - FRIEND_TEST_ALL_PREFIXES(PluginMetricsProviderTest, - ProvideStabilityMetricsWhenPendingTask); - struct ChildProcessStats; - - // Receives the plugin list from the PluginService and calls |done_callback|. - void OnGotPlugins(base::OnceClosure done_callback, - const std::vector<content::WebPluginInfo>& plugins); - - // Returns reference to ChildProcessStats corresponding to |data|. - ChildProcessStats& GetChildProcessStats( - const content::ChildProcessData& data); - - // Saves plugin information to local state. - void RecordCurrentState(); - - // content::BrowserChildProcessObserver: - void BrowserChildProcessLaunchedAndConnected( - const content::ChildProcessData& data) override; - void BrowserChildProcessCrashed( - const content::ChildProcessData& data, - const content::ChildProcessTerminationInfo& info) override; - void BrowserChildProcessKilled( - const content::ChildProcessData& data, - const content::ChildProcessTerminationInfo& info) override; - - // Posts a delayed task for RecordCurrentState. Returns true if new task is - // posted and false if there was one already waiting for execution. - bool RecordCurrentStateWithDelay(); - - // If a delayed RecordCurrnetState task exists then cancels it, calls - // RecordCurrentState immediately and returns true. Otherwise returns false. - bool RecordCurrentStateIfPending(); - - // Records the delay used internally by RecordCurrentStateWithDelay(). - static base::TimeDelta GetRecordStateDelay(); - - raw_ptr<PrefService> local_state_; - - // The list of plugins which was retrieved on the file thread. - std::vector<content::WebPluginInfo> plugins_; - - // Buffer of child process notifications for quick access. - std::map<std::u16string, ChildProcessStats> child_process_stats_buffer_; - - base::WeakPtrFactory<PluginMetricsProvider> weak_ptr_factory_{this}; -}; - -#endif // CHROME_BROWSER_METRICS_PLUGIN_METRICS_PROVIDER_H_
diff --git a/chrome/browser/metrics/plugin_metrics_provider_unittest.cc b/chrome/browser/metrics/plugin_metrics_provider_unittest.cc deleted file mode 100644 index e3db72d..0000000 --- a/chrome/browser/metrics/plugin_metrics_provider_unittest.cc +++ /dev/null
@@ -1,214 +0,0 @@ -// Copyright 2014 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/metrics/plugin_metrics_provider.h" - -#include <stddef.h> - -#include <string> -#include <utility> - -#include "base/run_loop.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/task_environment.h" -#include "chrome/common/pref_names.h" -#include "components/prefs/pref_service.h" -#include "components/prefs/scoped_user_pref_update.h" -#include "components/prefs/testing_pref_service.h" -#include "content/public/browser/child_process_data.h" -#include "content/public/browser/child_process_termination_info.h" -#include "content/public/common/process_type.h" -#include "content/public/common/webplugininfo.h" -#include "content/public/test/browser_task_environment.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/metrics_proto/system_profile.pb.h" - -namespace { - -content::WebPluginInfo CreateFakePluginInfo( - const std::string& name, - const base::FilePath::CharType* path, - const std::string& version) { - content::WebPluginInfo plugin(base::UTF8ToUTF16(name), base::FilePath(path), - base::UTF8ToUTF16(version), std::u16string()); - plugin.type = content::WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS; - return plugin; -} - -class PluginMetricsProviderTest : public ::testing::Test { - public: - PluginMetricsProviderTest(const PluginMetricsProviderTest&) = delete; - PluginMetricsProviderTest& operator=(const PluginMetricsProviderTest&) = - delete; - - protected: - PluginMetricsProviderTest() - : prefs_(new TestingPrefServiceSimple) { - PluginMetricsProvider::RegisterPrefs(prefs()->registry()); - } - - TestingPrefServiceSimple* prefs() { - return prefs_.get(); - } - - private: - std::unique_ptr<TestingPrefServiceSimple> prefs_; -}; - -} // namespace - -TEST_F(PluginMetricsProviderTest, IsPluginProcess) { - EXPECT_TRUE(PluginMetricsProvider::IsPluginProcess( - content::PROCESS_TYPE_PPAPI_PLUGIN)); - EXPECT_FALSE(PluginMetricsProvider::IsPluginProcess( - content::PROCESS_TYPE_GPU)); -} - -TEST_F(PluginMetricsProviderTest, Plugins) { - content::BrowserTaskEnvironment task_environment; - - PluginMetricsProvider provider(prefs()); - - std::vector<content::WebPluginInfo> plugins; - plugins.push_back(CreateFakePluginInfo("p1", FILE_PATH_LITERAL("p1.plugin"), - "1.5")); - plugins.push_back(CreateFakePluginInfo("p2", FILE_PATH_LITERAL("p2.plugin"), - "2.0")); - provider.SetPluginsForTesting(plugins); - - metrics::SystemProfileProto system_profile; - provider.ProvideSystemProfileMetrics(&system_profile); - - ASSERT_EQ(2, system_profile.plugin_size()); - EXPECT_EQ("p1", system_profile.plugin(0).name()); - EXPECT_EQ("p1.plugin", system_profile.plugin(0).filename()); - EXPECT_EQ("1.5", system_profile.plugin(0).version()); - EXPECT_TRUE(system_profile.plugin(0).is_pepper()); - EXPECT_EQ("p2", system_profile.plugin(1).name()); - EXPECT_EQ("p2.plugin", system_profile.plugin(1).filename()); - EXPECT_EQ("2.0", system_profile.plugin(1).version()); - EXPECT_TRUE(system_profile.plugin(1).is_pepper()); - - // Now set some plugin stability stats for p2 and verify they're recorded. - base::Value plugin_dict(base::Value::Type::DICTIONARY); - plugin_dict.SetStringKey(prefs::kStabilityPluginName, "p2"); - plugin_dict.SetIntKey(prefs::kStabilityPluginCrashes, 2); - { - ListPrefUpdate update(prefs(), prefs::kStabilityPluginStats); - update.Get()->Append(std::move(plugin_dict)); - } - - provider.ProvideStabilityMetrics(&system_profile); - - const metrics::SystemProfileProto_Stability& stability = - system_profile.stability(); - ASSERT_EQ(1, stability.plugin_stability_size()); - EXPECT_EQ("p2", stability.plugin_stability(0).plugin().name()); - EXPECT_EQ("p2.plugin", stability.plugin_stability(0).plugin().filename()); - EXPECT_EQ("2.0", stability.plugin_stability(0).plugin().version()); - EXPECT_TRUE(stability.plugin_stability(0).plugin().is_pepper()); - EXPECT_EQ(2, stability.plugin_stability(0).crash_count()); -} - -TEST_F(PluginMetricsProviderTest, RecordCurrentStateWithDelay) { - content::BrowserTaskEnvironment task_environment( - base::test::TaskEnvironment::TimeSource::MOCK_TIME); - - PluginMetricsProvider provider(prefs()); - - EXPECT_TRUE(provider.RecordCurrentStateWithDelay()); - EXPECT_FALSE(provider.RecordCurrentStateWithDelay()); - - task_environment.FastForwardBy(PluginMetricsProvider::GetRecordStateDelay()); - base::RunLoop().RunUntilIdle(); - - EXPECT_TRUE(provider.RecordCurrentStateWithDelay()); -} - -TEST_F(PluginMetricsProviderTest, RecordCurrentStateIfPending) { - content::BrowserTaskEnvironment task_environment( - base::test::TaskEnvironment::TimeSource::MOCK_TIME); - - PluginMetricsProvider provider(prefs()); - - // First there should be no need to force RecordCurrentState. - EXPECT_FALSE(provider.RecordCurrentStateIfPending()); - - // After delayed task is posted RecordCurrentStateIfPending should return - // true. - EXPECT_TRUE(provider.RecordCurrentStateWithDelay()); - EXPECT_TRUE(provider.RecordCurrentStateIfPending()); - - // If RecordCurrentStateIfPending was successful then we should be able to - // post a new delayed task. - EXPECT_TRUE(provider.RecordCurrentStateWithDelay()); -} - -TEST_F(PluginMetricsProviderTest, ProvideStabilityMetricsWhenPendingTask) { - content::BrowserTaskEnvironment task_environment; - - PluginMetricsProvider provider(prefs()); - - // Create plugin information for testing. - std::vector<content::WebPluginInfo> plugins; - plugins.push_back( - CreateFakePluginInfo("p1", FILE_PATH_LITERAL("p1.plugin"), "1.5")); - plugins.push_back( - CreateFakePluginInfo("p2", FILE_PATH_LITERAL("p2.plugin"), "1.5")); - provider.SetPluginsForTesting(plugins); - metrics::SystemProfileProto system_profile; - provider.ProvideSystemProfileMetrics(&system_profile); - - // Increase number of process launches which should also start a delayed - // task. - content::ChildProcessTerminationInfo abnormal_termination_info; - abnormal_termination_info.status = - base::TERMINATION_STATUS_ABNORMAL_TERMINATION; - abnormal_termination_info.exit_code = 1; - content::ChildProcessData child_process_data1( - content::PROCESS_TYPE_PPAPI_PLUGIN); - child_process_data1.name = u"p1"; - provider.BrowserChildProcessLaunchedAndConnected(child_process_data1); - provider.BrowserChildProcessCrashed(child_process_data1, - abnormal_termination_info); - - // A disconnect should not generate a crash event. - provider.BrowserChildProcessLaunchedAndConnected(child_process_data1); - provider.BrowserChildProcessHostDisconnected(child_process_data1); - - content::ChildProcessData child_process_data2( - content::PROCESS_TYPE_PPAPI_PLUGIN); - child_process_data2.name = u"p2"; - provider.BrowserChildProcessLaunchedAndConnected(child_process_data2); - provider.BrowserChildProcessCrashed(child_process_data2, - abnormal_termination_info); - - // A kill should generate a crash event - provider.BrowserChildProcessLaunchedAndConnected(child_process_data2); - provider.BrowserChildProcessKilled(child_process_data2, - abnormal_termination_info); - - // Call ProvideStabilityMetrics to check that it will force pending tasks to - // be executed immediately. - provider.ProvideStabilityMetrics(&system_profile); - - // Check current number of instances created. - const metrics::SystemProfileProto_Stability& stability = - system_profile.stability(); - size_t found = 0; - EXPECT_EQ(stability.plugin_stability_size(), 2); - for (int i = 0; i < 2; i++) { - std::string name = stability.plugin_stability(i).plugin().name(); - if (name == "p1") { - EXPECT_EQ(1, stability.plugin_stability(i).crash_count()); - found++; - } else if (name == "p2") { - EXPECT_EQ(2, stability.plugin_stability(i).crash_count()); - found++; - } else { - GTEST_FAIL() << "Unexpected plugin name : " << name; - } - } - EXPECT_EQ(found, 2U); -}
diff --git a/chrome/browser/nearby_sharing/webrtc_signaling_messenger_unittest.cc b/chrome/browser/nearby_sharing/webrtc_signaling_messenger_unittest.cc index 1dcad70..4830cb2 100644 --- a/chrome/browser/nearby_sharing/webrtc_signaling_messenger_unittest.cc +++ b/chrome/browser/nearby_sharing/webrtc_signaling_messenger_unittest.cc
@@ -25,14 +25,6 @@ const char kTestAccount[] = "test@test.test"; const char kCountryCode[] = "ZZ"; -chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse -CreateReceiveMessagesResponse(const std::string& msg) { - chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse - response; - response.mutable_inbox_message()->set_message(msg); - return response; -} - class FakeIncomingMessagesListener : public sharing::mojom::IncomingMessagesListener { public:
diff --git a/chrome/browser/page_load_metrics/observers/security_state_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/security_state_page_load_metrics_observer_browsertest.cc index 66ccabe..0a43f65 100644 --- a/chrome/browser/page_load_metrics/observers/security_state_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/security_state_page_load_metrics_observer_browsertest.cc
@@ -25,6 +25,8 @@ #include "components/ukm/test_ukm_recorder.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/fenced_frame_test_util.h" +#include "content/public/test/prerender_test_util.h" #include "content/public/test/test_utils.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -588,3 +590,102 @@ EXPECT_LE(kMinForegroundTime.InMilliseconds(), safety_tip_samples.front().min); } + +class SecurityStatePageLoadMetricsMPArchBrowserTest + : public SecurityStatePageLoadMetricsBrowserTest { + public: + SecurityStatePageLoadMetricsMPArchBrowserTest() = default; + ~SecurityStatePageLoadMetricsMPArchBrowserTest() override = default; + + content::WebContents* GetWebContents() { + return browser()->tab_strip_model()->GetActiveWebContents(); + } +}; + +class SecurityStatePageLoadMetricsPrerenderBrowserTest + : public SecurityStatePageLoadMetricsMPArchBrowserTest { + public: + SecurityStatePageLoadMetricsPrerenderBrowserTest() + : prerender_helper_(base::BindRepeating( + &SecurityStatePageLoadMetricsPrerenderBrowserTest::GetWebContents, + base::Unretained(this))) {} + ~SecurityStatePageLoadMetricsPrerenderBrowserTest() override = default; + + void SetUp() override { + prerender_helper_.SetUp(embedded_test_server()); + SecurityStatePageLoadMetricsBrowserTest::SetUp(); + } + + content::test::PrerenderTestHelper* prerender_helper() { + return &prerender_helper_; + } + + private: + content::test::PrerenderTestHelper prerender_helper_; +}; + +IN_PROC_BROWSER_TEST_F( + SecurityStatePageLoadMetricsPrerenderBrowserTest, + EnsurePrerenderingDoesNotRecordOnCommitSecurityLevelHistogram) { + StartHttpsServer(net::EmbeddedTestServer::CERT_OK); + + GURL https_url = https_test_server()->GetURL("/title1.html"); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), https_url)); + + histogram_tester()->ExpectTotalCount("Security.SecurityLevel.OnCommit", 1); + + // Loads a page in the prerender. + GURL prerender_url = https_test_server()->GetURL("/title2.html"); + const int host_id = prerender_helper()->AddPrerender(prerender_url); + content::test::PrerenderHostObserver host_observer(*GetWebContents(), + host_id); + EXPECT_FALSE(host_observer.was_activated()); + + histogram_tester()->ExpectTotalCount("Security.SecurityLevel.OnCommit", 1); + + // Activate the page from the prerendering. + prerender_helper()->NavigatePrimaryPage(prerender_url); + EXPECT_TRUE(host_observer.was_activated()); + + // Prerendering doesn't invoke OnCommit method of PageLoadMetricsObserver + // even after activating the prerendered page. So, + // Security.SecurityLevel.OnCommit metric's count should not be changed. + histogram_tester()->ExpectTotalCount("Security.SecurityLevel.OnCommit", 1); +} + +class SecurityStatePageLoadMetricsFencedFrameBrowserTest + : public SecurityStatePageLoadMetricsMPArchBrowserTest { + public: + SecurityStatePageLoadMetricsFencedFrameBrowserTest() = default; + ~SecurityStatePageLoadMetricsFencedFrameBrowserTest() override = default; + + content::test::FencedFrameTestHelper& fenced_frame_test_helper() { + return fenced_frame_helper_; + } + + private: + content::test::FencedFrameTestHelper fenced_frame_helper_; +}; + +// TODO(crbug.com/1301880): This test will be enabled after toyoshim@'s CL +// restricts call to SecurityStatePageLoadMetricsObserver::OnCommit for fenced +// frames" +IN_PROC_BROWSER_TEST_F(SecurityStatePageLoadMetricsFencedFrameBrowserTest, + DISABLED_DoNotRecordOnCommitSecurityLevelHistogram) { + StartHttpsServer(net::EmbeddedTestServer::CERT_OK); + + GURL https_url = https_test_server()->GetURL("/title1.html"); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), https_url)); + + histogram_tester()->ExpectTotalCount("Security.SecurityLevel.OnCommit", 1); + + // Create a fenced frame. + GURL fenced_frame_url( + https_test_server()->GetURL("/fenced_frames/title1.html")); + content::RenderFrameHost* fenced_frame_host = + fenced_frame_test_helper().CreateFencedFrame( + GetWebContents()->GetMainFrame(), fenced_frame_url); + ASSERT_TRUE(fenced_frame_host); + + histogram_tester()->ExpectTotalCount("Security.SecurityLevel.OnCommit", 1); +}
diff --git a/chrome/browser/plugins/plugin_observer.cc b/chrome/browser/plugins/plugin_observer.cc index b3de6c7f..0351e391 100644 --- a/chrome/browser/plugins/plugin_observer.cc +++ b/chrome/browser/plugins/plugin_observer.cc
@@ -180,8 +180,6 @@ } void PluginObserver::CouldNotLoadPlugin(const base::FilePath& plugin_path) { - g_browser_process->GetMetricsServicesManager()->OnPluginLoadingError( - plugin_path); std::u16string plugin_name = PluginService::GetInstance()->GetPluginDisplayNameByPath(plugin_path); CreatePluginObserverInfoBar(
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index fa09f5d..4a5ff00 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -359,6 +359,13 @@ { key::kEnableAuthNegotiatePort, prefs::kEnableAuthNegotiatePort, base::Value::Type::BOOLEAN }, + { key::kAuthNegotiateDelegateAllowlist, + prefs::kAuthNegotiateDelegateAllowlist, + base::Value::Type::STRING }, + { key::kAuthServerAllowlist, + prefs::kAuthServerAllowlist, + base::Value::Type::STRING + }, { key::kGSSAPILibraryName, prefs::kGSSAPILibraryName, base::Value::Type::STRING }, @@ -1751,20 +1758,6 @@ std::make_unique<safe_browsing::SafeBrowsingPolicyHandler>()); handlers->AddHandler(std::make_unique<SimpleDeprecatingPolicyHandler>( std::make_unique<SimplePolicyHandler>( - key::kAuthServerWhitelist, // nocheck - prefs::kAuthServerAllowlist, base::Value::Type::STRING), - std::make_unique<SimplePolicyHandler>(key::kAuthServerAllowlist, - prefs::kAuthServerAllowlist, - base::Value::Type::STRING))); - handlers->AddHandler(std::make_unique<SimpleDeprecatingPolicyHandler>( - std::make_unique<SimplePolicyHandler>( - key::kAuthNegotiateDelegateWhitelist, // nocheck - prefs::kAuthNegotiateDelegateAllowlist, base::Value::Type::STRING), - std::make_unique<SimplePolicyHandler>( - key::kAuthNegotiateDelegateAllowlist, - prefs::kAuthNegotiateDelegateAllowlist, base::Value::Type::STRING))); - handlers->AddHandler(std::make_unique<SimpleDeprecatingPolicyHandler>( - std::make_unique<SimplePolicyHandler>( key::kNativeWindowOcclusionEnabled, policy::policy_prefs::kNativeWindowOcclusionEnabled, base::Value::Type::BOOLEAN),
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 819c39e..901a9ff 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -716,8 +716,6 @@ "data_reduction.last_enabled_time"; // Deprecated 02/2022. -const char kStabilityChildProcessCrashCount[] = - "user_experience_metrics.stability.child_process_crash_count"; #if !BUILDFLAG(IS_ANDROID) const char kMediaRouterCloudServicesPrefSet[] = "media_router.cloudservices.prefset"; @@ -733,6 +731,14 @@ "multidevice_setup.phone_hub_camera_roll_pending_state"; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +// Deprecated 03/2022. +const char kStabilityChildProcessCrashCount[] = + "user_experience_metrics.stability.child_process_crash_count"; +#if BUILDFLAG(ENABLE_PLUGINS) +const char kStabilityPluginStats[] = + "user_experience_metrics.stability.plugin_stats2"; +#endif + // Register local state used only for migration (clearing or moving to a new // key). void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) { @@ -763,8 +769,13 @@ registry->RegisterBooleanPref(kStabilitySessionEndCompleted, true); // Deprecated 02/2022. - registry->RegisterIntegerPref(kStabilityChildProcessCrashCount, 0); registry->RegisterBooleanPref(kWebSQLInThirdPartyContextEnabled, false); + + // Deprecated 03/2002. + registry->RegisterIntegerPref(kStabilityChildProcessCrashCount, 0); +#if BUILDFLAG(ENABLE_PLUGINS) + registry->RegisterListPref(kStabilityPluginStats); +#endif } // Register prefs used only for migration (clearing or moving to a new key). @@ -1596,6 +1607,12 @@ // Added 02/2022. local_state->ClearPref(kWebSQLInThirdPartyContextEnabled); + // Added 03/2002. + local_state->ClearPref(kStabilityChildProcessCrashCount); +#if BUILDFLAG(ENABLE_PLUGINS) + local_state->ClearPref(kStabilityPluginStats); +#endif + // Please don't delete the following line. It is used by PRESUBMIT.py. // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc index 0e932ac..adcd00e8 100644 --- a/chrome/browser/printing/print_view_manager_base.cc +++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -61,8 +61,11 @@ #include "printing/printing_features.h" #endif -#if BUILDFLAG(ENABLE_PRINT_PREVIEW) +#if !BUILDFLAG(IS_ANDROID) #include "chrome/browser/printing/print_error_dialog.h" +#endif + +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/printing/print_view_manager.h" #include "components/prefs/pref_service.h" #endif @@ -687,7 +690,7 @@ PrintManager::PrintingFailed(cookie); -#if BUILDFLAG(ENABLE_PRINT_PREVIEW) +#if !BUILDFLAG(IS_ANDROID) // Android does not implement this function. ShowPrintErrorDialog(); #endif
diff --git a/chrome/browser/resources/access_code_cast/BUILD.gn b/chrome/browser/resources/access_code_cast/BUILD.gn index f54e0a7..0c5add2 100644 --- a/chrome/browser/resources/access_code_cast/BUILD.gn +++ b/chrome/browser/resources/access_code_cast/BUILD.gn
@@ -14,8 +14,8 @@ html_to_js("web_components") { js_files = [ "access_code_cast.ts", - "code_input/code_input.ts", "error_message/error_message.ts", + "passcode_input/passcode_input.ts", ] } @@ -57,8 +57,8 @@ "access_code_cast.mojom-webui.js", "access_code_cast.ts", "browser_proxy.ts", - "code_input/code_input.ts", "error_message/error_message.ts", + "passcode_input/passcode_input.ts", "route_request_result_code.mojom-webui.js", ] }
diff --git a/chrome/browser/resources/access_code_cast/access_code_cast.html b/chrome/browser/resources/access_code_cast/access_code_cast.html index 0c5e85c..7588a35d 100644 --- a/chrome/browser/resources/access_code_cast/access_code_cast.html +++ b/chrome/browser/resources/access_code_cast/access_code_cast.html
@@ -14,11 +14,14 @@ .center-content { display: flex; justify-content: center; - text-align: center; width: 100%; } - .space { + .space-1 { + height: 8px; + } + + .space-2 { height: 32px; } @@ -46,11 +49,17 @@ <div slot="body"> <div id="codeInputView"> <div class="body-1">$i18n{accessCodeMessage}</div> - <div class="space"></div> + <div class="space-2"></div> <div class="center-content"> - <c2c-code-input length="6" value="" id="codeInput" - disabled="[[!canCast]]"></c2c-code-input> + <c2c-passcode-input + aria-label="[[inputLabel]]" + disabled="[[!canCast]]" + id="codeInput" + length="6" + value="{{accessCode}}" + ></c2c-passcode-input> </div> + <div class="space-1"></div> <template is="dom-if" if="[[qrScannerEnabled]]" class="center-content"> <div class="center-content"> <cr-button on-click="switchToQrInput" class="center text-button"> @@ -68,7 +77,7 @@ <div slot="button-container"> <cr-button on-click="close" class="cancel-button">$i18n{cancel}</cr-button> <cr-button id="castButton" on-click="addSinkAndCast" class="action-button" - disabled="[[castButtonDisabled(accessCode, canCast)]]"> + disabled="[[submitDisabled]]"> $i18n{submit} </cr-button> <cr-button id="backButton" on-click="switchToCodeInput"
diff --git a/chrome/browser/resources/access_code_cast/access_code_cast.ts b/chrome/browser/resources/access_code_cast/access_code_cast.ts index 2c3c6fc..35710b0 100644 --- a/chrome/browser/resources/access_code_cast/access_code_cast.ts +++ b/chrome/browser/resources/access_code_cast/access_code_cast.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import './code_input/code_input.js'; +import './passcode_input/passcode_input.js'; import './error_message/error_message.js'; import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; @@ -20,7 +20,7 @@ import {AddSinkResultCode, CastDiscoveryMethod, PageCallbackRouter} from './access_code_cast.mojom-webui.js'; import {BrowserProxy} from './browser_proxy.js'; -import {CodeInputElement} from './code_input/code_input.js'; +import {PasscodeInputElement} from './passcode_input/passcode_input.js'; import {ErrorMessageElement} from './error_message/error_message.js'; import {RouteRequestResultCode} from './route_request_result_code.mojom-webui.js'; @@ -34,14 +34,15 @@ backButton: CrButtonElement; castButton: CrButtonElement; codeInputView: HTMLDivElement; - codeInput: CodeInputElement; + codeInput: PasscodeInputElement; dialog: CrDialogElement; errorMessage: ErrorMessageElement; qrInputView: HTMLDivElement; } } -const AccessCodeCastElementBase = WebUIListenerMixin(I18nMixin(PolymerElement)); +const AccessCodeCastElementBase = + WebUIListenerMixin(I18nMixin(PolymerElement)); class AccessCodeCastElement extends AccessCodeCastElementBase { static get is() { @@ -52,13 +53,25 @@ return html`{__html_template__}`; } + static get properties() { + return { + accessCode: { + type: String, + value: '', + observer: 'accessCodeChange' + } + }; + } + private listenerIds: Array<number>; private router: PageCallbackRouter; private static readonly ACCESS_CODE_LENGTH = 6; private accessCode: string; private canCast: boolean; + private inputLabel: string; private state: PageState; + private submitDisabled: boolean; private qrScannerEnabled: boolean; constructor() { @@ -66,6 +79,7 @@ this.listenerIds = []; this.router = BrowserProxy.getInstance().callbackRouter; this.canCast = true; + this.inputLabel = this.i18n('inputLabel'); this.accessCode = ''; BrowserProxy.getInstance().isQrScanningAvailable().then((available) => { @@ -87,9 +101,6 @@ super.ready(); this.setState(PageState.CODE_INPUT); this.$.errorMessage.setNoError(); - this.$.codeInput.addEventListener('access-code-input', (e: any) => { - this.handleCodeInput(e); - }); this.$.dialog.showModal(); } @@ -115,6 +126,9 @@ } async addSinkAndCast() { + if (!BrowserProxy.getInstance().isDialog()) { + return; + } if (this.accessCode.length !== AccessCodeCastElement.ACCESS_CODE_LENGTH) { return; } @@ -151,20 +165,15 @@ this.close(); } - // Even though we can get this.accessCode directly, passing it triggers - // Polymer's data binding whenever this.accessCode updates. - castButtonDisabled(accessCode: string, canCast: boolean) { - if (!canCast) { - return true; - } - - return accessCode.length !== AccessCodeCastElement.ACCESS_CODE_LENGTH; - } - setAccessCodeForTest(value: string) { this.accessCode = value; } + private accessCodeChange() { + this.submitDisabled = !this.canCast || + this.accessCode.length !== AccessCodeCastElement.ACCESS_CODE_LENGTH; + } + private setState(state: PageState) { this.state = state; this.$.errorMessage.setNoError(); @@ -175,7 +184,7 @@ this.$.backButton.hidden = state !== PageState.QR_INPUT; if (state === PageState.CODE_INPUT) { - this.$.codeInput.clearInput(); + this.$.codeInput.value = ''; this.$.codeInput.focusInput(); } } @@ -185,10 +194,10 @@ } private handleEnterPressed() { - if (this.castButtonDisabled(this.accessCode, this.canCast)) { + if (this.submitDisabled) { return; } - if (this.$.codeInput.getFocusedIndex() === -1) { + if (!this.$.codeInput.focused) { return; } if (this.state !== PageState.CODE_INPUT) {
diff --git a/chrome/browser/resources/access_code_cast/code_input/code_input.html b/chrome/browser/resources/access_code_cast/code_input/code_input.html deleted file mode 100644 index 0f2811f2..0000000 --- a/chrome/browser/resources/access_code_cast/code_input/code_input.html +++ /dev/null
@@ -1,15 +0,0 @@ -<style> - cr-input { - display: inline-block; - font-size: 20px; - margin-inline-end: 4px; - margin-inline-start: 4px; - text-align: center; - width: 40px; - } -</style> -<template is="dom-repeat" items="[[inputs]]" as="inputIndex"> - <cr-input minlength="1" maxlength="1" id="input-[[index]]" - disabled="[[disabled]]" aria-label="[[getInputLabel(index)]]"> - </cr-input> -</template> \ No newline at end of file
diff --git a/chrome/browser/resources/access_code_cast/code_input/code_input.ts b/chrome/browser/resources/access_code_cast/code_input/code_input.ts deleted file mode 100644 index f75391e2..0000000 --- a/chrome/browser/resources/access_code_cast/code_input/code_input.ts +++ /dev/null
@@ -1,176 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; - -import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; -import {I18nMixin} from 'chrome://resources/js/i18n_mixin.js'; -import {WebUIListenerMixin} from 'chrome://resources/js/web_ui_listener_mixin.js'; -import {afterNextRender, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -const CodeInputElementBase = WebUIListenerMixin(I18nMixin(PolymerElement)); - -export class CodeInputElement extends CodeInputElementBase { - static get is() { - return 'c2c-code-input'; - } - - static get template() { - return html`{__html_template__}`; - } - - static get properties() { - return { - disabled: Boolean, - length: Number, - value: { - type: String, - value: '', - } - }; - } - - length: number; - value: string; - private inputs: string[]; - private inputElementsLoaded: boolean; - - constructor() { - super(); - this.inputElementsLoaded = false; - - afterNextRender(this, () => { - this.inputElementsLoaded = true; - - for(let i = 0; i < this.length; i++) { - const index = i; - this.getInput(i).addEventListener('input', (e: Event) => { - const input = e.target as CrInputElement; - this.handleInput(input.value, index); - }); - this.getInput(i).addEventListener('keydown', (k: KeyboardEvent) => { - if (k.key === 'Backspace') { - this.handleBackspace(index); - } - }); - } - }); - } - - ready() { - super.ready(); - this.inputs = Array(this.length).fill(''); - } - - clearInput() { - const clear = () => { - for (let i = 0; i < this.length; i++) { - this.getInput(i).value = ''; - } - }; - - this.afterInputsLoaded(clear); - } - - focusInput() { - const focus = () => { - for (let i = 0; i < this.length; i++) { - if (this.getInput(i).value === '') { - this.getInput(i).focusInput(); - return; - } - } - this.getInput(this.length - 1).focusInput(); - }; - - this.afterInputsLoaded(focus); - } - - getFocusedIndex() { - for (let i = 0; i < this.length; i++) { - if (this.getInput(i) === this.shadowRoot!.activeElement) { - return i; - } - } - - return -1; - } - - getInput(index: number): CrInputElement { - const el = this.shadowRoot!.querySelector('#input-' + index); - return el as CrInputElement; - } - - setValue(value: string) { - if (value.length > this.length) { - return; - } - - this.clearInput(); - - for (let i = 0 ; i < value.length; i++) { - this.getInput(i).value = value[i]; - } - - this.updateValue(); - } - - private afterInputsLoaded(callback: Function) { - if (this.inputElementsLoaded) { - callback(); - } else { - afterNextRender(this, () => { - callback(); - }); - } - } - - private focusNext(index: number) { - if (index + 1 < this.length) { - this.getInput(index + 1).focusInput(); - } - } - - private focusPrev(index: number) { - if (index > 0) { - this.getInput(index - 1).focusInput(); - } - } - - private getInputLabel(index: number) { - return this.i18n('enterCharacter', index + 1, this.length); - } - - private handleInput(value: string, index: number) { - if (value.length) { - this.focusNext(index); - this.getInput(index).value = value.trim().toUpperCase()[0]; - } - - this.updateValue(); - } - - private handleBackspace(index: number) { - if (index > 0 && !this.getInput(index).value.length) { - this.getInput(index - 1).value = ''; - this.focusPrev(index); - } else if (this.getInput(index).inputElement.selectionStart === 0) { - this.focusPrev(index); - } - - this.updateValue(); - } - - private updateValue() { - for (let i = 0; i < this.length; i++) { - this.inputs[i] = this.getInput(i).value; - } - this.value = ''.concat(...this.inputs); - this.dispatchEvent(new CustomEvent('access-code-input', { - detail: {value: this.value} - })); - } -} - -customElements.define(CodeInputElement.is, CodeInputElement);
diff --git a/chrome/browser/resources/access_code_cast/passcode_input/passcode_input.html b/chrome/browser/resources/access_code_cast/passcode_input/passcode_input.html new file mode 100644 index 0000000..39f90a3 --- /dev/null +++ b/chrome/browser/resources/access_code_cast/passcode_input/passcode_input.html
@@ -0,0 +1,137 @@ +<style include="cr-shared-style"> + :host { + --passcode-input-active-color: var(--google-blue-50); + --passcode-input-background-color: var(--google-grey-50); + --passcode-input-background-color-focused: var(--google-grey-100); + --passcode-input-color: var(--cr-primary-text-color); + --passcode-input-color-disabled: var(--google-grey-600); + --passcode-input-focus-color: var(--google-blue-600); + } + + @media (prefers-color-scheme: dark) { + :host { + --passcode-input-active-color: rgba(138, 180, 248, 0.3); + --passcode-input-background-color: rgba(0, 0, 0, 0.15); + --passcode-input-background-color-focused: rgba(0, 0, 0, 0.3); + --passcode-input-focus-color: var(--google-blue-300); + } + } + + @keyframes blink { + from { + background-color: var(--passcode-input-focus-color); + } + to { + background-color: var(--passcode-input-focus-color); + } + 50% { + background-color: transparent; + } + } + + #container { + height: 48px; + position: relative; + text-align: unset; + } + + .char { + color: var(--passcode-input-color); + margin: auto; + } + + .char-box { + background-color: var(--passcode-input-background-color); + border-radius: 4px; + font-family: inherit; + font-size: 20px; + height: 40px; + line-height: 40px; + margin: 4px; + position: relative; + text-align: center; + transition: background-color 120ms ease-out; + vertical-align: middle; + width: 40px; + } + + .char-box-container { + display: flex; + margin-inline-start: 14px; + position: absolute; + } + + .cursor-filled::after { + animation: 1s blink step-end infinite; + background-color: var(--passcode-input-focus-color); + content: ''; + height: 20px; + margin-inline-start: 2px; + position: absolute; + top: 10px; + width: 2px; + } + + .cursor-empty::before { + animation: 1s blink step-end infinite; + background-color: var(--passcode-input-focus-color); + content: ''; + height: 20px; + margin-inline-start: -1px; + position: absolute; + top: 10px; + width: 2px; + } + + .cursor-start::before { + animation: 1s blink step-end infinite; + background-color: var(--passcode-input-focus-color); + content: ''; + height: 20px; + margin-inline-start: -4px; + position: absolute; + top: 10px; + width: 2px; + } + + .disabled { + color: var(--passcode-input-color-disabled); + } + + .focused { + background-color: var(--passcode-input-background-color-focused); + transition: background-color 120ms ease-in; + } + + .active { + background-color: var(--passcode-input-active-color); + } + + .hidden-input { + font-family: monospace; + font-size: 20px; + letter-spacing: 36px; + opacity: 0; + padding: 11px; + position: absolute; + z-index: 100; + } +</style> +<div id='container'> + <input + aria-label="[[ariaLabel]]" + autocomplete="off" + class="hidden-input" + disabled="[[disabled]]" + id="inputElement" + spellcheck="false" + type="text" + > + <div class="char-box-container" aria-hidden="true"> + <template is="dom-repeat" items="[[charDisplayBoxes]]" as="charBox"> + <div class="char-box" id="char-box-[[index]]"> + <p class="char" id="char-[[index]]"></p> + </div> + </template> + </div> +</div>
diff --git a/chrome/browser/resources/access_code_cast/passcode_input/passcode_input.ts b/chrome/browser/resources/access_code_cast/passcode_input/passcode_input.ts new file mode 100644 index 0000000..18402f8c --- /dev/null +++ b/chrome/browser/resources/access_code_cast/passcode_input/passcode_input.ts
@@ -0,0 +1,250 @@ +// 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. + +import {afterNextRender, html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +type ForEachCallback = (el: HTMLParagraphElement|HTMLDivElement, index: number) => void; + +export interface PasscodeInputElement { + $: { + inputElement: HTMLInputElement; + container: HTMLDivElement; + } +} + +export class PasscodeInputElement extends PolymerElement { + static get is() { + return 'c2c-passcode-input'; + } + + static get template() { + return html`{__html_template__}`; + } + + static get properties() { + return { + ariaLabel: { + type: String, + value: '', + }, + disabled: { + type: Boolean, + observer: 'disabledChange' + }, + length: Number, + value: { + type: String, + value: '', + observer: 'valueChange', + notify: true, + reflectToAttribute: true, + } + }; + } + + length: number; + value: string; + focused: boolean; + disabled: boolean; + private afterFirstRender: boolean; + private charDisplayBoxes: string[]; + + private static readonly PASSCODE_INPUT_SIZE = 40; + private static readonly PASSCODE_BOX_SPACING = 8; + + constructor() { + super(); + this.focused = false; + this.afterFirstRender = false; + afterNextRender(this, () => { + this.afterFirstRender = true; + }); + } + + ready() { + super.ready(); + this.charDisplayBoxes = Array(this.length).fill(''); + const boxWithMarginWidth = PasscodeInputElement.PASSCODE_INPUT_SIZE + + PasscodeInputElement.PASSCODE_BOX_SPACING; + const elementBaseWidth = boxWithMarginWidth * this.length; + this.$.container.style.width = elementBaseWidth + + (0.5 * PasscodeInputElement.PASSCODE_INPUT_SIZE) + + PasscodeInputElement.PASSCODE_BOX_SPACING + 'px'; + const inputEl = this.$.inputElement; + inputEl.style.width = (elementBaseWidth + /* input border */ 2) + 'px'; + inputEl.maxLength = this.length; + + // Set event listeners + inputEl.addEventListener('blur', () => { + this.handleOnBlur(); + }); + inputEl.addEventListener('click', () => { + this.renderSelection(); + }); + inputEl.addEventListener('focus', () => { + this.handleOnFocus(); + }); + inputEl.addEventListener('input', () => { + this.handleOnInput(); + }); + inputEl.addEventListener('keyup', () => { + this.renderSelection(); + }); + inputEl.addEventListener('select', () => { + this.renderSelection(); + }); + } + + getCharBox(boxIndex: number) { + const el = this.shadowRoot!.querySelector('#char-box-' + boxIndex)!; + return el as HTMLDivElement; + } + + getDisplayChar(charIndex: number) { + const el = this.shadowRoot!.querySelector('#char-' + charIndex)!; + return el as HTMLParagraphElement; + } + + focusInput() { + this.afterPageLoaded(() => { + this.$.inputElement.focus(); + this.handleOnFocus(); + this.renderSelection(); + }); + } + + private disabledChange() { + this.afterPageLoaded(() => { + if (this.disabled) { + this.forEach('char', (char) => { + char.classList.add('disabled'); + }); + } else { + this.forEach('char', (char) => { + char.classList.remove('disabled'); + }); + } + }); + } + + private valueChange() { + if (this.$.inputElement.value.toUpperCase() !== this.value) { + this.$.inputElement.value = this.value; + } + this.afterPageLoaded(() => { + this.displayChars(); + }); + } + + // Make the char boxes from startIndex to endIndex (including startIndex and + // not including endIndex) active. This highlights these boxes. If only + // startIndex is passed, then make active only that char box. Passing -1 + // makes all boxes inactive. + private makeActive(startIndex: number, endIndex?: number) { + this.forEach('char-box', (charbox, index) => { + if ((!endIndex && index === startIndex) || + (endIndex && index >= startIndex && index < endIndex)) { + charbox.classList.add('active'); + } else { + charbox.classList.remove('active'); + } + }); + } + + private renderSelection() { + if (!this.focused) { + return; + } + + const selectionStart = this.$.inputElement.selectionStart; + const selectionEnd = this.$.inputElement.selectionEnd; + if (selectionStart === null || selectionEnd === null) { + return; + } + + if (selectionStart !== null && selectionStart === selectionEnd) { + if (selectionStart === 0) { + this.makeActive(0); + } else if (selectionStart === this.length || + this.getDisplayChar(selectionStart).innerText.length) { + this.makeActive(selectionStart - 1); + } else { + this.makeActive(selectionStart); + } + this.placeCursor(selectionStart); + } else { + this.removeCursor(); + this.makeActive(selectionStart, selectionEnd); + } + } + + private placeCursor(cursorIndex: number) { + this.removeCursor(); + + if (cursorIndex < this.length && cursorIndex === this.value.length) { + this.getDisplayChar(cursorIndex).classList.add('cursor-empty'); + return; + } + if (cursorIndex === 0) { + this.getDisplayChar(0).classList.add('cursor-start'); + return; + } + this.getDisplayChar(cursorIndex - 1).classList.add('cursor-filled'); + } + + private removeCursor() { + this.forEach('char', (char) => { + char.classList.remove('cursor-filled', 'cursor-empty', 'cursor-start'); + }); + } + + private forEach(elementType: 'char'|'char-box', callback: ForEachCallback) { + let el: HTMLDivElement | HTMLParagraphElement | null; + for (let i = 0; i < this.length; i++) { + el = this.shadowRoot!.querySelector('#' + elementType + '-' + i); + if (el !== null) { + callback(el, i); + } + } + } + + private handleOnFocus() { + this.focused = true; + this.forEach('char-box', (charBox) => { + charBox.classList.add('focused'); + }); + } + + private handleOnBlur() { + this.focused = false; + this.removeCursor(); + this.makeActive(-1); + this.forEach('char-box', (charBox) => { + charBox.classList.remove('focused'); + }); + } + + private handleOnInput() { + this.displayChars(); + this.renderSelection(); + } + + private displayChars() { + const input = this.$.inputElement; + this.set('value', input.value.toUpperCase()); + this.forEach('char', (char, index) => { + char.innerText = index < this.value.length ? this.value[index] : ''; + }); + } + + private async afterPageLoaded(callback: () => void) { + if (this.afterFirstRender) { + callback(); + } else { + afterNextRender(this, callback); + } + } +} + +customElements.define(PasscodeInputElement.is, PasscodeInputElement); \ No newline at end of file
diff --git a/chrome/browser/resources/app_settings/app.html b/chrome/browser/resources/app_settings/app.html index 5836d851..367769f 100644 --- a/chrome/browser/resources/app_settings/app.html +++ b/chrome/browser/resources/app_settings/app.html
@@ -82,6 +82,7 @@ <app-management-file-handling-item class="permission-card-row separated-row" file-handling-header="$i18n{appManagementFileHandlingHeader}" + file-handling-set-defaults="$i18n{fileHandlingSetDefaults}" app="[[app_]]"> </app-management-file-handling-item> <app-management-more-permissions-item
diff --git a/chrome/browser/resources/app_settings/app.ts b/chrome/browser/resources/app_settings/app.ts index f40d432..c42ce81 100644 --- a/chrome/browser/resources/app_settings/app.ts +++ b/chrome/browser/resources/app_settings/app.ts
@@ -11,6 +11,7 @@ import 'chrome://resources/cr_components/app_management/window_mode_item.js'; import 'chrome://resources/cr_components/app_management/icons.js'; import 'chrome://resources/cr_components/app_management/uninstall_button.js'; +import 'chrome://resources/cr_components/localized_link/localized_link.js'; import {App} from 'chrome://resources/cr_components/app_management/app_management.mojom-webui.js'; import {BrowserProxy} from 'chrome://resources/cr_components/app_management/browser_proxy.js';
diff --git a/chrome/browser/resources/app_settings/web_app_settings.ts b/chrome/browser/resources/app_settings/web_app_settings.ts index 268eec0..3224f883 100644 --- a/chrome/browser/resources/app_settings/web_app_settings.ts +++ b/chrome/browser/resources/app_settings/web_app_settings.ts
@@ -10,7 +10,8 @@ export {AppManagementPermissionItemElement} from 'chrome://resources/cr_components/app_management/permission_item.js'; export {createTriStatePermission} from 'chrome://resources/cr_components/app_management/permission_util.js'; export {AppManagementRunOnOsLoginItemElement} from 'chrome://resources/cr_components/app_management/run_on_os_login_item.js'; -export {AppType, InstallReason, OptionalBool, RunOnOsLoginMode, WindowMode} from 'chrome://resources/cr_components/app_management/types.mojom-webui.js'; +export {AppManagementToggleRowElement} from 'chrome://resources/cr_components/app_management/toggle_row.js'; +export {AppType, InstallReason, InstallSource, OptionalBool, RunOnOsLoginMode, WindowMode} from 'chrome://resources/cr_components/app_management/types.mojom-webui.js'; export {getPermissionValueBool} from 'chrome://resources/cr_components/app_management/util.js'; export {AppManagementWindowModeElement} from 'chrome://resources/cr_components/app_management/window_mode_item.js'; export {WebAppSettingsAppElement} from './app.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index b4fb442a..dbaed85 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -47,7 +47,7 @@ "background/editing/intent_handler.js", "background/event_source.js", "background/gesture_command_data.js", - "background/gesture_command_handler.js", + "background/gesture_interface.js", "background/injected_script_loader.js", "background/keyboard_handler.js", "background/keymaps/key_map.js", @@ -126,6 +126,7 @@ "background/es6_loader.js", "background/find_handler.js", "background/focus_automation_handler.js", + "background/gesture_command_handler.js", "background/live_regions.js", "background/media_automation_handler.js", "background/range_automation_handler.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js index 3426cfba3..e758a17b 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
@@ -9,6 +9,7 @@ import {Earcons} from './earcons.js'; import {FindHandler} from './find_handler.js'; import {FocusAutomationHandler} from './focus_automation_handler.js'; +import {GestureCommandHandler} from './gesture_command_handler.js'; import {LiveRegions} from './live_regions.js'; import {MediaAutomationHandler} from './media_automation_handler.js'; import {PageLoadSoundHandler} from './page_load_sound_handler.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js index 0949016f..5957c9d 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
@@ -12,8 +12,7 @@ */ ChromeVoxBackgroundTest = class extends ChromeVoxNextE2ETest { /** @override */ - setUp() { - super.setUp(); + async setUpDeferred() { window.doGesture = this.doGesture; window.simulateHitTestResult = this.simulateHitTestResult; window.press = this.press; @@ -21,6 +20,11 @@ window.ActionType = chrome.automation.ActionType; this.forceContextualLastOutput(); + + await importModule( + 'GestureCommandHandler', + '/chromevox/background/gesture_command_handler.js'); + await super.setUpDeferred(); } simulateHitTestResult(node) {
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 97099e5..900d039 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
@@ -306,15 +306,15 @@ case 'nextGranularity': case 'previousGranularity': { const backwards = command === 'previousGranularity'; - let gran = GestureCommandHandler.granularity; + let gran = GestureInterface.getGranularity(); const next = backwards ? (--gran >= 0 ? gran : GestureGranularity.COUNT - 1) : ++gran % GestureGranularity.COUNT; - GestureCommandHandler.granularity = - /** @type {GestureGranularity} */ (next); + GestureInterface.setGranularity( + /** @type {GestureGranularity} */ (next)); let announce = ''; - switch (GestureCommandHandler.granularity) { + switch (GestureInterface.getGranularity()) { case GestureGranularity.CHARACTER: announce = Msgs.getMsg('character_granularity'); break; @@ -1042,7 +1042,7 @@ case 'nextAtGranularity': case 'previousAtGranularity': const backwards = command === 'previousAtGranularity'; - switch (GestureCommandHandler.granularity) { + switch (GestureInterface.getGranularity()) { case GestureGranularity.CHARACTER: command = backwards ? 'previousCharacter' : 'nextCharacter'; break;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_command_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_command_handler.js index 0d5211c..f28d154 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_command_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_command_handler.js
@@ -6,19 +6,11 @@ * @fileoverview Handles gesture-based commands. */ -goog.provide('GestureCommandHandler'); - -goog.require('ChromeVoxState'); -goog.require('CommandHandlerInterface'); -goog.require('EventGenerator'); -goog.require('EventSourceState'); -goog.require('GestureCommandData'); -goog.require('PointerHandler'); - -goog.scope(function() { const RoleType = chrome.automation.RoleType; const Gesture = chrome.accessibilityPrivate.Gesture; +export const GestureCommandHandler = {}; + /** * Global setting for the enabled state of this handler. * @param {boolean} state @@ -26,6 +18,12 @@ GestureCommandHandler.setEnabled = function(state) { GestureCommandHandler.enabled_ = state; }; +chrome.runtime.onMessage.addListener((message) => { + if (message.target === 'GestureCommandHandler' && + message.action === 'setEnabled') { + GestureCommandHandler.setEnabled(message.value); + } +}); /** * Global setting for the enabled state of this handler. @@ -126,6 +124,10 @@ GestureCommandHandler.onAccessibilityGesture_); GestureCommandHandler.pointerHandler_ = new PointerHandler(); + + GestureInterface.granularityGetter = () => GestureCommandHandler.granularity; + GestureInterface.granularitySetter = (granularity) => + GestureCommandHandler.granularity = granularity; }; /** @@ -135,4 +137,3 @@ GestureCommandHandler.granularity = GestureGranularity.LINE; GestureCommandHandler.init_(); -}); // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_interface.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_interface.js new file mode 100644 index 0000000..551ae2df --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_interface.js
@@ -0,0 +1,38 @@ +// 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. + +/** + * @fileoverview Interface to prevent circular dependencies between + * CommandHandler and GestureCommandHandler. + */ + +goog.provide('GestureInterface'); + +goog.require('GestureGranularity'); + +goog.scope(function() { +/** @return {GestureGranularity} */ +GestureInterface.getGranularity = function() { + if (GestureInterface.granularityGetter) { + return GestureInterface.granularityGetter(); + } else { + throw new Error('GestureInterface not initialized before access.'); + } +}; + +/** @param {GestureGranularity} granularity */ +GestureInterface.setGranularity = function(granularity) { + if (GestureInterface.granularitySetter) { + GestureInterface.granularitySetter(granularity); + } else { + throw new Error('GestureInterface not initialized before setting a value.'); + } +}; + +/** @public {?function(): GestureGranularity} */ +GestureInterface.granularityGetter = null; + +/** @public {?function(GestureGranularity)} */ +GestureInterface.granularitySetter = null; +}); // goog.scope
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js index b64c921..377e55b 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
@@ -8,20 +8,30 @@ goog.require('AutomationPredicate'); goog.require('AutomationUtil'); +goog.require('AutoScrollHandler'); goog.require('BackgroundKeyboardHandler'); goog.require('BrailleCommandData'); goog.require('BrailleCommandHandler'); goog.require('BrailleKeyCommand'); goog.require('ChromeVoxBackground'); goog.require('ChromeVoxEditableTextBase'); +goog.require('ChromeVoxKbHandler'); +goog.require('ChromeVoxPrefs'); goog.require('ChromeVoxState'); +goog.require('Color'); goog.require('CommandHandlerInterface'); goog.require('CommandStore'); +goog.require('CustomAutomationEvent'); goog.require('DesktopAutomationHandler'); +goog.require('EventGenerator'); +goog.require('EventSourceState'); goog.require('ExtensionBridge'); -goog.require('GestureCommandHandler'); +goog.require('GestureCommandData'); +goog.require('GestureInterface'); goog.require('JaPhoneticMap'); +goog.require('KeyCode'); goog.require('LocaleOutputHelper'); +goog.require('LogStore'); goog.require('MathHandler'); goog.require('NavBraille'); goog.require('Output'); @@ -29,5 +39,7 @@ goog.require('PanelCommand'); goog.require('PhoneticData'); goog.require('SmartStickyMode'); +goog.require('PointerHandler'); +goog.require('TreeDumper'); goog.require('constants'); goog.require('cursors.Cursor');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/kbexplorer.js b/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/kbexplorer.js index f836f07..ec59fe3 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/kbexplorer.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/kbexplorer.js
@@ -46,7 +46,8 @@ KbExplorer.onAccessibilityGesture); chrome.accessibilityPrivate.setKeyboardListener(true, true); window.backgroundWindow['BrailleCommandHandler']['setEnabled'](false); - window.backgroundWindow['GestureCommandHandler']['setEnabled'](false); + chrome.runtime.sendMessage( + {target: 'GestureCommandHandler', action: 'setEnabled', value: false}); ChromeVoxKbHandler.handlerKeyMap = KeyMap.get(); @@ -296,7 +297,8 @@ KbExplorer.onAccessibilityGesture); chrome.accessibilityPrivate.setKeyboardListener(true, false); window.backgroundWindow['BrailleCommandHandler']['setEnabled'](true); - window.backgroundWindow['GestureCommandHandler']['setEnabled'](true); + chrome.runtime.sendMessage( + {target: 'GestureCommandHandler', action: 'setEnabled', value: true}); } /** @private */
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test_base.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test_base.js index ff4fef9..9a8fe3fb0 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test_base.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test_base.js
@@ -27,4 +27,4 @@ getPanel() { return this.getPanelWindow().Panel; } -}; \ No newline at end of file +};
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js index 9776fa2..e9c1de9 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js
@@ -117,6 +117,9 @@ await super.setUpDeferred(); await importModule( 'CommandHandler', '/chromevox/background/command_handler.js'); + await importModule( + 'GestureCommandHandler', + '/chromevox/background/gesture_command_handler.js'); } /** @override */
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/mock_tts.js b/chrome/browser/resources/chromeos/accessibility/common/testing/mock_tts.js similarity index 93% rename from chrome/browser/resources/chromeos/accessibility/select_to_speak/mock_tts.js rename to chrome/browser/resources/chromeos/accessibility/common/testing/mock_tts.js index 29c4ddc..74b0fadb 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/mock_tts.js +++ b/chrome/browser/resources/chromeos/accessibility/common/testing/mock_tts.js
@@ -4,9 +4,9 @@ /* * A mock text-to-speech engine for tests. - * This class has functions and callbacks necessary for Select-to-Speak - * to function. It keeps track of the utterances currently being spoken, - * and whether TTS should be speaking or is stopped. + * This class has functions and callbacks necessary for accessibility extensions + * (Select-to-Speak, ChromeVox) to function. It keeps track of the utterances + * currently being spoken, and whether TTS should be speaking or is stopped. * @constructor */ var MockTts = function() {
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn index 0d12bd2..3911f33 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
@@ -106,7 +106,7 @@ "../common/testing/callback_helper.js", "../common/testing/e2e_test_base.js", "../common/testing/mock_storage.js", - "mock_tts.js", + "../common/testing/mock_tts.js", "select_to_speak_e2e_test_base.js", "pipe.jpg", ]
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js index 5fb7ff8a..ae41a7e5 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js
@@ -5,7 +5,7 @@ GEN_INCLUDE(['../../../../../../ui/webui/resources/js/cr.js']); GEN_INCLUDE(['fake_chrome_event.js']); GEN_INCLUDE(['select_to_speak_e2e_test_base.js']); -GEN_INCLUDE(['mock_tts.js']); +GEN_INCLUDE(['../common/testing/mock_tts.js']); GEN_INCLUDE(['fake_settings_private.js']); SelectToSpeakEnhancedNetworkTtsVoicesTest = class extends SelectToSpeakE2ETest {
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_keystroke_selection_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_keystroke_selection_test.js index 6b4c82f..900e40c 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_keystroke_selection_test.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_keystroke_selection_test.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. GEN_INCLUDE(['select_to_speak_e2e_test_base.js']); -GEN_INCLUDE(['mock_tts.js']); +GEN_INCLUDE(['../common/testing/mock_tts.js']); /** * Browser tests for select-to-speak's feature to speak text
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_mouse_selection_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_mouse_selection_test.js index 6900d4689..8cbdf97 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_mouse_selection_test.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_mouse_selection_test.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. GEN_INCLUDE(['select_to_speak_e2e_test_base.js']); -GEN_INCLUDE(['mock_tts.js']); +GEN_INCLUDE(['../common/testing/mock_tts.js']); /** * Browser tests for select-to-speak's feature to speak text
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_navigation_control_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_navigation_control_test.js index 0c93ef5..46b410a 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_navigation_control_test.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_navigation_control_test.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. GEN_INCLUDE(['select_to_speak_e2e_test_base.js']); -GEN_INCLUDE(['mock_tts.js']); +GEN_INCLUDE(['../common/testing/mock_tts.js']); /** * Browser tests for select-to-speak's navigation control features.
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/tts_manager_unittest.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/tts_manager_unittest.js index d20ca8a9d..831a03e 100644 --- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/tts_manager_unittest.js +++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/tts_manager_unittest.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. GEN_INCLUDE(['select_to_speak_e2e_test_base.js']); -GEN_INCLUDE(['mock_tts.js']); +GEN_INCLUDE(['../common/testing/mock_tts.js']); /** Mock TTS client. */ class MockTtsClient {
diff --git a/chrome/browser/resources/nearby_share/shared/BUILD.gn b/chrome/browser/resources/nearby_share/shared/BUILD.gn index 167aff8..538f707 100644 --- a/chrome/browser/resources/nearby_share/shared/BUILD.gn +++ b/chrome/browser/resources/nearby_share/shared/BUILD.gn
@@ -179,6 +179,7 @@ ":nearby_page_template", ":nearby_share_settings_behavior", "//ui/webui/resources/js:i18n_behavior", + "//ui/webui/resources/js:load_time_data", ] } @@ -357,6 +358,7 @@ ":nearby_share_settings_behavior.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/js:i18n_behavior.m", + "//ui/webui/resources/js:load_time_data", ] extra_deps = [ ":nearby_visibility_page_module" ] }
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.js b/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.js index bf2c324..cbd0839 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.js +++ b/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.js
@@ -601,6 +601,18 @@ }, /** + * Return the selected visibility as a enum to nearby_visibiity_page when + * logging metric to avoid potential race condition + * + * @return {?nearbyShare.mojom.Visibility} + * + * @public + */ + getSelectedVisibility() { + return visibilityStringToValue(this.selectedVisibility); + }, + + /** * Returns the icon based on Light/Dark mode. * @returns {string} * @private
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_metrics_logger.js b/chrome/browser/resources/nearby_share/shared/nearby_metrics_logger.js index b26b79c..839d2e1 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_metrics_logger.js +++ b/chrome/browser/resources/nearby_share/shared/nearby_metrics_logger.js
@@ -16,7 +16,8 @@ DEVICE_NAME_PAGE: 0, VISIBILITY_PAGE: 1, COMPLETE: 2, - MAX: 3, + INITIAL_PAGE: 3, + MAX: 4, }; /** @@ -35,12 +36,35 @@ MAX: 4, }; +/** + * This enum is tied directly to a UMA enum defined in + * //tools/metrics/histograms/enums.xml, and should always reflect it (do not + * change one without changing the other). + * These values are persisted to logs. Entries should not be renumbered and + * numeric values should never be reused. + * @enum {number} + */ +const NearbyShareOnboardingFlowEvent = { + ONBOARDING_SHOWN: 1, + CONFIRM_ON_INITIAL_PAGE: 12, + CANCEL_ON_INITIAL_PAGE: 13, + VISIBILITY_CLICKED_ON_INITIAL_PAGE: 14, + DEVICE_VISIBILITY_PAGE_SHOWN: 141, + ALL_CONTACTS_SELECTED_AND_CONFIRMED: 1412, + SOME_CONTACTS_SELECTED_AND_CONFIRMED: 1413, + HIDDEN_SELECTED_AND_CONFIRMED: 1414, + MANAGE_CONTACTS_SELECTED: 1415, + CANCEL_SELECTED_ON_VISIBILITY_PAGE: 1416, +}; + const NearbyShareOnboardingResultHistogramName = 'Nearby.Share.Onboarding.Result'; const NearbyShareOnboardingEntryPointHistogramName = 'Nearby.Share.Onboarding.EntryPoint'; const NearbyShareOnboardingDurationHistogramName = 'Nearby.Share.Onboarding.Duration'; +const NearbyShareOnboardingFlowEventHistogramName = + 'Nearby.Share.Onboarding.FlowEvent'; /** * Tracks time that onboarding is started. Gets set to null after onboarding is @@ -64,7 +88,36 @@ const urlParams = new URLSearchParams(url.search); nearbyShareOnboardingEntryPoint = - getOnboardingEntrypointFromQueryParam(urlParams.get('entrypoint')); + getOnboardingEntrypointFromQueryParam_(urlParams.get('entrypoint')); + } else { + assertNotReached('Invalid nearbyShareOnboardingEntryPoint'); + } + + chrome.send('metricsHandler:recordInHistogram', [ + NearbyShareOnboardingEntryPointHistogramName, + nearbyShareOnboardingEntryPoint, NearbyShareOnboardingEntryPoint.MAX + ]); + // Set time at which onboarding was initiated to track duration. + onboardingInitiatedTimestamp = window.performance.now(); +} + +/** + * Records the one-page onboarding flow entrypoint and stores the time at which + * one-page onboarding was initiated. The url param is used to infer the + * entrypoint. + * @param {URL} url + */ +/* #export */ function processOnePageOnboardingInitiatedMetrics(url) { + let nearbyShareOnboardingEntryPoint; + + if (url.hostname === 'nearby') { + nearbyShareOnboardingEntryPoint = + NearbyShareOnboardingEntryPoint.SHARE_SHEET; + } else if (url.hostname === 'os-settings') { + const urlParams = new URLSearchParams(url.search); + + nearbyShareOnboardingEntryPoint = + getOnboardingEntrypointFromQueryParam_(urlParams.get('entrypoint')); } else { assertNotReached('Invalid nearbyShareOnboardingEntryPoint'); } @@ -74,6 +127,11 @@ nearbyShareOnboardingEntryPoint, NearbyShareOnboardingEntryPoint.MAX ]); + chrome.send('metricsHandler:recordSparseHistogram', [ + NearbyShareOnboardingFlowEventHistogramName, + NearbyShareOnboardingFlowEvent.ONBOARDING_SHOWN + ]); + // Set time at which onboarding was initiated to track duration. onboardingInitiatedTimestamp = window.performance.now(); } @@ -81,8 +139,10 @@ /** * @param {?string} queryParam * @return {NearbyShareOnboardingEntryPoint} + * + * @private */ -function getOnboardingEntrypointFromQueryParam(queryParam) { +function getOnboardingEntrypointFromQueryParam_(queryParam) { switch (queryParam) { case 'settings': return NearbyShareOnboardingEntryPoint.SETTINGS; @@ -113,6 +173,48 @@ } /** + * If one-page onboarding was cancelled this function is invoked to record + * during which step the cancellation occurred. + * + * @param {NearbyShareOnboardingFinalState} nearbyShareOnboardingFinalState + */ +/* #export */ function processOnePageOnboardingCancelledMetrics( + nearbyShareOnboardingFinalState) { + if (!onboardingInitiatedTimestamp) { + return; + } + chrome.send('metricsHandler:recordInHistogram', [ + NearbyShareOnboardingResultHistogramName, nearbyShareOnboardingFinalState, + NearbyShareOnboardingFinalState.MAX + ]); + + chrome.send('metricsHandler:recordSparseHistogram', [ + NearbyShareOnboardingFlowEventHistogramName, + getOnboardingCancelledFlowEvent_(nearbyShareOnboardingFinalState) + ]); + onboardingInitiatedTimestamp = null; +} + +/** + * Get the corresponding onboarding canceling event. + * + * @param {NearbyShareOnboardingFinalState} nearbyShareOnboardingFinalState + * @returns {NearbyShareOnboardingFlowEvent} + * + * @private + */ +function getOnboardingCancelledFlowEvent_(nearbyShareOnboardingFinalState) { + switch (nearbyShareOnboardingFinalState) { + case NearbyShareOnboardingFinalState.INITIAL_PAGE: + return NearbyShareOnboardingFlowEvent.CANCEL_ON_INITIAL_PAGE; + case NearbyShareOnboardingFinalState.VISIBILITY_PAGE: + return NearbyShareOnboardingFlowEvent.CANCEL_SELECTED_ON_VISIBILITY_PAGE; + default: + assertNotReached('Invalid final state for cancel event'); + } +} + +/** * Records a metric for successful onboarding flow completion and the time it * took to complete. */ @@ -133,3 +235,113 @@ onboardingInitiatedTimestamp = null; } + +/** + * Records a metric for successful one-page onboarding flow completion and the + * time it took to complete. + * + * @param {NearbyShareOnboardingFinalState} nearbyShareOnboardingFinalState + * @param {?nearbyShare.mojom.Visibility} visibility + */ +/* #export */ function processOnePageOnboardingCompleteMetrics( + nearbyShareOnboardingFinalState, visibility) { + if (!onboardingInitiatedTimestamp) { + return; + } + + chrome.send('metricsHandler:recordSparseHistogram', [ + NearbyShareOnboardingFlowEventHistogramName, + getOnboardingCompleteFlowEvent_(nearbyShareOnboardingFinalState, visibility) + ]); + + chrome.send('metricsHandler:recordInHistogram', [ + NearbyShareOnboardingResultHistogramName, + NearbyShareOnboardingFinalState.COMPLETE, + NearbyShareOnboardingFinalState.MAX + ]); + + chrome.send('metricsHandler:recordMediumTime', [ + NearbyShareOnboardingDurationHistogramName, + window.performance.now() - onboardingInitiatedTimestamp + ]); + + onboardingInitiatedTimestamp = null; +} + +/** + * Gets the corresponding onboarding complete flow event based on final state + * and visibility selected. + * + * @param {NearbyShareOnboardingFinalState} nearbyShareOnboardingFinalState + * @param {?nearbyShare.mojom.Visibility} visibility + * @returns {NearbyShareOnboardingFlowEvent} + * + * @private + */ +function getOnboardingCompleteFlowEvent_( + nearbyShareOnboardingFinalState, visibility) { + switch (nearbyShareOnboardingFinalState) { + case NearbyShareOnboardingFinalState.INITIAL_PAGE: + return NearbyShareOnboardingFlowEvent.CONFIRM_ON_INITIAL_PAGE; + case NearbyShareOnboardingFinalState.VISIBILITY_PAGE: + return getOnboardingCompleteFlowEventOnVisibilityPage_(visibility); + default: + assertNotReached('Invalid final state'); + } +} + +/** + * Gets the corresponding onboarding complete flow event on visibility + * selection page based on final visibility selected. + * + * @param {?nearbyShare.mojom.Visibility} visibility + * @returns {NearbyShareOnboardingFlowEvent} + * + * @private + */ +function getOnboardingCompleteFlowEventOnVisibilityPage_(visibility) { + switch (visibility) { + case nearbyShare.mojom.Visibility.kAllContacts: + return NearbyShareOnboardingFlowEvent.ALL_CONTACTS_SELECTED_AND_CONFIRMED; + case nearbyShare.mojom.Visibility.kSelectedContacts: + return NearbyShareOnboardingFlowEvent + .SOME_CONTACTS_SELECTED_AND_CONFIRMED; + case nearbyShare.mojom.Visibility.kNoOne: + return NearbyShareOnboardingFlowEvent.HIDDEN_SELECTED_AND_CONFIRMED; + default: + assertNotReached('Invalid visibility'); + } +} + +/** + * Records a metric for users clicking the visibility selection button on + * the initial onboarding page. + */ +/* #export */ +function processOnePageOnboardingVisibilityButtonOnInitialPageClickedMetrics() { + chrome.send('metricsHandler:recordSparseHistogram', [ + NearbyShareOnboardingFlowEventHistogramName, + NearbyShareOnboardingFlowEvent.VISIBILITY_CLICKED_ON_INITIAL_PAGE + ]); +} + +/** + * Records a metrics for successfully displaying visibility selection page. + */ +/* #export */ function processOnePageOnboardingVisibilityPageShownMetrics() { + chrome.send('metricsHandler:recordSparseHistogram', [ + NearbyShareOnboardingFlowEventHistogramName, + NearbyShareOnboardingFlowEvent.DEVICE_VISIBILITY_PAGE_SHOWN + ]); +} + +/** + * Records a metrics for users clicking Manage Contacts button on the + * visibility selection page. + */ +/* #export */ function processOnePageOnboardingManageContactsMetrics() { + chrome.send('metricsHandler:recordSparseHistogram', [ + NearbyShareOnboardingFlowEventHistogramName, + NearbyShareOnboardingFlowEvent.MANAGE_CONTACTS_SELECTED + ]); +}
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_onboarding_one_page.js b/chrome/browser/resources/nearby_share/shared/nearby_onboarding_one_page.js index 2c26c08..fd00f03 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_onboarding_one_page.js +++ b/chrome/browser/resources/nearby_share/shared/nearby_onboarding_one_page.js
@@ -61,7 +61,8 @@ /** @private */ onClose_() { - // TODO(crbug.com/1265562): Add new metrics + processOnePageOnboardingCancelledMetrics( + NearbyShareOnboardingFinalState.INITIAL_PAGE); this.fire('onboarding-cancelled'); }, @@ -80,7 +81,7 @@ /** @private */ onViewEnterStart_() { this.$$('#deviceName').focus(); - // TODO(crbug.com/1265562): Add new metrics + processOnePageOnboardingInitiatedMetrics(new URL(document.URL)); }, /** @private */ @@ -108,6 +109,9 @@ this.set('settings.visibility', this.getDefaultVisibility_()); this.set('settings.isOnboardingComplete', true); this.set('settings.enabled', true); + processOnePageOnboardingCompleteMetrics( + NearbyShareOnboardingFinalState.INITIAL_PAGE, + this.getDefaultVisibility_()); this.fire('onboarding-complete'); } }); @@ -125,6 +129,7 @@ * nearby_share_prefs.cc:kNearbySharingBackgroundVisibilityName */ this.set('settings.visibility', this.getDefaultVisibility_()); + processOnePageOnboardingVisibilityButtonOnInitialPageClickedMetrics(); this.fire('change-page', {page: 'visibility'}); }, @@ -181,7 +186,7 @@ * setting visibility selection to 'all contacts' in nearby_visibility_page in * existing onboarding workflow. * - * @return {number} default visibility + * @return {?nearbyShare.mojom.Visibility} default visibility * * TODO(crbug.com/1265562): remove this function once the old onboarding is * deprecated and default visibility is changed in @@ -226,7 +231,7 @@ case nearbyShare.mojom.Visibility.kSelectedContacts: return 'contact-group'; case nearbyShare.mojom.Visibility.kNoOne: - return 'visibility-off"'; + return 'visibility-off'; default: return 'contact-all'; }
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_shared.gni b/chrome/browser/resources/nearby_share/shared/nearby_shared.gni index 49b63283..88a9846 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_shared.gni +++ b/chrome/browser/resources/nearby_share/shared/nearby_shared.gni
@@ -8,7 +8,7 @@ "chrome/browser/resources/nearby_share/shared/nearby_contact_manager.html|getContactManager,observeContactManager", "ui/webui/resources/html/assert.html|assert,assertNotReached", "ui/webui/resources/html/cr.html|sendWithPromise", - "chrome/browser/resources/nearby_share/shared/nearby_metrics_logger.html|processOnboardingInitiatedMetrics,processOnboardingCompleteMetrics,processOnboardingCancelledMetrics,NearbyShareOnboardingFinalState", + "chrome/browser/resources/nearby_share/shared/nearby_metrics_logger.html|processOnboardingInitiatedMetrics,processOnboardingCompleteMetrics,processOnboardingCancelledMetrics,NearbyShareOnboardingFinalState,processOnePageOnboardingInitiatedMetrics,processOnePageOnboardingCancelledMetrics,processOnePageOnboardingCompleteMetrics,processOnePageOnboardingVisibilityButtonOnInitialPageClickedMetrics,processOnePageOnboardingVisibilityPageShownMetrics,processOnePageOnboardingManageContactsMetrics", ] nearby_shared_namespace_rewrites = [
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js b/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js index 7bd854a..906c46a0 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js +++ b/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js
@@ -33,7 +33,17 @@ listeners: { 'next': 'onNext_', 'manage-contacts': 'onManageContacts_', - 'close': 'onClose_' + 'close': 'onClose_', + 'view-enter-start': 'onVisibilityViewEnterStart_', + }, + + /** + * Determines if the feature flag for One-page onboarding workflow is enabled. + * @return {boolean} whether the one-page onboarding is enabled + * @private + */ + isOnePageOnboardingEnabled_() { + return loadTimeData.getBoolean('isOnePageOnboardingEnabled'); }, /** @private */ @@ -43,19 +53,41 @@ contactVisibility.saveVisibilityAndAllowedContacts(); this.set('settings.isOnboardingComplete', true); this.set('settings.enabled', true); - processOnboardingCompleteMetrics(); + if (this.isOnePageOnboardingEnabled_()) { + processOnePageOnboardingCompleteMetrics( + NearbyShareOnboardingFinalState.VISIBILITY_PAGE, + contactVisibility.getSelectedVisibility()); + } else { + processOnboardingCompleteMetrics(); + } + this.fire('onboarding-complete'); }, /** @private */ onClose_() { - processOnboardingCancelledMetrics( - NearbyShareOnboardingFinalState.VISIBILITY_PAGE); + if (this.isOnePageOnboardingEnabled_()) { + processOnePageOnboardingCancelledMetrics( + NearbyShareOnboardingFinalState.VISIBILITY_PAGE); + } else { + processOnboardingCancelledMetrics( + NearbyShareOnboardingFinalState.VISIBILITY_PAGE); + } this.fire('onboarding-cancelled'); }, /** @private */ + onVisibilityViewEnterStart_() { + if (this.isOnePageOnboardingEnabled_()) { + processOnePageOnboardingVisibilityPageShownMetrics(); + } + }, + + /** @private */ onManageContacts_() { + if (this.isOnePageOnboardingEnabled_()) { + processOnePageOnboardingManageContactsMetrics(); + } window.open(this.i18n('nearbyShareManageContactsUrl'), '_blank'); },
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_card.html b/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_card.html index 37603bdd..7a6bad5 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_card.html +++ b/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_card.html
@@ -19,12 +19,12 @@ background-color: var(--google-blue-100); } - .favicon-container { + #faviconContainer { text-align: center; width: auto; } - .favicon-container ul { + #faviconContainer ul { list-style-type: none; margin-block-end: 0; margin-block-start: 0; @@ -32,7 +32,7 @@ padding: 0; } - .favicon-container li { + #faviconContainer li { display: inline; margin-inline-end: -6px; } @@ -133,3 +133,7 @@ on-click="onCloseClick_"></cr-icon-button> </template> </div> +<template is="dom-if" if="[[showDiscountConsentDialog_]]" restamp> + <discount-consent-dialog id="discountConsentDialog" + on-close="onDiscountConsentDialogClose_"]></discount-consent-dialog> +</template>
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_card.ts b/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_card.ts index 88b8056..a3fd4ae 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_card.ts +++ b/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_card.ts
@@ -42,6 +42,18 @@ cancelButton?: ButtonInfo; } +/** + * Indicate the variation of the consent card. + * * Default, StringChange, and Dialog has one step. + * * Inline has two steps. + */ +export enum DiscountConsentVariation { + Default = 0, + StringChange = 1, + Inline = 2, + Dialog = 3 +} + // This is a configurable multi-step card. Each step is represented by the Step // interface. export class DiscountConsentCard extends I18nMixin @@ -56,9 +68,12 @@ static get properties() { return { - merchants: {type: Array, observer: 'onMerchantsChanged_'}, + merchants: Array, currentStep: {type: Number, value: 0}, - steps_: {type: Array, computed: 'computeSteps_(showCloseButton_)'}, + steps_: { + type: Array, + computed: 'computeSteps_(showCloseButton_, stepOneContent_)' + }, colorConsentContainer_: { type: Boolean, computed: 'computeColorConsentContainer_(currentStep)', @@ -68,7 +83,10 @@ type: Boolean, value: () => loadTimeData.getBoolean( 'modulesCartDiscountInlineCardShowCloseButton') - } + }, + stepOneContent_: + {type: String, computed: 'computeStepOneContent_(merchants)'}, + showDiscountConsentDialog_: {type: Boolean, value: false} }; } @@ -83,21 +101,21 @@ // This is a Finch parameter that decides whether we should change container // background color. private colorConsentContainer_: boolean; + private stepOneContent_: string; + private showDiscountConsentDialog_: boolean; + private getTotalStep_(): number { - // TODO(crbug.com/1298116): Return number based on finch flags. If - // inline-variation return 2, otherwise return 1. - return 2; - } - - private getStepOneContent_(): string { - // TODO(crbug.com/1298116): Return strings based on finch flags. - return loadTimeData.getString('modulesCartDiscountConsentContent'); + // Inline-variation is 2, see ntp_feature::DiscountConsentNtpVariation. + if (loadTimeData.getInteger('modulesCartDiscountConsentVariation') === + DiscountConsentVariation.Inline) { + return 2; + } + return 1; } private getStepTwoContent_(): string { - // TODO(crbug.com/1298116): Return strings based on finch flags. - return loadTimeData.getString('modulesCartDiscountConsentContent'); + return loadTimeData.getString('modulesCartConsentStepTwoContent'); } private computeColorConsentContainer_(currentStep: number) { @@ -105,27 +123,30 @@ currentStep === 1; } - private computeSteps_(showCloseButton: boolean): Array<Step> { + private computeSteps_( + showCloseButton: boolean, stepOneContent: string): Array<Step> { const steps = []; steps.push({ id: 'step1', - content: this.getStepOneContent_(), + content: stepOneContent, hasOneButton: true, actionButton: { - // TODO(crbug.com/1298116): Load string from resource. - text: 'continue', + text: loadTimeData.getString('modulesCartConsentStepOneButton'), onClickHandler: () => { - if (this.currentStep < this.getTotalStep_()) { + if (this.currentStep + 1 < this.getTotalStep_()) { this.currentStep++; } else { - // TODO(crbug.com/1298116): Show DiscountConsentDialog. + this.showDiscountConsentDialog_ = true; } // TODO(crbug.com/1298116): Record user click on this button. }, } }); - // TODO(crbug.com/1298116): Gate second step with a finch flag. + if (this.getTotalStep_() === 1) { + return steps; + } + const step2: Step = { id: 'step2', content: this.getStepTwoContent_(), @@ -153,14 +174,27 @@ return steps; } - private onMerchantsChanged_() { - if (this.currentStep === 0) { - // TODO(crbug.com/1298116): Build strings with merchant names and string - // template from resource. We should also handle the case where the string - // gets too long here. - this.steps_[0].content = this.merchants[0].merchant + ', ' + - this.merchants[1].merchant + ' and more'; + private computeStepOneContent_(merchants: MerchantCart[]): string { + const stepOneUseStaticContent = + loadTimeData.getBoolean('modulesCartStepOneUseStaticContent'); + if (!stepOneUseStaticContent) { + // TODO(crbug.com/1298116): We should also handle the case where the + // string gets too long here. + if (merchants.length === 1) { + return loadTimeData.getStringF( + 'modulesCartConsentStepOneOneMerchantContent', + merchants[0].merchant); + } else if (merchants.length === 2) { + return loadTimeData.getStringF( + 'modulesCartConsentStepOneTwoMerchantsContent', + merchants[0].merchant, merchants[1].merchant); + } else if (merchants.length >= 3) { + return loadTimeData.getStringF( + 'modulesCartConsentStepOneThreeMerchantsContent', + merchants[0].merchant, merchants[1].merchant); + } } + return loadTimeData.getString('modulesCartStepOneStaticContent'); } private getFaviconUrl_(url: string): string { @@ -181,6 +215,10 @@ new CustomEvent('discount-consent-rejected', {composed: true})); } } + + private onDiscountConsentDialogClose_() { + this.showDiscountConsentDialog_ = false; + } }
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_dialog.html b/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_dialog.html index 4e69c07e..af744427 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_dialog.html +++ b/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_dialog.html
@@ -49,7 +49,7 @@ <cr-dialog id="dialog" show-close-button on-cancel="onDismissClick_" show-on-attach> - <div slot="title">[[dialogTitle]]</div> + <div slot="title">$i18n{modulesCartSentence}</div> <div slot="body"> <div id="content-container"> <div id="content-title">$i18n{modulesCartDiscountConentTitle}</div>
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_dialog.ts b/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_dialog.ts index 00efd2073..da06b8a 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_dialog.ts +++ b/chrome/browser/resources/new_tab_page/modules/cart/discount_consent_dialog.ts
@@ -7,11 +7,8 @@ import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; -import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {loadTimeData} from '../../i18n_setup.js'; - import {getTemplate} from './discount_consent_dialog.html.js'; export interface DiscountConsentDialog { @@ -31,12 +28,6 @@ return getTemplate(); } - static get properties() { - return {dialogTitle: String}; - } - - dialogTitle: string; - private onRejectClick_() { this.$.dialog.close(); this.dispatchEvent(
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/module.html b/chrome/browser/resources/new_tab_page/modules/cart/module.html index a6bd640..3254f24 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/module.html +++ b/chrome/browser/resources/new_tab_page/modules/cart/module.html
@@ -299,26 +299,34 @@ <div id="leftProbe" class="probe"></div> <template id="consentCardElement" is="dom-if" if="[[showDiscountConsent]]"> - <div id="consentCard"> - <div id="consentIconContainer"> - <div id="consentIcon"></div> + <!-- TODO(crbug.com/1298116): Move this template to + discount_consent_card. --> + <template is="dom-if" if="[[!discountConsentHasTwoSteps_]]" restamp> + <div id="consentCard"> + <div id="consentIconContainer"> + <div id="consentIcon"></div> + </div> + <span id="consentContent"> + $i18n{modulesCartDiscountConsentContent} + </span> + <div id="consentButtonContainer"> + <cr-button id="cancelButton" + class="cancel-button" on-click="onDiscountConsentRejected_" + on-auxclick="onDisallowDiscount_"> + $i18n{modulesCartDiscountConsentReject} + </cr-button> + <cr-button id="actionButton" + class="action-button" on-click="onDiscountConsentAccepted_" + on-auxclick="onAllowDiscount_"> + $i18n{modulesCartDiscountConsentAccept} + </cr-button> + </div> </div> - <span id="consentContent"> - $i18n{modulesCartDiscountConsentContent} - </span> - <div id="consentButtonContainer"> - <cr-button id="cancelButton" - class="cancel-button" on-click="onDisallowDiscount_" - on-auxclick="onDisallowDiscount_"> - $i18n{modulesCartDiscountConsentReject} - </cr-button> - <cr-button id="actionButton" - class="action-button" on-click="onAllowDiscount_" - on-auxclick="onAllowDiscount_"> - $i18n{modulesCartDiscountConsentAccept} - </cr-button> - </div> - </div> + </template> + <template is="dom-if" if="[[discountConsentHasTwoSteps_]]" restamp> + <discount-consent-card id="consentCardV2" + merchants="[[firstThreeCartItems_]]"></discount-consent-card> + </template> </template> <template id="cartItemRepeat" is="dom-repeat" items="[[cartItems]]"> <div class="cart-container">
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/module.ts b/chrome/browser/resources/new_tab_page/modules/cart/module.ts index 9ee179d..61be33f 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/cart/module.ts
@@ -12,6 +12,7 @@ import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; +import {EventTracker} from 'chrome://resources/js/event_tracker.m.js'; import {DomIf, DomRepeat, DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {MerchantCart} from '../../chrome_cart.mojom-webui.js'; @@ -20,6 +21,7 @@ import {ModuleDescriptor} from '../module_descriptor.js'; import {ChromeCartProxy} from './chrome_cart_proxy.js'; +import {DiscountConsentVariation} from './discount_consent_card.js'; import {getTemplate} from './module.html.js'; export interface ChromeCartModuleElement { @@ -76,6 +78,14 @@ }, confirmDiscountConsentString_: String, + discountConsentHasTwoSteps_: { + type: Boolean, + value: () => + loadTimeData.getInteger('modulesCartDiscountConsentVariation') > + DiscountConsentVariation.StringChange + }, + firstThreeCartItems_: + {type: Array, computed: 'computeFirstThreeCartItems_(cartItems)'} }; } @@ -94,6 +104,9 @@ private intersectionObserver_: IntersectionObserver|null = null; private currentMenuIndex_: number = 0; + private discountConsentHasTwoSteps_: boolean; + private firstThreeCartItems_: MerchantCart[]; + private eventTracker_: EventTracker = new EventTracker(); connectedCallback() { super.connectedCallback(); @@ -121,11 +134,30 @@ }, {root: this.$.cartCarousel}); this.shadowRoot!.querySelectorAll('.probe').forEach( el => this.intersectionObserver_!.observe(el)); + + this.eventTracker_.add( + this, 'discount-consent-accepted', + () => this.onDiscountConsentAccepted_); + this.eventTracker_.add( + this, 'discount-consent-rejected', + () => this.onDiscountConsentRejected_()); + this.eventTracker_.add( + this, 'discount-consent-dismissed', + () => this.onDiscountConsentDismissed_()); } disconnectedCallback() { super.disconnectedCallback(); this.intersectionObserver_!.disconnect(); + + this.eventTracker_.remove(this, 'discount-consent-accepted'); + this.eventTracker_.remove(this, 'discount-consent-rejected'); + this.eventTracker_.remove(this, 'discount-consent-dismissed'); + } + + private computeFirstThreeCartItems_(cartItems: MerchantCart[]): + MerchantCart[] { + return cartItems.slice(0, 3); } private getFaviconUrl_(url: string): string { @@ -315,7 +347,8 @@ // TODO(crbug.com/1198632): This could make a left scroll jump over cart // items. if (index === 0) { - const consentCard = this.shadowRoot!.getElementById('consentCard'); + const consentCard = this.shadowRoot!.getElementById( + this.discountConsentHasTwoSteps_ ? 'consentCardV2' : 'consentCard'); if (consentCard) { leftPosition -= consentCard.offsetWidth; } @@ -364,7 +397,7 @@ chrome.metricsPrivate.recordSmallCount('NewTabPage.Carts.ClickCart', index); } - private onDisallowDiscount_() { + private onDiscountConsentRejected_() { this.showDiscountConsent = false; this.confirmDiscountConsentString_ = loadTimeData.getString('modulesCartDiscountConsentRejectConfirmation'); @@ -374,7 +407,7 @@ 'NewTabPage.Carts.RejectDiscountConsent'); } - private onAllowDiscount_() { + private onDiscountConsentAccepted_() { this.showDiscountConsent = false; this.confirmDiscountConsentString_ = loadTimeData.getString('modulesCartDiscountConsentAcceptConfirmation'); @@ -384,6 +417,12 @@ 'NewTabPage.Carts.AcceptDiscountConsent'); } + private onDiscountConsentDismissed_() { + this.showDiscountConsent = false; + ChromeCartProxy.getHandler().onDiscountConsentDismissed(); + // TODO(crbug.com/1298116): Record user dismiss action. + } + private onConfirmDiscountConsentClick_() { this.$.confirmDiscountConsentToast.hide(); }
diff --git a/chrome/browser/resources/new_tab_page/new_tab_page.ts b/chrome/browser/resources/new_tab_page/new_tab_page.ts index 5c931fc..0f7a43e 100644 --- a/chrome/browser/resources/new_tab_page/new_tab_page.ts +++ b/chrome/browser/resources/new_tab_page/new_tab_page.ts
@@ -21,7 +21,7 @@ export {LogoElement} from './logo.js'; export {recordDuration, recordLoadDuration, recordOccurence, recordPerdecage} from './metrics_utils.js'; export {ChromeCartProxy} from './modules/cart/chrome_cart_proxy.js'; -export {DiscountConsentCard} from './modules/cart/discount_consent_card.js'; +export {DiscountConsentCard, DiscountConsentVariation} from './modules/cart/discount_consent_card.js'; export {DiscountConsentDialog} from './modules/cart/discount_consent_dialog.js'; export {chromeCartDescriptor, ChromeCartModuleElement} from './modules/cart/module.js'; export {chromeCartDescriptor as chromeCartV2Descriptor, ChromeCartModuleElement as ChromeCartV2ModuleElement} from './modules/cart_v2/module.js';
diff --git a/chrome/browser/resources/pdf/elements/viewer-bookmark.js b/chrome/browser/resources/pdf/elements/viewer-bookmark.ts similarity index 75% rename from chrome/browser/resources/pdf/elements/viewer-bookmark.js rename to chrome/browser/resources/pdf/elements/viewer-bookmark.ts index f4447145..4b85385 100644 --- a/chrome/browser/resources/pdf/elements/viewer-bookmark.js +++ b/chrome/browser/resources/pdf/elements/viewer-bookmark.ts
@@ -8,12 +8,20 @@ import 'chrome://resources/polymer/v3_0/paper-styles/color.js'; import './shared-css.js'; +import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {Bookmark} from '../bookmark_type.js'; /** Amount that each level of bookmarks is indented by (px). */ -const BOOKMARK_INDENT = 20; +const BOOKMARK_INDENT: number = 20; + +export interface ViewerBookmarkElement { + $: { + item: HTMLElement, + expand: CrIconButtonElement, + }; +} export class ViewerBookmarkElement extends PolymerElement { static get is() { @@ -26,7 +34,6 @@ static get properties() { return { - /** @type {Bookmark} */ bookmark: { type: Object, observer: 'bookmarkChanged_', @@ -37,10 +44,8 @@ observer: 'depthChanged_', }, - /** @private */ childDepth_: Number, - /** @private */ childrenShown_: { type: Boolean, reflectToAttribute: true, @@ -49,51 +54,45 @@ }; } - /** @override */ + bookmark: Bookmark; + depth: number; + private childDepth_: number; + private childrenShown_: boolean; + ready() { super.ready(); this.$.item.addEventListener('keydown', e => { - const keyboardEvent = /** @type {!KeyboardEvent} */ (e); - if (keyboardEvent.key === 'Enter') { - this.onEnter_(keyboardEvent); - } else if (keyboardEvent.key === ' ') { - this.onSpace_(keyboardEvent); + if (e.key === 'Enter') { + this.onEnter_(e); + } else if (e.key === ' ') { + this.onSpace_(e); } }); } - /** - * @param {string} eventName - * @param {*=} detail - * @private - */ - fire_(eventName, detail) { + private fire_(eventName: string, detail?: any) { this.dispatchEvent( new CustomEvent(eventName, {bubbles: true, composed: true, detail})); } - /** @private */ - bookmarkChanged_() { + private bookmarkChanged_() { this.$.expand.style.visibility = this.bookmark.children.length > 0 ? 'visible' : 'hidden'; } - /** @private */ - depthChanged_() { + private depthChanged_() { this.childDepth_ = this.depth + 1; this.$.item.style.paddingInlineStart = (this.depth * BOOKMARK_INDENT) + 'px'; } - /** @private */ - onClick_() { + private onClick_() { if (this.bookmark.page != null) { if (this.bookmark.zoom != null) { this.fire_('change-zoom', {zoom: this.bookmark.zoom}); } - if (this.bookmark.x != null && - this.bookmark.y != null) { + if (this.bookmark.x != null && this.bookmark.y != null) { this.fire_('change-page-and-xy', { page: this.bookmark.page, x: this.bookmark.x, @@ -109,11 +108,7 @@ } } - /** - * @param {!KeyboardEvent} e - * @private - */ - onEnter_(e) { + private onEnter_(e: KeyboardEvent) { // Don't allow events which have propagated up from the expand button to // trigger a click. if (e.target !== this.$.expand) { @@ -121,11 +116,7 @@ } } - /** - * @param {!KeyboardEvent} e - * @private - */ - onSpace_(e) { + private onSpace_(e: KeyboardEvent) { // cr-icon-button stops propagation of space events, so there's no need // to check the event source here. this.onClick_(); @@ -133,22 +124,20 @@ e.preventDefault(); } - /** - * @param {!Event} e - * @private - */ - toggleChildren_(e) { + private toggleChildren_(e: Event) { this.childrenShown_ = !this.childrenShown_; e.stopPropagation(); // Prevent the above onClick_ handler from firing. } - /** - * @return {string} - * @private - */ - getAriaExpanded_() { + private getAriaExpanded_(): string { return this.childrenShown_ ? 'true' : 'false'; } } +declare global { + interface HTMLElementTagNameMap { + 'viewer-bookmark': ViewerBookmarkElement; + } +} + customElements.define(ViewerBookmarkElement.is, ViewerBookmarkElement);
diff --git a/chrome/browser/resources/pdf/elements/viewer-document-outline.js b/chrome/browser/resources/pdf/elements/viewer-document-outline.ts similarity index 83% rename from chrome/browser/resources/pdf/elements/viewer-document-outline.js rename to chrome/browser/resources/pdf/elements/viewer-document-outline.ts index 222d3d37..dec7706 100644 --- a/chrome/browser/resources/pdf/elements/viewer-document-outline.js +++ b/chrome/browser/resources/pdf/elements/viewer-document-outline.ts
@@ -20,10 +20,17 @@ static get properties() { return { - /** @type {!Array<!Bookmark>} */ bookmarks: Array, }; } + + bookmarks: Bookmark[]; +} + +declare global { + interface HTMLElementTagNameMap { + 'viewer-document-outline': ViewerDocumentOutlineElement; + } } customElements.define(
diff --git a/chrome/browser/resources/pdf/elements/viewer-download-controls.js b/chrome/browser/resources/pdf/elements/viewer-download-controls.ts similarity index 63% rename from chrome/browser/resources/pdf/elements/viewer-download-controls.js rename to chrome/browser/resources/pdf/elements/viewer-download-controls.ts index 658ad77e..9ac730d 100644 --- a/chrome/browser/resources/pdf/elements/viewer-download-controls.js +++ b/chrome/browser/resources/pdf/elements/viewer-download-controls.ts
@@ -2,17 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; import 'chrome://resources/cr_elements/icons.m.js'; import './icons.js'; import './shared-css.js'; import {AnchorAlignment, CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; +import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {SaveRequestType} from '../constants.js'; +export interface ViewerDownloadControlsElement { + $: { + download: CrIconButtonElement, + menu: CrActionMenuElement, + }; +} + export class ViewerDownloadControlsElement extends PolymerElement { static get is() { return 'viewer-download-controls'; @@ -39,7 +48,6 @@ 'hasEnteredAnnotationMode)', }, - /** @private */ menuOpen_: { type: Boolean, reflectToAttribute: true, @@ -48,73 +56,38 @@ }; } - constructor() { - super(); + hasEdits: boolean; + hasEnteredAnnotationMode: boolean; + isFormFieldFocused: boolean; + private downloadHasPopup_: string; + private menuOpen_: boolean; + private waitForFormFocusChange_: PromiseResolver<boolean>|null = null; - // Polymer properties - /** @private {string} */ - this.downloadHasPopup_; - - /** @type {boolean} */ - this.hasEdits; - - /** @type {boolean} */ - this.hasEnteredAnnotationMode; - - /** @type {boolean} */ - this.isFormFieldFocused; - - // Non-Polymer properties - /** @private {?PromiseResolver<boolean>} */ - this.waitForFormFocusChange_ = null; - } - - /** @return {boolean} */ - isMenuOpen() { + isMenuOpen(): boolean { return this.menuOpen_; } closeMenu() { - this.getDownloadMenu_().close(); + this.$.menu.close(); } - /** - * @param {!CustomEvent<!{value: boolean}>} e - * @private - */ - onOpenChanged_(e) { + private onOpenChanged_(e: CustomEvent<{value: boolean}>) { this.menuOpen_ = e.detail.value; } - /** - * @return {boolean} - * @private - */ - hasEditsToSave_() { + private hasEditsToSave_(): boolean { return this.hasEnteredAnnotationMode || this.hasEdits; } /** - * @return {string} The value for the aria-haspopup attribute for the download - * button. - * @private + * @return The value for the aria-haspopup attribute for the download button. */ - computeDownloadHasPopup_() { + private computeDownloadHasPopup_(): string { return this.hasEditsToSave_() ? 'menu' : 'false'; } - /** - * @return {!CrActionMenuElement} - * @private - */ - getDownloadMenu_() { - return /** @type {!CrActionMenuElement} */ ( - this.shadowRoot.querySelector('#menu')); - } - - /** @private */ - showDownloadMenu_() { - this.getDownloadMenu_().showAt(this.$.download, { + private showDownloadMenu_() { + this.$.menu.showAt(this.$.download, { anchorAlignmentX: AnchorAlignment.CENTER, }); // For tests @@ -122,8 +95,7 @@ 'download-menu-shown-for-testing', {bubbles: true, composed: true})); } - /** @private */ - onDownloadClick_() { + private onDownloadClick_() { this.waitForEdits_().then(hasEdits => { if (hasEdits) { this.showDownloadMenu_(); @@ -134,11 +106,10 @@ } /** - * @return {!Promise<boolean>} Promise that resolves with true if the PDF has - * edits and/or annotations, and false otherwise. - * @private + * @return Promise that resolves with true if the PDF has edits and/or + * annotations, and false otherwise. */ - waitForEdits_() { + private waitForEdits_(): Promise<boolean> { if (this.hasEditsToSave_()) { return Promise.resolve(true); } @@ -149,8 +120,7 @@ return this.waitForFormFocusChange_.promise; } - /** @private */ - onFormFieldFocusedChanged_() { + private onFormFieldFocusedChanged_() { if (!this.waitForFormFocusChange_) { return; } @@ -159,28 +129,29 @@ this.waitForFormFocusChange_ = null; } - /** - * @param {!SaveRequestType} type - * @private - */ - dispatchSaveEvent_(type) { + private dispatchSaveEvent_(type: SaveRequestType) { this.dispatchEvent( new CustomEvent('save', {detail: type, bubbles: true, composed: true})); } - /** @private */ - onDownloadOriginalClick_() { + private onDownloadOriginalClick_() { this.dispatchSaveEvent_(SaveRequestType.ORIGINAL); - this.getDownloadMenu_().close(); + this.$.menu.close(); } - /** @private */ - onDownloadEditedClick_() { + private onDownloadEditedClick_() { this.dispatchSaveEvent_( this.hasEnteredAnnotationMode ? SaveRequestType.ANNOTATION : SaveRequestType.EDITED); - this.getDownloadMenu_().close(); + this.$.menu.close(); } } + +declare global { + interface HTMLElementTagNameMap { + 'viewer-download-controls': ViewerDownloadControlsElement; + } +} + customElements.define( ViewerDownloadControlsElement.is, ViewerDownloadControlsElement);
diff --git a/chrome/browser/resources/pdf/elements/viewer-page-selector.html b/chrome/browser/resources/pdf/elements/viewer-page-selector.html index 89cae2a..cb77849 100644 --- a/chrome/browser/resources/pdf/elements/viewer-page-selector.html +++ b/chrome/browser/resources/pdf/elements/viewer-page-selector.html
@@ -13,7 +13,7 @@ --page-selector-spacing: 4px; } - #pageselector::selection { + #pageSelector::selection { background-color: var(--viewer-text-input-selection-color); } @@ -41,9 +41,9 @@ } </style> <div id="content"> - <input part="input" type="text" id="pageselector" value="[[pageNo]]" + <input part="input" type="text" id="pageSelector" value="[[pageNo]]" on-pointerup="select" on-input="onInput_" on-change="pageNoCommitted" aria-label="$i18n{labelPageNumber}"> <span id="divider">/</span> <span id="pagelength">[[docLength]]</span> - </div> \ No newline at end of file + </div>
diff --git a/chrome/browser/resources/pdf/elements/viewer-page-selector.js b/chrome/browser/resources/pdf/elements/viewer-page-selector.ts similarity index 60% rename from chrome/browser/resources/pdf/elements/viewer-page-selector.js rename to chrome/browser/resources/pdf/elements/viewer-page-selector.ts index 30b99f6..519718b 100644 --- a/chrome/browser/resources/pdf/elements/viewer-page-selector.js +++ b/chrome/browser/resources/pdf/elements/viewer-page-selector.ts
@@ -6,6 +6,12 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +export interface ViewerPageSelectorElement { + $: { + pageSelector: HTMLInputElement, + }; +} + export class ViewerPageSelectorElement extends PolymerElement { static get is() { return 'viewer-page-selector'; @@ -17,9 +23,7 @@ static get properties() { return { - /** - * The number of pages the document contains. - */ + /** The number of pages the document contains. */ docLength: {type: Number, value: 1, observer: 'docLengthChanged_'}, /** @@ -35,48 +39,46 @@ }; } - /** @return {!HTMLInputElement} */ - get pageSelector() { - return /** @type {!HTMLInputElement} */ (this.$.pageselector); - } + docLength: number; + pageNo: number; pageNoCommitted() { - const page = parseInt(this.pageSelector.value, 10); + const page = parseInt(this.$.pageSelector.value, 10); if (!isNaN(page) && page <= this.docLength && page > 0) { this.dispatchEvent(new CustomEvent('change-page', { - detail: {page: page - 1, origin: 'pageselector'}, + detail: {page: page - 1, origin: 'pageSelector'}, composed: true, })); } else { - this.pageSelector.value = this.pageNo.toString(); + this.$.pageSelector.value = this.pageNo.toString(); } - this.pageSelector.blur(); + this.$.pageSelector.blur(); } - /** @private */ - docLengthChanged_() { + private docLengthChanged_() { const numDigits = this.docLength.toString().length; this.style.setProperty('--page-length-digits', `${numDigits}`); } select() { - this.pageSelector.select(); + this.$.pageSelector.select(); } - /** - * @return {boolean} True if the selector input field is currently focused. - */ - isActive() { - return this.shadowRoot.activeElement === this.pageSelector; + /** @return True if the selector input field is currently focused. */ + isActive(): boolean { + return this.shadowRoot!.activeElement === this.$.pageSelector; } - /** - * Immediately remove any non-digit characters. - * @private - */ - onInput_() { - this.pageSelector.value = this.pageSelector.value.replace(/[^\d]/, ''); + /** Immediately remove any non-digit characters. */ + private onInput_() { + this.$.pageSelector.value = this.$.pageSelector.value.replace(/[^\d]/, ''); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'viewer-page-selector': ViewerPageSelectorElement; } }
diff --git a/chrome/browser/resources/pdf/elements/viewer-password-dialog.js b/chrome/browser/resources/pdf/elements/viewer-password-dialog.ts similarity index 69% rename from chrome/browser/resources/pdf/elements/viewer-password-dialog.js rename to chrome/browser/resources/pdf/elements/viewer-password-dialog.ts index a516e4f2..e719960 100644 --- a/chrome/browser/resources/pdf/elements/viewer-password-dialog.js +++ b/chrome/browser/resources/pdf/elements/viewer-password-dialog.ts
@@ -8,8 +8,19 @@ import 'chrome://resources/cr_elements/shared_style_css.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; +import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; +import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +export interface ViewerPasswordDialogElement { + $: { + dialog: CrDialogElement, + password: CrInputElement, + submit: CrButtonElement, + }; +} + export class ViewerPasswordDialogElement extends PolymerElement { static get is() { return 'viewer-password-dialog'; @@ -25,12 +36,14 @@ }; } + invalid: boolean; + close() { this.$.dialog.close(); } deny() { - const password = /** @type {!CrInputElement} */ (this.$.password); + const password = this.$.password; password.disabled = false; this.$.submit.disabled = false; this.invalid = true; @@ -40,7 +53,7 @@ } submit() { - const password = /** @type {!CrInputElement} */ (this.$.password); + const password = this.$.password; if (password.value.length === 0) { return; } @@ -52,5 +65,11 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'viewer-password-dialog': ViewerPasswordDialogElement; + } +} + customElements.define( ViewerPasswordDialogElement.is, ViewerPasswordDialogElement);
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-sidenav.js b/chrome/browser/resources/pdf/elements/viewer-pdf-sidenav.ts similarity index 77% rename from chrome/browser/resources/pdf/elements/viewer-pdf-sidenav.js rename to chrome/browser/resources/pdf/elements/viewer-pdf-sidenav.ts index 8a3927c5..df9b628 100644 --- a/chrome/browser/resources/pdf/elements/viewer-pdf-sidenav.js +++ b/chrome/browser/resources/pdf/elements/viewer-pdf-sidenav.ts
@@ -29,7 +29,6 @@ return { activePage: Number, - /** @type {!Array<!Bookmark>} */ bookmarks: { type: Array, value: () => [], @@ -39,7 +38,6 @@ docLength: Number, - /** @private */ thumbnailView_: { type: Boolean, value: true, @@ -47,49 +45,43 @@ }; } - /** @private */ - onThumbnailClick_() { + activePage: number; + bookmarks: Bookmark[]; + clockwiseRotations: number; + docLength: number; + private thumbnailView_: boolean; + + private onThumbnailClick_() { record(UserAction.SELECT_SIDENAV_THUMBNAILS); this.thumbnailView_ = true; } - /** @private */ - onOutlineClick_() { + private onOutlineClick_() { record(UserAction.SELECT_SIDENAV_OUTLINE); this.thumbnailView_ = false; } - /** - * @return {string} - * @private - */ - outlineButtonClass_() { + private outlineButtonClass_(): string { return this.thumbnailView_ ? '' : 'selected'; } - /** - * @return {string} - * @private - */ - thumbnailButtonClass_() { + private thumbnailButtonClass_(): string { return this.thumbnailView_ ? 'selected' : ''; } - /** - * @return {string} - * @private - */ - getAriaSelectedThumbnails_() { + private getAriaSelectedThumbnails_(): string { return this.thumbnailView_ ? 'true' : 'false'; } - /** - * @return {string} - * @private - */ - getAriaSelectedOutline_() { + private getAriaSelectedOutline_(): string { return this.thumbnailView_ ? 'false' : 'true'; } } +declare global { + interface HTMLElementTagNameMap { + 'viewer-pdf-sidenav': ViewerPdfSidenavElement; + } +} + customElements.define(ViewerPdfSidenavElement.is, ViewerPdfSidenavElement);
diff --git a/chrome/browser/resources/pdf/elements/viewer-properties-dialog.html b/chrome/browser/resources/pdf/elements/viewer-properties-dialog.html index 18d3ad9..33c130be 100644 --- a/chrome/browser/resources/pdf/elements/viewer-properties-dialog.html +++ b/chrome/browser/resources/pdf/elements/viewer-properties-dialog.html
@@ -41,7 +41,7 @@ white-space: normal; } </style> -<cr-dialog show-on-attach> +<cr-dialog id="dialog" show-on-attach> <div slot="title">$i18n{propertiesDialogTitle}</div> <div slot="body"> <table>
diff --git a/chrome/browser/resources/pdf/elements/viewer-properties-dialog.js b/chrome/browser/resources/pdf/elements/viewer-properties-dialog.ts similarity index 63% rename from chrome/browser/resources/pdf/elements/viewer-properties-dialog.js rename to chrome/browser/resources/pdf/elements/viewer-properties-dialog.ts index d791c83..2a78913 100644 --- a/chrome/browser/resources/pdf/elements/viewer-properties-dialog.js +++ b/chrome/browser/resources/pdf/elements/viewer-properties-dialog.ts
@@ -6,10 +6,17 @@ import 'chrome://resources/cr_elements/shared_style_css.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {DocumentMetadata} from '../constants.js'; +export interface ViewerPropertiesDialogElement { + $: { + dialog: CrDialogElement, + }; +} + export class ViewerPropertiesDialogElement extends PolymerElement { static get is() { return 'viewer-properties-dialog'; @@ -21,47 +28,33 @@ static get properties() { return { - /** @type {!DocumentMetadata} */ documentMetadata: Object, - fileName: String, - pageCount: Number, }; } - /** - * @return {!CrDialogElement} - * @private - */ - getDialog_() { - return /** @type {!CrDialogElement} */ ( - this.shadowRoot.querySelector('cr-dialog')); - } + documentMetadata: DocumentMetadata; + fileName: string; + pageCount: number; - /** - * @param {string} yesLabel - * @param {string} noLabel - * @param {boolean} linearized - * @return {string} - * @private - */ - getFastWebViewValue_(yesLabel, noLabel, linearized) { + private getFastWebViewValue_( + yesLabel: string, noLabel: string, linearized: boolean): string { return linearized ? yesLabel : noLabel; } - /** - * @param {string} value - * @return {string} - * @private - */ - getOrPlaceholder_(value) { + private getOrPlaceholder_(value: string): string { return value || '-'; } - /** @private */ - onClickClose_() { - this.getDialog_().close(); + private onClickClose_() { + this.$.dialog.close(); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'viewer-properties-dialog': ViewerPropertiesDialogElement; } }
diff --git a/chrome/browser/resources/pdf/elements/viewer-thumbnail-bar.js b/chrome/browser/resources/pdf/elements/viewer-thumbnail-bar.js deleted file mode 100644 index 05f060c..0000000 --- a/chrome/browser/resources/pdf/elements/viewer-thumbnail-bar.js +++ /dev/null
@@ -1,243 +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. - -import './viewer-thumbnail.js'; - -import {assert} from 'chrome://resources/js/assert.m.js'; -import {FocusOutlineManager} from 'chrome://resources/js/cr/ui/focus_outline_manager.m.js'; -import {EventTracker} from 'chrome://resources/js/event_tracker.m.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; -import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {PluginController, PluginControllerEventType} from '../controller.js'; -import {ViewerThumbnailElement} from './viewer-thumbnail.js'; - -export class ViewerThumbnailBarElement extends PolymerElement { - static get is() { - return 'viewer-thumbnail-bar'; - } - - static get template() { - return html`{__html_template__}`; - } - - static get properties() { - return { - activePage: { - type: Number, - observer: 'activePageChanged_', - }, - - clockwiseRotations: Number, - - docLength: Number, - - isPluginActive_: Boolean, - - /** @private {Array<number>} */ - pageNumbers_: { - type: Array, - computed: 'computePageNumbers_(docLength)', - }, - }; - } - - constructor() { - super(); - - // TODO(dhoss): Remove `this.inTest` when implemented a mock plugin - // controller. - /** @type {boolean} */ - this.inTest = false; - - /** @private {!PluginController} */ - this.pluginController_ = PluginController.getInstance(); - - /** @private {boolean} */ - this.isPluginActive_ = this.pluginController_.isActive; - - /** @private {!EventTracker} */ - this.tracker_ = new EventTracker(); - - // Listen to whether the plugin is active. Thumbnails should be hidden - // when the plugin is inactive. - this.tracker_.add( - this.pluginController_.getEventTarget(), - PluginControllerEventType.IS_ACTIVE_CHANGED, - e => this.isPluginActive_ = e.detail); - } - - ready() { - super.ready(); - - this.addEventListener('focus', this.onFocus_); - this.addEventListener('keydown', this.onKeydown_); - - const thumbnailsDiv = this.shadowRoot.querySelector('#thumbnails'); - assert(thumbnailsDiv); - - /** @private {!IntersectionObserver} */ - this.intersectionObserver_ = new IntersectionObserver(entries => { - entries.forEach(entry => { - const thumbnail = /** @type {!ViewerThumbnailElement} */ (entry.target); - - if (!entry.isIntersecting) { - thumbnail.clearImage(); - return; - } - - if (thumbnail.isPainted()) { - return; - } - thumbnail.setPainted(); - - if (!this.isPluginActive_ || this.inTest) { - return; - } - - this.pluginController_.requestThumbnail(thumbnail.pageNumber) - .then(response => { - const array = new Uint8ClampedArray(response.imageData); - const imageData = new ImageData(array, response.width); - thumbnail.image = imageData; - }); - }); - }, { - root: thumbnailsDiv, - // The root margin is set to 100% on the bottom to prepare thumbnails that - // are one standard scroll finger swipe away. - // The root margin is set to 500% on the top to discard thumbnails that - // far from view, but to avoid regenerating thumbnails that are close. - rootMargin: '500% 0% 100%', - }); - - FocusOutlineManager.forDocument(document); - } - - /** - * Changes the focus to the thumbnail of the new active page if the focus was - * already on a thumbnail. - * @private - */ - activePageChanged_() { - if (this.shadowRoot.activeElement) { - this.getThumbnailForPage(this.activePage).focusAndScroll(); - } - } - - /** - * @param {number} pageNumber - * @private - */ - clickThumbnailForPage(pageNumber) { - if (pageNumber < 1 || pageNumber > this.docLength) { - return; - } - - this.getThumbnailForPage(pageNumber).getClickTarget().click(); - } - - /** - * @param {number} pageNumber - * @return {?ViewerThumbnailElement} - */ - getThumbnailForPage(pageNumber) { - return /** @type {ViewerThumbnailElement} */ (this.shadowRoot.querySelector( - `viewer-thumbnail:nth-child(${pageNumber})`)); - } - - /** - * @return {!Array<number>} The array of page numbers. - * @private - */ - computePageNumbers_() { - return Array.from({length: this.docLength}, (_, i) => i + 1); - } - - /** - * @param {number} pageNumber - * @return {string} - * @private - */ - getAriaLabel_(pageNumber) { - return loadTimeData.getStringF('thumbnailPageAriaLabel', pageNumber); - } - - /** - * @param {number} page - * @return {boolean} Whether the page is the current page. - * @private - */ - isActivePage_(page) { - return this.activePage === page; - } - - /** @private */ - onDomChange_() { - this.shadowRoot.querySelectorAll('viewer-thumbnail').forEach(thumbnail => { - this.intersectionObserver_.observe(thumbnail); - }); - } - - /** - * Forwards focus to a thumbnail when tabbing. - * @private - */ - onFocus_() { - // Ignore focus triggered by mouse to allow the focus to go straight to the - // thumbnail being clicked. - const focusOutlineManager = FocusOutlineManager.forDocument(document); - if (!focusOutlineManager.visible) { - return; - } - - // Change focus to the thumbnail of the active page. - const activeThumbnail = - this.shadowRoot.querySelector('viewer-thumbnail[is-active]'); - if (activeThumbnail) { - activeThumbnail.focus(); - return; - } - - // Otherwise change to the first thumbnail, if there is one. - const firstThumbnail = this.shadowRoot.querySelector('viewer-thumbnail'); - if (!firstThumbnail) { - return; - } - firstThumbnail.focus(); - } - - /** - * @param {!Event} e - * @private - */ - onKeydown_(e) { - const keyboardEvent = /** @type {!KeyboardEvent} */ (e); - if (keyboardEvent.key === 'Tab') { - // On shift+tab, first redirect focus from the thumbnails to: - // 1) Avoid focusing on the thumbnail bar. - // 2) Focus to the element before the thumbnail bar from any thumbnail. - if (e.shiftKey) { - this.focus(); - return; - } - - // On tab, first redirect focus to the last thumbnail to focus to the - // element after the thumbnail bar from any thumbnail. - this.shadowRoot.querySelector('viewer-thumbnail:last-of-type').focus({ - preventScroll: true - }); - } else if (keyboardEvent.key === 'ArrowRight') { - // Prevent default arrow scroll behavior. - keyboardEvent.preventDefault(); - this.clickThumbnailForPage(this.activePage + 1); - } else if (keyboardEvent.key === 'ArrowLeft') { - // Prevent default arrow scroll behavior. - keyboardEvent.preventDefault(); - this.clickThumbnailForPage(this.activePage - 1); - } - } -} - -customElements.define(ViewerThumbnailBarElement.is, ViewerThumbnailBarElement);
diff --git a/chrome/browser/resources/pdf/elements/viewer-thumbnail-bar.ts b/chrome/browser/resources/pdf/elements/viewer-thumbnail-bar.ts new file mode 100644 index 0000000..7280714 --- /dev/null +++ b/chrome/browser/resources/pdf/elements/viewer-thumbnail-bar.ts
@@ -0,0 +1,220 @@ +// 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. + +import './viewer-thumbnail.js'; + +import {assert} from 'chrome://resources/js/assert.m.js'; +import {FocusOutlineManager} from 'chrome://resources/js/cr/ui/focus_outline_manager.m.js'; +import {EventTracker} from 'chrome://resources/js/event_tracker.m.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {PluginController, PluginControllerEventType} from '../controller.js'; +import {ViewerThumbnailElement} from './viewer-thumbnail.js'; + +export class ViewerThumbnailBarElement extends PolymerElement { + static get is() { + return 'viewer-thumbnail-bar'; + } + + static get template() { + return html`{__html_template__}`; + } + + static get properties() { + return { + activePage: { + type: Number, + observer: 'activePageChanged_', + }, + + clockwiseRotations: Number, + docLength: Number, + isPluginActive_: Boolean, + + pageNumbers_: { + type: Array, + computed: 'computePageNumbers_(docLength)', + }, + }; + } + + activePage: number; + clockwiseRotations: number; + docLength: number; + private isPluginActive_: boolean; + private pageNumbers_: number[]; + private intersectionObserver_: IntersectionObserver; + private pluginController_: PluginController = PluginController.getInstance(); + private tracker_: EventTracker = new EventTracker(); + + // TODO(dhoss): Remove `this.inTest` when implemented a mock plugin + // controller. + inTest: boolean = false; + + constructor() { + super(); + + this.isPluginActive_ = this.pluginController_.isActive; + + // Listen to whether the plugin is active. Thumbnails should be hidden + // when the plugin is inactive. + this.tracker_.add( + this.pluginController_.getEventTarget(), + PluginControllerEventType.IS_ACTIVE_CHANGED, + (e: CustomEvent<boolean>) => this.isPluginActive_ = e.detail); + } + + ready() { + super.ready(); + + this.addEventListener('focus', this.onFocus_); + this.addEventListener('keydown', this.onKeydown_); + + const thumbnailsDiv = this.shadowRoot!.querySelector('#thumbnails'); + assert(thumbnailsDiv); + + // TODO(crbug.com/1260303): Change `any` to `IntersectionObserverEntry`. + this.intersectionObserver_ = + new IntersectionObserver((entries: IntersectionObserverEntry[]) => { + entries.forEach(entry => { + const thumbnail = entry.target as ViewerThumbnailElement; + + if (!entry.isIntersecting) { + thumbnail.clearImage(); + return; + } + + if (thumbnail.isPainted()) { + return; + } + thumbnail.setPainted(); + + if (!this.isPluginActive_ || this.inTest) { + return; + } + + this.pluginController_.requestThumbnail(thumbnail.pageNumber) + .then(response => { + const array = new Uint8ClampedArray(response.imageData); + const imageData = new ImageData(array, response.width); + thumbnail.image = imageData; + }); + }); + }, { + root: thumbnailsDiv, + // The root margin is set to 100% on the bottom to prepare thumbnails + // that are one standard scroll finger swipe away. The root margin is + // set to 500% on the top to discard thumbnails that are far from + // view, but to avoid regenerating thumbnails that are close. + rootMargin: '500% 0% 100%', + }); + + FocusOutlineManager.forDocument(document); + } + + /** + * Changes the focus to the thumbnail of the new active page if the focus was + * already on a thumbnail. + */ + private activePageChanged_() { + if (this.shadowRoot!.activeElement) { + this.getThumbnailForPage(this.activePage)!.focusAndScroll(); + } + } + + private clickThumbnailForPage(pageNumber: number) { + const thumbnail = this.getThumbnailForPage(pageNumber); + if (!thumbnail) { + return; + } + + thumbnail.getClickTarget().click(); + } + + getThumbnailForPage(pageNumber: number): ViewerThumbnailElement|null { + return this.shadowRoot!.querySelector( + `viewer-thumbnail:nth-child(${pageNumber})`); + } + + /** @return The array of page numbers. */ + private computePageNumbers_(): number[] { + return Array.from({length: this.docLength}, (_, i) => i + 1); + } + + private getAriaLabel_(pageNumber: number): string { + return loadTimeData.getStringF('thumbnailPageAriaLabel', pageNumber); + } + + /** @return Whether the page is the current page. */ + private isActivePage_(page: number): boolean { + return this.activePage === page; + } + + private onDomChange_() { + this.shadowRoot!.querySelectorAll('viewer-thumbnail').forEach(thumbnail => { + this.intersectionObserver_.observe(thumbnail); + }); + } + + /** Forwards focus to a thumbnail when tabbing. */ + private onFocus_() { + // Ignore focus triggered by mouse to allow the focus to go straight to the + // thumbnail being clicked. + const focusOutlineManager = FocusOutlineManager.forDocument(document); + if (!focusOutlineManager.visible) { + return; + } + + // Change focus to the thumbnail of the active page. + const activeThumbnail = + this.shadowRoot!.querySelector<ViewerThumbnailElement>( + 'viewer-thumbnail[is-active]'); + if (activeThumbnail) { + activeThumbnail.focus(); + return; + } + + // Otherwise change to the first thumbnail, if there is one. + const firstThumbnail = this.shadowRoot!.querySelector('viewer-thumbnail'); + if (!firstThumbnail) { + return; + } + firstThumbnail.focus(); + } + + private onKeydown_(e: KeyboardEvent) { + if (e.key === 'Tab') { + // On shift+tab, first redirect focus from the thumbnails to: + // 1) Avoid focusing on the thumbnail bar. + // 2) Focus to the element before the thumbnail bar from any thumbnail. + if (e.shiftKey) { + this.focus(); + return; + } + + // On tab, first redirect focus to the last thumbnail to focus to the + // element after the thumbnail bar from any thumbnail. + this.shadowRoot! + .querySelector<ViewerThumbnailElement>( + 'viewer-thumbnail:last-of-type')!.focus({preventScroll: true}); + } else if (e.key === 'ArrowRight') { + // Prevent default arrow scroll behavior. + e.preventDefault(); + this.clickThumbnailForPage(this.activePage + 1); + } else if (e.key === 'ArrowLeft') { + // Prevent default arrow scroll behavior. + e.preventDefault(); + this.clickThumbnailForPage(this.activePage - 1); + } + } +} + +declare global { + interface HTMLElementTagNameMap { + 'viewer-thumbnail-bar': ViewerThumbnailBarElement; + } +} + +customElements.define(ViewerThumbnailBarElement.is, ViewerThumbnailBarElement);
diff --git a/chrome/browser/resources/pdf/elements/viewer-thumbnail.js b/chrome/browser/resources/pdf/elements/viewer-thumbnail.ts similarity index 73% rename from chrome/browser/resources/pdf/elements/viewer-thumbnail.js rename to chrome/browser/resources/pdf/elements/viewer-thumbnail.ts index 04a31374..eb37471 100644 --- a/chrome/browser/resources/pdf/elements/viewer-thumbnail.js +++ b/chrome/browser/resources/pdf/elements/viewer-thumbnail.ts
@@ -10,13 +10,17 @@ // The maximum widths of thumbnails for each layout (px). // These constants should be kept in sync with `kMaxWidthPortraitPx` and // `kMaxWidthLandscapePx` in pdf/thumbnail.cc. -/** @type {number} */ -const PORTRAIT_WIDTH = 108; -/** @type {number} */ -const LANDSCAPE_WIDTH = 140; +const PORTRAIT_WIDTH: number = 108; -/** @type {string} */ -export const PAINTED_ATTRIBUTE = 'painted'; +const LANDSCAPE_WIDTH: number = 140; + +export const PAINTED_ATTRIBUTE: string = 'painted'; + +export interface ViewerThumbnailElement { + $: { + thumbnail: HTMLElement, + }; +} export class ViewerThumbnailElement extends PolymerElement { static get is() { @@ -45,14 +49,17 @@ }; } + clockwiseRotations: number; + isActive: boolean; + pageNumber: number; + constructor() { super(); this.addEventListener('keydown', this.onKeydown_); } - /** @param {!ImageData} imageData */ - set image(imageData) { + set image(imageData: ImageData) { let canvas = this.getCanvas_(); if (!canvas) { canvas = document.createElement('canvas'); @@ -61,7 +68,7 @@ // has restricted access rights. canvas.oncontextmenu = e => e.preventDefault(); - this.shadowRoot.querySelector('#thumbnail').appendChild(canvas); + this.$.thumbnail.appendChild(canvas); } canvas.width = imageData.width; @@ -69,7 +76,7 @@ this.styleCanvas_(); - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext('2d')!; ctx.putImageData(imageData, 0, 0); } @@ -87,26 +94,18 @@ this.removeAttribute(PAINTED_ATTRIBUTE); } - /** @return {!HTMLElement} */ - getClickTarget() { - return /** @type {!HTMLElement} */ ( - this.shadowRoot.querySelector('#thumbnail')); + getClickTarget(): HTMLElement { + return this.$.thumbnail; } - /** @private */ - clockwiseRotationsChanged_() { + private clockwiseRotationsChanged_() { if (this.getCanvas_()) { this.styleCanvas_(); } } - /** - * @return {?HTMLCanvasElement} - * @private - */ - getCanvas_() { - return /** @type {?HTMLCanvasElement} */ ( - this.shadowRoot.querySelector('canvas')); + private getCanvas_(): HTMLCanvasElement|null { + return this.shadowRoot!.querySelector('canvas'); } /** @@ -114,12 +113,10 @@ * dimensions of the image data, and the screen resolution. The plugin * scales the thumbnail image data by the device to pixel ratio, so that * scaling must be taken into account on the UI. - * @param {boolean} rotated - * @return {!{width: number, height: number}} - * @private */ - getThumbnailCssSize_(rotated) { - const canvas = this.getCanvas_(); + private getThumbnailCssSize_(rotated: boolean): + {width: number, height: number} { + const canvas = this.getCanvas_()!; const isPortrait = canvas.width < canvas.height !== rotated; const orientedWidth = rotated ? canvas.height : canvas.width; const orientedHeight = rotated ? canvas.width : canvas.height; @@ -129,9 +126,9 @@ // thumbnail. const cssWidth = Math.min( isPortrait ? PORTRAIT_WIDTH : LANDSCAPE_WIDTH, - parseInt(orientedWidth / window.devicePixelRatio, 10)); + Math.trunc(orientedWidth / window.devicePixelRatio)); const scale = cssWidth / orientedWidth; - const cssHeight = parseInt(orientedHeight * scale, 10); + const cssHeight = Math.trunc(orientedHeight * scale); return {width: cssWidth, height: cssHeight}; } @@ -146,8 +143,7 @@ this.focus({preventScroll: true}); } - /** @return {boolean} */ - isPainted() { + isPainted(): boolean { return this.hasAttribute(PAINTED_ATTRIBUTE); } @@ -155,31 +151,27 @@ this.toggleAttribute(PAINTED_ATTRIBUTE, true); } - /** @private */ - isActiveChanged_() { + private isActiveChanged_() { if (this.isActive) { this.scrollIntoView({block: 'nearest'}); } } - /** @private */ - focusThumbnailNext_() { + private focusThumbnailNext_() { if (this.nextElementSibling && this.nextElementSibling.matches('viewer-thumbnail')) { - this.nextElementSibling.focusAndScroll(); + (this.nextElementSibling as ViewerThumbnailElement).focusAndScroll(); } } - /** @private */ - focusThumbnailPrev_() { + private focusThumbnailPrev_() { if (this.previousElementSibling && this.previousElementSibling.matches('viewer-thumbnail')) { - this.previousElementSibling.focusAndScroll(); + (this.previousElementSibling as ViewerThumbnailElement).focusAndScroll(); } } - /** @private */ - onClick_() { + private onClick_() { this.dispatchEvent(new CustomEvent('change-page', { detail: {page: this.pageNumber - 1, origin: 'thumbnail'}, bubbles: true, @@ -187,27 +179,22 @@ })); } - /** - * @param {!Event} e - * @private - */ - onKeydown_(e) { - const keyboardEvent = /** @type {!KeyboardEvent} */ (e); - switch (keyboardEvent.key) { + private onKeydown_(e: KeyboardEvent) { + switch (e.key) { case 'ArrowDown': // Prevent default arrow scroll behavior. - keyboardEvent.preventDefault(); + e.preventDefault(); this.focusThumbnailNext_(); break; case 'ArrowUp': - // Prevent default arrow scroll behavior. - keyboardEvent.preventDefault(); + // e default arrow scroll behavior. + e.preventDefault(); this.focusThumbnailPrev_(); break; case 'Enter': case ' ': // Prevent default space scroll behavior. - keyboardEvent.preventDefault(); + e.preventDefault(); this.onClick_(); break; } @@ -216,13 +203,12 @@ /** * Sets the canvas CSS size to maintain the resolution of the thumbnail at any * rotation. - * @private */ - styleCanvas_() { + private styleCanvas_() { assert(this.clockwiseRotations >= 0 && this.clockwiseRotations < 4); - const canvas = this.getCanvas_(); - const div = this.shadowRoot.querySelector('#thumbnail'); + const canvas = this.getCanvas_()!; + const div = this.shadowRoot!.querySelector<HTMLElement>('#thumbnail')!; const degreesRotated = this.clockwiseRotations * 90; canvas.style.transform = `rotate(${degreesRotated}deg)`; @@ -241,4 +227,10 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'viewer-thumbnail': ViewerThumbnailElement; + } +} + customElements.define(ViewerThumbnailElement.is, ViewerThumbnailElement);
diff --git a/chrome/browser/resources/pdf/pdf.gni b/chrome/browser/resources/pdf/pdf.gni index 9bb0512..9c04208 100644 --- a/chrome/browser/resources/pdf/pdf.gni +++ b/chrome/browser/resources/pdf/pdf.gni
@@ -26,15 +26,15 @@ # Files that need to be passed to html_to_js() that are used only in PDF Viewer. pdf_webcomponents_files = [ "elements/shared-css.js", - "elements/viewer-bookmark.js", - "elements/viewer-document-outline.js", - "elements/viewer-download-controls.js", - "elements/viewer-page-selector.js", - "elements/viewer-password-dialog.js", - "elements/viewer-pdf-sidenav.js", - "elements/viewer-properties-dialog.js", - "elements/viewer-thumbnail-bar.js", - "elements/viewer-thumbnail.js", + "elements/viewer-bookmark.ts", + "elements/viewer-document-outline.ts", + "elements/viewer-download-controls.ts", + "elements/viewer-page-selector.ts", + "elements/viewer-password-dialog.ts", + "elements/viewer-pdf-sidenav.ts", + "elements/viewer-properties-dialog.ts", + "elements/viewer-thumbnail-bar.ts", + "elements/viewer-thumbnail.ts", "elements/viewer-toolbar.js", "pdf_viewer.js", ]
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js index f3d7130..0dc5743 100644 --- a/chrome/browser/resources/pdf/pdf_viewer.js +++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -1026,7 +1026,7 @@ this.viewport.goToPage(e.detail.page); if (e.detail.origin === 'bookmark') { record(UserAction.FOLLOW_BOOKMARK); - } else if (e.detail.origin === 'pageselector') { + } else if (e.detail.origin === 'pageSelector') { record(UserAction.PAGE_SELECTOR_NAVIGATE); } else if (e.detail.origin === 'thumbnail') { record(UserAction.THUMBNAIL_NAVIGATE);
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js index 444adae..96d6d9db 100644 --- a/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js +++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_subpage.js
@@ -528,6 +528,7 @@ networkStates.forEach(state => { assert(state.type === mojom.NetworkType.kVPN); switch (state.typeState.vpn.type) { + case mojom.VpnType.kIKEv2: case mojom.VpnType.kL2TPIPsec: case mojom.VpnType.kOpenVPN: case mojom.VpnType.kWireGuard:
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.js index 7f37d88..80ec186 100644 --- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.js +++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.js
@@ -110,6 +110,7 @@ supportedLinks: [], runOnOsLogin: null, fileHandlingState: null, + installSource: apps.mojom.InstallSource.kUnknown, }; if (optConfig) {
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/types.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/types.js index ff5e86b..b46588ee 100644 --- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/types.js +++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/types.js
@@ -41,6 +41,11 @@ let WindowMode; /** + * @typedef {apps.mojom.InstallSource} + */ +let InstallSource; + +/** * Must be kept in sync with * ui/webui/resources/cr_components/app_management/constants.ts * @enum {number}
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 ee45d00c..8caf22e8 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
@@ -3,11 +3,14 @@ width: 100%; } - :host([selected]) [focus-row-container], - :host(:not([selected])) [focus-row-container]:hover { + :host([selected]) [focus-row-container] { background-color: var(--cros-highlight-color); } + :host(:not([selected])) [focus-row-container]:hover { + background-color: var(--cros-highlight-color-hover); + } + :host-context([dir=rtl]) #actionTypeIcon { transform: scaleX(-1); /* Invert X: flip on the Y axis (aka mirror). */ }
diff --git a/chrome/browser/resources/settings/privacy_sandbox/app.html b/chrome/browser/resources/settings/privacy_sandbox/app.html index ed173829..009f212 100644 --- a/chrome/browser/resources/settings/privacy_sandbox/app.html +++ b/chrome/browser/resources/settings/privacy_sandbox/app.html
@@ -311,7 +311,7 @@ <div class="ad-personalization-title" slot="title"> <cr-icon-button id="adPersonalizationBackButton" class="icon-arrow-back" - on-click="onAdPersonalizationRowClick_"> + on-click="onAdPersonalizationBackButtonClick_"> </cr-icon-button> <span class="flex"> $i18n{privacySandboxAdPersonalizationDialogTitle}
diff --git a/chrome/browser/resources/settings/privacy_sandbox/app.ts b/chrome/browser/resources/settings/privacy_sandbox/app.ts index 42b6984..80b0dda 100644 --- a/chrome/browser/resources/settings/privacy_sandbox/app.ts +++ b/chrome/browser/resources/settings/privacy_sandbox/app.ts
@@ -189,26 +189,41 @@ // Stop the propagation of events, so that clicking on links inside // actionable items won't trigger action. e.stopPropagation(); + this.metricsBrowserProxy_.recordAction( + 'Settings.PrivacySandbox.AdPersonalization.LearnMoreClicked'); this.privacySandboxSettingsView_ = PrivacySandboxSettingsView.LEARN_MORE_DIALOG; } private onAdPersonalizationRowClick_() { + this.metricsBrowserProxy_.recordAction( + 'Settings.PrivacySandbox.AdPersonalization.Opened'); this.privacySandboxSettingsView_ = PrivacySandboxSettingsView.AD_PERSONALIZATION_DIALOG; } private onAdPersonalizationRemovedRowClick_() { + this.metricsBrowserProxy_.recordAction( + 'Settings.PrivacySandbox.RemovedInterests.Opened'); this.privacySandboxSettingsView_ = PrivacySandboxSettingsView.AD_PERSONALIZATION_REMOVED_DIALOG; } + private onAdPersonalizationBackButtonClick_() { + this.privacySandboxSettingsView_ = + PrivacySandboxSettingsView.AD_PERSONALIZATION_DIALOG; + } + private onAdMeasurementRowClick_() { + this.metricsBrowserProxy_.recordAction( + 'Settings.PrivacySandbox.AdMeasurement.Opened'); this.privacySandboxSettingsView_ = PrivacySandboxSettingsView.AD_MEASUREMENT_DIALOG; } private onSpamAndFraudRowClick_() { + this.metricsBrowserProxy_.recordAction( + 'Settings.PrivacySandbox.SpamFraud.Opened'); this.privacySandboxSettingsView_ = PrivacySandboxSettingsView.SPAM_AND_FRAUD_DIALOG; } @@ -245,6 +260,10 @@ this.blockedTopics_ = this.blockedTopics_.slice(); // If the interest was previously removed, set it to allowed, and vice // versa. + this.metricsBrowserProxy_.recordAction( + interest.removed ? + 'Settings.PrivacySandbox.RemovedInterests.TopicAdded' : + 'Settings.PrivacySandbox.AdPersonalization.TopicRemoved'); this.privacySandboxBrowserProxy_.setTopicAllowed( interest.topic!, /*allowed=*/ interest.removed); } @@ -273,6 +292,10 @@ this.blockedSites_ = this.blockedSites_.slice(); // If the interest was previously removed, set it to allowed, and vice // versa. + this.metricsBrowserProxy_.recordAction( + interest.removed ? + 'Settings.PrivacySandbox.RemovedInterests.SiteAdded' : + 'Settings.PrivacySandbox.AdPersonalization.SiteRemoved'); this.privacySandboxBrowserProxy_.setFledgeJoiningAllowed( interest.site!, /*allowed=*/ interest.removed); }
diff --git a/chrome/browser/themes/theme_helper.cc b/chrome/browser/themes/theme_helper.cc index 76a3a8b..2532c17 100644 --- a/chrome/browser/themes/theme_helper.cc +++ b/chrome/browser/themes/theme_helper.cc
@@ -322,7 +322,7 @@ ui::NativeTheme* native_theme) const { // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is // complete. -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(USE_GTK) || BUILDFLAG(IS_CHROMEOS_LACROS) // On Linux the GTK system theme provides the high contrast colors, // so don't use the IncreasedContrastThemeSupplier. return false; @@ -382,12 +382,10 @@ return GetColor(TP::COLOR_TOOLBAR, incognito, theme_supplier); case TP::COLOR_BOOKMARK_FAVICON: { SkColor color; - if (theme_supplier && - theme_supplier->GetColor(TP::COLOR_TOOLBAR_BUTTON_ICON, &color)) { - return color; - } else { - return SK_ColorTRANSPARENT; - } + return (theme_supplier && + theme_supplier->GetColor(TP::COLOR_TOOLBAR_BUTTON_ICON, &color)) + ? color + : SK_ColorTRANSPARENT; } case TP::COLOR_FLYING_INDICATOR_BACKGROUND: return GetColor(TP::COLOR_TOOLBAR, incognito, theme_supplier); @@ -516,35 +514,11 @@ return IncreaseLightness( GetColor(TP::COLOR_NTP_TEXT, incognito, theme_supplier), 0.40); case TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE: - case TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE: { + case TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_INACTIVE: return GetColor(id == TP::COLOR_WINDOW_CONTROL_BUTTON_BACKGROUND_ACTIVE ? TP::COLOR_FRAME_ACTIVE : TP::COLOR_FRAME_INACTIVE, incognito, theme_supplier); - } - case TP::COLOR_THUMBNAIL_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE: { - // TODO(crbug.com/1292546): Make into a recipe once we have Color - // Pipeline support for Theme Properties. - SkColor background_color = - GetColor(TP::COLOR_FRAME_ACTIVE, incognito, theme_supplier); - // TODO(crbug.com/1292546): : Use kColorAccent when porting to color - // pipeline. - SkColor active_tab_title_color = color_utils::IsDark(background_color) - ? gfx::kGoogleBlue300 - : gfx::kGoogleBlue600; - - // Check if the preferred light/dark color meets desired minimum contrast - // against the current background color and if not, adjust alpha. - color_utils::BlendResult blend_color_result = - color_utils::BlendForMinContrast( - active_tab_title_color, background_color, absl::nullopt, - color_utils::kMinimumVisibleContrastRatio); - return blend_color_result.color; - } - case TP::COLOR_THUMBNAIL_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE: - return color_utils::GetColorWithMaxContrast(GetDefaultColor( - TP::COLOR_THUMBNAIL_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE, incognito, - theme_supplier)); } return TP::GetDefaultColor(id, incognito, UseDarkModeColors(theme_supplier));
diff --git a/chrome/browser/themes/theme_properties.h b/chrome/browser/themes/theme_properties.h index 6115464..19070d2 100644 --- a/chrome/browser/themes/theme_properties.h +++ b/chrome/browser/themes/theme_properties.h
@@ -298,10 +298,6 @@ COLOR_OMNIBOX_SECURITY_CHIP_SECURE, COLOR_OMNIBOX_SECURITY_CHIP_DANGEROUS, - // The colors used for thumbnail tab visualizations, - COLOR_THUMBNAIL_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE, - COLOR_THUMBNAIL_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE, - // Colors used for the Bookmark bar COLOR_BOOKMARK_BAR_BACKGROUND, COLOR_BOOKMARK_BUTTON_ICON,
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index df8dd0a..ee9e238 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1293,11 +1293,15 @@ "tabs/pinned_tab_service_factory.h", "tabs/saved_tab_groups/saved_tab_group.cc", "tabs/saved_tab_groups/saved_tab_group.h", + "tabs/saved_tab_groups/saved_tab_group_keyed_service.cc", + "tabs/saved_tab_groups/saved_tab_group_keyed_service.h", "tabs/saved_tab_groups/saved_tab_group_model.cc", "tabs/saved_tab_groups/saved_tab_group_model.h", - "tabs/saved_tab_groups/saved_tab_group_model_factory.cc", - "tabs/saved_tab_groups/saved_tab_group_model_factory.h", + "tabs/saved_tab_groups/saved_tab_group_model_listener.cc", + "tabs/saved_tab_groups/saved_tab_group_model_listener.h", "tabs/saved_tab_groups/saved_tab_group_model_observer.h", + "tabs/saved_tab_groups/saved_tab_group_service_factory.cc", + "tabs/saved_tab_groups/saved_tab_group_service_factory.h", "tabs/tab_change_type.h", "tabs/tab_group.cc", "tabs/tab_group.h",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java index 52fbb405..5f8c03c1 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -435,33 +435,36 @@ @Override public void onSwitchToTab(AutocompleteMatch suggestion, int matchIndex) { - Tab tab = mAutocomplete.getMatchingTabForSuggestion(matchIndex); - if (tab == null || !mTabWindowManagerSupplier.hasValue()) { + if (maybeSwitchToTab(matchIndex)) { + recordMetrics(matchIndex, WindowOpenDisposition.SWITCH_TO_TAB, suggestion); + } else { onSuggestionClicked(suggestion, matchIndex, suggestion.getUrl()); - return; } + } + + @VisibleForTesting + public boolean maybeSwitchToTab(int matchIndex) { + Tab tab = mAutocomplete.getMatchingTabForSuggestion(matchIndex); + if (tab == null || !mTabWindowManagerSupplier.hasValue()) return false; // When invoked directly from a browser, we want to trigger switch to tab animation. // If invoked from other activities, ex. searchActivity, we do not need to trigger the // animation since Android will show the animation for switching apps. - if (tab.getWindowAndroid().getActivityState() != ActivityState.STOPPED - && tab.getWindowAndroid().getActivityState() != ActivityState.DESTROYED) { - TabModel tabModel = mTabWindowManagerSupplier.get().getTabModelForTab(tab); - assert tabModel != null; - - int tabIndex = TabModelUtils.getTabIndexById(tabModel, tab.getId()); - // In the event the user deleted the tab as part during the interaction with the - // Omnibox, reject the switch to tab action. - if (tabIndex < 0) { - onSuggestionClicked(suggestion, matchIndex, suggestion.getUrl()); - return; - } - - tabModel.setIndex(tabIndex, TabSelectionType.FROM_OMNIBOX, false); - } else { + if (tab.getWindowAndroid().getActivityState() == ActivityState.STOPPED + || tab.getWindowAndroid().getActivityState() == ActivityState.DESTROYED) { mBringTabToFrontCallback.onResult(tab); + return true; } - recordMetrics(matchIndex, WindowOpenDisposition.SWITCH_TO_TAB, suggestion); + + TabModel tabModel = mTabWindowManagerSupplier.get().getTabModelForTab(tab); + if (tabModel == null) return false; + + int tabIndex = TabModelUtils.getTabIndexById(tabModel, tab.getId()); + // In the event the user deleted the tab as part during the interaction with the + // Omnibox, reject the switch to tab action. + if (tabIndex == TabModel.INVALID_TAB_INDEX) return false; + tabModel.setIndex(tabIndex, TabSelectionType.FROM_OMNIBOX, false); + return true; } @Override
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index c721fd5..c65d3b5 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -5387,8 +5387,8 @@ <message name="IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT" desc="Header for sign in sheet. Sheet is shown to prompt user for sign in consent." translateable="false"> Sign in to <ph name="SITE_ETLD_PLUS_ONE">%1$s<ex>rp.example</ex></ph> with <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">%2$s<ex>idp.com</ex></ph> </message> - <message name="IDS_ACCOUNT_SELECTION_DATA_SHARING_CONSENT_NO_LINKS" desc="The consent text shown to the user before sign up." translateable="false"> - To continue, <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">%1$s<ex>idp.com</ex></ph> will share your name, email, address, and profile picture with this site. + <message name="IDS_ACCOUNT_SELECTION_DATA_SHARING_CONSENT_NO_TOS" desc="The consent text shown to the user before sign up when there are no terms of service." translateable="false"> + To continue, <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">%1$s<ex>idp.com</ex></ph> will share your name, email, address, and profile picture with this site. See this site's <ph name="BEGIN_LINK1"><link_privacy_policy></ph>privacy policy<ph name="END_LINK1"></link_privacy_policy></ph>. </message> <message name="IDS_ACCOUNT_SELECTION_DATA_SHARING_CONSENT" desc="The consent text shown to the user before sign up." translateable="false"> To continue, <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">%1$s<ex>idp.com</ex></ph> will share your name, email, address, and profile picture with this site. See this site's <ph name="BEGIN_LINK1"><link_privacy_policy></ph>privacy policy<ph name="END_LINK1"></link_privacy_policy></ph> and <ph name="BEGIN_LINK2"><link_terms_of_service></ph>terms of service<ph name="END_LINK2"></link_terms_of_service></ph>.
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java index abda010..51be240 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -19,6 +19,7 @@ import android.view.View.OnClickListener; import android.view.ViewStub; import android.widget.ImageButton; +import android.widget.ImageView; import androidx.annotation.ColorRes; import androidx.annotation.VisibleForTesting; @@ -96,6 +97,7 @@ private ImageButton[] mToolbarButtons; private ImageButton mOptionalButton; private boolean mOptionalButtonUsesTint; + private ImageView mToolbarShadow; private NavigationPopup mNavigationPopup; @@ -298,6 +300,13 @@ } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + mToolbarShadow = (ImageView) getRootView().findViewById(R.id.toolbar_shadow); + } + + @Override public void onWindowFocusChanged(boolean hasWindowFocus) { // Ensure the the popup is not shown after resuming activity from background. if (hasWindowFocus && mNavigationPopup != null) { @@ -364,6 +373,17 @@ mShowTabStack || enabled ? View.VISIBLE : View.GONE); } + /** + * Update the visibility of the toolbar shadow. + */ + private void updateShadowVisibility() { + int shadowVisibility = mIsInTabSwitcherMode ? View.INVISIBLE : View.VISIBLE; + + if (mToolbarShadow != null && mToolbarShadow.getVisibility() != shadowVisibility) { + mToolbarShadow.setVisibility(shadowVisibility); + } + } + @Override boolean isReadyForTextureCapture() { return !urlHasFocus(); @@ -485,7 +505,10 @@ MenuButtonCoordinator menuButtonCoordinator) { boolean isInTabSwitcherMode = mShowTabStack && inTabSwitcherMode; mIsInTabSwitcherMode = isInTabSwitcherMode; - if (isGridTabSwitcherEnabled()) { + if (isTabletGridTabSwitcherPolishEnabled()) { + // No impact to tablet toolbar. + return; + } else if (isGridTabSwitcherEnabled()) { setTabSwitcherModeWithAnimation(delayAnimation); } else { if (mIsInTabSwitcherMode) { @@ -513,6 +536,7 @@ if (mIsInTabSwitcherMode) { mLocationBar.setUrlBarFocusable(false); + updateShadowVisibility(); } setVisibility(View.VISIBLE); setAlpha(startAlpha); @@ -528,6 +552,7 @@ setVisibility(endVisibility); if (!mIsInTabSwitcherMode) { mLocationBar.setUrlBarFocusable(true); + updateShadowVisibility(); } } }); @@ -797,4 +822,9 @@ private boolean isGridTabSwitcherEnabled() { return CachedFeatureFlags.isEnabled(ChromeFeatureList.GRID_TAB_SWITCHER_FOR_TABLETS); } + + private boolean isTabletGridTabSwitcherPolishEnabled() { + return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + ChromeFeatureList.GRID_TAB_SWITCHER_FOR_TABLETS, "enable_launch_polish", false); + } }
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java index 0ae77467..fbe750a 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java
@@ -189,24 +189,24 @@ SpanApplier.SpanInfo termsOfServiceSpan = createLink(context, properties.mTermsOfServiceUrl, "link_terms_of_service"); - // TODO(crbug.com/1293913): Validate string choices. - int consentTextId = (privacyPolicySpan == null && termsOfServiceSpan == null) - ? R.string.account_selection_data_sharing_consent_no_links + int consentTextId = termsOfServiceSpan == null + ? R.string.account_selection_data_sharing_consent_no_tos : R.string.account_selection_data_sharing_consent; String consentText = String.format(view.getContext().getString(consentTextId), properties.mFormattedIdpEtldPlusOne); - // If the consent text includes the link for the privacy policy or the terms of service, - // and there is no corresponding URL, remove the link tag. + // If the consent text includes the link for the privacy policy and there is no + // corresponding URL, remove the link tag. This cannot happen for the terms of service + // as we just performed the check. This could potentially happen for privacy policy + // because the API checks whether there is some nonempty string provided, but we later + // transform this into a URL, and it may become empty when sanity checking. List<SpanApplier.SpanInfo> spans = new ArrayList<>(); if (privacyPolicySpan == null) { consentText = consentText.replaceAll("</?link_privacy_policy>", ""); } else { spans.add(privacyPolicySpan); } - if (termsOfServiceSpan == null) { - consentText = consentText.replaceAll("</?link_terms_of_service>", ""); - } else { + if (termsOfServiceSpan != null) { spans.add(termsOfServiceSpan); }
diff --git a/chrome/browser/ui/app_list/reorder/app_list_reorder_core.cc b/chrome/browser/ui/app_list/reorder/app_list_reorder_core.cc index 539b98d..4ec75ab 100644 --- a/chrome/browser/ui/app_list/reorder/app_list_reorder_core.cc +++ b/chrome/browser/ui/app_list/reorder/app_list_reorder_core.cc
@@ -493,7 +493,7 @@ std::vector<reorder::ReorderParam> GenerateReorderParamsForAppListItems( ash::AppListSortOrder order, const std::vector<const ChromeAppListItem*>& app_list_items) { - DCHECK_GT(app_list_items.size(), 1); + DCHECK_GT(app_list_items.size(), 1u); switch (order) { case ash::AppListSortOrder::kNameAlphabetical: case ash::AppListSortOrder::kNameReverseAlphabetical: {
diff --git a/chrome/browser/ui/app_list/search/ranking/query_highlighter.cc b/chrome/browser/ui/app_list/search/ranking/query_highlighter.cc index 11bb279..2e857963 100644 --- a/chrome/browser/ui/app_list/search/ranking/query_highlighter.cc +++ b/chrome/browser/ui/app_list/search/ranking/query_highlighter.cc
@@ -8,6 +8,26 @@ #include "chrome/browser/ui/app_list/search/search_tags_util.h" namespace app_list { +namespace { + +using TextVector = std::vector<ash::SearchResultTextItem>; + +void SetMatchTags(const std::u16string& query, TextVector& text_vector) { + for (auto& item : text_vector) { + if (item.GetType() != ash::SearchResultTextItemType::kString) + continue; + + ash::SearchResultTags tags = item.GetTextTags(); + // Remove any existing match tags before re-calculating them. + for (auto& tag : tags) { + tag.styles &= ~ash::SearchResultTag::MATCH; + } + AppendMatchTags(query, item.GetText(), &tags); + item.SetTextTags(tags); + } +} + +} // namespace QueryHighlighter::QueryHighlighter() = default; QueryHighlighter::~QueryHighlighter() = default; @@ -28,8 +48,13 @@ if (result->display_type() == ChromeSearchResult::DisplayType::kAnswerCard) continue; - result->SetTitleTags(CalculateTags(last_query_, result->title())); - result->SetDetailsTags(CalculateTags(last_query_, result->details())); + TextVector title_vector = result->title_text_vector(); + SetMatchTags(last_query_, title_vector); + result->SetTitleTextVector(title_vector); + + TextVector details_vector = result->details_text_vector(); + SetMatchTags(last_query_, details_vector); + result->SetDetailsTextVector(details_vector); } }
diff --git a/chrome/browser/ui/app_list/search/ranking/query_highlighter_unittest.cc b/chrome/browser/ui/app_list/search/ranking/query_highlighter_unittest.cc new file mode 100644 index 0000000..0918f6f --- /dev/null +++ b/chrome/browser/ui/app_list/search/ranking/query_highlighter_unittest.cc
@@ -0,0 +1,111 @@ +// 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/ranking/query_highlighter.h" + +#include "chrome/browser/ui/app_list/search/chrome_search_result.h" +#include "chrome/browser/ui/app_list/search/ranking/ranker.h" +#include "chrome/browser/ui/app_list/search/ranking/types.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace app_list { +namespace { + +using Tag = ash::SearchResultTag; + +class TestResult : public ChromeSearchResult { + public: + TestResult() = default; + ~TestResult() override = default; + + // ChromeSearchResult overrides: + void Open(int event_flags) override {} +}; + +Results MakeResults(const std::vector<std::u16string>& titles) { + Results results; + for (const auto& title : titles) { + auto result = std::make_unique<TestResult>(); + result->SetTitle(title); + result->SetTitleTags({Tag(Tag::URL | Tag::MATCH, 0, title.length())}); + results.push_back(std::move(result)); + } + return results; +} + +} // namespace + +TEST(QueryHighlighterTest, KeepExistingNonMatchTags) { + QueryHighlighter highlighter; + + ResultsMap results; + CategoriesList categories({{.category = Category::kWeb}}); + highlighter.Start(u"example", results, categories); + + results[ResultType::kOmnibox] = MakeResults({u"example_result"}); + + // The example result is initialized with a URL tag. + auto tags = + results[ResultType::kOmnibox][0]->title_text_vector()[0].GetTextTags(); + ASSERT_EQ(tags.size(), 1); + EXPECT_TRUE(tags[0].styles & Tag::URL); + + highlighter.UpdateResultRanks(results, ProviderType::kOmnibox); + + // The URL tag should still be there. + tags = results[ResultType::kOmnibox][0]->title_text_vector()[0].GetTextTags(); + ASSERT_GE(tags.size(), 1); + EXPECT_TRUE(tags[0].styles & Tag::URL); +} + +TEST(QueryHighlighterTest, RemoveExistingMatchTags) { + QueryHighlighter highlighter; + + ResultsMap results; + CategoriesList categories({{.category = Category::kWeb}}); + highlighter.Start(u"example", results, categories); + + results[ResultType::kOmnibox] = MakeResults({u"example_result"}); + + // The example result is initialized with a MATCH tag. + auto tags = + results[ResultType::kOmnibox][0]->title_text_vector()[0].GetTextTags(); + ASSERT_EQ(tags.size(), 1); + EXPECT_TRUE(tags[0].styles & Tag::MATCH); + + highlighter.UpdateResultRanks(results, ProviderType::kOmnibox); + + // The MATCH tag should be removed. + tags = results[ResultType::kOmnibox][0]->title_text_vector()[0].GetTextTags(); + ASSERT_GE(tags.size(), 1); + EXPECT_FALSE(tags[0].styles & Tag::MATCH); +} + +TEST(QueryHighlighterTest, AppendMatchTags) { + QueryHighlighter highlighter; + + ResultsMap results; + CategoriesList categories({{.category = Category::kWeb}}); + highlighter.Start(u"example", results, categories); + + results[ResultType::kOmnibox] = MakeResults({u"example_result"}); + + // The example result is initialized with one tag. + auto tags = + results[ResultType::kOmnibox][0]->title_text_vector()[0].GetTextTags(); + EXPECT_EQ(tags.size(), 1); + + highlighter.UpdateResultRanks(results, ProviderType::kOmnibox); + + // The query highlighter should have appended more tags, all of which are + // MATCH only. + tags = results[ResultType::kOmnibox][0]->title_text_vector()[0].GetTextTags(); + ASSERT_GT(tags.size(), 1); + for (int i = 1; i < tags.size(); ++i) { + EXPECT_EQ(tags[i].styles, Tag::MATCH); + } +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_tags_util.cc b/chrome/browser/ui/app_list/search/search_tags_util.cc index 761619e1..ab43f87 100644 --- a/chrome/browser/ui/app_list/search/search_tags_util.cc +++ b/chrome/browser/ui/app_list/search/search_tags_util.cc
@@ -54,15 +54,21 @@ ChromeSearchResult::Tags CalculateTags(const std::u16string& query, const std::u16string& text) { + ChromeSearchResult::Tags tags; + AppendMatchTags(query, text, &tags); + return tags; +} + +void AppendMatchTags(const std::u16string& query, + const std::u16string& text, + ChromeSearchResult::Tags* tags) { const auto matches = FindTermMatches(query, text); const auto classes = ClassifyTermMatches(matches, text.length(), /*match_style=*/ACMatchClassification::MATCH, /*non_match_style=*/ACMatchClassification::NONE); - ChromeSearchResult::Tags tags; - ACMatchClassificationsToTags(text, classes, &tags); - return tags; + ACMatchClassificationsToTags(text, classes, tags); } } // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_tags_util.h b/chrome/browser/ui/app_list/search/search_tags_util.h index 77cf027..c79b484d 100644 --- a/chrome/browser/ui/app_list/search/search_tags_util.h +++ b/chrome/browser/ui/app_list/search/search_tags_util.h
@@ -15,13 +15,17 @@ const ACMatchClassifications& text_classes, ChromeSearchResult::Tags* tags); -// TODO(crbug.com/1258415): Remove references to this from individual providers -// once the productivity launcher is enabled. -// Calculates ChromeSearchResult tags for highlighting occurrences of |query| in -// |text|. +// TODO(crbug.com/1258415): Remove this and its references once the productivity +// launcher is enabled. ChromeSearchResult::Tags CalculateTags(const std::u16string& query, const std::u16string& text); +// Calculates ChromeSearchResult tags for highlighting occurrences of |query| in +// |text|, and appends them to supplied Tags. +void AppendMatchTags(const std::u16string& query, + const std::u16string& text, + ChromeSearchResult::Tags* tags); + } // namespace app_list #endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_TAGS_UTIL_H_
diff --git a/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.cc b/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.cc index 4ec55bf..81f1d19b 100644 --- a/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.cc +++ b/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.cc
@@ -367,3 +367,16 @@ /*description_placeholder_text=*/std::string(), /*category_tag=*/std::string(), extra_diagnostics); } + +std::string ChromeDesksTemplatesDelegate::GetAppShortName( + const std::string& app_id) { + std::string name; + auto* app_service_proxy = apps::AppServiceProxyFactory::GetForProfile( + ProfileManager::GetActiveUserProfile()); + DCHECK(app_service_proxy); + + app_service_proxy->AppRegistryCache().ForOneApp( + app_id, + [&name](const apps::AppUpdate& update) { name = update.ShortName(); }); + return name; +}
diff --git a/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.h b/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.h index cebd2ee..8b658d6 100644 --- a/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.h +++ b/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.h
@@ -49,6 +49,7 @@ base::TimeDelta delay) override; bool IsWindowSupportedForDeskTemplate(aura::Window* window) const override; void OpenFeedbackDialog(const std::string& extra_diagnostics) override; + std::string GetAppShortName(const std::string& app_id) override; }; #endif // CHROME_BROWSER_UI_ASH_DESKS_TEMPLATES_CHROME_DESKS_TEMPLATES_DELEGATE_H_
diff --git a/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc b/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc index a92e1e3..fe95cee 100644 --- a/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc +++ b/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc
@@ -1125,7 +1125,7 @@ // once the extension is deprecated. IN_PROC_BROWSER_TEST_F(DesksTemplatesClientTest, SystemUIBasic) { auto* desk_model = DesksTemplatesClient::Get()->GetDeskModel(); - ASSERT_EQ(0, desk_model->GetEntryCount()); + ASSERT_EQ(0u, desk_model->GetEntryCount()); ash::ToggleOverview(); ash::WaitForOverviewEnterAnimation(); @@ -1146,7 +1146,7 @@ ash::WaitForDesksTemplatesUI(); - EXPECT_EQ(1, desk_model->GetEntryCount()); + EXPECT_EQ(1u, desk_model->GetEntryCount()); // Tests that since we have one template right now, so that the expanded state // desk button is shown, and the desk templates grid has one item. @@ -1999,7 +1999,7 @@ IN_PROC_BROWSER_TEST_F(DesksTemplatesClientArcTest, SystemUILaunchTemplateWithArcApp) { auto* desk_model = DesksTemplatesClient::Get()->GetDeskModel(); - ASSERT_EQ(0, desk_model->GetEntryCount()); + ASSERT_EQ(0u, desk_model->GetEntryCount()); constexpr char kTestAppPackage[] = "test.arc.app.package"; arc_helper()->InstallTestApps(kTestAppPackage, /*multi_app=*/false); @@ -2026,7 +2026,7 @@ ash::WaitForOverviewEnterAnimation(); ClickSaveDeskAsTemplateButton(); - ASSERT_EQ(1, desk_model->GetEntryCount()); + ASSERT_EQ(1u, desk_model->GetEntryCount()); // Exit overview and close the Arc window. We'll need to verify if it // reopens later.
diff --git a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc index 76a260c..d753a36 100644 --- a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc +++ b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc
@@ -300,7 +300,7 @@ if (has_files) { ResolveImages(); } else { - DCHECK_GT(image_preview_->GetImageViewCount(), 0); + DCHECK_GT(image_preview_->GetImageViewCount(), 0u); const auto icon_color = ColorProvider::Get()->GetContentLayerColor( ColorProvider::ContentLayerType::kIconColorProminent); gfx::ImageSkia file_type_icon = gfx::CreateVectorIcon(
diff --git a/chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.cc index b5cab1f..f1cb294f 100644 --- a/chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.cc +++ b/chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.cc
@@ -145,7 +145,8 @@ Show(); } else if (visibility == content::Visibility::HIDDEN) { HideBubble(); - bubble_state_ = BubbleState::kShowingIcon; + if (bubble_state_ != BubbleState::kShowingIcon) + bubble_state_ = BubbleState::kHidden; } #endif }
diff --git a/chrome/browser/ui/color/BUILD.gn b/chrome/browser/ui/color/BUILD.gn index 982970d..b18a4ae 100644 --- a/chrome/browser/ui/color/BUILD.gn +++ b/chrome/browser/ui/color/BUILD.gn
@@ -29,7 +29,9 @@ deps = [ ":color_headers", "//build:branding_buildflags", + "//build:chromeos_buildflags", "//chrome/browser:theme_properties", + "//ui/base:buildflags", "//ui/color:color", "//ui/color:mixers", ]
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h index af4edf29..acb38aa 100644 --- a/chrome/browser/ui/color/chrome_color_id.h +++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -211,6 +211,9 @@ ThemeProperties::COLOR_TAB_GROUP_BOOKMARK_BAR_CYAN) \ E(kColorTabGroupBookmarkBarOrange, \ ThemeProperties::COLOR_TAB_GROUP_BOOKMARK_BAR_ORANGE) \ + /* Thumbnail tab colors. */ \ + E_CPONLY(kColorThumbnailTabBackground) \ + E_CPONLY(kColorThumbnailTabForeground) \ /* Toolbar colors. */ \ E(kColorToolbar, ThemeProperties::COLOR_TOOLBAR) \ E(kColorToolbarButtonBackground, \
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc index c5e56ba5..96b1d74 100644 --- a/chrome/browser/ui/color/chrome_color_mixer.cc +++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -327,6 +327,11 @@ mixer[kColorTabGroupBookmarkBarOrange] = SelectColorBasedOnDarkInputOrMode( dark_mode, input_transform, flat_orange, {gfx::kGoogleOrange050}); + mixer[kColorThumbnailTabBackground] = ui::BlendForMinContrast( + ui::kColorAccent, ui::kColorFrameActive, absl::nullopt, + color_utils::kMinimumVisibleContrastRatio); + mixer[kColorThumbnailTabForeground] = + ui::GetColorWithMaxContrast(kColorThumbnailTabBackground); mixer[kColorToolbar] = {dark_mode ? kDarkToolbarColor : kLightToolbarColor}; mixer[kColorToolbarButtonBackground] = ui::GetColorWithMaxContrast(kColorToolbarButtonText);
diff --git a/chrome/browser/ui/color/omnibox_color_mixer.cc b/chrome/browser/ui/color/omnibox_color_mixer.cc index ba7c317..b329cf1 100644 --- a/chrome/browser/ui/color/omnibox_color_mixer.cc +++ b/chrome/browser/ui/color/omnibox_color_mixer.cc
@@ -4,7 +4,11 @@ #include "chrome/browser/ui/color/omnibox_color_mixer.h" +#include "build/build_config.h" +#include "build/buildflag.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/color/chrome_color_id.h" +#include "ui/base/buildflags.h" #include "ui/color/color_id.h" #include "ui/color/color_mixer.h" #include "ui/color/color_provider.h" @@ -13,10 +17,41 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" +namespace { + +// The contrast for omnibox colors in high contrast mode. +constexpr float kOmniboxHighContrastRatio = 6.0f; + +} // namespace + void AddOmniboxColorMixer(ui::ColorProvider* provider, const ui::ColorProviderManager::Key& key) { ui::ColorMixer& mixer = provider->AddMixer(); +// Only apply custom high contrast handling on platforms where we are not using +// the system theme for high contrast. +#if BUILDFLAG(USE_GTK) || BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_WIN) + const bool high_contrast_custom_handling = false; +#else + const bool high_contrast_custom_handling = + key.contrast_mode == ui::ColorProviderManager::ContrastMode::kHigh; +#endif + + const float contrast_ratio = high_contrast_custom_handling + ? kOmniboxHighContrastRatio + : color_utils::kMinimumReadableContrastRatio; + // kColorOmniboxResultsBackgroundSelected, kColorOmniboxResultsTextSelected, + // kColorOmniboxResultsTextDimmedSelected, kColorOmniboxResultsIconSelected, + // and kColorOmniboxResultsUrlSelected will use inverted base colors in high + // contrast mode. + const auto selected_background_color = + high_contrast_custom_handling + ? ui::ContrastInvert(kColorOmniboxBackground) + : kColorOmniboxBackground; + const auto selected_text_color = high_contrast_custom_handling + ? ui::ContrastInvert(kColorOmniboxText) + : kColorOmniboxText; + // Omnibox background colors. mixer[kColorOmniboxBackground] = ui::GetResultingPaintColor(ui::FromTransformInput(), kColorToolbar); @@ -26,7 +61,7 @@ // Omnibox text colors. mixer[kColorOmniboxText] = ui::GetResultingPaintColor( ui::FromTransformInput(), kColorOmniboxBackground); - mixer[kColorOmniboxResultsTextSelected] = {kColorOmniboxText}; + mixer[kColorOmniboxResultsTextSelected] = {selected_text_color}; mixer[kColorOmniboxKeywordSelected] = ui::SelectBasedOnDarkInput( kColorOmniboxBackground, gfx::kGoogleGrey100, kColorOmniboxResultsUrl); @@ -48,10 +83,11 @@ // Results icon colors. { - const auto results_icon = [](ui::ColorId text_id, - ui::ColorId background_id) { + const auto results_icon = [contrast_ratio](ui::ColorId text_id, + ui::ColorId background_id) { return ui::BlendForMinContrast(ui::DeriveDefaultIconColor(text_id), - background_id); + background_id, absl::nullopt, + contrast_ratio); }; mixer[kColorOmniboxResultsIcon] = results_icon(kColorOmniboxText, kColorOmniboxResultsBackground); @@ -62,12 +98,14 @@ // Dimmed text colors. { - const auto blend_with_clamped_contrast = [](ui::ColorId foreground_id, - ui::ColorId background_id) { - return ui::BlendForMinContrast( - foreground_id, foreground_id, - ui::BlendForMinContrast(background_id, background_id)); - }; + const auto blend_with_clamped_contrast = + [contrast_ratio](ui::ColorId foreground_id, ui::ColorId background_id) { + return ui::BlendForMinContrast( + foreground_id, foreground_id, + ui::BlendForMinContrast(background_id, background_id, + absl::nullopt, contrast_ratio), + contrast_ratio); + }; mixer[kColorOmniboxResultsTextDimmed] = blend_with_clamped_contrast( kColorOmniboxText, kColorOmniboxResultsBackgroundHovered); mixer[kColorOmniboxResultsTextDimmedSelected] = @@ -79,26 +117,29 @@ // Results URL colors. { - const auto url_color = [](ui::ColorId id) { + const auto url_color = [contrast_ratio](ui::ColorId id, + ui::ColorTransform background) { return ui::BlendForMinContrast( gfx::kGoogleBlue500, id, - ui::SelectBasedOnDarkInput(kColorOmniboxBackground, - gfx::kGoogleBlue050, gfx::kGoogleBlue900)); + ui::SelectBasedOnDarkInput(background, gfx::kGoogleBlue050, + gfx::kGoogleBlue900), + contrast_ratio); }; - mixer[kColorOmniboxResultsUrl] = - url_color(kColorOmniboxResultsBackgroundHovered); - mixer[kColorOmniboxResultsUrlSelected] = - url_color(kColorOmniboxResultsBackgroundSelected); + + mixer[kColorOmniboxResultsUrl] = url_color( + kColorOmniboxResultsBackgroundHovered, kColorOmniboxBackground); + mixer[kColorOmniboxResultsUrlSelected] = url_color( + kColorOmniboxResultsBackgroundSelected, selected_background_color); } // Security chip colors. { - const auto security_chip_color = [](SkColor dark_input, - SkColor light_input) { + const auto security_chip_color = [contrast_ratio](SkColor dark_input, + SkColor light_input) { return ui::BlendForMinContrast( ui::SelectBasedOnDarkInput(kColorOmniboxBackground, dark_input, light_input), - kColorOmniboxBackgroundHovered); + kColorOmniboxBackgroundHovered, absl::nullopt, contrast_ratio); }; mixer[kColorOmniboxSecurityChipDangerous] =
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc new file mode 100644 index 0000000..d2eae3c --- /dev/null +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
@@ -0,0 +1,24 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h" + +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h" +#include "components/keyed_service/core/keyed_service.h" + +class Profile; + +SavedTabGroupKeyedService::SavedTabGroupKeyedService(Profile* profile) + : model_(profile), listener_(&model_), profile_(profile) {} + +SavedTabGroupKeyedService::~SavedTabGroupKeyedService() = default; + +SavedTabGroupModel* SavedTabGroupKeyedService::model() { + return &model_; +} + +Profile* SavedTabGroupKeyedService::profile() { + return profile_; +}
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h new file mode 100644 index 0000000..b89a18c2 --- /dev/null +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h
@@ -0,0 +1,31 @@ +// 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_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_KEYED_SERVICE_H_ +#define CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_KEYED_SERVICE_H_ + +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h" +#include "components/keyed_service/core/keyed_service.h" + +class Profile; + +class SavedTabGroupKeyedService : public KeyedService { + public: + explicit SavedTabGroupKeyedService(Profile* profile); + SavedTabGroupKeyedService(const SavedTabGroupKeyedService&) = delete; + SavedTabGroupKeyedService& operator=(const SavedTabGroupKeyedService& other) = + delete; + ~SavedTabGroupKeyedService() override; + + SavedTabGroupModel* model(); + Profile* profile(); + + private: + SavedTabGroupModel model_; + SavedTabGroupModelListener listener_; + Profile* profile_ = nullptr; +}; + +#endif // CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_KEYED_SERVICE_H_
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.cc index 8314bf74..f26c8cc 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.cc +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.cc
@@ -1,26 +1,27 @@ // 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/tabs/saved_tab_groups/saved_tab_group_model.h" #include <vector> #include "base/observer_list.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_observer.h" +#include "chrome/browser/ui/tabs/tab_group.h" #include "components/tab_groups/tab_group_color.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_visual_data.h" -struct SavedTabGroup; - SavedTabGroupModel::SavedTabGroupModel() = default; SavedTabGroupModel::~SavedTabGroupModel() = default; +SavedTabGroupModel::SavedTabGroupModel(Profile* profile) : profile_(profile) {} + int SavedTabGroupModel::GetIndexOf(tab_groups::TabGroupId tab_group_id) { - for (int i = 0; i < Count(); i++) { + for (int i = 0; i < Count(); i++) if (saved_tab_groups_[i].group_id == tab_group_id) return i; - } return -1; } @@ -37,15 +38,13 @@ if (!Contains(tab_group_id)) return; - const SavedTabGroup& saved_group = - saved_tab_groups_[GetIndexOf(tab_group_id)]; + const int index = GetIndexOf(tab_group_id); + saved_tab_groups_.erase(saved_tab_groups_.begin() + index); // Notify before the saved tab group is removed to give observers a chance to // update their views respectively. for (auto& observer : observers_) - observer.SavedTabGroupWillBeRemoved(saved_group); - - saved_tab_groups_.erase(saved_tab_groups_.begin() + GetIndexOf(tab_group_id)); + observer.SavedTabGroupRemoved(index); } void SavedTabGroupModel::Add(const SavedTabGroup& saved_group) { @@ -53,8 +52,9 @@ return; saved_tab_groups_.emplace_back(std::move(saved_group)); + const int index = Count() - 1; for (auto& observer : observers_) - observer.SavedTabGroupAdded(saved_tab_groups_[Count() - 1]); + observer.SavedTabGroupAdded(saved_tab_groups_[index], index); } void SavedTabGroupModel::Update( @@ -63,7 +63,8 @@ if (!Contains(tab_group_id)) return; - SavedTabGroup& saved_group = saved_tab_groups_[GetIndexOf(tab_group_id)]; + const int index = GetIndexOf(tab_group_id); + SavedTabGroup& saved_group = saved_tab_groups_[index]; if (saved_group.title == visual_data->title() && saved_group.color == visual_data->color()) return; @@ -71,7 +72,7 @@ saved_group.title = visual_data->title(); saved_group.color = visual_data->color(); for (auto& observer : observers_) - observer.SavedTabGroupUpdated(saved_group); + observer.SavedTabGroupUpdated(saved_group, index); } void SavedTabGroupModel::AddObserver(SavedTabGroupModelObserver* observer) {
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h index 4863490..8b848d2 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h
@@ -9,24 +9,24 @@ #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group.h" -#include "base/containers/contains.h" #include "base/observer_list.h" -#include "components/keyed_service/core/keyed_service.h" #include "components/tab_groups/tab_group_color.h" #include "components/tab_groups/tab_group_id.h" #include "components/tab_groups/tab_group_visual_data.h" +class Profile; class SavedTabGroupModelObserver; struct SavedTabGroup; // Serves to maintain the current state of all saved tab groups in the current // session. -class SavedTabGroupModel : public KeyedService { +class SavedTabGroupModel { public: SavedTabGroupModel(); + explicit SavedTabGroupModel(Profile* profile); SavedTabGroupModel(const SavedTabGroupModel&) = delete; SavedTabGroupModel& operator=(const SavedTabGroupModel& other) = delete; - ~SavedTabGroupModel() override; + ~SavedTabGroupModel(); const std::vector<SavedTabGroup>& saved_tab_groups() { return saved_tab_groups_; @@ -40,6 +40,7 @@ int Count() { return saved_tab_groups_.size(); } bool IsEmpty() { return Count() <= 0; } const SavedTabGroup* Get(const tab_groups::TabGroupId tab_group_id); + Profile* profile() { return profile_; } // Updates a single tab groups visual data (title, color). void Update(const tab_groups::TabGroupId tab_group_id, @@ -56,6 +57,7 @@ // The observers. base::ObserverList<SavedTabGroupModelObserver>::Unchecked observers_; std::vector<SavedTabGroup> saved_tab_groups_; + Profile* profile_ = nullptr; }; #endif // CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_MODEL_H_
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_factory.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_factory.cc deleted file mode 100644 index 025ed42..0000000 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_factory.cc +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_factory.h" - -#include "base/no_destructor.h" -#include "chrome/browser/profiles/incognito_helpers.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h" -#include "components/keyed_service/content/browser_context_dependency_manager.h" - -SavedTabGroupModelFactory& SavedTabGroupModelFactory::GetInstance() { - static base::NoDestructor<SavedTabGroupModelFactory> instance; - return *instance; -} - -// static -SavedTabGroupModel* SavedTabGroupModelFactory::GetForProfile(Profile* profile) { - return static_cast<SavedTabGroupModel*>( - GetInstance().GetServiceForBrowserContext(profile, true)); -} - -SavedTabGroupModelFactory::SavedTabGroupModelFactory() - : BrowserContextKeyedServiceFactory( - "SavedTabGroupModel", - BrowserContextDependencyManager::GetInstance()) {} - -SavedTabGroupModelFactory::~SavedTabGroupModelFactory() = default; - -KeyedService* SavedTabGroupModelFactory::BuildServiceInstanceFor( - content::BrowserContext* context) const { - return new SavedTabGroupModel(); -}
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_factory.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_factory.h deleted file mode 100644 index 92887b5..0000000 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_factory.h +++ /dev/null
@@ -1,32 +0,0 @@ -// 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_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_MODEL_FACTORY_H_ -#define CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_MODEL_FACTORY_H_ - -#include "base/memory/singleton.h" -#include "components/keyed_service/content/browser_context_keyed_service_factory.h" - -class Profile; -class SavedTabGroupModel; - -class SavedTabGroupModelFactory : public BrowserContextKeyedServiceFactory { - public: - SavedTabGroupModelFactory(); - SavedTabGroupModelFactory(const SavedTabGroupModelFactory&) = delete; - void operator=(const SavedTabGroupModelFactory&) = delete; - ~SavedTabGroupModelFactory() override; - - static SavedTabGroupModelFactory& GetInstance(); - static SavedTabGroupModel* GetForProfile(Profile* profile); - - private: - friend struct base::DefaultSingletonTraits<SavedTabGroupModelFactory>; - - // BrowserContextKeyedServiceFactory overrides. - KeyedService* BuildServiceInstanceFor( - content::BrowserContext* context) const override; -}; - -#endif // CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_MODEL_FACTORY_H_
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc new file mode 100644 index 0000000..68e6f9dd --- /dev/null +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.cc
@@ -0,0 +1,94 @@ +// 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/tabs/saved_tab_groups/saved_tab_group_model_listener.h" + +#include "base/containers/flat_set.h" +#include "base/memory/raw_ptr.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h" +#include "chrome/browser/ui/tabs/tab_group.h" +#include "chrome/browser/ui/tabs/tab_group_model.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" + +SavedTabGroupModelListener::SavedTabGroupModelListener() = default; + +SavedTabGroupModelListener::SavedTabGroupModelListener( + SavedTabGroupModel* model) + : model_(model) { + BrowserList::GetInstance()->AddObserver(this); + for (Browser* browser : *BrowserList::GetInstance()) + OnBrowserAdded(browser); +} + +SavedTabGroupModelListener::~SavedTabGroupModelListener() { + BrowserList::GetInstance()->RemoveObserver(this); + for (Browser* browser : *BrowserList::GetInstance()) { + // Note: Can no longer call OnBrowserRemoved here because model_ is already + // destroyed. + observed_browsers_.erase(browser); + browser->tab_strip_model()->RemoveObserver(this); + } +} + +void SavedTabGroupModelListener::OnBrowserAdded(Browser* browser) { + if (model_->profile() != browser->profile()) + return; + observed_browsers_.insert(browser); + browser->tab_strip_model()->AddObserver(this); +} + +void SavedTabGroupModelListener::OnBrowserRemoved(Browser* browser) { + if (model_->profile() != browser->profile()) + return; + observed_browsers_.erase(browser); + browser->tab_strip_model()->RemoveObserver(this); +} + +void SavedTabGroupModelListener::OnTabGroupChanged( + const TabGroupChange& change) { + const TabStripModel* tab_strip_model = change.model; + if (!model_->Contains(change.group)) + return; + + const TabGroup* group = + tab_strip_model->group_model()->GetTabGroup(change.group); + switch (change.type) { + // Called when a group is created the first tab is added. + case TabGroupChange::kCreated: { + NOTIMPLEMENTED(); + return; + } + // Called when a tab groups editor menu is opened. + case TabGroupChange::kEditorOpened: { + NOTIMPLEMENTED(); + return; + } + // Called when the tabs in the group changes. + case TabGroupChange::kContentsChanged: { + // TODO(dljames): kContentsChanged will update the urls associated with + // the group stored in the model with TabGroupId change.group. + NOTIMPLEMENTED(); + return; + } + // Called when a groups title or color changes + case TabGroupChange::kVisualsChanged: { + const tab_groups::TabGroupVisualData* visual_data = group->visual_data(); + model_->Update(change.group, visual_data); + return; + } + // Called when a groups is moved by interacting with its header. + case TabGroupChange::kMoved: { + NOTIMPLEMENTED(); + return; + } + // Called when the last tab in the groups is removed. + case TabGroupChange::kClosed: { + NOTIMPLEMENTED(); + return; + } + } +}
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h new file mode 100644 index 0000000..13056b87 --- /dev/null +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_listener.h
@@ -0,0 +1,41 @@ +// 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_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_MODEL_LISTENER_H_ +#define CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_MODEL_LISTENER_H_ + +#include "base/containers/flat_set.h" +#include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/browser_list_observer.h" +#include "chrome/browser/ui/tabs/tab_strip_model_observer.h" + +class Browser; +class SavedTabGroupModel; + +// Serves to maintain and listen to browsers who contain saved tab groups and +// update the model if a saved tab group was changed. +class SavedTabGroupModelListener : public BrowserListObserver, + public TabStripModelObserver { + public: + // Used for testing. + SavedTabGroupModelListener(); + explicit SavedTabGroupModelListener(SavedTabGroupModel* model); + SavedTabGroupModelListener(const SavedTabGroupModelListener&) = delete; + SavedTabGroupModelListener& operator=( + const SavedTabGroupModelListener& other) = delete; + ~SavedTabGroupModelListener() override; + + // BrowserListObserver: + void OnBrowserAdded(Browser* browser) override; + void OnBrowserRemoved(Browser* browser) override; + + // TabStripModelObserver: + void OnTabGroupChanged(const TabGroupChange& change) override; + + private: + base::flat_set<raw_ptr<Browser>> observed_browsers_; + SavedTabGroupModel* model_ = nullptr; +}; + +#endif // CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_MODEL_LISTENER_H_
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_observer.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_observer.h index 16bbb5d1..9ab280bd 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_observer.h +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_observer.h
@@ -16,13 +16,13 @@ delete; // Called when a saved tab group is added to the backend. - virtual void SavedTabGroupAdded(const SavedTabGroup& group) = 0; + virtual void SavedTabGroupAdded(const SavedTabGroup& group, int index) = 0; // Called when a saved tab group will be removed from the backend. - virtual void SavedTabGroupWillBeRemoved(const SavedTabGroup& group) = 0; + virtual void SavedTabGroupRemoved(int index) = 0; // Called when the title, urls, or color change - virtual void SavedTabGroupUpdated(const SavedTabGroup& group) = 0; + virtual void SavedTabGroupUpdated(const SavedTabGroup& group, int index) = 0; // Called when the order of saved tab groups in the bookmark bar are changed virtual void SavedTabGroupMoved(const SavedTabGroup& group) = 0;
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_unittest.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_unittest.cc index 254d00a0..6e1507b 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_unittest.cc +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_unittest.cc
@@ -30,16 +30,16 @@ void TearDown() override { saved_tab_group_model_.reset(); } - void SavedTabGroupAdded(const SavedTabGroup& group) override { + void SavedTabGroupAdded(const SavedTabGroup& group, int index) override { retrieved_group_.emplace_back(group); + retrieved_index_ = index; } - void SavedTabGroupWillBeRemoved(const SavedTabGroup& group) override { - retrieved_group_.emplace_back(group); - } + void SavedTabGroupRemoved(int index) override { retrieved_index_ = index; } - void SavedTabGroupUpdated(const SavedTabGroup& group) override { + void SavedTabGroupUpdated(const SavedTabGroup& group, int index) override { retrieved_group_.emplace_back(group); + retrieved_index_ = index; } void SavedTabGroupMoved(const SavedTabGroup& group) override { @@ -48,6 +48,7 @@ std::unique_ptr<SavedTabGroupModel> saved_tab_group_model_; std::vector<SavedTabGroup> retrieved_group_; + int retrieved_index_ = -1; std::string base_path_ = "file:///c:/tmp/"; }; @@ -259,16 +260,21 @@ SavedTabGroup group_4(id_4, title_4, color_4, urls_4); saved_tab_group_model_->Add(group_4); - SavedTabGroup received_group = retrieved_group_[retrieved_group_.size() - 1]; + const int index = retrieved_group_.size() - 1; + ASSERT_GE(index, 0); + + SavedTabGroup received_group = retrieved_group_[index]; EXPECT_EQ(group_4.group_id, received_group.group_id); EXPECT_EQ(group_4.title, received_group.title); EXPECT_EQ(group_4.color, received_group.color); EXPECT_EQ(group_4.urls, received_group.urls); + EXPECT_EQ(saved_tab_group_model_->GetIndexOf(received_group.group_id), + retrieved_index_); } -// Tests that SavedTabGroupModelObserver::WillBeRemoved passes the correct +// Tests that SavedTabGroupModelObserver::Removed passes the correct // element from the model. -TEST_F(SavedTabGroupModelObserverTest, WillBeRemovedElement) { +TEST_F(SavedTabGroupModelObserverTest, RemovedElement) { tab_groups::TabGroupId id_4 = tab_groups::TabGroupId::GenerateNew(); const std::u16string title_4 = u"Test Test"; const tab_groups::TabGroupColorId& color_4 = @@ -281,14 +287,22 @@ saved_tab_group_model_->Add(group_4); saved_tab_group_model_->Remove(id_4); - SavedTabGroup received_group = retrieved_group_[retrieved_group_.size() - 1]; + const int index = retrieved_group_.size() - 1; + ASSERT_GE(index, 0); + + SavedTabGroup received_group = retrieved_group_[index]; EXPECT_EQ(group_4.group_id, received_group.group_id); EXPECT_EQ(group_4.title, received_group.title); EXPECT_EQ(group_4.color, received_group.color); EXPECT_EQ(group_4.urls, received_group.urls); + + // The model will removed an and send the index that element was at before it + // was removed. Because the only element in the model exists, we get -1. + EXPECT_EQ(saved_tab_group_model_->GetIndexOf(received_group.group_id), -1); + EXPECT_EQ(retrieved_index_, 0); } -// Tests that SavedTabGroupModelObserver::WillBeRemoved passes the correct +// Tests that SavedTabGroupModelObserver::Updated passes the correct // element from the model. TEST_F(SavedTabGroupModelObserverTest, UpdatedElement) { tab_groups::TabGroupId id_4 = tab_groups::TabGroupId::GenerateNew(); @@ -310,9 +324,14 @@ /*is_collapsed*/ false); saved_tab_group_model_->Update(id_4, &new_visual_data); - SavedTabGroup received_group = retrieved_group_[retrieved_group_.size() - 1]; + const int index = retrieved_group_.size() - 1; + ASSERT_GE(index, 0); + + SavedTabGroup received_group = retrieved_group_[index]; EXPECT_EQ(id_4, received_group.group_id); EXPECT_EQ(new_title, received_group.title); EXPECT_EQ(new_color, received_group.color); EXPECT_EQ(group_4.urls, received_group.urls); + EXPECT_EQ(saved_tab_group_model_->GetIndexOf(received_group.group_id), + retrieved_index_); }
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.cc new file mode 100644 index 0000000..079a85c --- /dev/null +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.cc
@@ -0,0 +1,36 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h" + +#include "base/no_destructor.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +SavedTabGroupServiceFactory& SavedTabGroupServiceFactory::GetInstance() { + static base::NoDestructor<SavedTabGroupServiceFactory> instance; + return *instance; +} + +// static +SavedTabGroupKeyedService* SavedTabGroupServiceFactory::GetForProfile( + Profile* profile) { + return static_cast<SavedTabGroupKeyedService*>( + GetInstance().GetServiceForBrowserContext(profile, true /* create */)); +} + +SavedTabGroupServiceFactory::SavedTabGroupServiceFactory() + : BrowserContextKeyedServiceFactory( + "SavedTabGroupKeyedService", + BrowserContextDependencyManager::GetInstance()) {} + +SavedTabGroupServiceFactory::~SavedTabGroupServiceFactory() = default; + +KeyedService* SavedTabGroupServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + Profile* profile = Profile::FromBrowserContext(context); + return new SavedTabGroupKeyedService(profile); +}
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h new file mode 100644 index 0000000..6ac98ff4 --- /dev/null +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h
@@ -0,0 +1,32 @@ +// 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_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class Profile; + +class SavedTabGroupServiceFactory : public BrowserContextKeyedServiceFactory { + public: + SavedTabGroupServiceFactory(); + SavedTabGroupServiceFactory(const SavedTabGroupServiceFactory&) = delete; + void operator=(const SavedTabGroupServiceFactory&) = delete; + ~SavedTabGroupServiceFactory() override; + + static SavedTabGroupServiceFactory& GetInstance(); + static SavedTabGroupKeyedService* GetForProfile(Profile* profile); + + private: + friend struct base::DefaultSingletonTraits<SavedTabGroupServiceFactory>; + + // BrowserContextKeyedServiceFactory overrides. + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; +}; + +#endif // CHROME_BROWSER_UI_TABS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ui/tabs/tab_group.cc b/chrome/browser/ui/tabs/tab_group.cc index 795ae9e..b9f1ef5 100644 --- a/chrome/browser/ui/tabs/tab_group.cc +++ b/chrome/browser/ui/tabs/tab_group.cc
@@ -12,8 +12,10 @@ #include "base/check_op.h" #include "chrome/browser/ui/tab_ui_helper.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h" #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h" -#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_factory.h" + +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h" #include "chrome/browser/ui/tabs/tab_group_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/grit/generated_resources.h" @@ -142,16 +144,16 @@ urls.push_back(url); } - SavedTabGroupModel* backend = - SavedTabGroupModelFactory::GetForProfile(controller_->GetProfile()); + SavedTabGroupKeyedService* backend = + SavedTabGroupServiceFactory::GetForProfile(controller_->GetProfile()); SavedTabGroup saved_tab_group(id_, visual_data_->title(), visual_data_->color(), urls); - backend->Add(saved_tab_group); + backend->model()->Add(saved_tab_group); } void TabGroup::UnsaveGroup() { is_saved_ = false; - SavedTabGroupModel* backend = - SavedTabGroupModelFactory::GetForProfile(controller_->GetProfile()); - backend->Remove(id_); + SavedTabGroupKeyedService* backend = + SavedTabGroupServiceFactory::GetForProfile(controller_->GetProfile()); + backend->model()->Remove(id_); }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index 242bfe77..415d360 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1269,7 +1269,7 @@ if (!group_model_) return; - TabGroupChange change(group, TabGroupChange::kCreated); + TabGroupChange change(this, group, TabGroupChange::kCreated); for (auto& observer : observers_) observer.OnTabGroupChanged(change); } @@ -1278,7 +1278,7 @@ if (!group_model_) return; - TabGroupChange change(group, TabGroupChange::kEditorOpened); + TabGroupChange change(this, group, TabGroupChange::kEditorOpened); for (auto& observer : observers_) observer.OnTabGroupChanged(change); } @@ -1288,7 +1288,7 @@ if (!group_model_) return; - TabGroupChange change(group, TabGroupChange::kContentsChanged); + TabGroupChange change(this, group, TabGroupChange::kContentsChanged); for (auto& observer : observers_) observer.OnTabGroupChanged(change); } @@ -1299,7 +1299,7 @@ if (!group_model_) return; - TabGroupChange change(group, visuals); + TabGroupChange change(this, group, visuals); for (auto& observer : observers_) observer.OnTabGroupChanged(change); } @@ -1308,7 +1308,7 @@ if (!group_model_) return; - TabGroupChange change(group, TabGroupChange::kMoved); + TabGroupChange change(this, group, TabGroupChange::kMoved); for (auto& observer : observers_) observer.OnTabGroupChanged(change); } @@ -1317,7 +1317,7 @@ if (!group_model_) return; - TabGroupChange change(group, TabGroupChange::kClosed); + TabGroupChange change(this, group, TabGroupChange::kClosed); for (auto& observer : observers_) observer.OnTabGroupChanged(change); }
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.cc b/chrome/browser/ui/tabs/tab_strip_model_observer.cc index 4c321a5c..530bb99b 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_observer.cc +++ b/chrome/browser/ui/tabs/tab_strip_model_observer.cc
@@ -153,10 +153,11 @@ //////////////////////////////////////////////////////////////////////////////// // TabGroupChange // -TabGroupChange::TabGroupChange(tab_groups::TabGroupId group, +TabGroupChange::TabGroupChange(TabStripModel* model, + tab_groups::TabGroupId group, Type type, std::unique_ptr<Delta> deltap) - : group(group), type(type), delta(std::move(deltap)) {} + : group(group), model(model), type(type), delta(std::move(deltap)) {} TabGroupChange::~TabGroupChange() = default; @@ -168,9 +169,11 @@ return static_cast<const VisualsChange*>(delta.get()); } -TabGroupChange::TabGroupChange(tab_groups::TabGroupId group, +TabGroupChange::TabGroupChange(TabStripModel* model, + tab_groups::TabGroupId group, VisualsChange deltap) - : TabGroupChange(group, + : TabGroupChange(model, + group, Type::kVisualsChanged, std::make_unique<VisualsChange>(std::move(deltap))) {}
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.h b/chrome/browser/ui/tabs/tab_strip_model_observer.h index 591d919..e020717 100644 --- a/chrome/browser/ui/tabs/tab_strip_model_observer.h +++ b/chrome/browser/ui/tabs/tab_strip_model_observer.h
@@ -269,15 +269,19 @@ const tab_groups::TabGroupVisualData* new_visuals; }; - TabGroupChange(tab_groups::TabGroupId group, + TabGroupChange(TabStripModel* model, + tab_groups::TabGroupId group, Type type, std::unique_ptr<Delta> deltap = nullptr); - explicit TabGroupChange(tab_groups::TabGroupId group, VisualsChange deltap); + TabGroupChange(TabStripModel* model, + tab_groups::TabGroupId group, + VisualsChange deltap); ~TabGroupChange(); const VisualsChange* GetVisualsChange() const; tab_groups::TabGroupId group; + TabStripModel* model; Type type; private:
diff --git a/chrome/browser/ui/user_education/test_help_bubble.cc b/chrome/browser/ui/user_education/test_help_bubble.cc index 004776e6..4cf3492e 100644 --- a/chrome/browser/ui/user_education/test_help_bubble.cc +++ b/chrome/browser/ui/user_education/test_help_bubble.cc
@@ -42,6 +42,7 @@ void TestHelpBubble::SimulateButtonPress(int button_index) { CHECK_LT(button_index, static_cast<int>(params_.buttons.size())); std::move(params_.buttons[button_index].callback).Run(); + Close(); } void TestHelpBubble::CloseBubbleImpl() {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index d564e59..86c78ce 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -18,6 +18,7 @@ #include "base/i18n/rtl.h" #include "base/memory/raw_ptr.h" #include "base/metrics/user_metrics.h" +#include "base/notreached.h" #include "base/observer_list.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -42,6 +43,9 @@ #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_observer.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h" #include "chrome/browser/ui/tabs/tab_group_model.h" #include "chrome/browser/ui/tabs/tab_group_theme.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -144,6 +148,9 @@ // Margin around the content. constexpr int kBookmarkBarHorizontalMargin = 8; +// Max width of the buttons in the bookmark bar. +constexpr int kMaxButtonWidth = 150; + // Used to globally disable rich animations. bool animations_enabled = true; @@ -371,14 +378,15 @@ // ------------------------------------------------------- // Buttons used for tab groups on the bookmark bar -class BookmarkTabGroupButton : public BookmarkMenuButtonBase { +class TabGroupButton : public BookmarkMenuButtonBase { public: - METADATA_HEADER(BookmarkTabGroupButton); - explicit BookmarkTabGroupButton( - PressedCallback callback, - const std::u16string& title = std::u16string()) + METADATA_HEADER(TabGroupButton); + explicit TabGroupButton(PressedCallback callback, + const std::u16string& title, + tab_groups::TabGroupColorId color) : BookmarkMenuButtonBase(std::move(callback), title) { show_animation_ = std::make_unique<gfx::SlideAnimation>(this); + tab_group_color_id_ = color; if (!animations_enabled) { // For some reason during testing the events generated by animating // throw off the test. So, don't animate while testing. @@ -387,8 +395,8 @@ show_animation_->Show(); } } - BookmarkTabGroupButton(const BookmarkTabGroupButton&) = delete; - BookmarkTabGroupButton& operator=(const BookmarkTabGroupButton&) = delete; + TabGroupButton(const TabGroupButton&) = delete; + TabGroupButton& operator=(const TabGroupButton&) = delete; std::u16string GetTooltipText(const gfx::Point& p) const override { return label()->GetPreferredSize().width() > label()->size().width() @@ -397,6 +405,11 @@ } void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + // If the button would have no name, avoid crashing by setting the name + // explicitly empty. + if (GetAccessibleName().empty()) + node_data->SetNameExplicitlyEmpty(); + BookmarkMenuButtonBase::GetAccessibleNodeData(node_data); node_data->AddStringAttribute( ax::mojom::StringAttribute::kRoleDescription, @@ -404,8 +417,8 @@ IDS_ACCNAME_BOOKMARK_FOLDER_BUTTON_ROLE_DESCRIPTION)); } - // Set the background color and stroke width/color according to flag - // parameter. Colored dot icon added and text inversion set in + // Set the text color, background color, and stroke width/color according to + // flag parameter. Colored dot icon added and text inversion set in // ConfigureButton. void OnPaintBackground(gfx::Canvas* canvas) override { const ui::ThemeProvider* const tp = GetThemeProvider(); @@ -418,6 +431,9 @@ SkColor background_color = tp->GetColor(GetTabGroupBookmarkColorId(tab_group_color_id_)); SkColor border_color = background_color; + SkColor text_color = + tp->GetColor(GetTabGroupDialogColorId(tab_group_color_id_)); + SetEnabledTextColors(text_color); // Show 2px border on hover. if (GetState() == STATE_HOVERED || GetState() == STATE_PRESSED) { @@ -449,7 +465,7 @@ float button_radius_ = 5.0f; }; -BEGIN_METADATA(BookmarkTabGroupButton, BookmarkMenuButtonBase) +BEGIN_METADATA(TabGroupButton, BookmarkMenuButtonBase) END_METADATA // OverflowButton (chevron) -------------------------------------------------- @@ -596,8 +612,11 @@ } BookmarkBarView::~BookmarkBarView() { - if (model_) - model_->RemoveObserver(this); + if (bookmark_model_) + bookmark_model_->RemoveObserver(this); + + if (saved_tab_group_model_) + saved_tab_group_model_->RemoveObserver(this); // It's possible for the menu to outlive us, reset the observer to make sure // it doesn't have a reference to us. @@ -681,20 +700,20 @@ if (!child->GetVisible()) break; if (child->bounds().Contains(adjusted_loc)) - return model_->bookmark_bar_node()->children()[i].get(); + return bookmark_model_->bookmark_bar_node()->children()[i].get(); } // Then the overflow button. if (overflow_button_->GetVisible() && overflow_button_->bounds().Contains(adjusted_loc)) { *model_start_index = GetFirstHiddenNodeIndex(); - return model_->bookmark_bar_node(); + return bookmark_model_->bookmark_bar_node(); } // And finally the other folder. if (other_bookmarks_button_->GetVisible() && other_bookmarks_button_->bounds().Contains(adjusted_loc)) { - return model_->other_node(); + return bookmark_model_->other_node(); } return nullptr; @@ -703,13 +722,13 @@ MenuButton* BookmarkBarView::GetMenuButtonForNode(const BookmarkNode* node) { if (node == managed_->managed_node()) return managed_bookmarks_button_; - if (node == model_->other_node()) + if (node == bookmark_model_->other_node()) return other_bookmarks_button_; - if (node == model_->bookmark_bar_node()) + if (node == bookmark_model_->bookmark_bar_node()) return overflow_button_; // TODO: add logic to handle saved groups node(crbug.com/1223929 and // crbug.com/1223919) - int index = model_->bookmark_bar_node()->GetIndexOf(node); + int index = bookmark_model_->bookmark_bar_node()->GetIndexOf(node); if (index == -1 || !node->is_folder()) return nullptr; return static_cast<MenuButton*>( @@ -818,6 +837,10 @@ gfx::Size size = bookmarks_separator_view_->GetPreferredSize(); width += size.width(); } + if (tab_groups_separator_view_ && tab_groups_separator_view_->GetVisible()) { + gfx::Size size = tab_groups_separator_view_->GetPreferredSize(); + width += size.width(); + } if (apps_page_shortcut_->GetVisible()) { gfx::Size size = apps_page_shortcut_->GetPreferredSize(); width += size.width() + bookmark_bar_button_padding; @@ -834,7 +857,7 @@ void BookmarkBarView::Layout() { // Skip layout during destruction, when no model exists. - if (!model_) + if (!bookmark_model_) return; int x = kBookmarkBarHorizontalMargin; @@ -912,51 +935,92 @@ x += managed_bookmarks_pref.width() + bookmark_bar_button_padding; } - if (model_->loaded() && !model_->bookmark_bar_node()->children().empty()) { - bool last_visible = x < max_x; + if (saved_tab_group_model_) { + // Add the tabgroup buttons to the bookmarks bar if we have buttons saved. + bool can_render_button_bounds = x < max_x; + for (auto* saved_group_button : tab_group_buttons_) { + views::View* child = saved_group_button; + + // Set visibility if there is room. + gfx::Size pref = child->GetPreferredSize(); + int next_x = x + pref.width() + bookmark_bar_button_padding; + can_render_button_bounds = next_x < max_x; + child->SetVisible(can_render_button_bounds); + + // Only need to set bounds if the view is actually visible. + if (can_render_button_bounds) + child->SetBounds(x, y, pref.width(), button_height); + x = next_x; + } + + // Add the tabgroups separator after the buttons have been added. + gfx::Size tab_groups_separator_pref = + tab_groups_separator_view_->GetPreferredSize(); + tab_groups_separator_view_->SetBounds( + x, center_y(tab_groups_separator_pref.height()), + tab_groups_separator_pref.width(), tab_groups_separator_pref.height()); + x += tab_groups_separator_pref.width(); + } + + if (bookmark_model_->loaded() && + !bookmark_model_->bookmark_bar_node()->children().empty()) { + bool can_render_button_bounds = x < max_x; size_t button_count = bookmark_buttons_.size(); + size_t tab_group_offset = 0; + if (base::FeatureList::IsEnabled(features::kTabGroupsSave)) + tab_group_offset = tab_group_buttons_.size(); for (size_t i = 0; i <= button_count; ++i) { if (i == button_count) { // Add another button if there is room for it (and there is another // button to load). - if (!last_visible || !model_->loaded() || - model_->bookmark_bar_node()->children().size() <= button_count) + if (!can_render_button_bounds || + bookmark_model_->bookmark_bar_node()->children().size() <= + button_count) break; - InsertBookmarkButtonAtIndex( + InsertButtonAtIndex( CreateBookmarkButton( - model_->bookmark_bar_node()->children()[i].get()), - i); + bookmark_model_->bookmark_bar_node()->children()[i].get()), + i + tab_group_offset); button_count = bookmark_buttons_.size(); } views::View* child = bookmark_buttons_[i]; - // customize child appearance?? - + // If the child view can fit in the bookmarks comfortably, make it visible + // and set its bounds. gfx::Size pref = child->GetPreferredSize(); int next_x = x + pref.width() + bookmark_bar_button_padding; - last_visible = next_x < max_x; - child->SetVisible(last_visible); + can_render_button_bounds = next_x < max_x; + child->SetVisible(can_render_button_bounds); // Only need to set bounds if the view is actually visible. - if (last_visible) + if (can_render_button_bounds) child->SetBounds(x, y, pref.width(), button_height); x = next_x; } } + // Only render the tab group separtor if there are groups and bookmarks + // visible. Must done after the bookmark buttons are rendered. + if (saved_tab_group_model_) { + const bool groups_visible = saved_tab_group_model_->Count() != 0; + const bool bookmarks_visible = + !bookmark_buttons_.empty() && bookmark_buttons_[0]->GetVisible(); + tab_groups_separator_view_->SetVisible(groups_visible && bookmarks_visible); + } + // Layout the right side buttons. x = max_x + bookmark_bar_button_padding; // The overflow button. overflow_button_->SetBounds(x, y, overflow_pref.width(), button_height); const bool show_overflow = - model_->loaded() && - (model_->bookmark_bar_node()->children().size() > + bookmark_model_->loaded() && + (bookmark_model_->bookmark_bar_node()->children().size() > bookmark_buttons_.size() || (!bookmark_buttons_.empty() && !bookmark_buttons_.back()->GetVisible())); overflow_button_->SetVisible(show_overflow); x += overflow_pref.width(); - // Separator. + // Bookmarks Separator. if (bookmarks_separator_view_->GetVisible()) { bookmarks_separator_view_->SetBounds( x, center_y(bookmarks_separator_pref.height()), @@ -1054,7 +1118,7 @@ bool BookmarkBarView::GetDropFormats( int* formats, std::set<ui::ClipboardFormatType>* format_types) { - if (!model_ || !model_->loaded()) + if (!bookmark_model_ || !bookmark_model_->loaded()) return false; *formats = ui::OSExchangeData::URL; format_types->insert(bookmarks::BookmarkNodeData::GetBookmarkFormatType()); @@ -1066,7 +1130,7 @@ } bool BookmarkBarView::CanDrop(const ui::OSExchangeData& data) { - if (!model_ || !model_->loaded() || + if (!bookmark_model_ || !bookmark_model_->loaded() || !browser_->profile()->GetPrefs()->GetBoolean( bookmarks::prefs::kEditBookmarksEnabled)) return false; @@ -1122,12 +1186,13 @@ location.button_type == DROP_OTHER_FOLDER) { const BookmarkNode* node; if (location.button_type == DROP_OTHER_FOLDER) { - node = model_->other_node(); + node = bookmark_model_->other_node(); } else if (location.button_type == DROP_OVERFLOW) { - node = model_->bookmark_bar_node(); + node = bookmark_model_->bookmark_bar_node(); } else { - node = - model_->bookmark_bar_node()->children()[location.index.value()].get(); + node = bookmark_model_->bookmark_bar_node() + ->children()[location.index.value()] + .get(); } StartShowFolderDropMenuTimer(node); } @@ -1244,8 +1309,8 @@ void BookmarkBarView::BookmarkModelBeingDeleted(BookmarkModel* model) { NOTREACHED(); // Do minimal cleanup, presumably we'll be deleted shortly. - model_->RemoveObserver(this); - model_ = nullptr; + bookmark_model_->RemoveObserver(this); + bookmark_model_ = nullptr; drop_weak_ptr_factory_.InvalidateWeakPtrs(); } @@ -1350,8 +1415,7 @@ // Create the new buttons. for (size_t i = 0; i < node->children().size(); ++i) { - InsertBookmarkButtonAtIndex(CreateBookmarkButton(node->children()[i].get()), - i); + InsertButtonAtIndex(CreateBookmarkButton(node->children()[i].get()), i); } LayoutAndPaint(); @@ -1364,6 +1428,49 @@ BookmarkNodeChangedImpl(model, node); } +void BookmarkBarView::SavedTabGroupAdded(const SavedTabGroup& group, + int index) { + InvalidateDrop(); + SavedTabGroupAddedImpl(group, index); + LayoutAndPaint(); + drop_weak_ptr_factory_.InvalidateWeakPtrs(); +} + +void BookmarkBarView::SavedTabGroupRemoved(int index) { + InvalidateDrop(); + SavedTabGroupRemovedImpl(index); + LayoutAndPaint(); + drop_weak_ptr_factory_.InvalidateWeakPtrs(); +} + +void BookmarkBarView::SavedTabGroupUpdated(const SavedTabGroup& group, + int index) { + InvalidateDrop(); + SavedTabGroupRemovedImpl(index); + SavedTabGroupAddedImpl(group, index); + LayoutAndPaint(); + drop_weak_ptr_factory_.InvalidateWeakPtrs(); +} + +void BookmarkBarView::SavedTabGroupMoved(const SavedTabGroup& group) { + // TODO(dljames): Find the current index for [group] in [tab_group_buttons_]. + // Find the new index for [ group ] in [saved_tab_group_model_]. Swap + // from current -> new. + NOTIMPLEMENTED(); +} + +void BookmarkBarView::SavedTabGroupAddedImpl(const SavedTabGroup& group, + int index) { + InsertButtonAtIndex(CreateTabGroupButton(group, index), index); +} + +void BookmarkBarView::SavedTabGroupRemovedImpl(int index) { + StopThrobbing(true); + views::LabelButton* button = tab_group_buttons_[index]; + tab_group_buttons_.erase(tab_group_buttons_.begin() + index); + RemoveChildViewT(button); +} + void BookmarkBarView::WriteDragDataForView(View* sender, const gfx::Point& press_pt, ui::OSExchangeData* data) { @@ -1372,7 +1479,7 @@ const auto* node = GetNodeForSender(sender); ui::ImageModel icon; if (node->is_url()) { - const gfx::Image& image = model_->GetFavicon(node); + const gfx::Image& image = bookmark_model_->GetFavicon(node); icon = image.IsEmpty() ? ui::ImageModel::FromImage(favicon::GetDefaultFavicon()) : ui::ImageModel::FromImage(image); @@ -1457,39 +1564,36 @@ ui::DispositionFromEventFlags(event.flags()), false); } else { - // saved tab groups flag - if (base::FeatureList::IsEnabled(features::kTabGroupsSave) && - !node->is_permanent_node()) { - // Record as bookmark folder launch in dev when rendering tab groups from - // folder data. - RecordBookmarkFolderLaunch(BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR); - // TODO: Handle click if group has already been opened (crbug.com/1238539) - // left click on a saved tab group opens all links in new group - std::vector<const bookmarks::BookmarkNode*> selection = {node}; - // This happens when trying to open an empty bookmarks folder. - // See https://crbug.com/1271130 - if (!chrome::HasBookmarkURLs(selection)) - return; - chrome::OpenAllIfAllowed(browser_, GetPageNavigatorGetter(), selection, - WindowOpenDisposition::NEW_BACKGROUND_TAB, true); - } else { - RecordBookmarkFolderOpen(BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR); - const size_t start_index = - (node == model_->bookmark_bar_node()) ? GetFirstHiddenNodeIndex() : 0; - bookmark_menu_ = - new BookmarkMenuController(browser_, GetPageNavigatorGetter(), - GetWidget(), node, start_index, false); - bookmark_menu_->set_observer(this); - bookmark_menu_->RunMenuAt(this); - } + RecordBookmarkFolderOpen(BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR); + const size_t start_index = (node == bookmark_model_->bookmark_bar_node()) + ? GetFirstHiddenNodeIndex() + : 0; + bookmark_menu_ = + new BookmarkMenuController(browser_, GetPageNavigatorGetter(), + GetWidget(), node, start_index, false); + bookmark_menu_->set_observer(this); + bookmark_menu_->RunMenuAt(this); } } +void BookmarkBarView::OnTabGroupButtonPressed(const SavedTabGroup* group, + const ui::Event& event) { + // TODO: Handle click if group has already been opened (crbug.com/1238539) + // left click on a saved tab group opens all links in new group + + // This happens when trying to open an empty saved tab group. + // See https://crbug.com/1271130 + if (!(group->urls.empty())) + return; + chrome::OpenSavedTabGroup(browser_, GetPageNavigatorGetter(), group, + WindowOpenDisposition::NEW_BACKGROUND_TAB); +} + void BookmarkBarView::ShowContextMenuForViewImpl( views::View* source, const gfx::Point& point, ui::MenuSourceType source_type) { - if (!model_->loaded()) { + if (!bookmark_model_->loaded()) { // Don't do anything if the model isn't loaded. return; } @@ -1497,7 +1601,7 @@ const BookmarkNode* parent = nullptr; std::vector<const BookmarkNode*> nodes; if (source == other_bookmarks_button_) { - parent = model_->other_node(); + parent = bookmark_model_->other_node(); // Do this so the user can open all bookmarks. BookmarkContextMenu makes // sure the user can't edit/delete the node in this case. nodes.push_back(parent); @@ -1513,16 +1617,18 @@ size_t bookmark_button_index = GetIndexForButton(source); DCHECK_NE(static_cast<size_t>(-1), bookmark_button_index); DCHECK_LT(bookmark_button_index, bookmark_buttons_.size()); - const BookmarkNode* node = - model_->bookmark_bar_node()->children()[bookmark_button_index].get(); + const BookmarkNode* node = bookmark_model_->bookmark_bar_node() + ->children()[bookmark_button_index] + .get(); nodes.push_back(node); parent = node->parent(); // saved tab groups feature flag. if (base::FeatureList::IsEnabled(features::kTabGroupsSave) && !node->is_url()) { RecordBookmarkFolderOpen(BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR); - const size_t start_index = - (node == model_->bookmark_bar_node()) ? GetFirstHiddenNodeIndex() : 0; + const size_t start_index = (node == bookmark_model_->bookmark_bar_node()) + ? GetFirstHiddenNodeIndex() + : 0; bookmark_menu_ = new BookmarkMenuController(browser_, GetPageNavigatorGetter(), GetWidget(), node, start_index, false); @@ -1531,7 +1637,7 @@ return; } } else { - parent = model_->bookmark_bar_node(); + parent = bookmark_model_->bookmark_bar_node(); nodes.push_back(parent); } // |close_on_remove| only matters for nested menus. We're not nested at this @@ -1579,6 +1685,17 @@ base::BindRepeating( &BookmarkBarView::OnAppsPageShortcutVisibilityPrefChanged, base::Unretained(this))); + + if (base::FeatureList::IsEnabled(features::kTabGroupsSave)) { + tab_groups_separator_view_ = + AddChildView(std::make_unique<ButtonSeparatorView>()); + saved_tab_group_model_ = + SavedTabGroupServiceFactory::GetForProfile(browser_->profile()) + ->model(); + saved_tab_group_model_->AddObserver(this); + InsertTabGroupButtonsFromModel(); + } + if (read_later_button_) { profile_pref_registrar_.Add( bookmarks::prefs::kShowReadingListInBookmarkBar, @@ -1586,6 +1703,7 @@ &BookmarkBarView::OnReadingListVisibilityPrefChanged, base::Unretained(this))); } + profile_pref_registrar_.Add( bookmarks::prefs::kShowManagedBookmarksInBookmarkBar, base::BindRepeating(&BookmarkBarView::OnShowManagedBookmarksPrefChanged, @@ -1603,12 +1721,13 @@ set_context_menu_controller(this); - model_ = BookmarkModelFactory::GetForBrowserContext(browser_->profile()); + bookmark_model_ = + BookmarkModelFactory::GetForBrowserContext(browser_->profile()); managed_ = ManagedBookmarkServiceFactory::GetForProfile(browser_->profile()); - if (model_) { - model_->AddObserver(this); - if (model_->loaded()) - BookmarkModelLoaded(model_, false); + if (bookmark_model_) { + bookmark_model_->AddObserver(this); + if (bookmark_model_->loaded()) + BookmarkModelLoaded(bookmark_model_, false); // else case: we'll receive notification back from the BookmarkModel when // done loading, then we'll populate the bar. } @@ -1625,7 +1744,7 @@ // Title is set in Loaded. auto button = std::make_unique<BookmarkFolderButton>(base::BindRepeating( [](BookmarkBarView* bar, const ui::Event& event) { - bar->OnMenuButtonPressed(bar->model_->other_node(), event); + bar->OnMenuButtonPressed(bar->bookmark_model_->other_node(), event); }, base::Unretained(this))); button->SetID(VIEW_ID_OTHER_BOOKMARKS); @@ -1649,7 +1768,8 @@ auto button = std::make_unique<OverflowButton>( base::BindRepeating( [](BookmarkBarView* bar, const ui::Event& event) { - bar->OnMenuButtonPressed(bar->model_->bookmark_bar_node(), event); + bar->OnMenuButtonPressed(bar->bookmark_model_->bookmark_bar_node(), + event); }, base::Unretained(this)), this); @@ -1686,25 +1806,29 @@ node->url(), url_formatter::kFormatUrlOmitDefaults, net::UnescapeRule::SPACES, nullptr, nullptr, nullptr)); } else { - // saved tab groups feature flag. - if (base::FeatureList::IsEnabled(features::kTabGroupsSave)) { - button = std::make_unique<BookmarkTabGroupButton>( - base::BindRepeating(&BookmarkBarView::OnMenuButtonPressed, - base::Unretained(this), node), - node->GetTitle()); - button->GetViewAccessibility().OverrideDescription(""); - } else { - button = std::make_unique<BookmarkFolderButton>( - base::BindRepeating(&BookmarkBarView::OnMenuButtonPressed, - base::Unretained(this), node), - node->GetTitle()); - } + button = std::make_unique<BookmarkFolderButton>( + base::BindRepeating(&BookmarkBarView::OnMenuButtonPressed, + base::Unretained(this), node), + node->GetTitle()); } ConfigureButton(node, button.get()); bookmark_buttons_.insert(bookmark_buttons_.cbegin() + index, button.get()); return button; } +std::unique_ptr<views::View> BookmarkBarView::CreateTabGroupButton( + const SavedTabGroup& group, + const size_t index) { + std::unique_ptr<views::LabelButton> button; + button = std::make_unique<TabGroupButton>( + base::BindRepeating(&BookmarkBarView::OnTabGroupButtonPressed, + base::Unretained(this), &group), + group.title, group.color); + ConfigureButton(group, button.get()); + tab_group_buttons_.insert(tab_group_buttons_.begin() + index, button.get()); + return button; +} + std::unique_ptr<views::LabelButton> BookmarkBarView::CreateAppsPageShortcutButton() { auto button = std::make_unique<ShortcutButton>( @@ -1731,48 +1855,13 @@ const ui::ThemeProvider* const tp = GetThemeProvider(); if (tp) { text_color = tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT); - if (node->is_folder()) { - // If saved tab groups is enabled, set text color or dot if indicated by - // flag parameter. Chip background and border colors are set in - // OnPaintBackground. - if (base::FeatureList::IsEnabled(features::kTabGroupsSave)) { - // Use this variable to set the tab_group_color for all folders in the - // bookmark bar - tab_groups::TabGroupColorId tab_group_color_id = - tab_groups::TabGroupColorId::kGrey; - - // In most cases our text color will match the hover border color - // However, for yellow, orange, and custom colors this may not be true - // for contrast and visibility, so a default grey color may be - // more appropriate. - SkColor background_color = - tp->GetColor(GetTabGroupBookmarkColorId(tab_group_color_id)); - text_color = tp->GetColor(GetTabGroupDialogColorId(tab_group_color_id)); - bool meets_contrast_req = - color_utils::GetContrastRatio(background_color, text_color) >= - color_utils::kMinimumVisibleContrastRatio; - if (!meets_contrast_req) - text_color = gfx::kGoogleGrey800; - - // Set empty border using the default horizontal padding (but leaving - // vertical empty). This provides enough space to render some - // background to the left and right of the label. There's no need to - // set the top and bottom margins because the bookmarks bar is a fixed - // height and the button will be stretched vertically to fit. - gfx::Insets insets = - GetLayoutProvider()->GetInsetsMetric(views::INSETS_LABEL_BUTTON); - insets.set_top(0); - insets.set_bottom(0); - button->SetBorder(views::CreateEmptyBorder(insets)); - } else { - button->SetImageModel(views::Button::STATE_NORMAL, - chrome::GetBookmarkFolderIcon( - chrome::BookmarkFolderIconType::kNormal, - kColorBookmarkFolderIcon)); - } - } - button->SetEnabledTextColors(text_color); + if (node->is_folder()) { + button->SetImageModel( + views::Button::STATE_NORMAL, + chrome::GetBookmarkFolderIcon(chrome::BookmarkFolderIconType::kNormal, + kColorBookmarkFolderIcon)); + } } button->set_context_menu_controller(this); @@ -1781,7 +1870,7 @@ // Themify chrome:// favicons and the default one. This is similar to // code in the tabstrip. bool themify_icon = node->url().SchemeIs(content::kChromeUIScheme); - gfx::ImageSkia favicon = model_->GetFavicon(node).AsImageSkia(); + gfx::ImageSkia favicon = bookmark_model_->GetFavicon(node).AsImageSkia(); if (favicon.isNull()) { if (ui::TouchUiController::Get()->touch_ui() && tp) { // This favicon currently does not match the default favicon icon used @@ -1810,7 +1899,49 @@ button->SetImageModel(views::Button::STATE_NORMAL, ui::ImageModel::FromImageSkia(favicon)); } - constexpr int kMaxButtonWidth = 150; + + button->SetMaxSize(gfx::Size(kMaxButtonWidth, 0)); +} + +void BookmarkBarView::ConfigureButton(const SavedTabGroup& saved_group, + views::LabelButton* button) { + button->SetText(saved_group.title); + button->SetAccessibleName(saved_group.title); + button->SetID(VIEW_ID_BOOKMARK_BAR_ELEMENT); + // We don't always have a theme provider (ui tests, for example). + SkColor text_color = gfx::kPlaceholderColor; + const ui::ThemeProvider* const tp = GetThemeProvider(); + if (tp) { + tab_groups::TabGroupColorId tab_group_color_id = saved_group.color; + + // In most cases our text color will match the hover border color. + // However, for yellow, orange, and custom colors/themes this may not be + // true with respect to contrast and visibility, so a default grey color may + // be more appropriate. + SkColor background_color = + tp->GetColor(GetTabGroupBookmarkColorId(tab_group_color_id)); + text_color = tp->GetColor(GetTabGroupDialogColorId(tab_group_color_id)); + bool meets_contrast_req = + color_utils::GetContrastRatio(background_color, text_color) >= + color_utils::kMinimumVisibleContrastRatio; + if (!meets_contrast_req) + text_color = gfx::kGoogleGrey800; + + // Set empty border using the default horizontal padding (but leaving + // vertical empty). This provides enough space to render some + // background to the left and right of the label. There's no need to + // set the top and bottom margins because the bookmarks bar is a fixed + // height and the button will be stretched vertically to fit. + gfx::Insets insets = + GetLayoutProvider()->GetInsetsMetric(views::INSETS_LABEL_BUTTON); + insets.set_top(0); + insets.set_bottom(0); + button->SetBorder(views::CreateEmptyBorder(insets)); + } + + button->SetEnabledTextColors(text_color); + // TODO (dljames): Add set_context_menu_controller and set_drag_controller to + // this button once dragging and the context menu are built. button->SetMaxSize(gfx::Size(kMaxButtonWidth, 0)); } @@ -1822,7 +1953,7 @@ return needs_layout_and_paint; if (index < bookmark_buttons_.size()) { const BookmarkNode* node = parent->children()[index].get(); - InsertBookmarkButtonAtIndex(CreateBookmarkButton(node), index); + InsertButtonAtIndex(CreateBookmarkButton(node), index); return true; } // If the new node was added after the last button we've created we may be @@ -1897,7 +2028,7 @@ return; size_t start_index = 0; - if (node == model_->bookmark_bar_node()) + if (node == bookmark_model_->bookmark_bar_node()) start_index = GetFirstHiddenNodeIndex(); drop_info_->is_menu_showing = true; @@ -1933,8 +2064,8 @@ const ui::DropTargetEvent& event, const bookmarks::BookmarkNodeData& data, DropLocation* location) { - DCHECK(model_); - DCHECK(model_->loaded()); + DCHECK(bookmark_model_); + DCHECK(bookmark_model_->loaded()); DCHECK(data.is_valid()); *location = DropLocation(); @@ -1958,7 +2089,8 @@ } else if (bookmark_buttons_.empty()) { // No bookmarks, accept the drop. location->index = 0; - const BookmarkNode* node = data.GetFirstNode(model_, profile->GetPath()); + const BookmarkNode* node = + data.GetFirstNode(bookmark_model_, profile->GetPath()); int ops = node && managed_->CanBeEditedByUser(node) ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK; @@ -1976,7 +2108,7 @@ if (button_x < button_w) { found = true; const BookmarkNode* node = - model_->bookmark_bar_node()->children()[i].get(); + bookmark_model_->bookmark_bar_node()->children()[i].get(); if (node->is_folder()) { if (button_x <= views::kDropBetweenPixels) { location->index = i; @@ -2023,20 +2155,20 @@ if (location->on) { const BookmarkNode* parent = (location->button_type == DROP_OTHER_FOLDER) - ? model_->other_node() - : model_->bookmark_bar_node() + ? bookmark_model_->other_node() + : bookmark_model_->bookmark_bar_node() ->children()[location->index.value()] .get(); location->operation = chrome::GetBookmarkDropOperation( profile, event, data, parent, parent->children().size()); if (location->operation != DragOperation::kNone && !data.has_single_url() && - data.GetFirstNode(model_, profile->GetPath()) == parent) { + data.GetFirstNode(bookmark_model_, profile->GetPath()) == parent) { // Don't open a menu if the node being dragged is the menu to open. location->on = false; } } else { location->operation = chrome::GetBookmarkDropOperation( - profile, event, data, model_->bookmark_bar_node(), + profile, event, data, bookmark_model_->bookmark_bar_node(), location->index.value()); } } @@ -2056,7 +2188,7 @@ std::find(bookmark_buttons_.cbegin(), bookmark_buttons_.cend(), sender); DCHECK(i != bookmark_buttons_.cend()); size_t child = i - bookmark_buttons_.cbegin(); - return model_->bookmark_bar_node()->children()[child].get(); + return bookmark_model_->bookmark_bar_node()->children()[child].get(); } void BookmarkBarView::WriteBookmarkDragData(const BookmarkNode* node, @@ -2072,7 +2204,7 @@ // Determine which visible button is showing the bookmark (or is an ancestor // of the bookmark). - const BookmarkNode* bbn = model_->bookmark_bar_node(); + const BookmarkNode* bbn = bookmark_model_->bookmark_bar_node(); const BookmarkNode* parent_on_bb = node; while (parent_on_bb) { const BookmarkNode* parent = parent_on_bb->parent(); @@ -2102,7 +2234,7 @@ views::Button* BookmarkBarView::DetermineViewToThrobFromRemove( const BookmarkNode* parent, size_t old_index) { - const BookmarkNode* bbn = model_->bookmark_bar_node(); + const BookmarkNode* bbn = bookmark_model_->bookmark_bar_node(); const BookmarkNode* old_node = parent; size_t old_index_on_bb = old_index; while (old_node && old_node != bbn) { @@ -2132,7 +2264,7 @@ if (!theme_provider) return; for (size_t i = 0; i < bookmark_buttons_.size(); ++i) { - ConfigureButton(model_->bookmark_bar_node()->children()[i].get(), + ConfigureButton(bookmark_model_->bookmark_bar_node()->children()[i].get(), bookmark_buttons_[i]); } @@ -2166,7 +2298,7 @@ } bool BookmarkBarView::UpdateOtherAndManagedButtonsVisibility() { - bool has_other_children = !model_->other_node()->children().empty(); + bool has_other_children = !bookmark_model_->other_node()->children().empty(); bool update_other = has_other_children != other_bookmarks_button_->GetVisible(); if (update_other) { @@ -2223,29 +2355,36 @@ LayoutAndPaint(); } -void BookmarkBarView::InsertBookmarkButtonAtIndex( - std::unique_ptr<views::View> button, - size_t index) { +void BookmarkBarView::InsertTabGroupButtonsFromModel() { + const std::vector<SavedTabGroup>& saved_groups = + saved_tab_group_model_->saved_tab_groups(); + for (size_t i = 0; i < saved_groups.size(); i++) + InsertButtonAtIndex(CreateTabGroupButton(saved_groups[i], i), i); +} + +void BookmarkBarView::InsertButtonAtIndex(std::unique_ptr<views::View> button, + size_t index) { // All of the secondary buttons are always in the view hierarchy, even if // they're not visible. The order should be: [Apps shortcut] [Managed bookmark -// button] ..bookmark buttons.. [Overflow chevron] [Other bookmarks] +// button] [..tab group buttons..] [..bookmark buttons..] [Overflow chevron] +// [Other bookmarks] #if DCHECK_IS_ON() auto i = children().cbegin(); DCHECK_EQ(*i++, apps_page_shortcut_); DCHECK_EQ(*i++, managed_bookmarks_button_); - const auto is_bookmark_button = [this](const auto* v) { + const auto is_group_or_bookmark_button = [this](const auto* v) { const char* class_name = v->GetClassName(); if (base::FeatureList::IsEnabled(features::kTabGroupsSave)) return (class_name == BookmarkButton::kViewClassName || class_name == BookmarkFolderButton::kViewClassName || - class_name == BookmarkTabGroupButton::kViewClassName) && + class_name == TabGroupButton::kViewClassName) && v != overflow_button_ && v != other_bookmarks_button_; else return (class_name == BookmarkButton::kViewClassName || class_name == BookmarkFolderButton::kViewClassName) && v != overflow_button_ && v != other_bookmarks_button_; }; - i = std::find_if_not(i, children().cend(), is_bookmark_button); + i = std::find_if_not(i, children().cend(), is_group_or_bookmark_button); DCHECK_EQ(*i++, overflow_button_); DCHECK_EQ(*i++, other_bookmarks_button_); #endif @@ -2277,8 +2416,8 @@ size_t& index) { const BookmarkNode* root = (drop_info_->location.button_type == DROP_OTHER_FOLDER) - ? model_->other_node() - : model_->bookmark_bar_node(); + ? bookmark_model_->other_node() + : bookmark_model_->bookmark_bar_node(); if (drop_info_->location.index.has_value()) { // TODO(sky): optimize the SchedulePaint region.
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h index af8edab..d6de145 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
@@ -15,6 +15,7 @@ #include "chrome/browser/ui/bookmarks/bookmark_bar.h" #include "chrome/browser/ui/bookmarks/bookmark_bubble_observer.h" #include "chrome/browser/ui/bookmarks/bookmark_stats.h" +#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_model_observer.h" #include "chrome/browser/ui/tabs/tab_group_theme.h" #include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_observer.h" #include "components/bookmarks/browser/bookmark_model_observer.h" @@ -36,6 +37,7 @@ class BrowserView; class Profile; class ReadLaterButton; +class SavedTabGroupModel; namespace bookmarks { class BookmarkModel; @@ -70,7 +72,8 @@ public views::DragController, public views::AnimationDelegateViews, public BookmarkMenuControllerObserver, - public bookmarks::BookmarkBubbleObserver { + public bookmarks::BookmarkBubbleObserver, + public SavedTabGroupModelObserver { public: class ButtonSeparatorView; @@ -217,6 +220,15 @@ void BookmarkNodeFaviconChanged(bookmarks::BookmarkModel* model, const bookmarks::BookmarkNode* node) override; + // SavedTabGroupModelObserver: + void SavedTabGroupAdded(const SavedTabGroup& group, int index) override; + void SavedTabGroupRemoved(int index) override; + void SavedTabGroupUpdated(const SavedTabGroup& group, int index) override; + void SavedTabGroupMoved(const SavedTabGroup& group) override; + + void SavedTabGroupAddedImpl(const SavedTabGroup& group, int index); + void SavedTabGroupRemovedImpl(int index); + // views::DragController: void WriteDragDataForView(views::View* sender, const gfx::Point& press_pt, @@ -251,6 +263,8 @@ const ui::Event& event); void OnMenuButtonPressed(const bookmarks::BookmarkNode* node, const ui::Event& event); + void OnTabGroupButtonPressed(const SavedTabGroup* group, + const ui::Event& event); // NOTE: unless otherwise stated all methods that take an index are in terms // of the bookmark bar view. Typically the view index and model index are the @@ -276,6 +290,10 @@ std::unique_ptr<views::View> CreateBookmarkButton( const bookmarks::BookmarkNode* node); + // Create the button for rendering the specified save tab group. + std::unique_ptr<views::View> CreateTabGroupButton(const SavedTabGroup& group, + const size_t index); + // Creates the button for rendering the apps page shortcut. std::unique_ptr<views::LabelButton> CreateAppsPageShortcutButton(); @@ -284,6 +302,11 @@ void ConfigureButton(const bookmarks::BookmarkNode* node, views::LabelButton* button); + // Configures the button from the specified saved tab group. This sets the + // text, text color, highlight and background color of the tab group. + void ConfigureButton(const SavedTabGroup& saved_group, + views::LabelButton* button); + // Implementation for BookmarkNodeAddedImpl. Returns true if LayoutAndPaint() // is required. bool BookmarkNodeAddedImpl(bookmarks::BookmarkModel* model, @@ -365,10 +388,15 @@ SchedulePaint(); } + // Inserts the saved tab groups stored in saved_tab_group_model_ as buttons + // whenever a new bookmark_bar_view instance is created. When a new + // bookmark_bar_view is created, tab_group_buttons_ has no data, even if there + // exists data in saved_tab_group_model_. + void InsertTabGroupButtonsFromModel(); + // Inserts |button| in logical position |index| in the bar, maintaining // correct focus traversal order. - void InsertBookmarkButtonAtIndex(std::unique_ptr<views::View> button, - size_t index); + void InsertButtonAtIndex(std::unique_ptr<views::View> button, size_t index); // Returns the model index for the bookmark associated with |button|, // or size_t{-1} if |button| is not a bookmark button from this bar. @@ -403,7 +431,11 @@ // BookmarkModel that owns the entries and folders that are shown in this // view. This is owned by the Profile. - raw_ptr<bookmarks::BookmarkModel> model_ = nullptr; + raw_ptr<bookmarks::BookmarkModel> bookmark_model_ = nullptr; + + // SavedTabGroupModel that owns the saved tab groups that are shown in this + // view. This is owned by the Profile. + raw_ptr<SavedTabGroupModel> saved_tab_group_model_ = nullptr; // ManagedBookmarkService. This is owned by the Profile. raw_ptr<bookmarks::ManagedBookmarkService> managed_ = nullptr; @@ -443,6 +475,7 @@ std::vector<views::LabelButton*> tab_group_buttons_; raw_ptr<ButtonSeparatorView> bookmarks_separator_view_ = nullptr; + raw_ptr<ButtonSeparatorView> tab_groups_separator_view_ = nullptr; raw_ptr<ReadLaterButton> read_later_button_ = nullptr; raw_ptr<ButtonSeparatorView> read_later_separator_view_ = nullptr;
diff --git a/chrome/browser/ui/views/borealis/borealis_splash_screen_view.cc b/chrome/browser/ui/views/borealis/borealis_splash_screen_view.cc index 36ab612..7cc4b69 100644 --- a/chrome/browser/ui/views/borealis/borealis_splash_screen_view.cc +++ b/chrome/browser/ui/views/borealis/borealis_splash_screen_view.cc
@@ -5,12 +5,22 @@ #include "chrome/browser/ui/views/borealis/borealis_splash_screen_view.h" #include "ash/public/cpp/window_properties.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/task/post_task.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "chrome/browser/ash/borealis/borealis_service.h" #include "chrome/browser/ash/borealis/borealis_util.h" #include "chrome/browser/ash/borealis/borealis_window_manager.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/views/controls/image_view.h" #include "ui/views/controls/message_box_view.h" #include "ui/views/layout/box_layout.h" @@ -18,8 +28,26 @@ borealis::BorealisSplashScreenView* delegate_ = nullptr; +const SkColor background_color = SkColorSetARGB(255, 53, 51, 50); +const SkColor text_color = SkColorSetARGB(255, 209, 208, 207); +const int icon_width = 40; +const int icon_height = 40; + +gfx::Image ReadImageFile(std::string dlc_path) { + base::FilePath image_path = + base::FilePath(dlc_path.append("/splash_logo.png")); + std::string image_data; + + if (!base::ReadFileToString(image_path, &image_data)) { + LOG(ERROR) << "Failed to read borealis logo from disk."; + return gfx::Image(); + } + return gfx::Image::CreateFrom1xPNGBytes( + base::RefCountedString::TakeString(&image_data)); } +} // namespace + namespace borealis { // Declared in chrome/browser/ash/borealis/borealis_util.h. @@ -40,35 +68,78 @@ delegate_ = delegate.get(); views::DialogDelegate::CreateDialogWidget(std::move(delegate), nullptr, nullptr); + delegate_->GetBubbleFrameView()->SetBackgroundColor(background_color); delegate_->GetWidget()->GetNativeWindow()->SetProperty( ash::kShelfIDKey, ash::ShelfID(borealis::kInstallerAppId).Serialize()); } delegate_->GetWidget()->Show(); } -BorealisSplashScreenView::BorealisSplashScreenView(Profile* profile) { +BorealisSplashScreenView::BorealisSplashScreenView(Profile* profile) + : weak_factory_(this) { profile_ = profile; borealis::BorealisService::GetForProfile(profile_) ->WindowManager() .AddObserver(this); SetShowCloseButton(false); + SetHasWindowSizeControls(false); SetButtons(ui::DIALOG_BUTTON_NONE); views::LayoutProvider* provider = views::LayoutProvider::Get(); - SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, + + std::unique_ptr<views::BoxLayout> layout = std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG), - provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL))); + provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_HORIZONTAL)); + layout->set_minimum_cross_axis_size(icon_height); + layout->set_cross_axis_alignment( + views::BoxLayout::CrossAxisAlignment::kCenter); + SetLayoutManager(std::move(layout)); + set_margins(provider->GetDialogInsetsForContentType( - views::DialogContentType::kText, views::DialogContentType::kText)); + views::DialogContentType::kControl, views::DialogContentType::kText)); set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric( views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH)); - set_close_on_deactivate(false); + set_use_custom_frame(true); + SetBackground(views::CreateSolidBackground(background_color)); - // TODO: b/174589567 Make splash screen look like mockups. - views::MessageBoxView* message_box = - new views::MessageBoxView(u"BOREALIS IS STARTING... PLEASE WAIT"); - AddChildView(message_box); + // Get logo path and add it to view. + borealis::GetDlcPath(base::BindOnce(&BorealisSplashScreenView::OnGetRootPath, + weak_factory_.GetWeakPtr())); + + views::View* text_view = AddChildView(std::make_unique<views::View>()); + std::unique_ptr<views::BoxLayout> layout2 = + std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, + provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG), + provider->GetDistanceMetric( + views::DISTANCE_RELATED_CONTROL_HORIZONTAL)); + text_view->SetLayoutManager(std::move(layout2)); + + std::unique_ptr<views::BoxLayout> text_layout = + std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical); + text_layout->set_cross_axis_alignment( + views::BoxLayout::CrossAxisAlignment::kStart); + text_view->SetLayoutManager(std::move(text_layout)); + set_corner_radius(10); + set_fixed_width(380); + + std::unique_ptr<views::Label> steam_label = std::make_unique<views::Label>( + u"STEAM FOR CHROMEBOOK", + views::Label::CustomFont{gfx::FontList({"Google Sans"}, gfx::Font::NORMAL, + 18, gfx::Font::Weight::NORMAL)}); + steam_label->SetEnabledColor(text_color); + steam_label->SetBackgroundColor(background_color); + text_view->AddChildView(std::move(steam_label)); + + std::unique_ptr<views::Label> starting_label = std::make_unique<views::Label>( + u"STARTING UP...", + views::Label::CustomFont{gfx::FontList({"Google Sans"}, gfx::Font::NORMAL, + 18, gfx::Font::Weight::NORMAL)}); + starting_label->SetEnabledColor(text_color); + starting_label->SetBackgroundColor(background_color); + text_view->AddChildView(std::move(starting_label)); } void BorealisSplashScreenView::OnSessionStarted() { @@ -95,4 +166,22 @@ return delegate_; } +void BorealisSplashScreenView::OnGetRootPath(const std::string& path) { + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&ReadImageFile, path), + base::BindOnce(&BorealisSplashScreenView::CreateImageView, + weak_factory_.GetWeakPtr())); +} + +void BorealisSplashScreenView::CreateImageView(gfx::Image image) { + std::unique_ptr<views::ImageView> image_view = + std::make_unique<views::ImageView>(); + constexpr gfx::Size kRegularImageSize(icon_width, icon_height); + image_view->SetImage(image.AsImageSkia()); + image_view->SetImageSize(kRegularImageSize); + AddChildViewAt(std::move(image_view), 0); + Layout(); +} + } // namespace borealis
diff --git a/chrome/browser/ui/views/borealis/borealis_splash_screen_view.h b/chrome/browser/ui/views/borealis/borealis_splash_screen_view.h index 7919f80..2485bb3 100644 --- a/chrome/browser/ui/views/borealis/borealis_splash_screen_view.h +++ b/chrome/browser/ui/views/borealis/borealis_splash_screen_view.h
@@ -5,14 +5,14 @@ #ifndef CHROME_BROWSER_UI_VIEWS_BOREALIS_BOREALIS_SPLASH_SCREEN_VIEW_H_ #define CHROME_BROWSER_UI_VIEWS_BOREALIS_BOREALIS_SPLASH_SCREEN_VIEW_H_ +#include "chrome/browser/ash/borealis/borealis_util.h" #include "chrome/browser/ash/borealis/borealis_window_manager.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" - // A splash screen for borealis, displays when borealis is clicked and closed // when the first borealis window shows. namespace borealis { class BorealisSplashScreenView - : public views::BubbleDialogDelegateView, + : public views::DialogDelegateView, public borealis::BorealisWindowManager::AppWindowLifetimeObserver { public: explicit BorealisSplashScreenView(Profile* profile); @@ -26,9 +26,13 @@ borealis::BorealisWindowManager* window_manager) override; // Close this view when borealis window launches void OnSessionStarted() override; + void OnGetRootPath(const std::string& path); private: + void CreateImageView(gfx::Image image); + Profile* profile_ = nullptr; + base::WeakPtrFactory<BorealisSplashScreenView> weak_factory_; }; } // namespace borealis
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc index e18b631..d0fe0df0 100644 --- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc +++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
@@ -79,8 +79,6 @@ class WebContents; } // namespace content -using ui_test_utils::BrowserChangeObserver; - namespace web_app { namespace {
diff --git a/chrome/browser/ui/web_applications/web_app_badging_browsertest.cc b/chrome/browser/ui/web_applications/web_app_badging_browsertest.cc index 57409cd..912d016 100644 --- a/chrome/browser/ui/web_applications/web_app_badging_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_badging_browsertest.cc
@@ -24,7 +24,6 @@ #include "content/public/test/browser_test.h" using content::RenderFrameHost; -using content::WebContents; namespace web_app {
diff --git a/chrome/browser/ui/web_applications/web_app_metrics.cc b/chrome/browser/ui/web_applications/web_app_metrics.cc index 3a13756..19890d7 100644 --- a/chrome/browser/ui/web_applications/web_app_metrics.cc +++ b/chrome/browser/ui/web_applications/web_app_metrics.cc
@@ -27,7 +27,6 @@ #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" using DisplayMode = blink::mojom::DisplayMode; -using absl::optional; using content::WebContents; namespace web_app {
diff --git a/chrome/browser/ui/web_applications/web_share_target_browsertest.cc b/chrome/browser/ui/web_applications/web_share_target_browsertest.cc index fcacd92e..081840b 100644 --- a/chrome/browser/ui/web_applications/web_share_target_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_share_target_browsertest.cc
@@ -46,7 +46,6 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_LACROS) -#include "chrome/browser/apps/app_service/intent_util.h" #include "chromeos/crosapi/mojom/app_service_types.mojom.h" #include "chromeos/crosapi/mojom/sharesheet.mojom.h" #include "chromeos/crosapi/mojom/sharesheet_mojom_traits.h"
diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc index 52f29a4..4cdfd09 100644 --- a/chrome/browser/ui/webui/about_ui.cc +++ b/chrome/browser/ui/webui/about_ui.cc
@@ -33,6 +33,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/about_flags.h" +#include "chrome/browser/ash/borealis/borealis_credits.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" @@ -348,6 +349,20 @@ std::string contents_; }; +void OnBorealisCreditsLoaded(content::URLDataSource::GotDataCallback callback, + std::string credits_html) { + if (credits_html.empty()) { + credits_html = l10n_util::GetStringUTF8(IDS_BOREALIS_CREDITS_PLACEHOLDER); + } + std::move(callback).Run(base::RefCountedString::TakeString(&credits_html)); +} + +void HandleBorealisCredits(Profile* profile, + content::URLDataSource::GotDataCallback callback) { + borealis::LoadBorealisCredits( + profile, base::BindOnce(&OnBorealisCreditsLoaded, std::move(callback))); +} + class CrostiniCreditsHandler : public base::RefCountedThreadSafe<CrostiniCreditsHandler> { public: @@ -673,6 +688,9 @@ } else if (source_name_ == chrome::kChromeUICrostiniCreditsHost) { CrostiniCreditsHandler::Start(profile(), path, std::move(callback)); return; + } else if (source_name_ == chrome::kChromeUIBorealisCreditsHost) { + HandleBorealisCredits(profile(), std::move(callback)); + return; #endif #if !BUILDFLAG(IS_ANDROID) } else if (source_name_ == chrome::kChromeUITermsHost) { @@ -717,7 +735,8 @@ bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() { #if BUILDFLAG(IS_CHROMEOS_ASH) if (source_name_ == chrome::kChromeUIOSCreditsHost || - source_name_ == chrome::kChromeUICrostiniCreditsHost) { + source_name_ == chrome::kChromeUICrostiniCreditsHost || + source_name_ == chrome::kChromeUIBorealisCreditsHost) { return false; } #endif
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc index 31c0339..1345bc3 100644 --- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc +++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -10,6 +10,7 @@ #include "base/containers/contains.h" #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" +#include "base/i18n/message_formatter.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -20,6 +21,7 @@ #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_utils.h" +#include "chrome/grit/generated_resources.h" #include "components/app_constants/constants.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" #include "components/services/app_service/public/cpp/app_types.h" @@ -37,7 +39,9 @@ #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/webui/resources/cr_components/app_management/app_management.mojom.h" +#include "url/gurl.h" #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/components/arc/session/connection_holder.h" @@ -58,6 +62,13 @@ app_constants::kLacrosAppId, }; +#if BUILDFLAG(IS_WIN) +const char kFileHandlingLearnMore[] = ""; +#elif !BUILDFLAG(IS_CHROMEOS) +const char kFileHandlingLearnMore[] = + "https://support.google.com/chrome/?p=pwa_default_associations"; +#endif + #if BUILDFLAG(IS_CHROMEOS_ASH) constexpr char const* kAppIdsWithHiddenStoragePermission[] = { arc::kPlayStoreAppId, @@ -358,6 +369,7 @@ app->title = update.Name(); app->permissions = std::move(permissions); app->install_reason = update.InstallReason(); + app->install_source = update.InstallSource(); app->description = update.Description(); @@ -392,18 +404,36 @@ const bool fh_enabled = !provider->registrar().IsAppFileHandlerPermissionBlocked(app->id); std::string file_handling_types; + std::string file_handling_types_label; if (provider->os_integration_manager().IsFileHandlingAPIAvailable( app->id) && !provider->registrar().GetAppFileHandlers(app->id)->empty()) { - // TODO(crbug/1245293): elide types and add clickable link. auto [file_handling_types16, count] = web_app::GetFileTypeAssociationsHandledByWebAppForDisplay(profile_, app->id); file_handling_types = base::UTF16ToUTF8(file_handling_types16); + + const std::vector<std::string> all_extensions = + web_app::GetFileTypeAssociationsHandledByWebAppForDisplayAsList( + profile_, app->id); + std::vector<std::string> truncated_extensions = all_extensions; + // Only show at most 4 extensions. + truncated_extensions.resize(4); + file_handling_types_label = + base::UTF16ToUTF8(base::i18n::MessageFormatter::FormatWithNamedArgs( + l10n_util::GetStringUTF16(IDS_APP_MANAGEMENT_FILE_HANDLING_TYPES), + "FILE_TYPE_COUNT", static_cast<int>(all_extensions.size()), + "FILE_TYPE1", truncated_extensions[0], "FILE_TYPE2", + truncated_extensions[1], "FILE_TYPE3", truncated_extensions[2], + "FILE_TYPE4", truncated_extensions[3], "OVERFLOW_COUNT", + static_cast<int>(all_extensions.size()) - + static_cast<int>(truncated_extensions.size()), + "LINK", "#")); } // TODO(crbug/1252505): add file handling policy support. app->file_handling_state = app_management::mojom::FileHandlingState::New( - fh_enabled, /*is_managed=*/false, file_handling_types); + fh_enabled, /*is_managed=*/false, file_handling_types, + file_handling_types_label, GURL(kFileHandlingLearnMore)); } #endif
diff --git a/chrome/browser/ui/webui/app_settings/web_app_settings_ui.cc b/chrome/browser/ui/webui/app_settings/web_app_settings_ui.cc index 7109ea9c..3de0c1ad 100644 --- a/chrome/browser/ui/webui/app_settings/web_app_settings_ui.cc +++ b/chrome/browser/ui/webui/app_settings/web_app_settings_ui.cc
@@ -42,6 +42,8 @@ {"appManagementRunOnOsLoginModeLabel", IDS_APP_MANAGEMENT_RUN_ON_OS_LOGIN}, {"controlledSettingPolicy", IDS_CONTROLLED_SETTING_POLICY}, + {"fileHandlingSetDefaults", + IDS_APP_MANAGEMENT_FILE_HANDLING_SET_DEFAULTS_LINK}, }; html_source->AddLocalizedStrings(kLocalizedStrings); }
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index e23b58f..e5e9dec 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -686,6 +686,7 @@ #endif #if BUILDFLAG(IS_CHROMEOS_ASH) || url.host_piece() == chrome::kChromeUIOSCreditsHost || + url.host_piece() == chrome::kChromeUIBorealisCreditsHost || url.host_piece() == chrome::kChromeUICrostiniCreditsHost #endif ); // NOLINT @@ -1530,6 +1531,7 @@ GURL(chrome::kChromeUIBluetoothPairingURL), GURL(chrome::kOsUIComponentsUrl), GURL(chrome::kChromeUICrashesUrl), GURL(chrome::kOsUICrashesUrl), GURL(chrome::kOsUICreditsURL), + GURL(chrome::kChromeUIBorealisCreditsURL), GURL(chrome::kChromeUICrostiniCreditsURL), GURL(chrome::kChromeUICrostiniInstallerUrl), GURL(chrome::kChromeUICrostiniUpgraderUrl),
diff --git a/chrome/browser/ui/webui/metrics_handler.cc b/chrome/browser/ui/webui/metrics_handler.cc index 197e8c1..7f997d2 100644 --- a/chrome/browser/ui/webui/metrics_handler.cc +++ b/chrome/browser/ui/webui/metrics_handler.cc
@@ -45,6 +45,10 @@ "metricsHandler:recordMediumTime", base::BindRepeating(&MetricsHandler::HandleRecordMediumTime, base::Unretained(this))); + web_ui()->RegisterDeprecatedMessageCallback( + "metricsHandler:recordSparseHistogram", + base::BindRepeating(&MetricsHandler::HandleRecordSparseHistogram, + base::Unretained(this))); } void MetricsHandler::HandleRecordAction(const base::ListValue* args) { @@ -112,3 +116,10 @@ base::UmaHistogramMediumTimes(histogram_name, base::Milliseconds(value)); } + +void MetricsHandler::HandleRecordSparseHistogram(const base::ListValue* args) { + const std::string& histogram_name = args->GetListDeprecated()[0].GetString(); + int sample = args->GetListDeprecated()[1].GetInt(); + + base::UmaHistogramSparse(histogram_name, sample); +}
diff --git a/chrome/browser/ui/webui/metrics_handler.h b/chrome/browser/ui/webui/metrics_handler.h index 6f515e7a..5a21cf002 100644 --- a/chrome/browser/ui/webui/metrics_handler.h +++ b/chrome/browser/ui/webui/metrics_handler.h
@@ -60,6 +60,11 @@ // UmaHistogramMedium. Handles times up to 3 minutes. |args| contains the // histogram name and a value in milliseconds. void HandleRecordMediumTime(const base::ListValue* args); + + // Callback for the "metricsHandler:recordSparseHistogram" message. This + // records into a sparse histogram. |args| contains the histogram name and + // the sample value to record. + void HandleRecordSparseHistogram(const base::ListValue* args); }; #endif // CHROME_BROWSER_UI_WEBUI_METRICS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc index a2d0dca5..648aec2 100644 --- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc +++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -96,80 +96,63 @@ } // The Discount Consent V2 is gated by Chrome Cart, and that is enabled for -// en-us local only. So using plain en strings here are fine. +// en-us local only. So using plain en strings here is fine. void AddResourcesForCartDiscountConsentV2(content::WebUIDataSource* source) { - int discount_consent_variation = - ntp_features::kNtpChromeCartModuleDiscountConsentNtpVariation.Get(); - source->AddInteger("modulesCartDiscountConsentVariation", - discount_consent_variation); + AddRawStringOrDefault( + source, "modulesCartDiscountConsentContent", + ntp_features::kNtpChromeCartModuleDiscountConsentStringChangeContent + .Get(), + IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_CONTENT_V2); - if (discount_consent_variation == - static_cast<int>( - ntp_features::DiscountConsentNtpVariation::kStringChange)) { - AddRawStringOrDefault( - source, "modulesCartDiscountConsentContent", - ntp_features::kNtpChromeCartModuleDiscountConsentStringChangeContent - .Get(), - IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_CONTENT_V2); - } else { - if (discount_consent_variation == - static_cast<int>(ntp_features::DiscountConsentNtpVariation::kInline)) { - source->AddBoolean( - "modulesCartConsentStepTwoDifferentColor", - ntp_features:: - kNtpChromeCartModuleDiscountConsentInlineStepTwoDifferentColor - .Get()); - } else if (discount_consent_variation == - static_cast<int>( - ntp_features::DiscountConsentNtpVariation::kDialog)) { - AddRawStringOrDefault( - source, "modulesCartDiscountConentTitle", - ntp_features::kNtpChromeCartModuleDiscountConsentNtpDialogContentTitle - .Get(), - IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_TITLE); - } - source->AddBoolean( - "modulesCartStepOneUseStaticContent", - ntp_features:: - kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContent - .Get()); - // This does not have a raw string resource. - source->AddString( - "modulesCartStepOneStaticContent", - ntp_features::kNtpChromeCartModuleDiscountConsentNtpStepOneStaticContent - .Get()); + source->AddBoolean( + "modulesCartConsentStepTwoDifferentColor", + ntp_features:: + kNtpChromeCartModuleDiscountConsentInlineStepTwoDifferentColor.Get()); - AddRawStringOrDefault( - source, "modulesCartConsentStepOneOneMerchantContent", - ntp_features:: - kNtpChromeCartModuleDiscountConsentNtpStepOneContentOneCart.Get(), - IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_STEP_1_WITH_MERCHANT_NAME); - AddRawStringOrDefault( - source, "modulesCartConsentStepOneTwoMerchantsContent", - ntp_features:: - kNtpChromeCartModuleDiscountConsentNtpStepOneContentTwoCarts.Get(), - IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_STEP_1_WITH_TWO_MERCHANT_NAMES); - AddRawStringOrDefault( - source, "modulesCartConsentStepOneThreeMerchantsContent", - ntp_features:: - kNtpChromeCartModuleDiscountConsentNtpStepOneContentThreeCarts - .Get(), - IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_STEP_1_WITH_THREE_MERCHANT_NAMES); - AddRawStringOrDefault( - source, "modulesCartConsentStepTwoContent", - ntp_features::kNtpChromeCartModuleDiscountConsentNtpStepTwoContent - .Get(), - IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_CONTENT_V3); + AddRawStringOrDefault( + source, "modulesCartDiscountConentTitle", + ntp_features::kNtpChromeCartModuleDiscountConsentNtpDialogContentTitle + .Get(), + IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_TITLE); - source->AddLocalizedString( - "modulesCartConsentStepOneButton", - IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_STEP_1_CONTINUE); + source->AddBoolean( + "modulesCartStepOneUseStaticContent", + ntp_features:: + kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContent.Get()); + // This does not have a raw string resource. + source->AddString( + "modulesCartStepOneStaticContent", + ntp_features::kNtpChromeCartModuleDiscountConsentNtpStepOneStaticContent + .Get()); - source->AddBoolean( - "modulesCartDiscountInlineCardShowCloseButton", - ntp_features::kNtpChromeCartModuleDiscountConsentInlineShowCloseButton - .Get()); - } + AddRawStringOrDefault( + source, "modulesCartConsentStepOneOneMerchantContent", + ntp_features::kNtpChromeCartModuleDiscountConsentNtpStepOneContentOneCart + .Get(), + IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_STEP_1_WITH_MERCHANT_NAME); + AddRawStringOrDefault( + source, "modulesCartConsentStepOneTwoMerchantsContent", + ntp_features::kNtpChromeCartModuleDiscountConsentNtpStepOneContentTwoCarts + .Get(), + IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_STEP_1_WITH_TWO_MERCHANT_NAMES); + AddRawStringOrDefault( + source, "modulesCartConsentStepOneThreeMerchantsContent", + ntp_features:: + kNtpChromeCartModuleDiscountConsentNtpStepOneContentThreeCarts.Get(), + IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_STEP_1_WITH_THREE_MERCHANT_NAMES); + AddRawStringOrDefault( + source, "modulesCartConsentStepTwoContent", + ntp_features::kNtpChromeCartModuleDiscountConsentNtpStepTwoContent.Get(), + IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_CONTENT_V3); + + source->AddLocalizedString( + "modulesCartConsentStepOneButton", + IDS_NTP_MODULES_CART_DISCOUNT_CONSENT_STEP_1_CONTINUE); + + source->AddBoolean( + "modulesCartDiscountInlineCardShowCloseButton", + ntp_features::kNtpChromeCartModuleDiscountConsentInlineShowCloseButton + .Get()); } content::WebUIDataSource* CreateNewTabPageUiHtmlSource(Profile* profile) { @@ -397,6 +380,10 @@ }; source->AddLocalizedStrings(kStrings); + source->AddInteger( + "modulesCartDiscountConsentVariation", + ntp_features::kNtpChromeCartModuleDiscountConsentNtpVariation.Get()); + if (base::FeatureList::IsEnabled(commerce::kDiscountConsentV2)) { AddResourcesForCartDiscountConsentV2(source); } else {
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc index 48d2a51e..207e061 100644 --- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc +++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -182,6 +182,10 @@ AppLauncherHandler::~AppLauncherHandler() { Profile* webui_profile = Profile::FromWebUI(web_ui()); ExtensionRegistry::Get(webui_profile)->RemoveObserver(this); + // Destroy `extension_uninstall_dialog_` now, since `this` is an + // `ExtensionUninstallDialog::Delegate` and the dialog may call back into + // `this` when destroyed. + extension_uninstall_dialog_.reset(); } void AppLauncherHandler::CreateWebAppInfo(const web_app::AppId& app_id,
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.h b/chrome/browser/ui/webui/ntp/app_launcher_handler.h index 5a0934bd..359fe38 100644 --- a/chrome/browser/ui/webui/ntp/app_launcher_handler.h +++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.h
@@ -9,6 +9,7 @@ #include <set> #include <string> +#include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/scoped_observation.h" #include "base/task/cancelable_task_tracker.h" @@ -183,6 +184,9 @@ void HandleRunOnOsLogin(const base::ListValue* args); private: + FRIEND_TEST_ALL_PREFIXES(AppLauncherHandlerTest, + HandleClosedWhileUninstallingExtension); + struct AppInstallInfo { AppInstallInfo(); ~AppInstallInfo();
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler_unittest.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler_unittest.cc index 15c879b..63103af 100644 --- a/chrome/browser/ui/webui/ntp/app_launcher_handler_unittest.cc +++ b/chrome/browser/ui/webui/ntp/app_launcher_handler_unittest.cc
@@ -16,16 +16,18 @@ #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_sync_bridge.h" +#include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_profile.h" #include "content/public/browser/web_contents.h" -#include "content/public/test/browser_task_environment.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/test_web_ui.h" #include "content/public/test/web_contents_tester.h" +#include "extensions/common/extension_builder.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -namespace web_app { +using web_app::AppId; +using web_app::WebAppProvider; namespace { @@ -76,7 +78,7 @@ } // namespace -class AppLauncherHandlerTest : public testing::Test { +class AppLauncherHandlerTest : public BrowserWithTestWindowTest { public: AppLauncherHandlerTest() = default; @@ -86,13 +88,7 @@ ~AppLauncherHandlerTest() override = default; void SetUp() override { - testing::Test::SetUp(); - - TestingProfile::Builder builder; -#if BUILDFLAG(IS_CHROMEOS_LACROS) - builder.SetIsMainProfile(true); -#endif // BUILDFLAG(IS_CHROMEOS_LACROS) - testing_profile_ = builder.Build(); + BrowserWithTestWindowTest::SetUp(); extension_service_ = CreateTestExtensionService(); @@ -102,8 +98,6 @@ } protected: - Profile* profile() { return testing_profile_->GetOriginalProfile(); } - std::unique_ptr<TestAppLauncherHandler> GetAppLauncherHandler( content::TestWebUI* test_web_ui) { return std::make_unique<TestAppLauncherHandler>( @@ -113,7 +107,8 @@ // Install a web app and sets the locally installed property based on // |is_locally_installed|. AppId InstallWebApp(bool is_locally_installed = true) { - AppId installed_app_id = test::InstallWebApp(profile(), BuildWebAppInfo()); + AppId installed_app_id = + web_app::test::InstallWebApp(profile(), BuildWebAppInfo()); if (is_locally_installed) return installed_app_id; @@ -156,12 +151,11 @@ } std::unique_ptr<content::WebContents> CreateTestWebContents() { - auto site_instance = content::SiteInstance::Create(browser_context()); + auto site_instance = content::SiteInstance::Create(profile()); return content::WebContentsTester::CreateTestWebContents( - browser_context(), std::move(site_instance)); + profile(), std::move(site_instance)); } - private: extensions::ExtensionService* CreateTestExtensionService() { auto* extension_system = static_cast<extensions::TestExtensionSystem*>( extensions::ExtensionSystem::Get(profile())); @@ -172,11 +166,6 @@ return ext_service; } - content::BrowserContext* browser_context() { return testing_profile_.get(); } - - content::BrowserTaskEnvironment task_environment_; - content::RenderViewHostTestEnabler render_view_host_test_enabler_; - std::unique_ptr<TestingProfile> testing_profile_; web_app::OsIntegrationManager::ScopedSuppressForTesting os_hooks_suppress_; raw_ptr<extensions::ExtensionService> extension_service_; }; @@ -246,4 +235,24 @@ installed_app_id); } -} // namespace web_app +// Regression test for crbug.com/1302157. +TEST_F(AppLauncherHandlerTest, HandleClosedWhileUninstallingExtension) { + scoped_refptr<const extensions::Extension> extension = + extensions::ExtensionBuilder("foo").Build(); + extension_service_->AddExtension(extension.get()); + + AddTab(browser(), GURL("http://foo/1")); + content::WebContents* contents = + browser()->tab_strip_model()->GetWebContentsAt(0); + std::unique_ptr<content::WebContents> test_web_contents = + CreateTestWebContents(); + std::unique_ptr<content::TestWebUI> test_web_ui = CreateTestWebUI(contents); + std::unique_ptr<TestAppLauncherHandler> app_launcher_handler = + GetAppLauncherHandler(test_web_ui.get()); + + app_launcher_handler->CreateExtensionUninstallDialog()->ConfirmUninstall( + extension, extensions::UNINSTALL_REASON_USER_INITIATED, + extensions::UNINSTALL_SOURCE_CHROME_APPS_PAGE); + app_launcher_handler.reset(); + // No crash (in asan tester) indicates a passing score. +}
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc index 3001703..ee17d81 100644 --- a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc +++ b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc
@@ -24,6 +24,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" #include "chrome/browser/ui/tabs/tab_group_theme.h" @@ -625,11 +626,11 @@ colors["--tabstrip-focus-outline-color"] = color_utils::SkColorToRgbaString( embedder_->GetColorProviderColor(ui::kColorFocusableBorderFocused)); colors["--tabstrip-tab-active-title-background-color"] = - color_utils::SkColorToRgbaString(embedder_->GetColor( - ThemeProperties::COLOR_THUMBNAIL_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE)); + color_utils::SkColorToRgbaString( + embedder_->GetColorProviderColor(kColorThumbnailTabBackground)); colors["--tabstrip-tab-active-title-content-color"] = - color_utils::SkColorToRgbaString(embedder_->GetColor( - ThemeProperties::COLOR_THUMBNAIL_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE)); + color_utils::SkColorToRgbaString( + embedder_->GetColorProviderColor(kColorThumbnailTabForeground)); #if !BUILDFLAG(IS_CHROMEOS_ASH) colors["--tabstrip-scrollbar-thumb-color-rgb"] = @@ -927,16 +928,9 @@ bool active_tab_icon) { if (active_tab_icon) { return favicon::ThemeFavicon( - source, - embedder_->GetColor( - ThemeProperties:: - COLOR_THUMBNAIL_TAB_FOREGROUND_ACTIVE_FRAME_ACTIVE), - embedder_->GetColor( - ThemeProperties:: - COLOR_THUMBNAIL_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE), - embedder_->GetColor( - ThemeProperties:: - COLOR_THUMBNAIL_TAB_BACKGROUND_ACTIVE_FRAME_ACTIVE)); + source, embedder_->GetColorProviderColor(kColorThumbnailTabForeground), + embedder_->GetColorProviderColor(kColorThumbnailTabBackground), + embedder_->GetColorProviderColor(kColorThumbnailTabBackground)); } return favicon::ThemeFavicon(
diff --git a/chrome/browser/web_applications/daily_metrics_helper_unittest.cc b/chrome/browser/web_applications/daily_metrics_helper_unittest.cc index 6db252b..0b56c65 100644 --- a/chrome/browser/web_applications/daily_metrics_helper_unittest.cc +++ b/chrome/browser/web_applications/daily_metrics_helper_unittest.cc
@@ -18,7 +18,6 @@ namespace { -using base::Time; using testing::Contains; using testing::Key; using testing::Not;
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn index 658549e..13b757f 100644 --- a/chrome/browser/web_applications/extensions/BUILD.gn +++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -26,7 +26,6 @@ deps = [ "//base", - "//build:chromeos_buildflags", "//chrome/browser:browser_process", "//chrome/browser/profiles:profile", "//chrome/browser/web_applications", @@ -55,7 +54,7 @@ deps = [ ":extensions", - "//chrome/browser", + "//build:chromeos_buildflags", "//chrome/browser/web_applications:web_app_test_group", "//chrome/browser/web_applications:web_applications", "//chrome/browser/web_applications:web_applications_test_support", @@ -71,7 +70,14 @@ "//testing/gtest", ] + if (is_chromeos) { + deps += [ + "//chrome/browser", + "//components/policy/core/common:common_constants", + ] + } + if (is_chromeos_ash) { - deps += [ "//chrome/browser/chromeos:chromeos" ] + deps += [ "//ash/constants" ] } }
diff --git a/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc b/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc index 1dc0209..df241488 100644 --- a/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc +++ b/chrome/browser/web_applications/extensions/web_app_policy_manager_unittest.cc
@@ -15,7 +15,7 @@ #include "base/test/scoped_feature_list.h" #include "base/values.h" #include "build/build_config.h" -#include "chrome/browser/prefs/browser_prefs.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/web_applications/app_registrar_observer.h" #include "chrome/browser/web_applications/external_install_options.h" #include "chrome/browser/web_applications/externally_managed_app_manager.h" @@ -50,8 +50,6 @@ #include "components/policy/core/common/policy_pref_names.h" #endif // BUILDFLAG(IS_CHROMEOS) -using sync_preferences::TestingPrefServiceSyncable; - namespace web_app { namespace { @@ -312,7 +310,7 @@ scoped_feature_list_.InitAndEnableFeature(features::kWebAppsCrosapi); } else if (GetParam() == TestParam::kLacrosDisabled) { scoped_feature_list_.InitWithFeatures( - {}, {features::kWebAppsCrosapi, chromeos::features::kLacrosPrimary}); + {}, {features::kWebAppsCrosapi, ash::features::kLacrosPrimary}); } #endif // BUILDFLAG(IS_CHROMEOS_ASH) ChromeRenderViewHostTestHarness::SetUp();
diff --git a/chrome/browser/web_applications/os_integration/protocol_handler_manager_unittest.cc b/chrome/browser/web_applications/os_integration/protocol_handler_manager_unittest.cc index 056313b9..7831fde 100644 --- a/chrome/browser/web_applications/os_integration/protocol_handler_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/protocol_handler_manager_unittest.cc
@@ -32,7 +32,7 @@ } FakeWebAppProtocolHandlerManager& protocol_handler_manager() { - return *protocol_handler_manager_.get(); + return *protocol_handler_manager_; } FakeWebAppRegistryController& controller() {
diff --git a/chrome/browser/web_applications/os_integration/web_app_file_handler_manager_unittest.cc b/chrome/browser/web_applications/os_integration/web_app_file_handler_manager_unittest.cc index 11fabca..8956f17e 100644 --- a/chrome/browser/web_applications/os_integration/web_app_file_handler_manager_unittest.cc +++ b/chrome/browser/web_applications/os_integration/web_app_file_handler_manager_unittest.cc
@@ -182,7 +182,7 @@ } FakeWebAppFileHandlerManager& file_handler_manager() { - return *file_handler_manager_.get(); + return *file_handler_manager_; } FakeWebAppRegistryController& controller() {
diff --git a/chrome/browser/web_applications/preinstalled_web_app_manager_browsertest.cc b/chrome/browser/web_applications/preinstalled_web_app_manager_browsertest.cc index b5ec8e8..e819f796 100644 --- a/chrome/browser/web_applications/preinstalled_web_app_manager_browsertest.cc +++ b/chrome/browser/web_applications/preinstalled_web_app_manager_browsertest.cc
@@ -49,12 +49,6 @@ #include "ui/events/devices/device_data_manager_test_api.h" #include "ui/events/devices/touchscreen_device.h" -#if BUILDFLAG(IS_CHROMEOS) -#include "chrome/browser/apps/app_service/app_service_proxy.h" -#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" -#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" -#endif - #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/test/app_list_test_api.h" #include "chrome/browser/ui/app_list/app_list_client_impl.h"
diff --git a/chrome/browser/web_applications/test/fake_data_retriever.cc b/chrome/browser/web_applications/test/fake_data_retriever.cc index df34f64..bce7e2c1 100644 --- a/chrome/browser/web_applications/test/fake_data_retriever.cc +++ b/chrome/browser/web_applications/test/fake_data_retriever.cc
@@ -41,7 +41,7 @@ } void FakeDataRetriever::GetIcons(content::WebContents* web_contents, - const std::vector<GURL>& icon_urls, + std::vector<GURL> icon_urls, bool skip_page_favicons, GetIconsCallback callback) { if (get_icons_delegate_) {
diff --git a/chrome/browser/web_applications/test/fake_data_retriever.h b/chrome/browser/web_applications/test/fake_data_retriever.h index cf4616b..fb0101b 100644 --- a/chrome/browser/web_applications/test/fake_data_retriever.h +++ b/chrome/browser/web_applications/test/fake_data_retriever.h
@@ -35,7 +35,7 @@ bool bypass_service_worker_check, CheckInstallabilityCallback callback) override; void GetIcons(content::WebContents* web_contents, - const std::vector<GURL>& icon_urls, + std::vector<GURL> icon_urls, bool skip_page_favicons, GetIconsCallback callback) override;
diff --git a/chrome/browser/web_applications/web_app_data_retriever.cc b/chrome/browser/web_applications/web_app_data_retriever.cc index b310b36d..6ce17549 100644 --- a/chrome/browser/web_applications/web_app_data_retriever.cc +++ b/chrome/browser/web_applications/web_app_data_retriever.cc
@@ -112,7 +112,7 @@ } void WebAppDataRetriever::GetIcons(content::WebContents* web_contents, - const std::vector<GURL>& icon_urls, + std::vector<GURL> icon_urls, bool skip_page_favicons, GetIconsCallback callback) { Observe(web_contents); @@ -123,7 +123,7 @@ // TODO(loyso): Refactor WebAppIconDownloader: crbug.com/907296. icon_downloader_ = std::make_unique<WebAppIconDownloader>( - web_contents, icon_urls, + web_contents, std::move(icon_urls), base::BindOnce(&WebAppDataRetriever::OnIconsDownloaded, weak_ptr_factory_.GetWeakPtr()));
diff --git a/chrome/browser/web_applications/web_app_data_retriever.h b/chrome/browser/web_applications/web_app_data_retriever.h index 1907fb51..125250f 100644 --- a/chrome/browser/web_applications/web_app_data_retriever.h +++ b/chrome/browser/web_applications/web_app_data_retriever.h
@@ -73,7 +73,7 @@ // Downloads icons from |icon_urls|. Runs |callback| with a map of // the retrieved icons. virtual void GetIcons(content::WebContents* web_contents, - const std::vector<GURL>& icon_urls, + std::vector<GURL> icon_urls, bool skip_page_favicons, GetIconsCallback callback);
diff --git a/chrome/browser/web_applications/web_app_data_retriever_unittest.cc b/chrome/browser/web_applications/web_app_data_retriever_unittest.cc index a920bad..ce2158d 100644 --- a/chrome/browser/web_applications/web_app_data_retriever_unittest.cc +++ b/chrome/browser/web_applications/web_app_data_retriever_unittest.cc
@@ -325,12 +325,12 @@ web_contents_tester()->NavigateAndCommit(GURL("https://foo.example")); - const std::vector<GURL> icon_urls; bool skip_page_favicons = true; base::RunLoop run_loop; WebAppDataRetriever retriever; - retriever.GetIcons(web_contents(), icon_urls, skip_page_favicons, + retriever.GetIcons(web_contents(), /*icon_urls=*/std::vector<GURL>(), + skip_page_favicons, base::BindLambdaForTesting( [&](IconsDownloadedResult result, IconsMap icons_map, DownloadedIconsHttpResults icons_http_results) {
diff --git a/chrome/browser/web_applications/web_app_icon_downloader.cc b/chrome/browser/web_applications/web_app_icon_downloader.cc index e8de61f0e..ab72d2c 100644 --- a/chrome/browser/web_applications/web_app_icon_downloader.cc +++ b/chrome/browser/web_applications/web_app_icon_downloader.cc
@@ -18,10 +18,10 @@ WebAppIconDownloader::WebAppIconDownloader( content::WebContents* web_contents, - const std::vector<GURL>& extra_favicon_urls, + std::vector<GURL> extra_favicon_urls, WebAppIconDownloaderCallback callback) : content::WebContentsObserver(web_contents), - extra_favicon_urls_(extra_favicon_urls), + extra_favicon_urls_(std::move(extra_favicon_urls)), callback_(std::move(callback)) {} WebAppIconDownloader::~WebAppIconDownloader() = default;
diff --git a/chrome/browser/web_applications/web_app_icon_downloader.h b/chrome/browser/web_applications/web_app_icon_downloader.h index b1f0fd29..f4b251ff 100644 --- a/chrome/browser/web_applications/web_app_icon_downloader.h +++ b/chrome/browser/web_applications/web_app_icon_downloader.h
@@ -38,7 +38,7 @@ // |extra_favicon_urls| allows callers to provide icon urls that aren't // provided by the renderer (e.g touch icons on non-android environments). WebAppIconDownloader(content::WebContents* web_contents, - const std::vector<GURL>& extra_favicon_urls, + std::vector<GURL> extra_favicon_urls, WebAppIconDownloaderCallback callback); WebAppIconDownloader(const WebAppIconDownloader&) = delete; WebAppIconDownloader& operator=(const WebAppIconDownloader&) = delete;
diff --git a/chrome/browser/web_applications/web_app_icon_downloader_unittest.cc b/chrome/browser/web_applications/web_app_icon_downloader_unittest.cc index d647d70..f59245b 100644 --- a/chrome/browser/web_applications/web_app_icon_downloader_unittest.cc +++ b/chrome/browser/web_applications/web_app_icon_downloader_unittest.cc
@@ -21,8 +21,6 @@ #include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h" #include "third_party/skia/include/core/SkBitmap.h" -using content::RenderViewHostTester; - namespace web_app { namespace { @@ -82,7 +80,7 @@ std::vector<GURL> extra_favicon_urls) : WebAppIconDownloader( web_contents, - extra_favicon_urls, + std::move(extra_favicon_urls), base::BindOnce(&TestWebAppIconDownloader::DownloadsComplete, base::Unretained(this))) {} TestWebAppIconDownloader(const TestWebAppIconDownloader&) = delete;
diff --git a/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc b/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc index 5fb827f..e0bc7e1 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer_unittest.cc
@@ -18,7 +18,6 @@ #include "chrome/browser/web_applications/test/web_app_test.h" #include "chrome/browser/web_applications/web_app_helpers.h" #include "chrome/browser/web_applications/web_app_icon_manager.h" -#include "chrome/browser/web_applications/web_app_install_finalizer.h" #include "chrome/browser/web_applications/web_app_install_info.h" #include "chrome/browser/web_applications/web_app_install_manager.h" #include "chrome/browser/web_applications/web_app_install_manager_observer.h" @@ -142,7 +141,7 @@ file_handlers->push_back(std::move(file_handler)); } - WebAppInstallFinalizer& finalizer() { return *finalizer_.get(); } + WebAppInstallFinalizer& finalizer() { return *finalizer_; } WebAppRegistrar& registrar() { return fake_registry_controller_->registrar(); }
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc index 6844ae3..0bccb2d 100644 --- a/chrome/browser/web_applications/web_app_install_task.cc +++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -748,7 +748,7 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) data_retriever_->GetIcons( - web_contents(), icon_urls, skip_page_favicons, + web_contents(), std::move(icon_urls), skip_page_favicons, base::BindOnce(&WebAppInstallTask::OnIconsRetrievedShowDialog, GetWeakPtr(), std::move(web_app_info), for_installable_site)); @@ -775,7 +775,8 @@ // Skip downloading the page favicons as everything in is the URL list. data_retriever_->GetIcons( - web_contents, icon_urls, /*skip_page_favicons=*/true, + web_contents, std::move(icon_urls), + /*skip_page_favicons=*/true, base::BindOnce(&WebAppInstallTask::OnIconsRetrieved, GetWeakPtr(), std::move(web_application_info), std::move(finalize_options)));
diff --git a/chrome/browser/web_applications/web_app_installation_utils_unittest.cc b/chrome/browser/web_applications/web_app_installation_utils_unittest.cc index d3605ff..67e871f 100644 --- a/chrome/browser/web_applications/web_app_installation_utils_unittest.cc +++ b/chrome/browser/web_applications/web_app_installation_utils_unittest.cc
@@ -19,8 +19,6 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" -using base::UTF8ToUTF16; - namespace web_app { namespace {
diff --git a/chrome/browser/web_applications/web_app_origin_association_manager.cc b/chrome/browser/web_applications/web_app_origin_association_manager.cc index 1542606..7eefff1 100644 --- a/chrome/browser/web_applications/web_app_origin_association_manager.cc +++ b/chrome/browser/web_applications/web_app_origin_association_manager.cc
@@ -66,7 +66,7 @@ webapps::WebAppOriginAssociationFetcher& WebAppOriginAssociationManager::GetFetcher() { - return *(fetcher_.get()); + return *fetcher_; } } // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h index 02e7c498..4548cba 100644 --- a/chrome/browser/web_applications/web_app_registrar.h +++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -347,7 +347,7 @@ ++internal_iter_; FilterAndSkipApps(); } - WebAppType& operator*() const { return *internal_iter_->second.get(); } + WebAppType& operator*() const { return *internal_iter_->second; } bool operator!=(const Iter& iter) const { return internal_iter_ != iter.internal_iter_; }
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.cc b/chrome/browser/web_applications/web_app_sync_bridge.cc index 64e71dfd..78c48099 100644 --- a/chrome/browser/web_applications/web_app_sync_bridge.cc +++ b/chrome/browser/web_applications/web_app_sync_bridge.cc
@@ -25,7 +25,6 @@ #include "chrome/browser/web_applications/web_app_prefs_utils.h" #include "chrome/browser/web_applications/web_app_proto_utils.h" #include "chrome/browser/web_applications/web_app_registry_update.h" -#include "chrome/browser/web_applications/web_app_sync_bridge.h" #include "chrome/browser/web_applications/web_app_sync_install_delegate.h" #include "chrome/browser/web_applications/web_app_utils.h" #include "chrome/common/channel_info.h"
diff --git a/chrome/browser/web_applications/web_app_utils.cc b/chrome/browser/web_applications/web_app_utils.cc index 9d92a38..790bd5f 100644 --- a/chrome/browser/web_applications/web_app_utils.cc +++ b/chrome/browser/web_applications/web_app_utils.cc
@@ -288,6 +288,17 @@ std::tuple<std::u16string, size_t> GetFileTypeAssociationsHandledByWebAppForDisplay(Profile* profile, const AppId& app_id) { + auto extensions = + GetFileTypeAssociationsHandledByWebAppForDisplayAsList(profile, app_id); + return {base::UTF8ToUTF16(base::JoinString( + extensions, l10n_util::GetStringUTF8( + IDS_WEB_APP_FILE_HANDLING_LIST_SEPARATOR))), + extensions.size()}; +} + +std::vector<std::string> GetFileTypeAssociationsHandledByWebAppForDisplayAsList( + Profile* profile, + const AppId& app_id) { auto* provider = WebAppProvider::GetForLocalAppsUnchecked(profile); if (!provider) return {}; @@ -306,12 +317,7 @@ [](const std::string& extension) { return base::ToUpperASCII(extension.substr(1)); }); - - return { - base::UTF8ToUTF16(base::JoinString( - extensions_for_display, - l10n_util::GetStringUTF8(IDS_WEB_APP_FILE_HANDLING_LIST_SEPARATOR))), - extensions_for_display.size()}; + return extensions_for_display; } #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/web_applications/web_app_utils.h b/chrome/browser/web_applications/web_app_utils.h index 7106a83..671c8b5 100644 --- a/chrome/browser/web_applications/web_app_utils.h +++ b/chrome/browser/web_applications/web_app_utils.h
@@ -118,6 +118,12 @@ GetFileTypeAssociationsHandledByWebAppForDisplay(Profile* profile, const AppId& app_id); +// As above, but returns the extensions handled by the app as a vector of +// strings. +std::vector<std::string> GetFileTypeAssociationsHandledByWebAppForDisplayAsList( + Profile* profile, + const AppId& app_id); + // Updates the approved or disallowed protocol list for the given app. If // necessary, it also updates the protocol registration with the OS. void PersistProtocolHandlersUserChoice(
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 341d4c3..f52a789c 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1646243962-7b7500a9d762e0521acc4b122a90a18fe81dc05a.profdata +chrome-linux-main-1646287134-58bacca7d05c875a887e1733884118b0387614c1.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 80a538d..bdc5ea64 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1646243962-4e46f239b2896d5d1f8a30282562dc33c882f1c3.profdata +chrome-mac-arm-main-1646287134-25bd7dec5ee035828d5025229b896fadef3ac22f.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 592168d..38a59898 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1646243962-70daee8a5bf56a806e3330535829c6bcc69e440f.profdata +chrome-mac-main-1646287134-6b63b4c80bfa7fdeddd960cac28117f9550af45f.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index c832188..8a8814d 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1646243962-4f6458fc9bad2f39414b2dcd5d75951912983f24.profdata +chrome-win32-main-1646287134-1916aa0301b8cbec16c01d645f1f3475f2b2c127.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index b6c7adc..e85ab56 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1646243962-bed2ea6ef9147ee706d4a29a46c4724fb3b1b7a7.profdata +chrome-win64-main-1646297119-7f2e287cdadee45caa594da54faa6ff8e2122687.profdata
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index db91e4f..283d488a 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -1725,10 +1725,6 @@ // not happen if the browser crashes, so we remove the profile on next start. const char kProfilesDeleted[] = "profiles.profiles_deleted"; -// This is the location of a list of dictionaries of plugin stability stats. -const char kStabilityPluginStats[] = - "user_experience_metrics.stability.plugin_stats2"; - // On Chrome OS, total number of non-Chrome user process crashes // since the last report. const char kStabilityOtherUserCrashCount[] = @@ -1743,11 +1739,6 @@ const char kStabilitySystemUncleanShutdownCount[] = "user_experience_metrics.stability.system_unclean_shutdowns"; -// The keys below are used for the dictionaries in the -// kStabilityPluginStats list. -const char kStabilityPluginName[] = "name"; -const char kStabilityPluginCrashes[] = "crashes"; - // String containing the version of Chrome for which Chrome will not prompt the // user about setting Chrome as the default browser. const char kBrowserSuppressDefaultBrowserPrompt[] = @@ -3335,6 +3326,14 @@ // Boolean pref indicating whether the consent for discount has ever shown or // not. const char kCartDiscountConsentShown[] = "cart_discount_consent_shown"; +// A time pref indicating the timestamp of when user last explicitly dismissed +// the discount consent. +const char kDiscountConsentLastDimissedTime[] = + "discount_consent_last_dimissed_time"; +// An integer pref that keeps track of how many times user has explicitly +// dismissed the disount consent. +const char kDiscountConsentPastDismissedCount[] = + "discount_consent_dismissed_count"; #endif #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 1027a318..21f1dbf 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -569,10 +569,6 @@ extern const char kStabilityKernelCrashCount[]; extern const char kStabilitySystemUncleanShutdownCount[]; -extern const char kStabilityPluginStats[]; -extern const char kStabilityPluginName[]; -extern const char kStabilityPluginCrashes[]; - extern const char kBrowserSuppressDefaultBrowserPrompt[]; extern const char kBrowserWindowPlacement[]; @@ -1160,6 +1156,8 @@ extern const char kCartUsedDiscounts[]; extern const char kCartDiscountLastFetchedTime[]; extern const char kCartDiscountConsentShown[]; +extern const char kDiscountConsentLastDimissedTime[]; +extern const char kDiscountConsentPastDismissedCount[]; #endif #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc index bdb6091..48810316 100644 --- a/chrome/common/webui_url_constants.cc +++ b/chrome/common/webui_url_constants.cc
@@ -301,6 +301,8 @@ "chrome://internet-detail-dialog/"; const char kChromeUIInternetConfigDialogHost[] = "internet-config-dialog"; const char kChromeUIInternetDetailDialogHost[] = "internet-detail-dialog"; +const char kChromeUIBorealisCreditsHost[] = "borealis-credits"; +const char kChromeUIBorealisCreditsURL[] = "chrome://borealis-credits/"; const char kChromeUICrostiniCreditsHost[] = "crostini-credits"; const char kChromeUICrostiniCreditsURL[] = "chrome://crostini-credits/"; const char kChromeUILockScreenNetworkHost[] = "lock-network"; @@ -390,6 +392,7 @@ kChromeUIAddSupervisionHost, kChromeUIAssistantOptInHost, kChromeUIBluetoothPairingHost, + kChromeUIBorealisCreditsHost, kChromeUICertificateManagerHost, kChromeUICrostiniCreditsHost, kChromeUICrostiniInstallerHost, @@ -661,6 +664,7 @@ kChromeUIWebApksHost, #endif #if BUILDFLAG(IS_CHROMEOS_ASH) + kChromeUIBorealisCreditsHost, kChromeUICertificateManagerHost, kChromeUICrostiniCreditsHost, kChromeUICryptohomeHost,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h index 2c9bc82..67c7d02 100644 --- a/chrome/common/webui_url_constants.h +++ b/chrome/common/webui_url_constants.h
@@ -283,6 +283,8 @@ extern const char kChromeUIIntenetDetailDialogURL[]; extern const char kChromeUIInternetConfigDialogHost[]; extern const char kChromeUIInternetDetailDialogHost[]; +extern const char kChromeUIBorealisCreditsHost[]; +extern const char kChromeUIBorealisCreditsURL[]; extern const char kChromeUICrostiniCreditsHost[]; extern const char kChromeUICrostiniCreditsURL[]; extern const char kChromeUILockScreenNetworkHost[];
diff --git a/chrome/installer/mac/notarize_thing.py b/chrome/installer/mac/notarize_thing.py index f19cb5d..9d84fa06 100755 --- a/chrome/installer/mac/notarize_thing.py +++ b/chrome/installer/mac/notarize_thing.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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.
diff --git a/chrome/installer/mac/sign_chrome.py b/chrome/installer/mac/sign_chrome.py index 806b499..01c7d39 100755 --- a/chrome/installer/mac/sign_chrome.py +++ b/chrome/installer/mac/sign_chrome.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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. @@ -121,23 +121,34 @@ help='If provided, only the distributions matching the specified ' 'channel(s) will be produced. The string "stable" matches the None ' 'channel.') - - group = parser.add_mutually_exclusive_group(required=False) - group.add_argument( + parser.add_argument( '--notarize', - dest='notarize', - action='store_true', - help='Defaults to False. Submit the signed application and DMG to ' - 'Apple for notarization.') - group.add_argument('--no-notarize', dest='notarize', action='store_false') + nargs='?', + choices=model.NotarizeAndStapleLevel.valid_strings(), + const='staple', + default='none', + help='Specifies the requested notarization actions to be taken. ' + '`none` causes no notarization tasks to be performed. ' + '`nowait` submits the signed application and packaging to Apple for ' + 'notarization, but does not wait for a reply. ' + '`wait-nostaple` submits the signed application and packaging to Apple ' + 'for notarization, and waits for a reply, but does not staple the ' + 'resulting notarization ticket. ' + '`staple` submits the signed application and packaging to Apple for ' + 'notarization, waits for a reply, and staples the resulting ' + 'notarization ticket. ' + 'If the `--notarize` argument is not present, that is the equivalent ' + 'of `--notarize none`. If the `--notarize` argument is present but ' + 'has no option specified, that is the equivalent of `--notarize ' + 'staple`.') - parser.set_defaults(notarize=False) args = parser.parse_args() - if args.notarize: + notarization = model.NotarizeAndStapleLevel.from_string(args.notarize) + if notarization.should_notarize(): if not args.notary_user or not args.notary_password: - parser.error('The --notary-user and --notary-password arguments ' - 'are required with --notarize.') + parser.error('The `--notary-user` and `--notary-password` ' + 'arguments are required if notarizing.') config = create_config( (args.identity, args.installer_identity, args.notary_user, @@ -153,7 +164,7 @@ paths, config, disable_packaging=args.disable_packaging, - do_notarization=args.notarize, + notarization=notarization, skip_brands=args.skip_brands, channels=args.channels)
diff --git a/chrome/installer/mac/signing/model.py b/chrome/installer/mac/signing/model.py index 1cfeb552..b6ce9557 100644 --- a/chrome/installer/mac/signing/model.py +++ b/chrome/installer/mac/signing/model.py
@@ -6,6 +6,7 @@ This module contains classes that encapsulate data about the signing process. """ +from enum import Enum import os.path import re import string @@ -191,6 +192,45 @@ CodeSignOptions.LIBRARY_VALIDATION + CodeSignOptions.KILL) +class NotarizeAndStapleLevel(Enum): + """An enum specifying the level of notarization and stapling to do. + + `NONE` means no notarization tasks should be performed. + + `NOWAIT` means to submit the signed application and packaging to Apple for + notarization, but not to wait for a reply. + + `WAIT_NOSTAPLE` means to submit the signed application and packaging to + Apple for notarization, and wait for a reply, but not to staple the + resulting notarization ticket. + + `STAPLE` means to submit the signed application and packaging to Apple for + notarization, wait for a reply, and staple the resulting notarization + ticket. + """ + NONE = 0 + NOWAIT = 1 + WAIT_NOSTAPLE = 2 + STAPLE = 3 + + def should_notarize(self): + return self.value > self.NONE.value + + def should_wait(self): + return self.value > self.NOWAIT.value + + def should_staple(self): + return self.value > self.WAIT_NOSTAPLE.value + + @classmethod + def valid_strings(cls): + return tuple(level.name.lower().replace('_', '-') for level in cls) + + @classmethod + def from_string(cls, str): + return cls[str.upper().replace('-', '_')] + + class Distribution(object): """A Distribution represents a final, signed, and potentially channel- customized Chrome product.
diff --git a/chrome/installer/mac/signing/pipeline.py b/chrome/installer/mac/signing/pipeline.py index e54b7f66..d8a67690 100644 --- a/chrome/installer/mac/signing/pipeline.py +++ b/chrome/installer/mac/signing/pipeline.py
@@ -645,7 +645,7 @@ def sign_all(orig_paths, config, disable_packaging=False, - do_notarization=True, + notarization=model.NotarizeAndStapleLevel.STAPLE, skip_brands=[], channels=[]): """For each distribution in |config|, performs customization, signing, and @@ -659,11 +659,9 @@ unpackaged signed app bundle will be copied to |paths.output|. If False, the packaging specified in the distribution will be performed. - do_notarization: If True, the signed application bundle will be sent for - notarization by Apple. The resulting notarization ticket will then - be stapled. If |package_dmg| is also True, the stapled application - will be packaged in the DMG and then the DMG itself will be - notarized and stapled. + notarization: The level of notarization to be performed. If + |disable_packaging| is False, the packages (dmg/pkg) will undergo + the same notarization. skip_brands: A list of brand code strings. If a distribution has a brand code in this list, or if a distribution has a brand code and |skip_brands| contains *, that distribution will be skipped. @@ -689,7 +687,7 @@ # If not packaging and not notarizing, then simply drop the # signed bundle in the output directory when done signing. - if not do_packaging and not do_notarization: + if not do_packaging and not notarization.should_notarize(): dest_dir = paths.output else: dest_dir = notary_paths.work @@ -710,7 +708,7 @@ # If the build products are to be notarized, ZIP the app bundle # and submit it for notarization. - if do_notarization: + if notarization.should_notarize(): zip_file = os.path.join( notary_paths.work, dist_config.packaging_basename + '.zip') @@ -722,15 +720,18 @@ uuid = notarize.submit(zip_file, dist_config) uuids_to_config[uuid] = dist_config - # Wait for app notarization results to come back, stapling as they do. - if do_notarization: + # If needed, wait for app notarization results to come back, and staple + # if required. + if notarization.should_wait(): for result in notarize.wait_for_results(uuids_to_config.keys(), config): - dist_config = uuids_to_config[result] - dest_dir = os.path.join( - notary_paths.work, - _intermediate_work_dir_name(dist_config.distribution)) - _staple_chrome(notary_paths.replace_work(dest_dir), dist_config) + if notarization.should_staple(): + dist_config = uuids_to_config[result] + dest_dir = os.path.join( + notary_paths.work, + _intermediate_work_dir_name(dist_config.distribution)) + _staple_chrome( + notary_paths.replace_work(dest_dir), dist_config) # After all apps are optionally notarized, package as required. if not disable_packaging: @@ -753,23 +754,24 @@ if dist.package_as_dmg: dmg_path = _package_and_sign_dmg(paths, dist_config) - if do_notarization: + if notarization.should_notarize(): uuid = notarize.submit(dmg_path, dist_config) uuids_to_package_path[uuid] = dmg_path if dist.package_as_pkg: pkg_path = _package_and_sign_pkg(paths, dist_config) - if do_notarization: + if notarization.should_notarize(): uuid = notarize.submit(pkg_path, dist_config) uuids_to_package_path[uuid] = pkg_path - # Wait for packaging notarization results to come back, stapling as - # they do. - if do_notarization: + # If needed, wait for package notarization results to come back, and + # staple if required. + if notarization.should_wait(): for result in notarize.wait_for_results( uuids_to_package_path.keys(), config): - package_path = uuids_to_package_path[result] - notarize.staple(package_path) + if notarization.should_staple(): + package_path = uuids_to_package_path[result] + notarize.staple(package_path) _package_installer_tools(orig_paths, config)
diff --git a/chrome/installer/mac/signing/pipeline_test.py b/chrome/installer/mac/signing/pipeline_test.py index 833efa9..c505988 100644 --- a/chrome/installer/mac/signing/pipeline_test.py +++ b/chrome/installer/mac/signing/pipeline_test.py
@@ -1306,13 +1306,110 @@ self.assertEqual(1, kwargs['_package_installer_tools'].call_count) self.assertEqual(1, kwargs['run_command'].call_count) + def test_sign_notarize_no_wait(self, **kwargs): + manager = mock.Mock() + for attr in kwargs: + manager.attach_mock(kwargs[attr], attr) + + app_uuid = 'f38ee49c-c55b-4a10-a4f5-aaaa17636b76' + dmg_uuid = '9f49067e-a13d-436a-8016-3a22a4f6ef92' + kwargs['submit'].side_effect = [app_uuid, dmg_uuid] + kwargs['wait_for_results'].side_effect = [ + iter([app_uuid]), iter([dmg_uuid]) + ] + kwargs[ + '_package_and_sign_dmg'].return_value = '/$O/AppProduct-99.0.9999.99.dmg' + + config = test_config.TestConfig() + pipeline.sign_all( + self.paths, + config, + notarization=model.NotarizeAndStapleLevel.NOWAIT) + + self.assertEqual(1, kwargs['_package_installer_tools'].call_count) + + manager.assert_has_calls([ + # First customize the distribution and sign it. + mock.call._customize_and_sign_chrome(mock.ANY, mock.ANY, + '/$W_1/stable', mock.ANY), + + # Prepare the app for notarization. + mock.call.run_command([ + 'zip', '--recurse-paths', '--symlinks', '--quiet', + '/$W_1/AppProduct-99.0.9999.99.zip', 'App Product.app' + ], + cwd='/$W_1/stable'), + mock.call.submit('/$W_1/AppProduct-99.0.9999.99.zip', mock.ANY), + mock.call.shutil.rmtree('/$W_2'), + + # Make the DMG. + mock.call._package_and_sign_dmg(mock.ANY, mock.ANY), + + # Notarize the DMG. + mock.call.submit('/$O/AppProduct-99.0.9999.99.dmg', mock.ANY), + mock.call.shutil.rmtree('/$W_1'), + + # Package the installer tools. + mock.call._package_installer_tools(mock.ANY, mock.ANY), + ]) + + def test_sign_notarize_wait_no_staple(self, **kwargs): + manager = mock.Mock() + for attr in kwargs: + manager.attach_mock(kwargs[attr], attr) + + app_uuid = 'f38ee49c-c55b-4a10-a4f5-aaaa17636b76' + dmg_uuid = '9f49067e-a13d-436a-8016-3a22a4f6ef92' + kwargs['submit'].side_effect = [app_uuid, dmg_uuid] + kwargs['wait_for_results'].side_effect = [ + iter([app_uuid]), iter([dmg_uuid]) + ] + kwargs[ + '_package_and_sign_dmg'].return_value = '/$O/AppProduct-99.0.9999.99.dmg' + + config = test_config.TestConfig() + pipeline.sign_all( + self.paths, + config, + notarization=model.NotarizeAndStapleLevel.WAIT_NOSTAPLE) + + self.assertEqual(1, kwargs['_package_installer_tools'].call_count) + + manager.assert_has_calls([ + # First customize the distribution and sign it. + mock.call._customize_and_sign_chrome(mock.ANY, mock.ANY, + '/$W_1/stable', mock.ANY), + + # Prepare the app for notarization. + mock.call.run_command([ + 'zip', '--recurse-paths', '--symlinks', '--quiet', + '/$W_1/AppProduct-99.0.9999.99.zip', 'App Product.app' + ], + cwd='/$W_1/stable'), + mock.call.submit('/$W_1/AppProduct-99.0.9999.99.zip', mock.ANY), + mock.call.shutil.rmtree('/$W_2'), + mock.call.wait_for_results({app_uuid: None}.keys(), mock.ANY), + + # Make the DMG. + mock.call._package_and_sign_dmg(mock.ANY, mock.ANY), + + # Notarize the DMG. + mock.call.submit('/$O/AppProduct-99.0.9999.99.dmg', mock.ANY), + mock.call.wait_for_results({dmg_uuid: None}.keys(), mock.ANY), + mock.call.shutil.rmtree('/$W_1'), + + # Package the installer tools. + mock.call._package_installer_tools(mock.ANY, mock.ANY), + ]) + def test_sign_no_notarization(self, **kwargs): manager = mock.Mock() for attr in kwargs: manager.attach_mock(kwargs[attr], attr) config = test_config.TestConfig() - pipeline.sign_all(self.paths, config, do_notarization=False) + pipeline.sign_all( + self.paths, config, notarization=model.NotarizeAndStapleLevel.NONE) self.assertEqual(1, kwargs['_package_installer_tools'].call_count) @@ -1337,7 +1434,10 @@ config = test_config.TestConfig() pipeline.sign_all( - self.paths, config, disable_packaging=True, do_notarization=False) + self.paths, + config, + disable_packaging=True, + notarization=model.NotarizeAndStapleLevel.NONE) manager.assert_has_calls([ # First customize the distribution and sign it. @@ -1382,7 +1482,8 @@ ] config = Config() - pipeline.sign_all(self.paths, config, do_notarization=False) + pipeline.sign_all( + self.paths, config, notarization=model.NotarizeAndStapleLevel.NONE) self.assertEqual(1, kwargs['_package_installer_tools'].call_count) self.assertEqual(3, kwargs['_customize_and_sign_chrome'].call_count) @@ -1438,7 +1539,7 @@ pipeline.sign_all( self.paths, config, - do_notarization=False, + notarization=model.NotarizeAndStapleLevel.NONE, skip_brands=skip_brands, channels=include_channels)
diff --git a/chrome/installer/mac/signing/run_mac_signing_tests.py b/chrome/installer/mac/signing/run_mac_signing_tests.py index 4694fae8..f597f6c 100755 --- a/chrome/installer/mac/signing/run_mac_signing_tests.py +++ b/chrome/installer/mac/signing/run_mac_signing_tests.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # 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.
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc index 0174f52..ee8f84c 100644 --- a/chrome/installer/setup/install_worker.cc +++ b/chrome/installer/setup/install_worker.cc
@@ -556,12 +556,12 @@ // Only update if this machine is: // - domain joined, or - // - Azure Active Directory joined, or // - registered with MDM and is not windows home edition - if (!(base::win::IsEnrolledToDomain() || base::win::IsJoinedToAzureAD() || - (base::win::OSInfo::GetInstance()->version_type() != - base::win::SUITE_HOME && - base::win::IsDeviceRegisteredWithManagement()))) { + bool is_enterprise_version = + base::win::OSInfo::GetInstance()->version_type() != base::win::SUITE_HOME; + if (!(base::win::IsEnrolledToDomain() || + (base::win::IsDeviceRegisteredWithManagement() && + is_enterprise_version))) { return; }
diff --git a/chrome/installer/setup/install_worker_unittest.cc b/chrome/installer/setup/install_worker_unittest.cc index 846bb9c2..117d2af 100644 --- a/chrome/installer/setup/install_worker_unittest.cc +++ b/chrome/installer/setup/install_worker_unittest.cc
@@ -326,8 +326,7 @@ // bool: is domain joined // bool: is registered with MDM // bool: is Windows 10 home edition -// bool: is Azure Active Directory joined -using AddUpdateBrandCodeWorkItemTestParams = std::tuple<bool, bool, bool, bool>; +using AddUpdateBrandCodeWorkItemTestParams = std::tuple<bool, bool, bool>; // These tests run at system level. static const bool kSystemLevel = true; @@ -339,7 +338,6 @@ : is_domain_joined_(std::get<0>(GetParam())), is_registered_(std::get<1>(GetParam())), is_home_edition_(std::get<2>(GetParam())), - is_aad_joined_(std::get<3>(GetParam())), scoped_install_details_(kSystemLevel), current_version_(new base::Version("1.0.0.0")), installation_state_( @@ -353,8 +351,7 @@ scoped_os_info_override_( is_home_edition_ ? base::test::ScopedOSInfoOverride::Type::kWin10Home - : base::test::ScopedOSInfoOverride::Type::kWin10Pro), - scoped_aad_state_(is_aad_joined_) {} + : base::test::ScopedOSInfoOverride::Type::kWin10Pro) {} void SetUp() override { // Override registry so that tests don't mess up the machine's state. @@ -374,8 +371,7 @@ } if (!installer::GetUpdatedBrandCode(brand).empty() && - (is_domain_joined_ || is_aad_joined_ || - (is_registered_ && !is_home_edition_))) { + (is_domain_joined_ || (is_registered_ && !is_home_edition_))) { EXPECT_CALL(*work_item_list, AddSetRegStringValueWorkItem(_, _, _, _, _, _)) .WillOnce(Return(nullptr)); // Return value ignored. @@ -388,7 +384,6 @@ const bool is_domain_joined_; const bool is_registered_; const bool is_home_edition_; - const bool is_aad_joined_; install_static::ScopedInstallDetails scoped_install_details_; std::unique_ptr<base::Version> current_version_; @@ -400,7 +395,6 @@ base::win::ScopedDeviceRegisteredWithManagementForTesting scoped_registration_state_; base::test::ScopedOSInfoOverride scoped_os_info_override_; - base::win::ScopedAzureADJoinStateForTesting scoped_aad_state_; }; TEST_P(AddUpdateBrandCodeWorkItemTest, NoBrand) { @@ -434,14 +428,11 @@ const char* registered = std::get<1>(info.param) ? "registered" : "notregistered"; const char* home = std::get<2>(info.param) ? "home" : "nothome"; - const char* aad_joined = - std::get<3>(info.param) ? "aadjoined" : "notaadjoined"; - return base::StringPrintf("%s_%s_%s_%s", joined, registered, home, - aad_joined); + return base::StringPrintf("%s_%s_%s", joined, registered, home); } }; INSTANTIATE_TEST_SUITE_P(AddUpdateBrandCodeWorkItemTest, AddUpdateBrandCodeWorkItemTest, - Combine(Bool(), Bool(), Bool(), Bool()), + Combine(Bool(), Bool(), Bool()), AddUpdateBrandCodeWorkItemTestParamToString());
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index e9edb2d..20b7d090 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -6923,6 +6923,7 @@ "../browser/ui/app_list/search/ranking/best_match_ranker_unittest.cc", "../browser/ui/app_list/search/ranking/filtering_ranker_unittest.cc", "../browser/ui/app_list/search/ranking/ftrl_ranker_unittest.cc", + "../browser/ui/app_list/search/ranking/query_highlighter_unittest.cc", "../browser/ui/app_list/search/ranking/removed_results_ranker_unittest.cc", "../browser/ui/app_list/search/ranking/score_normalizing_ranker_unittest.cc", "../browser/ui/app_list/search/search_controller_impl_new_unittest.cc", @@ -7824,7 +7825,6 @@ if (enable_plugins) { sources += [ - "../browser/metrics/plugin_metrics_provider_unittest.cc", "../browser/plugins/chrome_plugin_service_filter_unittest.cc", "../browser/plugins/plugin_finder_unittest.cc", "../browser/plugins/plugin_info_host_impl_unittest.cc",
diff --git a/chrome/test/data/chromeos/file_manager/presentation.pptx b/chrome/test/data/chromeos/file_manager/presentation.pptx new file mode 100644 index 0000000..795200f7 --- /dev/null +++ b/chrome/test/data/chromeos/file_manager/presentation.pptx Binary files differ
diff --git a/chrome/test/data/chromeos/file_manager/sheet.xlsx b/chrome/test/data/chromeos/file_manager/sheet.xlsx new file mode 100644 index 0000000..3f1722da --- /dev/null +++ b/chrome/test/data/chromeos/file_manager/sheet.xlsx Binary files differ
diff --git a/chrome/test/data/pdf/basic_test.js b/chrome/test/data/pdf/basic_test.js index 5cd05ec..f3946e3 100644 --- a/chrome/test/data/pdf/basic_test.js +++ b/chrome/test/data/pdf/basic_test.js
@@ -44,7 +44,7 @@ // Test case where an <input> field is focused. toolbar.shadowRoot.querySelector('viewer-page-selector') - .pageSelector.focus(); + .$.pageSelector.focus(); chrome.test.assertTrue(shouldIgnoreKeyEvents()); // Test case where another field is focused.
diff --git a/chrome/test/data/pdf/material_elements_test.js b/chrome/test/data/pdf/material_elements_test.js index 35e31e8..c0b7131e 100644 --- a/chrome/test/data/pdf/material_elements_test.js +++ b/chrome/test/data/pdf/material_elements_test.js
@@ -23,7 +23,7 @@ selector.docLength = 1234; document.body.appendChild(selector); - const input = selector.pageSelector; + const input = selector.$.pageSelector; // Simulate entering text into `input` and pressing enter. function changeInput(newValue) { input.value = newValue;
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index ed321baf..54dbc14 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1134,52 +1134,7 @@ "reason_for_missing_test": "TODO(crbug.com/1213475) external data policy not supported yet" }, "ExternalPrintServersWhitelist": { - "os": [ - "chromeos_ash" - ], - "policy_pref_mapping_tests": [ - { - "note": "Check default values (no policies set).", - "prefs": { - "native_printing.external_print_servers_whitelist": { - "default_value": [] - } - } - }, - { - "note": "Simple value.", - "policies": { - "ExternalPrintServersWhitelist": [ - "id4", "id7", "id10" - ] - }, - "prefs": { - "native_printing.external_print_servers_whitelist": { - "value": [ - "id4", "id7", "id10" - ] - } - } - }, - { - "note": "ExternalPrintServersAllowlist has higher precedence.", - "policies": { - "ExternalPrintServersWhitelist": [ - "id1", "id2", "id3" - ], - "ExternalPrintServersAllowlist": [ - "id44", "id55" - ] - }, - "prefs": { - "native_printing.external_print_servers_whitelist": { - "value": [ - "id44", "id55" - ] - } - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "ExternalPrintServersAllowlist": { "os": [ @@ -1208,24 +1163,6 @@ ] } } - }, - { - "note": "ExternalPrintServersWhitelist has lower precedence.", - "policies": { - "ExternalPrintServersAllowlist": [ - "id1", "id2" - ], - "ExternalPrintServersWhitelist": [ - "id100", "id200" - ] - }, - "prefs": { - "native_printing.external_print_servers_whitelist": { - "value": [ - "id1", "id2" - ] - } - } } ] }, @@ -2915,27 +2852,7 @@ ] }, "AuthServerWhitelist": { - "os": [ - "win", - "linux", - "mac", - "chromeos_ash", - "chromeos_lacros", - "android" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "AuthServerWhitelist": "localhost" - }, - "prefs": { - "auth.server_allowlist": { - "location": "local_state", - "value": "localhost" - } - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "AuthServerAllowlist": { "os": [ @@ -2956,44 +2873,11 @@ "default_value": "" } } - }, - { - "note": "New policy override deprecated one.", - "policies": { - "AuthServerAllowlist": "192.168.0.*,192.168.1.*", - "AuthServerWhitelist": "192.168.0.*,192.168.1.*,192.168.2.*" - }, - "prefs": { - "auth.server_allowlist": { - "location": "local_state", - "value": "192.168.0.*,192.168.1.*" - } - } } ] }, "AuthNegotiateDelegateWhitelist": { - "os": [ - "win", - "linux", - "mac", - "chromeos_ash", - "chromeos_lacros", - "android" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "AuthNegotiateDelegateWhitelist": "localhost" - }, - "prefs": { - "auth.negotiate_delegate_whitelist": { - "location": "local_state", - "value": "localhost" - } - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "AuthNegotiateDelegateAllowlist": { "os": [ @@ -3025,19 +2909,6 @@ "value": "localhost,*.example.com" } } - }, - { - "note": "New policy overrides deprecated one", - "policies": { - "AuthNegotiateDelegateAllowlist": "localhost", - "AuthNegotiateDelegateWhitelist": "localhost,*.example.com" - }, - "prefs": { - "auth.negotiate_delegate_whitelist": { - "location": "local_state", - "value": "localhost" - } - } } ] }, @@ -3540,67 +3411,7 @@ ] }, "SpellcheckLanguageBlacklist": { - "os": [ - "win", - "linux", - "chromeos_ash", - "chromeos_lacros" - ], - "policy_pref_mapping_tests": [ - { - "note": "Check default values (no policies set)", - "prefs": { - "spellcheck.blocked_dictionaries": { - "default_value": [] - } - } - }, - { - "note": "Simple value", - "policies": { - "SpellcheckLanguageBlacklist": [ - "fr" - ] - }, - "prefs": { - "spellcheck.blocked_dictionaries": { - "value": [ - "fr" - ] - } - } - }, - { - "note": "SpellcheckEnabled precedence", - "policies": { - "SpellcheckLanguageBlacklist": [ - "fr" - ], - "SpellcheckEnabled": false - }, - "prefs": { - "spellcheck.blocked_dictionaries": { - "default_value": [] - } - } - }, - { - "note": "SpellcheckLanguage precedence", - "policies": { - "SpellcheckLanguageBlacklist": [ - "fr" - ], - "SpellcheckLanguage": [ - "fr" - ] - }, - "prefs": { - "spellcheck.blocked_dictionaries": { - "value": [] - } - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "SpellcheckLanguageBlocklist": { "os": [ @@ -3662,27 +3473,6 @@ "value": [] } } - }, - { - "note": "Precedence over SpellcheckLanguageBlacklist", - "policies": { - "SpellcheckLanguageBlocklist": [ - "fr", - "it" - ], - "SpellcheckLanguageBlacklist": [ - "it", - "es" - ] - }, - "prefs": { - "spellcheck.blocked_dictionaries": { - "value": [ - "fr", - "it" - ] - } - } } ] }, @@ -3738,25 +3528,7 @@ "reason_for_missing_test": "Policy was removed" }, "ExtensionInstallBlacklist": { - "os": [ - "win", - "linux", - "mac", - "chromeos_ash", - "chromeos_lacros" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "ExtensionInstallBlacklist": [ - "*" - ] - }, - "prefs": { - "extensions.install.denylist": {} - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "ExtensionInstallBlocklist": { "os": [ @@ -3780,25 +3552,7 @@ ] }, "ExtensionInstallWhitelist": { - "os": [ - "win", - "linux", - "mac", - "chromeos_ash", - "chromeos_lacros" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "ExtensionInstallWhitelist": [ - "lcncmkcnkcdbbanbjakcencbaoegdjlp" - ] - }, - "prefs": { - "extensions.install.allowlist": {} - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "ExtensionInstallAllowlist": { "os": [ @@ -10231,23 +9985,7 @@ ] }, "NativeMessagingBlacklist": { - "os": [ - "win", - "linux", - "mac" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "NativeMessagingBlacklist": [ - "*" - ] - }, - "prefs": { - "native_messaging.blacklist": {} - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "NativeMessagingBlocklist": { "os": [ @@ -10269,23 +10007,7 @@ ] }, "NativeMessagingWhitelist": { - "os": [ - "win", - "linux", - "mac" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "NativeMessagingWhitelist": [ - "native.messaging.host.name" - ] - }, - "prefs": { - "native_messaging.whitelist": {} - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "NativeMessagingAllowlist": { "os": [ @@ -12857,19 +12579,7 @@ "reason_for_missing_test": "Policy was removed" }, "NoteTakingAppsLockScreenWhitelist": { - "os": [ - "chromeos_ash" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "NoteTakingAppsLockScreenWhitelist": [] - }, - "prefs": { - "settings.note_taking_apps_lock_screen_whitelist": {} - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "NoteTakingAppsLockScreenAllowlist": { "os": [ @@ -13470,29 +13180,7 @@ ] }, "SafeBrowsingWhitelistDomains": { - "os": [ - "win", - "mac", - "linux", - "chromeos_ash", - "chromeos_lacros" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "SafeBrowsingWhitelistDomains": [ - "google.com" - ] - }, - "prefs": { - "safebrowsing.safe_browsing_whitelist_domains": { - "value": [ - "google.com" - ] - } - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "SafeBrowsingAllowlistDomains": { "os": [ @@ -13524,24 +13212,6 @@ "default_value": [] } } - }, - { - "note": "SafeBrowsingWhitelistDomains has been deprecated, and the new name should take precedence.", - "policies": { - "SafeBrowsingWhitelistDomains": [ - "old.name.com" - ], - "SafeBrowsingAllowlistDomains": [ - "new.name.com" - ] - }, - "prefs": { - "safebrowsing.safe_browsing_whitelist_domains": { - "value": [ - "new.name.com" - ] - } - } } ] }, @@ -14596,38 +14266,7 @@ ] }, "PerAppTimeLimitsWhitelist": { - "os": [ - "chromeos_ash" - ], - "policy_pref_mapping_tests": [ - { - "policies": { - "PerAppTimeLimitsWhitelist": { - "scheme_list": [ - "chrome", - "files" - ], - "domain_list": [ - "support.google.com", - "policies.google.com" - ], - "app_list": [ - { - "app_id": "pjkljhegncpnkpknbcohdijeoejaedia", - "app_type": "EXTENSION" - }, - { - "app_id": "iniodglblcgmngkgdipeiclkdjjpnlbn", - "app_type": "BUILT-IN" - } - ] - } - }, - "prefs": { - "child_user.per_app_time_limits.whitelist": {} - } - } - ] + "reason_for_missing_test": "Policy was removed" }, "PerAppTimeLimitsAllowlist": { "os": [
diff --git a/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js b/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js index c5ac0c9..46d15a3 100644 --- a/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js +++ b/chrome/test/data/webui/access_code_cast/access_code_cast_browsertest.js
@@ -69,18 +69,6 @@ }); // eslint-disable-next-line no-var -var AccessCodeCastCodeInputElementTest = class extends AccessCodeCastBrowserTest { - /** @override */ - get browsePreload() { - return 'chrome://access-code-cast/test_loader.html?module=access_code_cast/code_input_test.js'; - } -}; - -TEST_F('AccessCodeCastCodeInputElementTest', 'All', function() { - mocha.run(); -}); - -// eslint-disable-next-line no-var var AccessCodeCastErrorMessageElementTest = class extends AccessCodeCastBrowserTest { /** @override */ get browsePreload() { @@ -91,3 +79,15 @@ TEST_F('AccessCodeCastErrorMessageElementTest', 'All', function() { mocha.run(); }); + +// eslint-disable-next-line no-var +var AccessCodeCastPasscodeInputElementTest = class extends AccessCodeCastBrowserTest { + /** @override */ + get browsePreload() { + return 'chrome://access-code-cast/test_loader.html?module=access_code_cast/passcode_input_test.js'; + } +}; + +TEST_F('AccessCodeCastPasscodeInputElementTest', 'All', function() { + mocha.run(); +});
diff --git a/chrome/test/data/webui/access_code_cast/access_code_cast_test.js b/chrome/test/data/webui/access_code_cast/access_code_cast_test.js index 62f0d5f5..b62852c 100644 --- a/chrome/test/data/webui/access_code_cast/access_code_cast_test.js +++ b/chrome/test/data/webui/access_code_cast/access_code_cast_test.js
@@ -51,7 +51,10 @@ async isQrScanningAvailable() { return Promise.resolve(true); }, - closeDialog() {} + closeDialog() {}, + isDialog() { + return true; + } }; }
diff --git a/chrome/test/data/webui/access_code_cast/code_input_test.js b/chrome/test/data/webui/access_code_cast/code_input_test.js deleted file mode 100644 index 4b37aa7..0000000 --- a/chrome/test/data/webui/access_code_cast/code_input_test.js +++ /dev/null
@@ -1,100 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'chrome://access-code-cast/code_input/code_input.js'; - -import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; -import {waitAfterNextRender} from 'chrome://webui-test/test_util.js'; - -suite('CodeInputElementTest', () => { - /** @type {!CodeInputElement} */ - let c2cInput; - - setup(async () => { - loadTimeData.resetForTesting({}); - loadTimeData.getString = id => id; - - PolymerTest.clearBody(); - - c2cInput = document.createElement('c2c-code-input'); - c2cInput.length = 6; - document.body.appendChild(c2cInput); - - await waitAfterNextRender(); - }); - - test('value set correctly', () => { - const testValue = 'hello'; - c2cInput.setValue(testValue); - assertEquals(c2cInput.value, testValue); - }); - - test('focus advances on input', () => { - c2cInput.clearInput(); - c2cInput.focusInput(); - - assertEquals(c2cInput.getFocusedIndex(), 0); - - c2cInput.getInput(0).value = 'a'; - c2cInput.getInput(0).dispatchEvent(new InputEvent('input')); - assertEquals(c2cInput.getFocusedIndex(), 1); - - c2cInput.getInput(1).value = 'b'; - c2cInput.getInput(1).dispatchEvent(new InputEvent('input')); - assertEquals(c2cInput.getFocusedIndex(), 2); - - }); - - test('focus does not advance if it is the last box', () => { - c2cInput.clearInput(); - - c2cInput.getInput(5).focusInput(); - assertEquals(c2cInput.getFocusedIndex(), 5); - c2cInput.getInput(5).dispatchEvent(new InputEvent('input')); - assertEquals(c2cInput.getFocusedIndex(), 5); - }); - - test( - 'backspace on an empty input erases and focuses the previous input', - () => { - c2cInput.clearInput(); - const input1 = c2cInput.getInput(1); - const input2 = c2cInput.getInput(2); - input1.value = 'a'; - input2.focusInput(); - - assertEquals(input1.value, 'a'); - input2.dispatchEvent(new KeyboardEvent('keydown', {'key': 'Backspace'})); - assertEquals(c2cInput.getFocusedIndex(), 1); - assertEquals(input1.value, ''); - } - ); - - test('backspace on filled input does not change focus', () => { - c2cInput.clearInput(); - const input1 = c2cInput.getInput(1); - const input2 = c2cInput.getInput(2); - input1.value = 'a'; - input2.value = 'b'; - input2.focusInput(); - - assertEquals(input1.value, 'a'); - input2.dispatchEvent(new KeyboardEvent('keydown', {'key': 'Backspace'})); - assertEquals(c2cInput.getFocusedIndex(), 2); - assertEquals(input1.value, 'a'); - }); - - test('disabled state propogates correctly', () => { - c2cInput.clearInput(); - c2cInput.disabled = false; - assertFalse(c2cInput.getInput(0).disabled); - assertFalse(c2cInput.getInput(1).disabled); - assertFalse(c2cInput.getInput(2).disabled); - - c2cInput.disabled = true; - assertTrue(c2cInput.getInput(0).disabled); - assertTrue(c2cInput.getInput(1).disabled); - assertTrue(c2cInput.getInput(2).disabled); - }); -}); \ No newline at end of file
diff --git a/chrome/test/data/webui/access_code_cast/passcode_input_test.js b/chrome/test/data/webui/access_code_cast/passcode_input_test.js new file mode 100644 index 0000000..f0a6a9e2 --- /dev/null +++ b/chrome/test/data/webui/access_code_cast/passcode_input_test.js
@@ -0,0 +1,137 @@ +// 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. + +import 'chrome://access-code-cast/passcode_input/passcode_input.js'; + +import {waitAfterNextRender} from 'chrome://webui-test/test_util.js'; + +suite('PasscodeInputElementTest', () => { + /** @type {!PasscodeInputElement} */ + let c2cInput; + + setup(async () => { + PolymerTest.clearBody(); + + c2cInput = document.createElement('c2c-passcode-input'); + c2cInput.length = 6; + document.body.appendChild(c2cInput); + + await waitAfterNextRender(); + }); + + test('value set correctly', () => { + const testValue = 'hello'; + c2cInput.value = testValue; + assertEquals(c2cInput.$.inputElement.value, testValue); + }); + + test('focus shown correctly', async () => { + c2cInput.value = ''; + c2cInput.focusInput(); + await waitAfterNextRender(); + + assertTrue(c2cInput.focused); + assertTrue(c2cInput.getCharBox(0).classList.contains('focused')); + assertTrue(c2cInput.getCharBox(1).classList.contains('focused')); + assertTrue(c2cInput.getCharBox(2).classList.contains('focused')); + }); + + test('cursor is rendered correctly', async () => { + const testValue = 'test'; + c2cInput.value = testValue; + c2cInput.focusInput(); + + // Case 1: Cursor is after all text. + c2cInput.$.inputElement + .setSelectionRange(testValue.length, testValue.length); + c2cInput.$.inputElement.dispatchEvent(new Event('select')); + await waitAfterNextRender(); + + assertTrue(c2cInput.getDisplayChar(testValue.length).classList + .contains('cursor-empty')); + assertFalse(c2cInput.getDisplayChar(testValue.length).classList + .contains('cursor-start')); + assertFalse(c2cInput.getDisplayChar(testValue.length).classList + .contains('cursor-filled')); + assertFalse(c2cInput.getDisplayChar(testValue.length - 1).classList + .contains('cursor-empty')); + assertFalse(c2cInput.getDisplayChar(testValue.length - 1).classList + .contains('cursor-start')); + assertFalse(c2cInput.getDisplayChar(testValue.length - 1).classList + .contains('cursor-filled')); + assertFalse(c2cInput.getDisplayChar(testValue.length + 1).classList + .contains('cursor-empty')); + assertFalse(c2cInput.getDisplayChar(testValue.length + 1).classList + .contains('cursor-start')); + assertFalse(c2cInput.getDisplayChar(testValue.length + 1).classList + .contains('cursor-filled')); + + // Case 2: Cursor is before all text + c2cInput.$.inputElement.setSelectionRange(0, 0); + c2cInput.$.inputElement.dispatchEvent(new Event('select')); + await waitAfterNextRender(); + + assertFalse(c2cInput.getDisplayChar(0).classList + .contains('cursor-empty')); + assertTrue(c2cInput.getDisplayChar(0).classList + .contains('cursor-start')); + assertFalse(c2cInput.getDisplayChar(0).classList + .contains('cursor-filled')); + assertFalse(c2cInput.getDisplayChar(1).classList + .contains('cursor-empty')); + assertFalse(c2cInput.getDisplayChar(1).classList + .contains('cursor-start')); + assertFalse(c2cInput.getDisplayChar(1).classList + .contains('cursor-filled')); + assertFalse(c2cInput.getDisplayChar(2).classList + .contains('cursor-empty')); + assertFalse(c2cInput.getDisplayChar(2).classList + .contains('cursor-start')); + assertFalse(c2cInput.getDisplayChar(2).classList + .contains('cursor-filled')); + + // Case 3: Cursor is between characters of text + c2cInput.$.inputElement.setSelectionRange(1, 1); + c2cInput.$.inputElement.dispatchEvent(new Event('select')); + await waitAfterNextRender(); + + assertFalse(c2cInput.getDisplayChar(0).classList + .contains('cursor-empty')); + assertFalse(c2cInput.getDisplayChar(0).classList + .contains('cursor-start')); + assertTrue(c2cInput.getDisplayChar(0).classList + .contains('cursor-filled')); + assertFalse(c2cInput.getDisplayChar(1).classList + .contains('cursor-empty')); + assertFalse(c2cInput.getDisplayChar(1).classList + .contains('cursor-start')); + assertFalse(c2cInput.getDisplayChar(1).classList + .contains('cursor-filled')); + assertFalse(c2cInput.getDisplayChar(2).classList + .contains('cursor-empty')); + assertFalse(c2cInput.getDisplayChar(2).classList + .contains('cursor-start')); + assertFalse(c2cInput.getDisplayChar(2).classList + .contains('cursor-filled')); + }); + + test('disabled state propogates correctly', async () => { + c2cInput.value = ''; + c2cInput.disabled = false; + await waitAfterNextRender(); + + assertFalse(c2cInput.$.inputElement.disabled); + assertFalse(c2cInput.getDisplayChar(0).classList.contains('disabled')); + assertFalse(c2cInput.getDisplayChar(1).classList.contains('disabled')); + assertFalse(c2cInput.getDisplayChar(2).classList.contains('disabled')); + + c2cInput.disabled = true; + await waitAfterNextRender(); + + assertTrue(c2cInput.$.inputElement.disabled); + assertTrue(c2cInput.getDisplayChar(0).classList.contains('disabled')); + assertTrue(c2cInput.getDisplayChar(1).classList.contains('disabled')); + assertTrue(c2cInput.getDisplayChar(2).classList.contains('disabled')); + }); +});
diff --git a/chrome/test/data/webui/app_settings/app_test.ts b/chrome/test/data/webui/app_settings/app_test.ts index dafdece..0b8347b 100644 --- a/chrome/test/data/webui/app_settings/app_test.ts +++ b/chrome/test/data/webui/app_settings/app_test.ts
@@ -5,7 +5,7 @@ import 'chrome://webui-test/mojo_webui_test_support.js'; import 'chrome://app-settings/web_app_settings.js'; -import {App, AppManagementPermissionItemElement, AppType, BrowserProxy, createTriStatePermission, getPermissionValueBool, InstallReason, OptionalBool, PermissionType, PermissionTypeIndex, RunOnOsLoginMode, TriState, WebAppSettingsAppElement, WindowMode} from 'chrome://app-settings/web_app_settings.js'; +import {App, AppManagementPermissionItemElement, AppManagementToggleRowElement, AppType, BrowserProxy, createTriStatePermission, getPermissionValueBool, InstallReason, InstallSource, OptionalBool, PermissionType, PermissionTypeIndex, RunOnOsLoginMode, TriState, WebAppSettingsAppElement, WindowMode} from 'chrome://app-settings/web_app_settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {waitAfterNextRender} from 'chrome://webui-test/test_util.js'; @@ -35,8 +35,14 @@ hideResizeLocked: true, supportedLinks: [], runOnOsLogin: {loginMode: RunOnOsLoginMode.kNotRun, isManaged: false}, - fileHandlingState: - {enabled: false, isManaged: false, userVisibleTypes: 'TXT'}, + fileHandlingState: { + enabled: false, + isManaged: false, + userVisibleTypes: 'TXT', + userVisibleTypesLabel: 'Supported type: TXT', + learnMoreUrl: {url: 'https://google.com/'}, + }, + installSource: InstallSource.kUnknown, }; const permissionTypes = [ @@ -99,10 +105,14 @@ assertTrue(!!fileHandlingItem); assertEquals(fileHandlingItem.app.fileHandlingState!.enabled, false); - fileHandlingItem.click(); + const toggleRow = + fileHandlingItem.shadowRoot! + .querySelector<AppManagementToggleRowElement>('#toggle-row')!; + assertTrue(!!toggleRow); + toggleRow.click(); assertEquals(fileHandlingItem.app.fileHandlingState!.enabled, true); - fileHandlingItem.click(); + toggleRow.click(); assertEquals(fileHandlingItem.app.fileHandlingState!.enabled, false); });
diff --git a/chrome/test/data/webui/chromeos/fake_network_config_mojom.js b/chrome/test/data/webui/chromeos/fake_network_config_mojom.js index 3348dfc0..3286a163 100644 --- a/chrome/test/data/webui/chromeos/fake_network_config_mojom.js +++ b/chrome/test/data/webui/chromeos/fake_network_config_mojom.js
@@ -645,8 +645,10 @@ return new Promise(resolve => { this.methodCalled('getSupportedVpnTypes'); resolve({ - vpnTypes: - ['l2tpipsec', 'openvpn', 'thirdpartyvpn', 'arcvpn', 'wireguard'] + vpnTypes: [ + 'ikev2', 'l2tpipsec', 'openvpn', 'thirdpartyvpn', 'arcvpn', + 'wireguard' + ] }); }); }
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js b/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js index 41dc75f..993a9e6 100644 --- a/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js
@@ -23,6 +23,10 @@ const kCaHash = 'CAHASH'; const kUserHash1 = 'USERHASH1'; const kUserHash2 = 'USERHASH2'; + const kCaPem = 'test-pem'; + const kUserCertId = 'test-cert-id'; + const kTestVpnName = 'test-vpn'; + const kTestVpnHost = 'test-vpn-host'; suiteSetup(function() { mojoApi_ = new FakeNetworkConfig(); @@ -53,6 +57,31 @@ Polymer.dom.flush(); } + function initNetworkConfigWithCerts(hasServerCa, hasUserCert) { + const serverCas = []; + const userCerts = []; + if (hasServerCa) { + serverCas.push({ + hash: kCaHash, + pemOrId: kCaPem, + availableForNetworkAuth: true, + hardwareBacked: true, + deviceWide: true + }); + } + if (hasUserCert) { + userCerts.push({ + hash: kUserHash1, + pemOrId: kUserCertId, + availableForNetworkAuth: true, + hardwareBacked: true, + deviceWide: false + }); + } + mojoApi_.setCertificatesForTest(serverCas, userCerts); + initNetworkConfig(); + } + function flushAsync() { Polymer.dom.flush(); return new Promise(resolve => { @@ -152,6 +181,244 @@ }); }); + suite('IKEv2', function() { + setup(function() { + mojoApi_.resetForTest(); + setNetworkType(chromeos.networkConfig.mojom.NetworkType.kVPN); + }); + + teardown(function() { + PolymerTest.clearBody(); + }); + + // Sets all mandatory fields for an IKEv2 VPN service. + function setMandatoryFields() { + const configProperties = networkConfig.get('configProperties_'); + configProperties.name = kTestVpnName; + configProperties.typeConfig.vpn.host = kTestVpnHost; + } + + // Checks that if fields are shown or hidden properly when switching + // authentication type. + test('Switch Authentication Type', function() { + initNetworkConfig(); + + networkConfig.set('vpnType_', 'IKEv2'); + Polymer.dom.flush(); + assertTrue(!!networkConfig.$$('#ipsec-auth-type')); + assertFalse(!!networkConfig.$$('#l2tp-username-input')); + + // The authentication type is default to PSK. The PSK input should appear + // and the dropdowns for server CA and user certificate should be hidden. + assertEquals('PSK', networkConfig.ipsecAuthType_); + assertTrue(!!networkConfig.$$('#ipsec-psk-input')); + assertFalse(!!networkConfig.$$('#vpnServerCa')); + assertFalse(!!networkConfig.$$('#vpnUserCert')); + + // Switch the authentication type to Cert. The PSK input should be hidden + // and the dropdowns for server CA and user certificate should appear. + networkConfig.set('ipsecAuthType_', 'Cert'); + Polymer.dom.flush(); + assertFalse(!!networkConfig.$$('#ipsec-psk-input')); + assertTrue(!!networkConfig.$$('#vpnServerCa')); + assertTrue(!!networkConfig.$$('#vpnUserCert')); + }); + + test('No Certs', function() { + initNetworkConfigWithCerts( + /* hasServerCa= */ false, /* hasUserCert= */ false); + networkConfig.set('vpnType_', 'IKEv2'); + networkConfig.set('ipsecAuthType_', 'Cert'); + return mojoApi_.whenCalled('getNetworkCertificates').then(() => { + return flushAsync().then(() => { + assertEquals('no-certs', networkConfig.selectedServerCaHash_); + assertEquals('no-certs', networkConfig.selectedUserCertHash_); + + // Set all other mandatory fields. vpnIsConfigured_() should be false + // due to empty server CA and user cert. + setMandatoryFields(); + assertFalse(networkConfig.vpnIsConfigured_()); + }); + }); + }); + + test('No Server CA Certs', function() { + initNetworkConfigWithCerts( + /* hasServerCa= */ false, /* hasUserCert= */ true); + networkConfig.set('vpnType_', 'IKEv2'); + networkConfig.set('ipsecAuthType_', 'Cert'); + return mojoApi_.whenCalled('getNetworkCertificates').then(() => { + return flushAsync().then(() => { + assertEquals('no-certs', networkConfig.selectedServerCaHash_); + assertEquals(kUserHash1, networkConfig.selectedUserCertHash_); + + // Set all other mandatory fields. vpnIsConfigured_() should be false + // due to empty server CA. + setMandatoryFields(); + assertFalse(networkConfig.vpnIsConfigured_()); + }); + }); + }); + + test('No Client Certs', function() { + initNetworkConfigWithCerts( + /* hasServerCa= */ true, /* hasUserCert= */ false); + networkConfig.set('vpnType_', 'IKEv2'); + networkConfig.set('ipsecAuthType_', 'Cert'); + return mojoApi_.whenCalled('getNetworkCertificates').then(() => { + return flushAsync().then(() => { + assertEquals(kCaHash, networkConfig.selectedServerCaHash_); + assertEquals('no-certs', networkConfig.selectedUserCertHash_); + + // Set all other mandatory fields. vpnIsConfigured_() should be false + // due to empty client cert. + setMandatoryFields(); + assertFalse(networkConfig.vpnIsConfigured_()); + }); + }); + }); + + // Checks if the values of vpnIsConfigured_() and getPropertiesToSet_() are + // correct when the authentication type is PSK. + test('PSK', function() { + initNetworkConfig(); + networkConfig.set('vpnType_', 'IKEv2'); + networkConfig.set('ipsecAuthType_', 'PSK'); + Polymer.dom.flush(); + + setMandatoryFields(); + const configProperties = networkConfig.get('configProperties_'); + assertFalse(networkConfig.vpnIsConfigured_()); + configProperties.typeConfig.vpn.ipSec.psk = 'test-psk'; + assertTrue(networkConfig.vpnIsConfigured_()); + + const props = networkConfig.getPropertiesToSet_(); + const mojom = chromeos.networkConfig.mojom; + assertEquals(kTestVpnName, props.name); + assertEquals(kTestVpnHost, props.typeConfig.vpn.host); + assertEquals(mojom.VpnType.kIKEv2, props.typeConfig.vpn.type.value); + assertEquals('PSK', props.typeConfig.vpn.ipSec.authenticationType); + assertEquals(2, props.typeConfig.vpn.ipSec.ikeVersion); + assertFalse(props.typeConfig.vpn.ipSec.saveCredentials); + assertEquals('test-psk', props.typeConfig.vpn.ipSec.psk); + + networkConfig.set('vpnSaveCredentials_', true); + assertTrue(networkConfig.getPropertiesToSet_() + .typeConfig.vpn.ipSec.saveCredentials); + }); + + // Checks if values are read correctly for an existing service of PSK + // authentication. + test('Existing PSK', function() { + const mojom = chromeos.networkConfig.mojom; + const ikev2 = OncMojo.getDefaultManagedProperties( + mojom.NetworkType.kVPN, 'someguid', kTestVpnName); + ikev2.typeProperties.vpn.type = mojom.VpnType.kIKEv2; + ikev2.typeProperties.vpn.host = {activeValue: kTestVpnHost}; + ikev2.typeProperties.vpn.ipSec = { + authenticationType: {activeValue: 'PSK'}, + ikeVersion: {activeValue: 2}, + saveCredentials: {activeValue: true}, + }; + setNetworkConfig(ikev2); + initNetworkConfig(); + + return flushAsync().then(() => { + assertEquals('IKEv2', networkConfig.get('vpnType_')); + assertEquals('PSK', networkConfig.get('ipsecAuthType_')); + + // Populate the properties again. The values should be the same to what + // are set above. + const props = networkConfig.getPropertiesToSet_(); + assertEquals('someguid', props.guid); + assertEquals(kTestVpnName, props.name); + assertEquals(kTestVpnHost, props.typeConfig.vpn.host); + assertEquals(mojom.VpnType.kIKEv2, props.typeConfig.vpn.type.value); + assertEquals('PSK', props.typeConfig.vpn.ipSec.authenticationType); + assertEquals(2, props.typeConfig.vpn.ipSec.ikeVersion); + assertTrue(props.typeConfig.vpn.ipSec.saveCredentials); + }); + }); + + // Checks if the values of vpnIsConfigured_() and getPropertiesToSet_() are + // correct when the authentication type is user certificate. + test('Cert', function() { + initNetworkConfigWithCerts( + /* hasServerCa= */ true, /* hasUserCert= */ true); + networkConfig.set('vpnType_', 'IKEv2'); + networkConfig.set('ipsecAuthType_', 'Cert'); + return mojoApi_.whenCalled('getNetworkCertificates').then(() => { + return flushAsync().then(() => { + // The first Server CA and User certificate should be selected. + assertEquals(kCaHash, networkConfig.selectedServerCaHash_); + assertEquals(kUserHash1, networkConfig.selectedUserCertHash_); + + // Set all other mandatory fields. vpnIsConfigured_() should be true. + setMandatoryFields(); + assertTrue(networkConfig.vpnIsConfigured_()); + + const props = networkConfig.getPropertiesToSet_(); + const mojom = chromeos.networkConfig.mojom; + assertEquals(kTestVpnName, props.name); + assertEquals(kTestVpnHost, props.typeConfig.vpn.host); + assertEquals(mojom.VpnType.kIKEv2, props.typeConfig.vpn.type.value); + assertEquals('Cert', props.typeConfig.vpn.ipSec.authenticationType); + assertEquals(2, props.typeConfig.vpn.ipSec.ikeVersion); + assertEquals(1, props.typeConfig.vpn.ipSec.serverCaPems.length); + assertEquals(kCaPem, props.typeConfig.vpn.ipSec.serverCaPems[0]); + assertEquals('PKCS11Id', props.typeConfig.vpn.ipSec.clientCertType); + assertEquals( + kUserCertId, props.typeConfig.vpn.ipSec.clientCertPkcs11Id); + assertFalse(props.typeConfig.vpn.ipSec.saveCredentials); + }); + }); + }); + + // Checks if values are read correctly for an existing service of + // certificate authentication. + test('Existing Cert', function() { + const mojom = chromeos.networkConfig.mojom; + const ikev2 = OncMojo.getDefaultManagedProperties( + mojom.NetworkType.kVPN, 'someguid', kTestVpnName); + ikev2.typeProperties.vpn.type = mojom.VpnType.kIKEv2; + ikev2.typeProperties.vpn.host = {activeValue: kTestVpnHost}; + ikev2.typeProperties.vpn.ipSec = { + authenticationType: {activeValue: 'Cert'}, + clientCertType: {activeValue: 'PKCS11Id'}, + clientCertPkcs11Id: {activeValue: kUserCertId}, + ikeVersion: {activeValue: 2}, + saveCredentials: {activeValue: true}, + serverCaPems: {activeValue: [kCaPem]}, + }; + setNetworkConfig(ikev2); + initNetworkConfigWithCerts( + /* hasServerCa= */ true, /* hasUserCert= */ true); + return mojoApi_.whenCalled('getNetworkCertificates').then(() => { + return flushAsync().then(() => { + assertEquals('IKEv2', networkConfig.get('vpnType_')); + assertEquals('Cert', networkConfig.get('ipsecAuthType_')); + assertEquals(kCaHash, networkConfig.selectedServerCaHash_); + assertEquals(kUserHash1, networkConfig.selectedUserCertHash_); + + const props = networkConfig.getPropertiesToSet_(); + const mojom = chromeos.networkConfig.mojom; + assertEquals('someguid', props.guid); + assertEquals(kTestVpnName, props.name); + assertEquals(kTestVpnHost, props.typeConfig.vpn.host); + assertEquals(mojom.VpnType.kIKEv2, props.typeConfig.vpn.type.value); + assertEquals('Cert', props.typeConfig.vpn.ipSec.authenticationType); + assertEquals(2, props.typeConfig.vpn.ipSec.ikeVersion); + assertEquals(1, props.typeConfig.vpn.ipSec.serverCaPems.length); + assertEquals(kCaPem, props.typeConfig.vpn.ipSec.serverCaPems[0]); + assertEquals('PKCS11Id', props.typeConfig.vpn.ipSec.clientCertType); + assertEquals( + kUserCertId, props.typeConfig.vpn.ipSec.clientCertPkcs11Id); + assertTrue(props.typeConfig.vpn.ipSec.saveCredentials); + }); + }); + }); + }); + suite('L2TP/IPsec', function() { setup(function() { mojoApi_.resetForTest(); @@ -166,27 +433,11 @@ // and user certificate. function setMandatoryFields() { const configProperties = networkConfig.get('configProperties_'); - configProperties.name = 'test-vpn'; - configProperties.typeConfig.vpn.host = 'test-vpn-host'; + configProperties.name = kTestVpnName; + configProperties.typeConfig.vpn.host = kTestVpnHost; configProperties.typeConfig.vpn.l2tp.username = 'test-username'; } - test('Switch VPN Type', function() { - initNetworkConfig(); - - // Authentication type dropdown should only appear for L2TP/IPsec. Check - // that if this dom appear/disappear properly when switching VPN types. - assertFalse(!!networkConfig.$$('#vpn-ipsec-auth-type')); - - networkConfig.set('vpnType_', 'L2TP_IPsec'); - Polymer.dom.flush(); - assertTrue(!!networkConfig.$$('#vpn-ipsec-auth-type')); - - networkConfig.set('vpnType_', 'OpenVPN'); - Polymer.dom.flush(); - assertFalse(!!networkConfig.$$('#vpn-ipsec-auth-type')); - }); - test('Switch Authentication Type', function() { initNetworkConfig(); @@ -196,6 +447,8 @@ networkConfig.set('vpnType_', 'L2TP_IPsec'); Polymer.dom.flush(); assertEquals('PSK', networkConfig.ipsecAuthType_); + assertTrue(!!networkConfig.$$('#ipsec-auth-type')); + assertTrue(!!networkConfig.$$('#l2tp-username-input')); assertTrue(!!networkConfig.$$('#ipsec-psk-input')); assertFalse(!!networkConfig.$$('#vpnServerCa')); assertFalse(!!networkConfig.$$('#vpnUserCert')); @@ -205,6 +458,8 @@ networkConfig.set('ipsecAuthType_', 'Cert'); Polymer.dom.flush(); assertFalse(!!networkConfig.$$('#ipsec-psk-input')); + assertTrue(!!networkConfig.$$('#ipsec-auth-type')); + assertTrue(!!networkConfig.$$('#l2tp-username-input')); assertTrue(!!networkConfig.$$('#vpnServerCa')); assertTrue(!!networkConfig.$$('#vpnUserCert')); }); @@ -229,13 +484,8 @@ }); test('No Server CA Certs', function() { - mojoApi_.setCertificatesForTest([], [{ - hash: kUserHash1, - availableForNetworkAuth: true, - hardwareBacked: true, - deviceWide: false - }]); - initNetworkConfig(); + initNetworkConfigWithCerts( + /* hasServerCa= */ false, /* hasUserCert= */ true); networkConfig.set('vpnType_', 'L2TP_IPsec'); networkConfig.set('ipsecAuthType_', 'Cert'); return mojoApi_.whenCalled('getNetworkCertificates').then(() => { @@ -252,14 +502,8 @@ }); test('No Client Certs', function() { - mojoApi_.setCertificatesForTest( - [{ - hash: kCaHash, - availableForNetworkAuth: true, - hardwareBacked: true, - deviceWide: true - }], - []); + initNetworkConfigWithCerts( + /* hasServerCa= */ true, /* hasUserCert= */ false); initNetworkConfig(); networkConfig.set('vpnType_', 'L2TP_IPsec'); networkConfig.set('ipsecAuthType_', 'Cert'); @@ -277,20 +521,8 @@ }); test('Certs', function() { - mojoApi_.setCertificatesForTest( - [{ - hash: kCaHash, - availableForNetworkAuth: true, - hardwareBacked: true, - deviceWide: true - }], - [{ - hash: kUserHash1, - availableForNetworkAuth: true, - hardwareBacked: true, - deviceWide: false - }]); - initNetworkConfig(); + initNetworkConfigWithCerts( + /* hasServerCa= */ true, /* hasUserCert= */ true); networkConfig.set('vpnType_', 'L2TP_IPsec'); networkConfig.set('ipsecAuthType_', 'Cert'); return mojoApi_.whenCalled('getNetworkCertificates').then(() => { @@ -317,6 +549,29 @@ PolymerTest.clearBody(); }); + test('Switch VPN Type', function() { + initNetworkConfig(); + + // Default VPN type is OpenVPN. Verify the displayed items. + assertEquals('OpenVPN', networkConfig.get('vpnType_')); + assertFalse(!!networkConfig.$$('#ipsec-auth-type')); + assertFalse(!!networkConfig.$$('#l2tp-username-input')); + assertTrue(!!networkConfig.$$('#openvpn-username-input')); + assertTrue(!!networkConfig.$$('#vpnServerCa')); + assertTrue(!!networkConfig.$$('#vpnUserCert')); + + // Switch the VPN type to another and back again. Items should not change. + networkConfig.set('vpnType_', 'L2TP_IPsec'); + Polymer.dom.flush(); + networkConfig.set('vpnType_', 'OpenVPN'); + Polymer.dom.flush(); + assertFalse(!!networkConfig.$$('#ipsec-auth-type')); + assertFalse(!!networkConfig.$$('#l2tp-username-input')); + assertTrue(!!networkConfig.$$('#openvpn-username-input')); + assertTrue(!!networkConfig.$$('#vpnServerCa')); + assertTrue(!!networkConfig.$$('#vpnUserCert')); + }); + test('No Certs', function() { initNetworkConfig(); return mojoApi_.whenCalled('getNetworkCertificates').then(() => { @@ -330,20 +585,8 @@ }); test('Certs', function() { - mojoApi_.setCertificatesForTest( - [{ - hash: kCaHash, - availableForNetworkAuth: true, - hardwareBacked: true, - deviceWide: true - }], - [{ - hash: kUserHash1, - availableForNetworkAuth: true, - hardwareBacked: true, - deviceWide: false - }]); - initNetworkConfig(); + initNetworkConfigWithCerts( + /* hasServerCa= */ true, /* hasUserCert= */ true); return mojoApi_.whenCalled('getNetworkCertificates').then(() => { return flushAsync().then(() => { // The first Server CA should be selected. @@ -696,6 +939,7 @@ }], [{ hash: kUserHash1, + pemOrId: kUserCertId, availableForNetworkAuth: true, hardwareBacked: true, deviceWide: false @@ -727,12 +971,14 @@ [ { hash: kUserHash1, + pemOrId: kUserCertId, availableForNetworkAuth: true, hardwareBacked: true, deviceWide: false }, { hash: kUserHash2, + pemOrId: kUserCertId, availableForNetworkAuth: true, hardwareBacked: true, deviceWide: true
diff --git a/chrome/test/data/webui/nearby_share/shared/nearby_visibility_page_test.js b/chrome/test/data/webui/nearby_share/shared/nearby_visibility_page_test.js index a000a37..5728962 100644 --- a/chrome/test/data/webui/nearby_share/shared/nearby_visibility_page_test.js +++ b/chrome/test/data/webui/nearby_share/shared/nearby_visibility_page_test.js
@@ -3,6 +3,7 @@ // found in the LICENSE file. // clang-format off +// #import 'chrome://nearby/strings.m.js'; // #import 'chrome://nearby/shared/nearby_visibility_page.m.js'; // #import {setNearbyShareSettingsForTesting} from 'chrome://nearby/shared/nearby_share_settings.m.js'; // #import {FakeNearbyShareSettings} from './fake_nearby_share_settings.m.js';
diff --git a/chrome/test/data/webui/new_tab_page/modules/cart/cart.gni b/chrome/test/data/webui/new_tab_page/modules/cart/cart.gni index 662c8df4..ec013c0 100644 --- a/chrome/test/data/webui/new_tab_page/modules/cart/cart.gni +++ b/chrome/test/data/webui/new_tab_page/modules/cart/cart.gni
@@ -4,6 +4,7 @@ cart_test_files = [ "modules/cart/discount_consent_card_test.ts", + "modules/cart/discount_consent_card_test_utils.ts", "modules/cart/discount_consent_dialog_test.ts", "modules/cart/module_test.ts", ]
diff --git a/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_card_test.ts b/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_card_test.ts index 6eff2ae9..b11f4d3 100644 --- a/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_card_test.ts +++ b/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_card_test.ts
@@ -14,7 +14,12 @@ suiteSetup(() => { loadTimeData.overrideValues({ modulesCartConsentStepTwoDifferentColor: false, - modulesCartDiscountInlineCardShowCloseButton: false + modulesCartDiscountInlineCardShowCloseButton: false, + modulesCartDiscountConsentVariation: 2, + modulesCartStepOneUseStaticContent: true, + modulesCartConsentStepOneButton: 'Continue', + modulesCartStepOneStaticContent: 'Step one content', + modulesCartConsentStepTwoContent: 'Step two content', }); }); @@ -27,7 +32,20 @@ return flushTasks(); }); - test('Verify DOM has two steps', () => { + test('Verify DOM has two steps', async () => { + const cart = [{ + merchant: 'Amazon', + cartUrl: {url: 'https://amazon.com'}, + productImageUrls: [ + {url: 'https://image1.com'}, {url: 'https://image2.com'}, + {url: 'https://image3.com'} + ], + discountText: '' + }]; + + discountConsentCard.merchants = cart; + await flushTasks(); + var contentSteps = discountConsentCard.shadowRoot!.querySelectorAll( '#contentSteps .step-container'); assertEquals(contentSteps.length, 2); @@ -35,8 +53,14 @@ 'step1', contentSteps[0]!.getAttribute('id'), 'First content step should have id as step1'); assertEquals( + 'Step one content', + contentSteps[0]!.querySelector('.content')!.textContent!.trim()); + assertEquals( 'step2', contentSteps[1]!.getAttribute('id'), 'Second content step should have id as step2'); + assertEquals( + 'Step two content', + contentSteps[1]!.querySelector('.content')!.textContent!.trim()); }); test('Verify clicking continue button shows step 2 inline', () => { @@ -243,7 +267,7 @@ }); }); - test('Verfiy step 2 has background color', () => { + test('Verify step 2 has background color', () => { discountConsentCard.currentStep = 1; const consentCardContainer = discountConsentCard.shadowRoot!.querySelector( @@ -252,4 +276,235 @@ assertStyle(consentCardContainer!, 'background-color', goolgeBlue100); }); }); + + suite('Static content disabled for step one of cart module', () => { + suiteSetup(() => { + loadTimeData.overrideValues({ + modulesCartStepOneUseStaticContent: false, + modulesCartConsentStepOneOneMerchantContent: 'One merchant: $1', + modulesCartConsentStepOneTwoMerchantsContent: + 'Two merchants: $1 and $2', + modulesCartConsentStepOneThreeMerchantsContent: + 'Three merchants: $1, $2, and more' + }); + }); + + test('Verify step one content when one merchant cart shown', async () => { + const cart = [{ + merchant: 'Amazon', + cartUrl: {url: 'https://amazon.com'}, + productImageUrls: [ + {url: 'https://image1.com'}, {url: 'https://image2.com'}, + {url: 'https://image3.com'} + ], + discountText: '' + }]; + + discountConsentCard.merchants = cart; + await flushTasks(); + + var contentSteps = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .step-container'); + + assertEquals( + 'step1', contentSteps[0]!.getAttribute('id'), + 'First content step should have id as step1'); + assertEquals( + 'One merchant: Amazon', + contentSteps[0]!.querySelector('.content')!.textContent!.trim()); + }); + + test('Verify step one content when two merchant carts shown', async () => { + const carts = [ + { + merchant: 'Amazon', + cartUrl: {url: 'https://amazon.com'}, + productImageUrls: [ + {url: 'https://image1.com'}, {url: 'https://image2.com'}, + {url: 'https://image3.com'} + ], + discountText: '' + }, + { + merchant: 'eBay', + cartUrl: {url: 'https://ebay.com'}, + productImageUrls: + [{url: 'https://image4.com'}, {url: 'https://image5.com'}], + discountText: '' + } + ]; + + discountConsentCard.merchants = carts; + await flushTasks(); + + var contentSteps = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .step-container'); + + assertEquals( + 'step1', contentSteps[0]!.getAttribute('id'), + 'First content step should have id as step1'); + assertEquals( + 'Two merchants: Amazon and eBay', + contentSteps[0]!.querySelector('.content')!.textContent!.trim()); + }); + + test( + 'Verify step one content when three or more merchant carts shown', + async () => { + const carts = [ + { + merchant: 'Amazon', + cartUrl: {url: 'https://amazon.com'}, + productImageUrls: [ + {url: 'https://image1.com'}, {url: 'https://image2.com'}, + {url: 'https://image3.com'} + ], + discountText: '' + }, + { + merchant: 'eBay', + cartUrl: {url: 'https://ebay.com'}, + productImageUrls: + [{url: 'https://image4.com'}, {url: 'https://image5.com'}], + discountText: '' + }, + { + merchant: 'BestBuy', + cartUrl: {url: 'https://bestbuy.com'}, + productImageUrls: [], + discountText: '' + } + ]; + + discountConsentCard.merchants = carts; + await flushTasks(); + + var contentSteps = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .step-container'); + + assertEquals( + 'step1', contentSteps[0]!.getAttribute('id'), + 'First content step should have id as step1'); + assertEquals( + 'Three merchants: Amazon, eBay, and more', + contentSteps[0]!.querySelector('.content')!.textContent!.trim()); + }); + + test( + 'Verify step one content updated when merchant cart changed', + async () => { + var carts = [{ + merchant: 'Amazon', + cartUrl: {url: 'https://amazon.com'}, + productImageUrls: [ + {url: 'https://image1.com'}, {url: 'https://image2.com'}, + {url: 'https://image3.com'} + ], + discountText: '' + }]; + + discountConsentCard.merchants = carts; + await flushTasks(); + + var contentSteps = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .step-container'); + + assertEquals( + 'step1', contentSteps[0]!.getAttribute('id'), + 'First content step should have id as step1'); + assertEquals( + 'One merchant: Amazon', + contentSteps[0]!.querySelector('.content')!.textContent!.trim()); + + discountConsentCard.merchants = [ + { + merchant: 'Amazon', + cartUrl: {url: 'https://amazon.com'}, + productImageUrls: [ + {url: 'https://image1.com'}, {url: 'https://image2.com'}, + {url: 'https://image3.com'} + ], + discountText: '' + }, + { + merchant: 'eBay', + cartUrl: {url: 'https://ebay.com'}, + productImageUrls: + [{url: 'https://image4.com'}, {url: 'https://image5.com'}], + discountText: '' + } + ]; + + await flushTasks(); + + contentSteps = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .step-container'); + + assertEquals( + 'step1', contentSteps[0]!.getAttribute('id'), + 'First content step should have id as step1'); + assertEquals( + 'Two merchants: Amazon and eBay', + contentSteps[0]!.querySelector('.content')!.textContent!.trim()); + }); + }); + + suite('Enable the Dialog Variation', () => { + suiteSetup(() => { + loadTimeData.overrideValues({ + modulesCartDiscountConsentVariation: 3, + modulesCartSentence: 'Dialog title' + }); + }); + + test('Verify DOM has one step', async () => { + const cart = [{ + merchant: 'Amazon', + cartUrl: {url: 'https://amazon.com'}, + productImageUrls: [ + {url: 'https://image1.com'}, {url: 'https://image2.com'}, + {url: 'https://image3.com'} + ], + discountText: '' + }]; + + discountConsentCard.merchants = cart; + await flushTasks(); + + var contentSteps = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .step-container'); + assertEquals(contentSteps.length, 1); + + assertEquals( + 'step1', contentSteps[0]!.getAttribute('id'), + 'First content step should have id as step1'); + }); + + test( + 'Verify clicking continue in one step shows DiscountConsentDialog', + async () => { + assertEquals( + 0, + discountConsentCard.shadowRoot! + .querySelectorAll('#discountConsentDialog') + .length); + + var contentSelectedPage = + discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .iron-selected'); + assertEquals(contentSelectedPage.length, 1); + assertEquals( + 'step1', contentSelectedPage[0]!.getAttribute('id'), + 'Selected content step should have id as step1'); + + contentSelectedPage[0]!.querySelector<HTMLElement>( + '.action-button')!.click(); + await flushTasks(); + assertEquals( + 1, + discountConsentCard.shadowRoot! + .querySelectorAll('#discountConsentDialog') + .length); + }); + }); });
diff --git a/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_card_test_utils.ts b/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_card_test_utils.ts new file mode 100644 index 0000000..6035393 --- /dev/null +++ b/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_card_test_utils.ts
@@ -0,0 +1,42 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file + +import {DiscountConsentCard} from 'chrome://new-tab-page/new_tab_page.js'; +import {assertEquals} from 'chrome://webui-test/chai_assert.js'; + +export function clickAcceptButton(discountConsentCard: DiscountConsentCard) { + const contentSelectedPage = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .iron-selected'); + assertEquals(contentSelectedPage.length, 1); + assertEquals( + 'step2', contentSelectedPage[0]!.getAttribute('id'), + 'Selected content step should have id as step2'); + + contentSelectedPage[0]!.querySelector<HTMLElement>('.action-button')!.click(); +} + +export function clickCloseButton(discountConsentCard: DiscountConsentCard) { + discountConsentCard.shadowRoot!.querySelector<HTMLElement>('#close')!.click(); +} + +export function clickRejectButton(discountConsentCard: DiscountConsentCard) { + const contentSelectedPage = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .iron-selected'); + assertEquals(contentSelectedPage.length, 1); + assertEquals( + 'step2', contentSelectedPage[0]!.getAttribute('id'), + 'Selected content step should have id as step2'); + + contentSelectedPage[0]!.querySelector<HTMLElement>('.cancel-button')!.click(); +} + +export function nextStep(discountConsentCard: DiscountConsentCard) { + assertEquals( + 0, discountConsentCard.currentStep, + 'discountConsentCard is not in step 1'); + const contentSelectedPage = discountConsentCard.shadowRoot!.querySelectorAll( + '#contentSteps .iron-selected'); + + contentSelectedPage[0]!.querySelector<HTMLElement>('.action-button')!.click(); +}
diff --git a/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_dialog_test.ts b/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_dialog_test.ts index ab00d6f..93e060d 100644 --- a/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_dialog_test.ts +++ b/chrome/test/data/webui/new_tab_page/modules/cart/discount_consent_dialog_test.ts
@@ -67,10 +67,9 @@ }); test('verify dialogTitle property', () => { - discountConsentDialog.dialogTitle = 'Title'; const title = discountConsentDialog.shadowRoot!.querySelector('div[slot=title]'); assertTrue(title != null); - assertEquals('Title', title.textContent); + assertEquals('Your carts', title.textContent); }); });
diff --git a/chrome/test/data/webui/new_tab_page/modules/cart/module_test.ts b/chrome/test/data/webui/new_tab_page/modules/cart/module_test.ts index a548aec..42091f8 100644 --- a/chrome/test/data/webui/new_tab_page/modules/cart/module_test.ts +++ b/chrome/test/data/webui/new_tab_page/modules/cart/module_test.ts
@@ -5,7 +5,7 @@ import 'chrome://webui-test/mojo_webui_test_support.js'; import {CartHandlerRemote} from 'chrome://new-tab-page/chrome_cart.mojom-webui.js'; -import {$$, chromeCartDescriptor, ChromeCartModuleElement, ChromeCartProxy, CrAutoImgElement} from 'chrome://new-tab-page/new_tab_page.js'; +import {$$, chromeCartDescriptor, ChromeCartModuleElement, ChromeCartProxy, CrAutoImgElement, DiscountConsentCard, DiscountConsentVariation} from 'chrome://new-tab-page/new_tab_page.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; @@ -13,6 +13,7 @@ import {fakeMetricsPrivate, MetricsTracker} from '../../metrics_test_support.js'; import {assertNotStyle, installMock} from '../../test_support.js'; +import {clickAcceptButton, clickCloseButton, clickRejectButton, nextStep} from './discount_consent_card_test_utils.js'; suite('NewTabPageModulesChromeCartModuleTest', () => { let handler: TestBrowserProxy; @@ -751,6 +752,9 @@ consentCard.querySelector<HTMLElement>('#actionButton')!.innerText); assertEquals(0, metrics.count('NewTabPage.Carts.RejectDiscountConsent')); + const consentCardV2 = $$<HTMLElement>(moduleElement, '#consentCardV2'); + assertTrue(consentCardV2 === null); + // Act. consentCard.querySelector<HTMLElement>('#cancelButton')!.click(); await flushTasks(); @@ -798,78 +802,7 @@ assertEquals(1, metrics.count('NewTabPage.Carts.AcceptDiscountConsent')); }); - test('scroll with consent card', async () => { - // Arrange. - const dummyMerchant = { - merchant: 'Dummy', - cartUrl: {url: 'https://dummy.com'}, - productImageUrls: [], - }; - const carts = Array.from({length: 10}, () => dummyMerchant); - handler.setResultFor('getMerchantCarts', Promise.resolve({carts})); - handler.setResultFor( - 'getDiscountConsentCardVisible', - Promise.resolve({consentVisible: true})); - - // Arrange. - const moduleElement = - await chromeCartDescriptor.initialize(0) as ChromeCartModuleElement; - assertTrue(!!moduleElement); - document.body.append(moduleElement); - moduleElement.$.cartItemRepeat.render(); - const cartCarousel = moduleElement.$.cartCarousel; - moduleElement.scrollBehavior = 'auto'; - const onScroll = () => { - moduleElement.dispatchEvent(new Event('scroll-finish')); - }; - cartCarousel.addEventListener('scroll', onScroll, false); - - // Assert. - const cartItems = - moduleElement.shadowRoot!.querySelectorAll<HTMLAnchorElement>( - '.cart-item'); - assertEquals(10, cartItems.length); - - // Act. - let waitForLeftScrollVisibilityChange = - eventToPromise('left-scroll-hide', moduleElement); - let waitForRightScrollVisibilityChange = - eventToPromise('right-scroll-show', moduleElement); - moduleElement.style.width = '560px'; - await waitForLeftScrollVisibilityChange; - await waitForRightScrollVisibilityChange; - - // Assert. - checkScrollButtonVisibility(moduleElement, false, true); - checkVisibleRange(moduleElement, 0, 1); - - // Act. - waitForLeftScrollVisibilityChange = - eventToPromise('left-scroll-show', moduleElement); - let waitForScrollFinished = - eventToPromise('scroll-finish', moduleElement); - moduleElement.shadowRoot! - .querySelector<HTMLElement>('#rightScrollButton')!.click(); - await waitForScrollFinished; - await waitForLeftScrollVisibilityChange; - - // Assert. - checkScrollButtonVisibility(moduleElement, true, true); - checkVisibleRange(moduleElement, 2, 5); - - // Act. - waitForLeftScrollVisibilityChange = - eventToPromise('left-scroll-hide', moduleElement); - waitForScrollFinished = eventToPromise('scroll-finish', moduleElement); - moduleElement.shadowRoot!.querySelector<HTMLElement>( - '#leftScrollButton')!.click(); - await waitForScrollFinished; - await waitForLeftScrollVisibilityChange; - - // Assert. - checkScrollButtonVisibility(moduleElement, false, true); - checkVisibleRange(moduleElement, 0, 1); - }); + test('scroll with consent card', async () => testScrollWithConsent()); test('click on cart item', async () => { const carts = [ @@ -928,6 +861,80 @@ } assertEquals(0, handler.getCallCount('getDiscountURL')); }); + }); + + + async function testScrollWithConsent() { + // Arrange. + const dummyMerchant = { + merchant: 'Dummy', + cartUrl: {url: 'https://dummy.com'}, + productImageUrls: [], + }; + const carts = Array.from({length: 10}, () => dummyMerchant); + handler.setResultFor('getMerchantCarts', Promise.resolve({carts})); + handler.setResultFor( + 'getDiscountConsentCardVisible', + Promise.resolve({consentVisible: true})); + + // Arrange. + const moduleElement = + await chromeCartDescriptor.initialize(0) as ChromeCartModuleElement; + assertTrue(!!moduleElement); + document.body.append(moduleElement); + moduleElement.$.cartItemRepeat.render(); + const cartCarousel = moduleElement.$.cartCarousel; + moduleElement.scrollBehavior = 'auto'; + const onScroll = () => { + moduleElement.dispatchEvent(new Event('scroll-finish')); + }; + cartCarousel.addEventListener('scroll', onScroll, false); + + // Assert. + const cartItems = + moduleElement.shadowRoot!.querySelectorAll<HTMLAnchorElement>( + '.cart-item'); + assertEquals(10, cartItems.length); + + // Act. + let waitForLeftScrollVisibilityChange = + eventToPromise('left-scroll-hide', moduleElement); + let waitForRightScrollVisibilityChange = + eventToPromise('right-scroll-show', moduleElement); + moduleElement.style.width = '560px'; + await waitForLeftScrollVisibilityChange; + await waitForRightScrollVisibilityChange; + + // Assert. + checkScrollButtonVisibility(moduleElement, false, true); + checkVisibleRange(moduleElement, 0, 1); + + // Act. + waitForLeftScrollVisibilityChange = + eventToPromise('left-scroll-show', moduleElement); + let waitForScrollFinished = eventToPromise('scroll-finish', moduleElement); + moduleElement.shadowRoot!.querySelector<HTMLElement>( + '#rightScrollButton')!.click(); + await waitForScrollFinished; + await waitForLeftScrollVisibilityChange; + + // Assert. + checkScrollButtonVisibility(moduleElement, true, true); + checkVisibleRange(moduleElement, 2, 5); + + // Act. + waitForLeftScrollVisibilityChange = + eventToPromise('left-scroll-hide', moduleElement); + waitForScrollFinished = eventToPromise('scroll-finish', moduleElement); + moduleElement.shadowRoot!.querySelector<HTMLElement>( + '#leftScrollButton')!.click(); + await waitForScrollFinished; + await waitForLeftScrollVisibilityChange; + + // Assert. + checkScrollButtonVisibility(moduleElement, false, true); + checkVisibleRange(moduleElement, 0, 1); + } function checkScrollButtonVisibility( moduleElement: ChromeCartModuleElement, isLeftVisible: boolean, @@ -975,7 +982,6 @@ (cartCarousel.scrollLeft + cartCarousel.clientWidth) > (cart.offsetLeft + cart.offsetWidth); } - }); suite('rule-based discount', () => { suiteSetup(() => { @@ -1136,4 +1142,207 @@ assertEquals(1, metrics.count('NewTabPage.Carts.DiscountAt', 2)); }); }); + + suite('Discount consent v2', () => { + let moduleElement: ChromeCartModuleElement; + + setup(() => { + handler.setResultFor( + 'getDiscountConsentCardVisible', + Promise.resolve({consentVisible: true})); + loadTimeData.overrideValues({ + modulesCartDiscountInlineCardShowCloseButton: true, + modulesCartConsentStepTwoDifferentColor: false, + modulesCartDiscountConsentRejectConfirmation: 'Reject confirmation!', + modulesCartDiscountConsentAcceptConfirmation: 'Accept confirmation!', + modulesCartDiscountConsentVariation: DiscountConsentVariation.Inline, + modulesCartStepOneUseStaticContent: true, + modulesCartConsentStepOneButton: 'Continue', + modulesCartStepOneStaticContent: 'Step one consent', + modulesCartConsentStepTwoContent: 'Step two consent', + }); + }); + + async function testClickingAcceptButtonOnConsentCard() { + // Arrange. + const consentToast = moduleElement.$.confirmDiscountConsentToast; + assertEquals(0, metrics.count('NewTabPage.Carts.AcceptDiscountConsent')); + const consentCard = + $$<DiscountConsentCard>(moduleElement, '#consentCardV2')!; + nextStep(consentCard); + await flushTasks(); + + // Act. + clickAcceptButton(consentCard); + await flushTasks(); + + // Assert. + assertEquals(false, isVisible(consentCard)); + assertEquals(true, consentToast.open); + assertEquals( + 'Accept confirmation!', + moduleElement.$.confirmDiscountConsentMessage.innerText); + assertEquals(1, metrics.count('NewTabPage.Carts.AcceptDiscountConsent')); + } + + test('shows discount consent v2 in cart module', async () => { + const carts = [ + { + merchant: 'Foo', + cartUrl: {url: 'https://foo.com'}, + productImageUrls: [] + }, + { + merchant: 'Boo', + cartUrl: {url: 'https://Boo.com'}, + productImageUrls: [], + }, + ]; + handler.setResultFor('getMerchantCarts', Promise.resolve({carts})); + + // Arrange. + moduleElement = + await chromeCartDescriptor.initialize(0) as ChromeCartModuleElement; + assertTrue(!!moduleElement); + document.body.append(moduleElement); + moduleElement.$.consentCardElement.render(); + + // Assert. + const consentCard = + $$<DiscountConsentCard>(moduleElement, '#consentCardV2')!; + assertEquals(true, isVisible(consentCard)); + }); + + test('scroll with consent card v2', async () => testScrollWithConsent()); + + suite('Inline consent with close button', () => { + let consentCard: DiscountConsentCard; + + setup(async () => { + loadTimeData.overrideValues({ + modulesCartDiscountInlineCardShowCloseButton: true, + }); + + const carts = [ + { + merchant: 'Foo', + cartUrl: {url: 'https://foo.com'}, + productImageUrls: [] + }, + { + merchant: 'Boo', + cartUrl: {url: 'https://Boo.com'}, + productImageUrls: [], + }, + ]; + handler.setResultFor('getMerchantCarts', Promise.resolve({carts})); + moduleElement = + await chromeCartDescriptor.initialize(0) as ChromeCartModuleElement; + assertTrue(!!moduleElement); + document.body.append(moduleElement); + moduleElement.$.consentCardElement.render(); + + consentCard = $$<DiscountConsentCard>(moduleElement, '#consentCardV2')!; + }); + + test( + 'Verify clicking close button in step 1 hides consent card', + async () => { + // Act. + clickCloseButton(consentCard); + await flushTasks(); + + // Assert. + assertEquals(false, isVisible(consentCard)); + assertEquals(1, handler.getCallCount('onDiscountConsentDismissed')); + }); + + test( + 'Verify clicking close button in step 2 hides consent card', + async () => { + // Arrange. + const consentToast = moduleElement.$.confirmDiscountConsentToast; + assertEquals( + 0, metrics.count('NewTabPage.Carts.RejectDiscountConsent')); + nextStep(consentCard); + await flushTasks(); + + // Act. + clickCloseButton(consentCard); + await flushTasks(); + + // Assert. + assertEquals(false, isVisible(consentCard)); + assertEquals(true, consentToast.open); + assertEquals( + 'Reject confirmation!', + moduleElement.$.confirmDiscountConsentMessage.innerText); + assertEquals( + 1, metrics.count('NewTabPage.Carts.RejectDiscountConsent')); + assertEquals(0, handler.getCallCount('onDiscountConsentDismissed')); + }); + + test( + 'Verify clicking accept button in step 2 hides consent card', + async () => testClickingAcceptButtonOnConsentCard()); + }); + + suite('Inline consent with no close button', () => { + let consentCard: DiscountConsentCard; + + setup(async () => { + loadTimeData.overrideValues( + {modulesCartDiscountInlineCardShowCloseButton: false}); + + const carts = [ + { + merchant: 'Foo', + cartUrl: {url: 'https://foo.com'}, + productImageUrls: [] + }, + { + merchant: 'Boo', + cartUrl: {url: 'https://Boo.com'}, + productImageUrls: [], + }, + ]; + handler.setResultFor('getMerchantCarts', Promise.resolve({carts})); + moduleElement = + await chromeCartDescriptor.initialize(0) as ChromeCartModuleElement; + assertTrue(!!moduleElement); + document.body.append(moduleElement); + moduleElement.$.consentCardElement.render(); + + consentCard = $$<DiscountConsentCard>(moduleElement, '#consentCardV2')!; + }); + + test( + 'Verify clicking accpet button in step 2 hides consent card', + async () => testClickingAcceptButtonOnConsentCard()); + + test( + 'Verify clicking reject button in step 2 hides consent card', + async () => { + // Arrange. + const consentToast = moduleElement.$.confirmDiscountConsentToast; + assertEquals( + 0, metrics.count('NewTabPage.Carts.RejectDiscountConsent')); + nextStep(consentCard); + await flushTasks(); + + // Act. + clickRejectButton(consentCard); + await flushTasks(); + + // Assert. + assertEquals(false, isVisible(consentCard)); + assertEquals(true, consentToast.open); + assertEquals( + 'Reject confirmation!', + moduleElement.$.confirmDiscountConsentMessage.innerText); + assertEquals( + 1, metrics.count('NewTabPage.Carts.RejectDiscountConsent')); + }); + }); + }); });
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index ec39dd9f..606db64b 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -638,7 +638,8 @@ ['SiteSettingsPage', 'site_settings_page_test.js'], ['Slider', 'settings_slider_tests.js'], ['StartupUrlsPage', 'startup_urls_page_test.js'], - ['Subpage', 'settings_subpage_test.js'], + // Flaky on all OSes. TODO(crbug.com/1302405): Enable the test. + ['Subpage', 'settings_subpage_test.js', 'DISABLED_All'], ['SyncAccountControl', 'sync_account_control_test.js'], ['Textarea', 'settings_textarea_tests.js'], ['ToggleButton', 'settings_toggle_button_tests.js'],
diff --git a/chrome/test/data/webui/settings/privacy_sandbox_test.ts b/chrome/test/data/webui/settings/privacy_sandbox_test.ts index ef83b2fe..5ec5d2d 100644 --- a/chrome/test/data/webui/settings/privacy_sandbox_test.ts +++ b/chrome/test/data/webui/settings/privacy_sandbox_test.ts
@@ -393,6 +393,9 @@ // Clicking on the learn more link should open the dialog. page.shadowRoot!.querySelector<HTMLElement>('#learnMoreLink')!.click(); + assertEquals( + 'Settings.PrivacySandbox.AdPersonalization.LearnMoreClicked', + await metricsBrowserProxy.whenCalled('recordAction')); await flushTasks(); assertLearnMoreDialogVisible(); @@ -408,6 +411,9 @@ // Clicking on the ad personalization row should open the dialog. page.shadowRoot!.querySelector<HTMLElement>( '#adPersonalizationRow')!.click(); + assertEquals( + 'Settings.PrivacySandbox.AdPersonalization.Opened', + await metricsBrowserProxy.whenCalled('recordAction')); await flushTasks(); assertAdPersonalizationDialogVisible(); @@ -425,11 +431,15 @@ '#adPersonalizationRow')!.click(); await flushTasks(); assertAdPersonalizationDialogVisible(); + metricsBrowserProxy.resetResolver('recordAction'); // Clicking on the link row for removed interests should take you to the // removed interests page. page.shadowRoot! .querySelector<HTMLElement>('.ad-personalization-removed-row')!.click(); + assertEquals( + 'Settings.PrivacySandbox.RemovedInterests.Opened', + await metricsBrowserProxy.whenCalled('recordAction')); await flushTasks(); assertAdPersonalizationRemovedDialogVisible(); @@ -451,6 +461,9 @@ // Clicking on the ad measurement row should open the dialog. page.shadowRoot!.querySelector<HTMLElement>('#adMeasurementRow')!.click(); + assertEquals( + 'Settings.PrivacySandbox.AdMeasurement.Opened', + await metricsBrowserProxy.whenCalled('recordAction')); await flushTasks(); assertAdMeasurementDialogVisible(); @@ -482,6 +495,9 @@ // Clicking on the spam & fraud row should open the dialog. page.shadowRoot!.querySelector<HTMLElement>('#spamAndFraudRow')!.click(); + assertEquals( + 'Settings.PrivacySandbox.SpamFraud.Opened', + await metricsBrowserProxy.whenCalled('recordAction')); await flushTasks(); assertSpamAndFraudDialogVisible(); @@ -528,12 +544,15 @@ '#adPersonalizationBackButton')!.click(); await flushTasks(); assertAdPersonalizationDialogVisible(); + metricsBrowserProxy.resetResolver('recordAction'); // Remove topic from main page. const item = topTopicsSection.querySelector('privacy-sandbox-interest-item')!; item.shadowRoot!.querySelector('cr-button')!.click(); - await flushTasks(); + assertEquals( + 'Settings.PrivacySandbox.AdPersonalization.TopicRemoved', + await metricsBrowserProxy.whenCalled('recordAction')); // Assert the topic is no longer visible. assertEquals( @@ -545,6 +564,7 @@ .querySelector<HTMLElement>('.ad-personalization-removed-row')!.click(); await flushTasks(); assertAdPersonalizationRemovedDialogVisible(); + metricsBrowserProxy.resetResolver('recordAction'); // Assert the topic was moved to removed page. blockedTopics = blockedTopicsSection.querySelector('dom-repeat')!; @@ -558,8 +578,10 @@ assertEquals(2, items.length); for (const item of items) { item.shadowRoot!.querySelector('cr-button')!.click(); + assertEquals( + 'Settings.PrivacySandbox.RemovedInterests.TopicAdded', + await metricsBrowserProxy.whenCalled('recordAction')); } - await flushTasks(); // Assert all topics are gone. assertEquals( @@ -611,12 +633,15 @@ '#adPersonalizationBackButton')!.click(); await flushTasks(); assertAdPersonalizationDialogVisible(); + metricsBrowserProxy.resetResolver('recordAction'); // Remove site from main page. const item = joiningSitesSection.querySelector('privacy-sandbox-interest-item')!; item.shadowRoot!.querySelector('cr-button')!.click(); - await flushTasks(); + assertEquals( + 'Settings.PrivacySandbox.AdPersonalization.SiteRemoved', + await metricsBrowserProxy.whenCalled('recordAction')); // Assert the site is no longer visible. assertEquals( @@ -629,6 +654,7 @@ .querySelector<HTMLElement>('.ad-personalization-removed-row')!.click(); await flushTasks(); assertAdPersonalizationRemovedDialogVisible(); + metricsBrowserProxy.resetResolver('recordAction'); // Assert the site was moved to removed page. blockedSites = blockedSitesSection.querySelector('dom-repeat')!; @@ -642,8 +668,10 @@ assertEquals(2, items.length); for (const item of items) { item.shadowRoot!.querySelector('cr-button')!.click(); + assertEquals( + 'Settings.PrivacySandbox.RemovedInterests.SiteAdded', + await metricsBrowserProxy.whenCalled('recordAction')); } - await flushTasks(); // Assert all sites are gone. assertEquals(
diff --git a/chrome/updater/mac/signing/pipeline.py b/chrome/updater/mac/signing/pipeline.py index b019d43..3c0b5d7 100644 --- a/chrome/updater/mac/signing/pipeline.py +++ b/chrome/updater/mac/signing/pipeline.py
@@ -89,7 +89,7 @@ def sign_all(orig_paths, config, disable_packaging=False, - do_notarization=True, + notarization=model.NotarizeAndStapleLevel.STAPLE, skip_brands=[], channels=[]): """Code signs, packages, and signs the package, placing the result into @@ -100,10 +100,9 @@ orig_paths: A |model.Paths| object. config: The |config.CodeSignConfig| object. disable_packaging: Ignored. - do_notarization: If True, the signed application bundle will be sent for - notarization by Apple. The resulting notarization ticket will then - be stapled. The stapled application will be packaged in the DMG and - then the DMG itself will be notarized and stapled. + notarization: The level of notarization to be performed. If + |disable_packaging| is False, the dmg will undergo the same + notarization. skip_brands: Ignored. channels: Ignored. """ @@ -115,7 +114,7 @@ config.packaging_basename) _sign_app(paths, config, dest_dir) - if do_notarization: + if notarization.should_notarize(): zip_file = os.path.join(notary_paths.work, config.packaging_basename + '.zip') commands.run_command([ @@ -126,15 +125,16 @@ uuid = notarize.submit(zip_file, config) # Wait for the app notarization result to come back and staple. - if do_notarization: + if notarization.should_wait(): for _ in notarize.wait_for_results([uuid], config): pass # We are only waiting for a single notarization. - notarize.staple_bundled_parts( - # Only staple to the outermost app. - parts.get_parts(config)[-1:], - notary_paths.replace_work( - os.path.join(notary_paths.work, - config.packaging_basename))) + if notarization.should_staple(): + notarize.staple_bundled_parts( + # Only staple to the outermost app. + parts.get_parts(config)[-1:], + notary_paths.replace_work( + os.path.join(notary_paths.work, + config.packaging_basename))) # Package. dmg_path = _package_and_sign_dmg( @@ -143,8 +143,9 @@ config) # Notarize the package, then staple. - if do_notarization: + if notarization.should_wait(): for _ in notarize.wait_for_results( [notarize.submit(dmg_path, config)], config): pass # We are only waiting for a single notarization. - notarize.staple(dmg_path) + if notarization.should_staple(): + notarize.staple(dmg_path)
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn index 6ba68bf..8ea38c6 100644 --- a/chromecast/BUILD.gn +++ b/chromecast/BUILD.gn
@@ -732,10 +732,15 @@ min_sdk_version = 23 target_sdk_version = 31 + package_name = "cast_browser" + + # |package_id| is required because the default one conflicts with the base + # modules' ID (0x7f). + package_id = 125 + shared_libraries = [ "//chromecast/android:libcast_browser_android" ] product_config_java_packages = [ "org.chromium.chromecast.shell" ] deps = [ - ":cast_shell_apk_assets", "//base:base_java", "//chromecast/android:libcast_browser_android", "//chromecast/browser/android:cast_browser_java", @@ -745,6 +750,7 @@ loadable_modules = [ "$root_out_dir/libchrome_crashpad_handler.so" ] enable_multidex = true + proguard_enabled = !is_java_debug } } }
diff --git a/chromecast/browser/android/BUILD.gn b/chromecast/browser/android/BUILD.gn index e80ca4d..0f5f0f3 100644 --- a/chromecast/browser/android/BUILD.gn +++ b/chromecast/browser/android/BUILD.gn
@@ -22,6 +22,11 @@ jinja_template("cast_browser_manifest") { input = "apk/CastBrowserAndroidManifest.xml.jinja2" output = cast_browser_android_manifest + + variables = [ + "cast_build_architecture=$target_cpu", + "cast_build_incremental=$cast_build_incremental", + ] } java_cpp_template("cast_shell_build_config_gen") { @@ -70,7 +75,7 @@ android_resources("cast_browser_android_resources") { android_manifest = cast_browser_android_manifest android_manifest_dep = ":cast_browser_manifest" - sources = common_resources + extra_resources + sources = extra_resources } android_resources("cast_shell_android_stub_resources") {
diff --git a/chromecast/browser/android/apk/CastBrowserAndroidManifest.xml.jinja2 b/chromecast/browser/android/apk/CastBrowserAndroidManifest.xml.jinja2 index 607d794..97f385a 100644 --- a/chromecast/browser/android/apk/CastBrowserAndroidManifest.xml.jinja2 +++ b/chromecast/browser/android/apk/CastBrowserAndroidManifest.xml.jinja2
@@ -8,7 +8,14 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dist="http://schemas.android.com/apk/distribution" package="com.google.android.apps.mediashell" - featureSplit="cast_browser" > + featureSplit="cast_browser" + {% set architecture_digit = { + 'arm': 1, + 'x86': 2, + 'arm64': 3, + 'x64': 4, + }[cast_build_architecture] %} + android:versionCode="{{ cast_build_incremental }}{{ architecture_digit }}" > <dist:module dist:onDemand="false" dist:title="cast_browser">
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java index a40671c0..f967e2e 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java
@@ -86,8 +86,6 @@ private final Controller<Unit> mIsTestingState = new Controller<>(); // Set at creation. Handles destroying SurfaceHelper. private final Controller<CastWebContentsSurfaceHelper> mSurfaceHelperState = new Controller<>(); - // Detects if the Activity is being destroyed & finished - private final Controller<Intent> mDestroyedForFinishingState = new Controller<>(); @Nullable private CastWebContentsSurfaceHelper mSurfaceHelper; @@ -176,16 +174,6 @@ intent.setFlags(flags); startActivity(intent); })); - - // If the Activity is being destroyed and finished, but the mIsFinishingState is not set, - // then we should call onComponentClosed to end the Cast session. An example of this - // happening is when the back button is pressed. - Observable.not(mIsFinishingState) - .andThen(mDestroyedForFinishingState) - .map(Both::getSecond) - .map(Intent::getExtras) - .map(CastWebContentsIntentUtils::getSessionId) - .subscribe(Observers.onEnter(CastWebContentsComponent::onComponentClosed)); } @RequiresApi(Build.VERSION_CODES.S) @@ -232,9 +220,6 @@ if (DEBUG) Log.d(TAG, "onDestroy"); mCreatedState.reset(); - if (isFinishing()) { - mDestroyedForFinishingState.set(getIntent()); - } super.onDestroy(); }
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java index ef39a88d..22475f4 100644 --- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java +++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsActivityTest.java
@@ -8,31 +8,22 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyObject; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; -import android.content.BroadcastReceiver; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.media.AudioManager; -import android.net.Uri; import android.os.Build; -import android.os.PatternMatcher; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Window; import android.view.WindowManager; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; - import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -91,7 +82,6 @@ private CastWebContentsActivity mActivity; private ShadowActivity mShadowActivity; private @Mock WebContents mWebContents; - private String mSessionId; private static Intent defaultIntentForCastWebContentsActivity(WebContents webContents) { return CastWebContentsIntentUtils.requestStartCastActivity( @@ -101,10 +91,8 @@ @Before public void setUp() { MockitoAnnotations.initMocks(this); - Intent defaultIntent = defaultIntentForCastWebContentsActivity(mWebContents); - mSessionId = CastWebContentsIntentUtils.getSessionId(defaultIntent.getExtras()); - mActivityLifecycle = - Robolectric.buildActivity(CastWebContentsActivity.class, defaultIntent); + mActivityLifecycle = Robolectric.buildActivity(CastWebContentsActivity.class, + defaultIntentForCastWebContentsActivity(mWebContents)); mActivity = mActivityLifecycle.get(); mActivity.testingModeForTesting(); mShadowActivity = Shadows.shadowOf(mActivity); @@ -320,60 +308,4 @@ MotionEvent event = mock(MotionEvent.class); assertFalse(mActivity.dispatchTouchEvent(event)); } - - @Test - public void testComponentClosedWhenDestroyedBeforeIsFinishingStateAndActitivityIsFinishing() { - mActivityLifecycle.create(); - // This sets the Activity's "finishing" state, not to be confused with the finishing state - // we track separately in the Activity. This is checked in onDestroy to ensure the Activity - // is actually being destroyed and finished as opposed to being recreated (e.g. PIP mode or - // changing orientation) - mActivity.finish(); - verifyBroadcastedIntent(filterFor(CastWebContentsIntentUtils.ACTION_ACTIVITY_STOPPED), - () -> mActivityLifecycle.destroy(), true); - } - - @Test - public void - testComponentNotClosedWhenDestroyedBeforeIsFinishingStateAndActitivityIsNotFinishing() { - mActivityLifecycle.create(); - verifyBroadcastedIntent(filterFor(CastWebContentsIntentUtils.ACTION_ACTIVITY_STOPPED), - () -> mActivityLifecycle.destroy(), false); - } - - @Test - public void testComponentNotClosedWhenDestroyedAfterIsFinishingStateAndActivityIsFinishing() { - mActivityLifecycle.create(); - mActivity.finishForTesting(); - verifyBroadcastedIntent(filterFor(CastWebContentsIntentUtils.ACTION_ACTIVITY_STOPPED), - () -> mActivityLifecycle.destroy(), false); - } - - private IntentFilter filterFor(String action) { - IntentFilter filter = new IntentFilter(); - Uri instanceUri = CastWebContentsIntentUtils.getInstanceUri(mSessionId); - filter.addDataScheme(instanceUri.getScheme()); - filter.addDataAuthority(instanceUri.getAuthority(), null); - filter.addDataPath(instanceUri.getPath(), PatternMatcher.PATTERN_LITERAL); - filter.addAction(action); - return filter; - } - - private void verifyBroadcastedIntent( - IntentFilter filter, Runnable runnable, boolean shouldExpect) { - BroadcastReceiver receiver = mock(BroadcastReceiver.class); - LocalBroadcastManager.getInstance(RuntimeEnvironment.application) - .registerReceiver(receiver, filter); - try { - runnable.run(); - } finally { - LocalBroadcastManager.getInstance(RuntimeEnvironment.application) - .unregisterReceiver(receiver); - if (shouldExpect) { - verify(receiver).onReceive(any(Context.class), any(Intent.class)); - } else { - verify(receiver, times(0)).onReceive(any(Context.class), any(Intent.class)); - } - } - } }
diff --git a/chromecast/browser/metrics/cast_stability_metrics_provider.h b/chromecast/browser/metrics/cast_stability_metrics_provider.h index 3bb135f..6952a89 100644 --- a/chromecast/browser/metrics/cast_stability_metrics_provider.h +++ b/chromecast/browser/metrics/cast_stability_metrics_provider.h
@@ -41,7 +41,7 @@ ~CastStabilityMetricsProvider() override = default; - // metrics::MetricsDataProvider implementation: + // metrics::MetricsProvider implementation: void OnRecordingEnabled() override; void OnRecordingDisabled() override; void ProvideStabilityMetrics(
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 1ba5b355..f2bce554 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -1326,6 +1326,9 @@ <message name="IDS_ONC_VPN_OPENVPN_TLS_AUTH_CONTENTS" desc="Settings > Network > OpenVPN Network Detail Page > label for the key used to sign TLS control channel packets."> TLS authentication key </message> + <message name="IDS_ONC_VPN_TYPE_IKEV2" desc="ONC Property label for VPN.Type.IKEv2"> + IPsec (IKEv2) + </message> <message name="IDS_ONC_VPN_TYPE_L2TP_IPSEC" desc="ONC Property label for VPN.Type.L2TP-IPSec"> L2TP/IPsec </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_ONC_VPN_TYPE_IKEV2.png.sha1 b/chromeos/chromeos_strings_grd/IDS_ONC_VPN_TYPE_IKEV2.png.sha1 new file mode 100644 index 0000000..f3a46d45 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_ONC_VPN_TYPE_IKEV2.png.sha1
@@ -0,0 +1 @@ +63be125f140c863b6fb6381848d529eb5703fd1d \ No newline at end of file
diff --git a/chromeos/metrics/login_event_recorder.cc b/chromeos/metrics/login_event_recorder.cc index e56c8f3..7dd26f01 100644 --- a/chromeos/metrics/login_event_recorder.cc +++ b/chromeos/metrics/login_event_recorder.cc
@@ -6,6 +6,7 @@ #include <vector> +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/json/json_reader.h" @@ -297,6 +298,13 @@ DCHECK(base::CurrentUIThread::IsSet()); login_time_markers_.reserve(30); logout_time_markers_.reserve(30); + + // Remember login events for later retrieval by tests. + constexpr char kKeepLoginEventsForTesting[] = "keep-login-events-for-testing"; + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + kKeepLoginEventsForTesting)) { + PrepareEventCollectionForTesting(); // IN-TEST + } } LoginEventRecorder::~LoginEventRecorder() = default;
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni index 4f296f2..7f75fac 100644 --- a/chromeos/tast_control.gni +++ b/chromeos/tast_control.gni
@@ -142,6 +142,10 @@ "policy.JavaScriptAllowedForUrls", "policy.JavaScriptBlockedForUrls", "policy.ImagesForURLCheck.default", + + # https://crbug.com/1302469 (http://b/222407003) + "inputs.PhysicalKeyboardKoreanTyping", + "inputs.PhysicalKeyboardAutocorrect.en_us_2", ] # To disable a specific test in lacros_all_tast_tests, add it the following
diff --git a/components/autofill/core/browser/address_profile_save_manager.cc b/components/autofill/core/browser/address_profile_save_manager.cc index d90810f..69a18b3 100644 --- a/components/autofill/core/browser/address_profile_save_manager.cc +++ b/components/autofill/core/browser/address_profile_save_manager.cc
@@ -26,7 +26,7 @@ const std::string& app_locale, const GURL& url, bool allow_only_silent_updates, - bool did_complement_country) { + ProfileImportMetadata import_metadata) { // Without a personal data manager, profile storage is not possible. if (!personal_data_manager_) return; @@ -45,7 +45,7 @@ auto process_ptr = std::make_unique<ProfileImportProcess>( observed_profile, app_locale, url, personal_data_manager_, - allow_only_silent_updates, did_complement_country); + allow_only_silent_updates, import_metadata); MaybeOfferSavePrompt(std::move(process_ptr)); }
diff --git a/components/autofill/core/browser/address_profile_save_manager.h b/components/autofill/core/browser/address_profile_save_manager.h index 063f2175..8c8195a5 100644 --- a/components/autofill/core/browser/address_profile_save_manager.h +++ b/components/autofill/core/browser/address_profile_save_manager.h
@@ -40,14 +40,13 @@ // |allow_only_silent_updates| allows only for silent updates of profiles // that have either a structured name or address or both but do not fulfill // the import requirements. - // |did_complement_country| is passed through, to collect metrics on whether - // the profile is accepted/edited. - // TODO(crbug.com/1297032): Cleanup when launched. + // |import_metadata| is passed through, to collect metrics based on the + // profile import decision. void ImportProfileFromForm(const AutofillProfile& profile, const std::string& app_locale, const GURL& url, bool allow_only_silent_updates, - bool did_complement_country = false); + ProfileImportMetadata import_metadata); protected: // Initiates showing the prompt to the user.
diff --git a/components/autofill/core/browser/address_profile_save_manager_unittest.cc b/components/autofill/core/browser/address_profile_save_manager_unittest.cc index 945d5c3..ee847ea 100644 --- a/components/autofill/core/browser/address_profile_save_manager_unittest.cc +++ b/components/autofill/core/browser/address_profile_save_manager_unittest.cc
@@ -48,7 +48,8 @@ "Autofill.ProfileImport.UpdateProfileNumberOfEditedFields"; constexpr char kProfileUpdateNumberOfAffectedTypesHistogram[] = "Autofill.ProfileImport.UpdateProfileNumberOfAffectedFields"; -// Histograms related to kAutofillComplementCountryCodeOnImport + +// Histograms related to |kAutofillComplementCountryCodeOnImport| // TODO(crbug.com/1297032): Cleanup when launched. constexpr char kNewProfileWithComplementedCountryDecisionHistogram[] = "Autofill.ProfileImport.NewProfileWithComplementedCountryDecision"; @@ -59,6 +60,17 @@ constexpr char kProfileUpdateEditComplementedCountryHistogram[] = "Autofill.ProfileImport.UpdateProfileEditedComplementedCountry"; +// Histograms related to |kAutofillRemoveInvalidPhoneNumberOnImport| +// TODO(crbug.com/1298424): Cleanup when launched. +constexpr char kNewProfileWithRemovedPhoneNumberDecisionHistogram[] = + "Autofill.ProfileImport.NewProfileWithRemovedPhoneNumberDecision"; +constexpr char kProfileUpdateWithRemovedPhoneNumberDecisionHistogram[] = + "Autofill.ProfileImport.UpdateProfileWithRemovedPhoneNumberDecision"; +constexpr char + kSilentUpdatesWithRemovedPhoneNumberProfileImportTypeHistogram[] = + "Autofill.ProfileImport." + "SilentUpdatesWithRemovedPhoneNumberProfileImportType"; + class MockPersonalDataManager : public TestPersonalDataManager { public: MockPersonalDataManager() = default; @@ -158,10 +170,11 @@ class AddressProfileSaveManagerTest : public testing::Test, - public testing::WithParamInterface<std::tuple<bool>> { + public testing::WithParamInterface<std::tuple<bool, bool>> { public: void SetUp() override { complement_country_ = std::get<0>(GetParam()); + remove_invalid_phone_number_ = std::get<1>(GetParam()); // Enable both explicit save prompts and structured names. // The latter is needed to test the concept of silent updates. scoped_feature_list_.InitWithFeatures( @@ -185,6 +198,7 @@ MockPersonalDataManager mock_personal_data_manager_; base::test::ScopedFeatureList scoped_feature_list_; bool complement_country_; + bool remove_invalid_phone_number_; }; void AddressProfileSaveManagerTest::TestImportScenario( @@ -243,10 +257,13 @@ mock_personal_data_manager_.SetProfiles(&test_scenario.existing_profiles); // Initiate the profile import. + ProfileImportMetadata import_metadata{ + .did_complement_country = complement_country_, + .did_remove_invalid_phone_number = remove_invalid_phone_number_}; save_manager.ImportProfileFromForm( test_scenario.observed_profile, "en-US", url, /*allow_only_silent_updates=*/test_scenario.allow_only_silent_updates, - /*did_complement_country=*/complement_country_); + import_metadata); // Assert that there is a finished import process on record. ASSERT_NE(save_manager.last_import(), nullptr); @@ -274,6 +291,11 @@ ? kSilentUpdatesProfileImportTypeHistogram : kProfileImportTypeHistogram, test_scenario.expected_import_type, 1); + if (test_scenario.allow_only_silent_updates && remove_invalid_phone_number_) { + histogram_tester.ExpectUniqueSample( + kSilentUpdatesWithRemovedPhoneNumberProfileImportTypeHistogram, + test_scenario.expected_import_type, 1); + } const bool is_new_profile = test_scenario.expected_import_type == AutofillProfileImportType::kNewProfile; @@ -369,6 +391,20 @@ kProfileUpdateEditComplementedCountryHistogram, 0); } + // Metrics related to removing invalid phone numbers for non silent updates. + if (remove_invalid_phone_number_) { + histogram_tester.ExpectTotalCount( + !is_new_profile + ? kNewProfileWithRemovedPhoneNumberDecisionHistogram + : kProfileUpdateWithRemovedPhoneNumberDecisionHistogram, + 0); + histogram_tester.ExpectUniqueSample( + is_new_profile + ? kNewProfileWithRemovedPhoneNumberDecisionHistogram + : kProfileUpdateWithRemovedPhoneNumberDecisionHistogram, + test_scenario.user_decision, 1); + } + for (auto edited_type : test_scenario.expected_edited_types_for_metrics) { histogram_tester.ExpectBucketCount(affected_edits_histo, edited_type, 1); } @@ -1083,7 +1119,8 @@ EXPECT_CALL(mock_personal_data_manager_, SaveImportedProfile(test_profile)); save_manager.ImportProfileFromForm(test_profile, "en_US", GURL("https://www.noprompt.com"), - /*allow_only_silent_updates=*/false); + /*allow_only_silent_updates=*/false, + /*import_metadata=*/{}); } // Tests that a new profile is not imported when only silent updates are @@ -1305,10 +1342,11 @@ } // Runs the suite as if the the country was (not) complemented using -// |kAutofillComplementCountryCodeOnImport|. +// |kAutofillComplementCountryCodeOnImport| and as if the phone number was (not) +// removed with |kAutofillRemoveInvalidPhoneNumberOnImport|. INSTANTIATE_TEST_SUITE_P(, AddressProfileSaveManagerTest, - testing::Combine(testing::Bool())); + testing::Combine(testing::Bool(), testing::Bool())); } // namespace
diff --git a/components/autofill/core/browser/autofill_profile_import_process.cc b/components/autofill/core/browser/autofill_profile_import_process.cc index 1ecd3a6..b124ef2 100644 --- a/components/autofill/core/browser/autofill_profile_import_process.cc +++ b/components/autofill/core/browser/autofill_profile_import_process.cc
@@ -30,14 +30,14 @@ const GURL& form_source_url, const PersonalDataManager* personal_data_manager, bool allow_only_silent_updates, - bool did_complement_country) + ProfileImportMetadata import_metadata) : import_id_(GetImportId()), observed_profile_(observed_profile), app_locale_(app_locale), form_source_url_(form_source_url), personal_data_manager_(personal_data_manager), allow_only_silent_updates_(allow_only_silent_updates), - did_complement_country_(did_complement_country) { + import_metadata_(import_metadata) { DetermineProfileImportType(); } @@ -346,6 +346,10 @@ if (allow_only_silent_updates_) { // Record the import type for the silent updates. AutofillMetrics::LogSilentUpdatesProfileImportType(import_type_); + if (import_metadata_.did_remove_invalid_phone_number) { + AutofillMetrics::LogSilentUpdatesWithRemovedPhoneNumberProfileImportType( + import_type_); + } return; } @@ -356,18 +360,26 @@ // decision. if (import_type_ == AutofillProfileImportType::kNewProfile) { AutofillMetrics::LogNewProfileImportDecision(user_decision_); - if (did_complement_country_) { + if (import_metadata_.did_complement_country) { AutofillMetrics::LogNewProfileWithComplementedCountryImportDecision( user_decision_); } + if (import_metadata_.did_remove_invalid_phone_number) { + AutofillMetrics::LogNewProfileWithRemovedPhoneNumberImportDecision( + user_decision_); + } } else if (import_type_ == AutofillProfileImportType::kConfirmableMerge || import_type_ == AutofillProfileImportType::kConfirmableMergeAndSilentUpdate) { AutofillMetrics::LogProfileUpdateImportDecision(user_decision_); - if (did_complement_country_) { + if (import_metadata_.did_complement_country) { AutofillMetrics::LogProfileUpdateWithComplementedCountryImportDecision( user_decision_); } + if (import_metadata_.did_remove_invalid_phone_number) { + AutofillMetrics::LogProfileUpdateWithRemovedPhoneNumberImportDecision( + user_decision_); + } DCHECK(merge_candidate_.has_value() && import_candidate_.has_value()); @@ -397,13 +409,13 @@ for (const auto& difference : edit_difference) { if (import_type_ == AutofillProfileImportType::kNewProfile) { AutofillMetrics::LogNewProfileEditedType(difference.type); - if (did_complement_country_ && + if (import_metadata_.did_complement_country && difference.type == ServerFieldType::ADDRESS_HOME_COUNTRY) { AutofillMetrics::LogNewProfileEditedComplementedCountry(); } } else { AutofillMetrics::LogProfileUpdateEditedType(difference.type); - if (did_complement_country_ && + if (import_metadata_.did_complement_country && difference.type == ServerFieldType::ADDRESS_HOME_COUNTRY) { AutofillMetrics::LogProfileUpdateEditedComplementedCountry(); }
diff --git a/components/autofill/core/browser/autofill_profile_import_process.h b/components/autofill/core/browser/autofill_profile_import_process.h index 7b90710..9b9258b 100644 --- a/components/autofill/core/browser/autofill_profile_import_process.h +++ b/components/autofill/core/browser/autofill_profile_import_process.h
@@ -56,6 +56,21 @@ kMaxValue = kUnusableIncompleteProfile }; +// Metadata about the import, which is passed through from FormDataImporter to +// ProfileImportProcess. This is required to do metric collection, depending on +// the user's decision to (not) import, based on how we construct the candidate +// profile in FormDataImporter. +struct ProfileImportMetadata { + // Whether the profile's country was complemented automatically. + // TODO(crbug.com/1297032): Cleanup when launched. + bool did_complement_country = false; + // Whether the profile originally contained an invalid phone number, that was: + // - removed due to |kAutofillRemoveInvalidPhoneNumberOnImport| + // - the only requirement preventing an import. + // TODO(crbug.com/1298424): Cleanup when launched. + bool did_remove_invalid_phone_number = false; +}; + // This class holds the state associated with the import of an AutofillProfile // observed in a form submission and should be used as the follows: // @@ -79,7 +94,7 @@ const GURL& form_source_url, const PersonalDataManager* personal_data_manager, bool allow_only_silent_updates, - bool did_complement_country = false); + ProfileImportMetadata import_metadata = {}); ProfileImportProcess(const ProfileImportProcess&); ProfileImportProcess& operator=(const ProfileImportProcess& other); @@ -222,10 +237,9 @@ // If true, denotes that the import process allows only silent updates. bool allow_only_silent_updates_; - // Passed through from FormDataImporter, to collect metrics on whether the - // profile is accepted/edited. - // TODO(crbug.com/1297032): Cleanup when launched. - bool did_complement_country_; + // Metadata about the import, used for metric collection after the user's + // decision. + ProfileImportMetadata import_metadata_; }; } // namespace autofill
diff --git a/components/autofill/core/browser/form_data_importer.cc b/components/autofill/core/browser/form_data_importer.cc index 5cc5cbe..bd6c6a2 100644 --- a/components/autofill/core/browser/form_data_importer.cc +++ b/components/autofill/core/browser/form_data_importer.cc
@@ -549,6 +549,9 @@ // since they do not belong to the first phone number in the form. bool ignore_phone_number_fields = false; + // Metadata about the way we construct candidate_profile. + ProfileImportMetadata import_metadata; + // Go through each |form| field and attempt to constitute a valid profile. for (const auto& field : form) { // Reject fields that are not within the specified |section|. @@ -675,7 +678,6 @@ const std::string predicted_country_code = GetPredictedCountryCode( candidate_profile, client_->GetVariationConfigCountryCode(), app_locale_, import_log_buffer); - bool did_complement_country = false; // If the form doesn't contain a country field, complement the profile using // |predicted_country_code|. To give users the opportunity to edit, this is // only done with explicit save prompts enabled. @@ -691,11 +693,11 @@ AutofillType(ADDRESS_HOME_COUNTRY), base::ASCIIToUTF16(predicted_country_code), app_locale_, VerificationStatus::kObserved); - did_complement_country = true; + import_metadata.did_complement_country = true; } // Construct the phone number. Reject the whole profile if the number is - // invalid. + // invalid, unless |kAutofillRemoveInvalidPhoneNumberOnImport| is enabled. if (!combined_phone.IsEmpty()) { const std::string predicted_country_code_without_variation = GetPredictedCountryCode(candidate_profile, "", app_locale_, nullptr); @@ -721,11 +723,17 @@ !candidate_profile.SetInfoWithVerificationStatus( AutofillType(PHONE_HOME_WHOLE_NUMBER), constructed_number, phone_number_region, VerificationStatus::kObserved)) { - if (import_log_buffer) { - *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed - << "Invalid phone number." << CTag{}; + if (base::FeatureList::IsEnabled( + features::kAutofillRemoveInvalidPhoneNumberOnImport)) { + DCHECK(candidate_profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER).empty()); + import_metadata.did_remove_invalid_phone_number = true; + } else { + if (import_log_buffer) { + *import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed + << "Invalid phone number." << CTag{}; + } + has_invalid_phone_number = true; } - has_invalid_phone_number = true; } } @@ -794,11 +802,11 @@ // incognito mode. DCHECK(!personal_data_manager_->IsOffTheRecord()); - import_candidates.push_back(AddressProfileImportCandidate{ - .profile = candidate_profile, - .url = form.source_url(), - .all_requirements_fulfilled = all_fulfilled, - .did_complement_country = did_complement_country}); + import_candidates.push_back( + AddressProfileImportCandidate{.profile = candidate_profile, + .url = form.source_url(), + .all_requirements_fulfilled = all_fulfilled, + .import_metadata = import_metadata}); // Return true if a compelete importable profile was found. return all_fulfilled; @@ -818,8 +826,7 @@ continue; address_profile_save_manager_->ImportProfileFromForm( candidate.profile, app_locale_, candidate.url, - /*allow_only_silent_updates=*/false, - candidate.did_complement_country); + /*allow_only_silent_updates=*/false, candidate.import_metadata); // Limit the number of importable profiles to 2. if (++imported_profiles >= 2) return true; @@ -834,7 +841,7 @@ // First try to import a single complete profile. address_profile_save_manager_->ImportProfileFromForm( candidate.profile, app_locale_, candidate.url, - /*allow_only_silent_updates=*/true); + /*allow_only_silent_updates=*/true, candidate.import_metadata); } return false; }
diff --git a/components/autofill/core/browser/form_data_importer.h b/components/autofill/core/browser/form_data_importer.h index 05b3d19..cbc8fa0 100644 --- a/components/autofill/core/browser/form_data_importer.h +++ b/components/autofill/core/browser/form_data_importer.h
@@ -14,6 +14,7 @@ #include "base/memory/raw_ptr.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_client.h" +#include "components/autofill/core/browser/autofill_profile_import_process.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/payments/credit_card_save_manager.h" #include "components/autofill/core/browser/payments/local_card_migration_manager.h" @@ -127,9 +128,9 @@ GURL url; // Indicates if all import requirements have been fulfilled. bool all_requirements_fulfilled; - // Whether the profile's country was complemented automatically. - // TODO(crbug.com/1297032): Cleanup when launched. - bool did_complement_country; + // Metadata about the import, used for metric collection in + // ProfileImportProcess after the user's decision. + ProfileImportMetadata import_metadata; AddressProfileImportCandidate(AddressProfileImportCandidate&& other) = default; AddressProfileImportCandidate& operator=(
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc index 7088fd39..755d78d 100644 --- a/components/autofill/core/browser/form_data_importer_unittest.cc +++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -19,6 +19,7 @@ #include "base/feature_list.h" #include "base/guid.h" #include "base/memory/raw_ptr.h" +#include "base/ranges/ranges.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" @@ -699,6 +700,42 @@ import_with_country("", {ConstructDefaultProfileWithCountry("DE")}); } +TEST_P(FormDataImporterTest, InvalidPhoneNumber) { + std::vector<std::pair<ServerFieldType, std::string>> + profile_with_invalid_phone_number = GetDefaultProfileTypeValuePairs(); + auto phone_number_it = + base::ranges::find(profile_with_invalid_phone_number, + std::pair<ServerFieldType, std::string>( + PHONE_HOME_WHOLE_NUMBER, kDefaultPhone)); + phone_number_it->second = "invalid"; + std::unique_ptr<FormStructure> form_structure = + ConstructFormStructureFromTypeValuePairs( + profile_with_invalid_phone_number); + + // With |kAutofillRemoveInvalidPhoneNumberOnImport| disabled, profiles with + // invalid phone numbers are rejected. + { + base::test::ScopedFeatureList remove_invalid_phone_number_feature; + remove_invalid_phone_number_feature.InitAndDisableFeature( + features::kAutofillRemoveInvalidPhoneNumberOnImport); + + ImportAddressProfilesAndVerifyExpectation(*form_structure, {}); + } + + // With the feature enabled, the phone number is removed and the profile + // imported. + { + base::test::ScopedFeatureList remove_invalid_phone_number_feature; + remove_invalid_phone_number_feature.InitAndEnableFeature( + features::kAutofillRemoveInvalidPhoneNumberOnImport); + + profile_with_invalid_phone_number.erase(phone_number_it); + ImportAddressProfilesAndVerifyExpectation( + *form_structure, {ConstructProfileFromTypeValuePairs( + profile_with_invalid_phone_number)}); + } +} + // ImportAddressProfiles tests. TEST_P(FormDataImporterTest, ImportStructuredNameProfile) { base::test::ScopedFeatureList structured_addresses_feature;
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc index 6119619f8..d3336b0 100644 --- a/components/autofill/core/browser/metrics/autofill_metrics.cc +++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -3076,6 +3076,14 @@ "Autofill.ProfileImport.SilentUpdatesProfileImportType", import_type); } +void AutofillMetrics::LogSilentUpdatesWithRemovedPhoneNumberProfileImportType( + AutofillProfileImportType import_type) { + base::UmaHistogramEnumeration( + "Autofill.ProfileImport." + "SilentUpdatesWithRemovedPhoneNumberProfileImportType", + import_type); +} + void AutofillMetrics::LogNewProfileImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision) { base::UmaHistogramEnumeration("Autofill.ProfileImport.NewProfileDecision", @@ -3089,6 +3097,13 @@ decision); } +void AutofillMetrics::LogNewProfileWithRemovedPhoneNumberImportDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision) { + base::UmaHistogramEnumeration( + "Autofill.ProfileImport.NewProfileWithRemovedPhoneNumberDecision", + decision); +} + void AutofillMetrics::LogNewProfileEditedType(ServerFieldType edited_type) { base::UmaHistogramEnumeration( "Autofill.ProfileImport.NewProfileEditedType", @@ -3121,6 +3136,13 @@ decision); } +void AutofillMetrics::LogProfileUpdateWithRemovedPhoneNumberImportDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision) { + base::UmaHistogramEnumeration( + "Autofill.ProfileImport.UpdateProfileWithRemovedPhoneNumberDecision", + decision); +} + void AutofillMetrics::LogProfileUpdateAffectedType( ServerFieldType affected_type, AutofillClient::SaveAddressProfileOfferUserDecision decision) {
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.h b/components/autofill/core/browser/metrics/autofill_metrics.h index 348556c..bf71cce 100644 --- a/components/autofill/core/browser/metrics/autofill_metrics.h +++ b/components/autofill/core/browser/metrics/autofill_metrics.h
@@ -1935,6 +1935,12 @@ static void LogSilentUpdatesProfileImportType( AutofillProfileImportType import_type); + // Logs the type of profile import used for a silent update, which was only + // possible after an invalid phone number was removed. + // TODO(crbug.com/1298424): Cleanup when launched. + static void LogSilentUpdatesWithRemovedPhoneNumberProfileImportType( + AutofillProfileImportType import_type); + // Logs the user decision for importing a new profile. static void LogNewProfileImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision); @@ -1945,6 +1951,12 @@ static void LogNewProfileWithComplementedCountryImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Logs the user decision for importing a new profile, which was only possible + // after an invalid phone number was removed. + // TODO(crbug.com/1298424): Cleanup when launched. + static void LogNewProfileWithRemovedPhoneNumberImportDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Logs that a specific type was edited in a save prompt. static void LogNewProfileEditedType(ServerFieldType edited_type); @@ -1965,6 +1977,12 @@ static void LogProfileUpdateWithComplementedCountryImportDecision( AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Logs the user decision for updating an existing profile, which was only + // possible after an invalid phone number was removed. + // TODO(crbug.com/1298424): Cleanup when launched. + static void LogProfileUpdateWithRemovedPhoneNumberImportDecision( + AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Logs that a specific type changed in a profile update that received the // user |decision|. Note that additional manual edits in the update prompt are // not accounted for in this metric.
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index a2f9e4ffb..69a07a92 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -370,6 +370,13 @@ "AutofillRemoveInaccessibleProfileValues", base::FEATURE_DISABLED_BY_DEFAULT}; +// If enabled, invalid phone numbers are removed on profile import, rather than +// invalidating the entire profile. +// TODO(crbug.com/1298424): Cleanup when launched. +const base::Feature kAutofillRemoveInvalidPhoneNumberOnImport{ + "AutofillRemoveInvalidPhoneNumberOnImport", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether or not overall prediction are retrieved from the cache. const base::Feature kAutofillRetrieveOverallPredictionsFromCache{ "AutofillRetrieveOverallPredictionsFromCache",
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index ec32903f8..08fe889 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -134,9 +134,11 @@ COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillProfileImportFromUnfocusableFields; COMPONENT_EXPORT(AUTOFILL) -extern const base::Feature kAutofillRetrieveOverallPredictionsFromCache; +extern const base::Feature kAutofillRemoveInvalidPhoneNumberOnImport; COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillRemoveInaccessibleProfileValues; +COMPONENT_EXPORT(AUTOFILL) +extern const base::Feature kAutofillRetrieveOverallPredictionsFromCache; COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillSaveAndFillVPA; COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillSectionUponRedundantNameInfo;
diff --git a/components/autofill_assistant/browser/metrics.cc b/components/autofill_assistant/browser/metrics.cc index 6c00740..d6ab48c 100644 --- a/components/autofill_assistant/browser/metrics.cc +++ b/components/autofill_assistant/browser/metrics.cc
@@ -41,6 +41,8 @@ "Android.AutofillAssistant.PaymentRequest.AutofillChanged"; const char kPaymentRequestFirstNameOnly[] = "Android.AutofillAssistant.PaymentRequest.FirstNameOnly"; +const char kCupRpcVerificationEvent[] = + "Android.AutofillAssistant.CupRpcVerificationEvent"; const char kDependenciesInvalidated[] = "Android.AutofillAssistant.DependenciesInvalidated"; const char kOnboardingFetcherResultStatus[] = @@ -460,6 +462,12 @@ } // static +void Metrics::RecordCupRpcVerificationEvent(CupRpcVerificationEvent event) { + DCHECK_LE(event, CupRpcVerificationEvent::kMaxValue); + base::UmaHistogramEnumeration(kCupRpcVerificationEvent, event); +} + +// static void Metrics::RecordOnboardingFetcherResult( OnboardingFetcherResultStatus status) { DCHECK_LE(status, OnboardingFetcherResultStatus::kMaxValue);
diff --git a/components/autofill_assistant/browser/metrics.h b/components/autofill_assistant/browser/metrics.h index f72a4cf..4901170 100644 --- a/components/autofill_assistant/browser/metrics.h +++ b/components/autofill_assistant/browser/metrics.h
@@ -595,6 +595,39 @@ kMaxValue = CHROME_AUTOFILL }; + // Outcome of the CUP verification process for GetAction RPC calls. CUP + // verification is used to check whether the actions delivered to the client + // come from a trusted source, and requires the request from the client to be + // signed first. Events are only recorded for RPC calls where we support CUP. + // + // This verification event is recorded after the response is deserialized but + // before it's actually used in the client. This is the case even if the + // verification doesn't happen due to the request not being signed in the + // first place. HTTP failures are checked before the feature flags for + // signing and verification, and therefore a failing HTTP request with + // verification disabled will be logged as |HTTP_FAILED|. + // + // This enum is used in histograms, do not remove/renumber entries. Only add + // at the end and update kMaxValue. Also remember to update the + // CupRpcVerificationEvent enum listing in tools/metrics/histograms/enums.xml. + enum class CupRpcVerificationEvent { + // Signature doesn't match response or context, message origin cannot be + // confirmed. + VERIFICATION_FAILED = 0, + // Signature correctly matches the response and context. + VERIFICATION_SUCCEEDED = 1, + // Response parsing failed. Rpc verification won't be performed. + PARSING_FAILED = 2, + // Response verification is disabled. Rpc verification won't be performed. + VERIFICATION_DISABLED = 3, + // Request signing is disabled. Rpc verification won't be performed. + SIGNING_DISABLED = 4, + // HTTP call didn't return "OK" 200. Rpc verification won't be performed. + HTTP_FAILED = 5, + + kMaxValue = HTTP_FAILED + }; + // Used for bitmasks for the InitialContactFieldsStatus, // InitialBillingFieldsStatus and InitialShippingFieldsStatus metrics. enum AutofillAssistantProfileFields { @@ -713,6 +746,7 @@ UserDataSource source); static void RecordOnboardingFetcherResult( OnboardingFetcherResultStatus status); + static void RecordCupRpcVerificationEvent(CupRpcVerificationEvent event); // Intended for debugging: writes string representation of |reason| to // |out|.
diff --git a/components/autofill_assistant/browser/service/cup.cc b/components/autofill_assistant/browser/service/cup.cc index 2affb0a..175bce68 100644 --- a/components/autofill_assistant/browser/service/cup.cc +++ b/components/autofill_assistant/browser/service/cup.cc
@@ -12,14 +12,14 @@ namespace cup { bool ShouldSignRequests(RpcType rpc_type) { - return rpc_type == RpcType::GET_ACTIONS && + return IsRpcTypeSupported(rpc_type) && base::FeatureList::IsEnabled( autofill_assistant::features:: kAutofillAssistantSignGetActionsRequests); } bool ShouldVerifyResponses(RpcType rpc_type) { - return rpc_type == RpcType::GET_ACTIONS && + return IsRpcTypeSupported(rpc_type) && base::FeatureList::IsEnabled( autofill_assistant::features:: kAutofillAssistantSignGetActionsRequests) && @@ -28,6 +28,10 @@ kAutofillAssistantVerifyGetActionsResponses); } +bool IsRpcTypeSupported(RpcType rpc_type) { + return rpc_type == RpcType::GET_ACTIONS; +} + } // namespace cup } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/cup.h b/components/autofill_assistant/browser/service/cup.h index eb4d4a8..841399dc 100644 --- a/components/autofill_assistant/browser/service/cup.h +++ b/components/autofill_assistant/browser/service/cup.h
@@ -22,6 +22,9 @@ // |ShouldSignRequest| returns |false|. bool ShouldVerifyResponses(RpcType rpc_type); +// Whether this CUP implementation supports a given |rpc_type|. +bool IsRpcTypeSupported(RpcType rpc_type); + class CUP { public: virtual ~CUP() = default;
diff --git a/components/autofill_assistant/browser/service/cup_impl.cc b/components/autofill_assistant/browser/service/cup_impl.cc index ac00b359..9d3c58f 100644 --- a/components/autofill_assistant/browser/service/cup_impl.cc +++ b/components/autofill_assistant/browser/service/cup_impl.cc
@@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" +#include "components/autofill_assistant/browser/metrics.h" #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/switches.h" #include "components/client_update_protocol/ecdsa.h" @@ -127,6 +128,8 @@ autofill_assistant::ActionsResponseProto actions_response; if (!actions_response.ParseFromString(original_response)) { LOG(ERROR) << "Failed to parse server response"; + Metrics::RecordCupRpcVerificationEvent( + Metrics::CupRpcVerificationEvent::PARSING_FAILED); return absl::nullopt; } @@ -134,9 +137,13 @@ if (!query_signer_->ValidateResponse( serialized_response, actions_response.cup_data().ecdsa_signature())) { LOG(ERROR) << "CUP RPC response verification failed"; + Metrics::RecordCupRpcVerificationEvent( + Metrics::CupRpcVerificationEvent::VERIFICATION_FAILED); return absl::nullopt; } + Metrics::RecordCupRpcVerificationEvent( + Metrics::CupRpcVerificationEvent::VERIFICATION_SUCCEEDED); return serialized_response; }
diff --git a/components/autofill_assistant/browser/service/cup_impl_unittest.cc b/components/autofill_assistant/browser/service/cup_impl_unittest.cc index 1b0a2e2..fefc3e9 100644 --- a/components/autofill_assistant/browser/service/cup_impl_unittest.cc +++ b/components/autofill_assistant/browser/service/cup_impl_unittest.cc
@@ -3,35 +3,36 @@ // found in the LICENSE file. #include "cup_impl.h" - #include "base/command_line.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "components/autofill_assistant/browser/features.h" +#include "components/autofill_assistant/browser/metrics.h" #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/switches.h" #include "testing/gmock/include/gmock/gmock.h" +namespace autofill_assistant { + namespace { TEST(CUPImplTest, PacksAndSignsGetActionsRequest) { - autofill_assistant::cup::CUPImpl cup_{ - autofill_assistant::cup::CUPImpl::CreateQuerySigner(), - autofill_assistant::RpcType::GET_ACTIONS}; - autofill_assistant::ScriptActionRequestProto user_request; + cup::CUPImpl cup{cup::CUPImpl::CreateQuerySigner(), RpcType::GET_ACTIONS}; + ScriptActionRequestProto user_request; user_request.mutable_client_context()->set_experiment_ids("test"); std::string user_request_str; user_request.SerializeToString(&user_request_str); - auto packed_request_str = cup_.PackAndSignRequest(user_request_str); + auto packed_request_str = cup.PackAndSignRequest(user_request_str); - autofill_assistant::ScriptActionRequestProto packed_request; + ScriptActionRequestProto packed_request; EXPECT_TRUE(packed_request.ParseFromString(packed_request_str)); EXPECT_TRUE(packed_request.client_context().experiment_ids().empty()); EXPECT_FALSE(packed_request.cup_data().request().empty()); EXPECT_FALSE(packed_request.cup_data().query_cup2key().empty()); EXPECT_FALSE(packed_request.cup_data().hash_hex().empty()); - autofill_assistant::ScriptActionRequestProto actual_user_request; + ScriptActionRequestProto actual_user_request; EXPECT_TRUE( actual_user_request.ParseFromString(packed_request.cup_data().request())); EXPECT_EQ(actual_user_request.client_context().experiment_ids(), "test"); @@ -39,75 +40,80 @@ } TEST(CUPImplTest, IgnoresNonGetActionsRequest) { - autofill_assistant::cup::CUPImpl cup_{ - autofill_assistant::cup::CUPImpl::CreateQuerySigner(), - autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS}; + cup::CUPImpl cup{cup::CUPImpl::CreateQuerySigner(), + RpcType::GET_TRIGGER_SCRIPTS}; - EXPECT_EQ(cup_.PackAndSignRequest("a request"), "a request"); + EXPECT_EQ(cup.PackAndSignRequest("a request"), "a request"); } -TEST(CUPImplTest, UnpacksTrustedGetActionsResponse) { - // TODO(b/203031699): Write test for the successful case. -} - -TEST(CUPImplTest, FailsToUnpackNonTrustedGetActionsResponse) { - autofill_assistant::cup::CUPImpl cup_{ - autofill_assistant::cup::CUPImpl::CreateQuerySigner(), - autofill_assistant::RpcType::GET_ACTIONS}; - autofill_assistant::ScriptActionRequestProto user_request; - user_request.mutable_client_context()->set_experiment_ids("123"); +TEST(CUPImplTest, FailsToVerifyNonTrustedGetActionsResponse) { + base::HistogramTester histogram_tester; + cup::CUPImpl cup{cup::CUPImpl::CreateQuerySigner(), RpcType::GET_ACTIONS}; + ScriptActionRequestProto user_request; std::string user_request_str; user_request.SerializeToString(&user_request_str); - cup_.PackAndSignRequest(user_request_str); - cup_.GetQuerySigner().OverrideNonceForTesting(8, 12345); + cup.PackAndSignRequest(user_request_str); + cup.GetQuerySigner().OverrideNonceForTesting(8, 12345); - autofill_assistant::ActionsResponseProto user_response; - user_response.set_global_payload("adsf"); - std::string user_response_str; - user_response.SerializeToString(&user_response_str); autofill_assistant::ActionsResponseProto packed_response; - packed_response.mutable_cup_data()->set_response(user_response_str); packed_response.mutable_cup_data()->set_ecdsa_signature("not a signature"); - EXPECT_EQ(cup_.UnpackResponse(user_response_str), absl::nullopt); + EXPECT_EQ(cup.UnpackResponse(""), absl::nullopt); + histogram_tester.ExpectUniqueSample( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::VERIFICATION_FAILED, 1); +} + +TEST(CUPImplTest, FailsToParseInvalidProtoResponse) { + base::HistogramTester histogram_tester; + cup::CUPImpl cup{cup::CUPImpl::CreateQuerySigner(), RpcType::GET_ACTIONS}; + ScriptActionRequestProto user_request; + std::string user_request_str; + user_request.SerializeToString(&user_request_str); + + cup.PackAndSignRequest(user_request_str); + cup.GetQuerySigner().OverrideNonceForTesting(8, 12345); + + EXPECT_EQ(cup.UnpackResponse("invalid proto"), absl::nullopt); + histogram_tester.ExpectUniqueSample( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::PARSING_FAILED, 1); } TEST(CUPImplTest, IgnoresNonGetActionsResponse) { - autofill_assistant::cup::CUPImpl cup_{ - autofill_assistant::cup::CUPImpl::CreateQuerySigner(), - autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS}; + cup::CUPImpl cup{cup::CUPImpl::CreateQuerySigner(), + RpcType::GET_TRIGGER_SCRIPTS}; absl::optional<std::string> unpacked_response = - cup_.UnpackResponse("a response"); + cup.UnpackResponse("a response"); EXPECT_EQ(*unpacked_response, "a response"); } TEST(CUPImplTest, OverridesEcdsaPublicKeyWithCLIValue) { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - autofill_assistant::switches::kAutofillAssistantCupPublicKeyBase64, - "SGVsbG8="); - EXPECT_EQ(autofill_assistant::cup::CUPImpl::GetPublicKey(), "Hello"); + switches::kAutofillAssistantCupPublicKeyBase64, "SGVsbG8="); + EXPECT_EQ(cup::CUPImpl::GetPublicKey(), "Hello"); } TEST(CUPImplTest, HasValidEcdsaPublicKeyWithNotValidCLIValue) { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - autofill_assistant::switches::kAutofillAssistantCupPublicKeyBase64, - "Not valid base64"); - EXPECT_FALSE(autofill_assistant::cup::CUPImpl::GetPublicKey().empty()); + switches::kAutofillAssistantCupPublicKeyBase64, "Not valid base64"); + EXPECT_FALSE(cup::CUPImpl::GetPublicKey().empty()); } TEST(CUPImplTest, OverridesEcdsaKeyVersionithCLIValue) { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - autofill_assistant::switches::kAutofillAssistantCupKeyVersion, "15"); - EXPECT_EQ(autofill_assistant::cup::CUPImpl::GetKeyVersion(), 15); + switches::kAutofillAssistantCupKeyVersion, "15"); + EXPECT_EQ(cup::CUPImpl::GetKeyVersion(), 15); } TEST(CUPImplTest, HasValidEcdsaKeyVersionWithNotValidCLIValue) { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - autofill_assistant::switches::kAutofillAssistantCupKeyVersion, - "Not a number"); - EXPECT_GT(autofill_assistant::cup::CUPImpl::GetKeyVersion(), -1); + switches::kAutofillAssistantCupKeyVersion, "Not a number"); + EXPECT_GT(cup::CUPImpl::GetKeyVersion(), -1); } } // namespace + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service/service_request_sender_impl.cc b/components/autofill_assistant/browser/service/service_request_sender_impl.cc index b3d19e2..042c46f 100644 --- a/components/autofill_assistant/browser/service/service_request_sender_impl.cc +++ b/components/autofill_assistant/browser/service/service_request_sender_impl.cc
@@ -7,6 +7,7 @@ #include "base/feature_list.h" #include "base/strings/strcat.h" #include "components/autofill_assistant/browser/features.h" +#include "components/autofill_assistant/browser/metrics.h" #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/service/cup.h" #include "components/autofill_assistant/browser/service/cup_impl.h" @@ -120,11 +121,32 @@ loader_factory, std::move(callback)); } -void VerifyCupResponse( +void MaybeVerifyCupResponse( std::unique_ptr<autofill_assistant::cup::CUP> cup, + autofill_assistant::RpcType rpc_type, autofill_assistant::ServiceRequestSender::ResponseCallback callback, int http_status, const std::string& response) { + if (!autofill_assistant::cup::IsRpcTypeSupported(rpc_type)) { + return std::move(callback).Run(http_status, response); + } + if (http_status != net::HTTP_OK) { + autofill_assistant::Metrics::RecordCupRpcVerificationEvent( + autofill_assistant::Metrics::CupRpcVerificationEvent::HTTP_FAILED); + return std::move(callback).Run(http_status, std::string()); + } + if (!autofill_assistant::cup::ShouldSignRequests(rpc_type)) { + autofill_assistant::Metrics::RecordCupRpcVerificationEvent( + autofill_assistant::Metrics::CupRpcVerificationEvent::SIGNING_DISABLED); + return std::move(callback).Run(http_status, response); + } + if (!autofill_assistant::cup::ShouldVerifyResponses(rpc_type)) { + autofill_assistant::Metrics::RecordCupRpcVerificationEvent( + autofill_assistant::Metrics::CupRpcVerificationEvent:: + VERIFICATION_DISABLED); + return std::move(callback).Run(http_status, response); + } + absl::optional<std::string> unpacked_response = cup->UnpackResponse(response); if (!unpacked_response) { LOG(ERROR) << "Failed to unpack or verify a response."; @@ -162,22 +184,21 @@ const std::string& request_body, ResponseCallback callback, RpcType rpc_type) { - if (!cup::ShouldSignRequests(rpc_type)) { + if (!cup::IsRpcTypeSupported(rpc_type)) { InternalSendRequest(url, request_body, std::move(callback)); return; } - std::unique_ptr<cup::CUP> cup = - cup_factory_->CreateInstance(RpcType::GET_ACTIONS); - std::string signed_request = cup->PackAndSignRequest(request_body); - - auto maybe_wrapped_callback = std::move(callback); - if (cup::ShouldVerifyResponses(rpc_type)) { - maybe_wrapped_callback = base::BindOnce(&VerifyCupResponse, std::move(cup), - std::move(maybe_wrapped_callback)); + std::unique_ptr<cup::CUP> cup = cup_factory_->CreateInstance(rpc_type); + std::string maybe_signed_request = request_body; + if (cup::ShouldSignRequests(rpc_type)) { + maybe_signed_request = cup->PackAndSignRequest(request_body); } - InternalSendRequest(url, signed_request, std::move(maybe_wrapped_callback)); + auto wrapped_callback = base::BindOnce( + &MaybeVerifyCupResponse, std::move(cup), rpc_type, std::move(callback)); + + InternalSendRequest(url, maybe_signed_request, std::move(wrapped_callback)); } void ServiceRequestSenderImpl::InternalSendRequest(
diff --git a/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc b/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc index 896e175..9a461b7 100644 --- a/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc +++ b/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc
@@ -10,9 +10,11 @@ #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/test/gmock_callback_support.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" #include "components/autofill_assistant/browser/features.h" +#include "components/autofill_assistant/browser/metrics.h" #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/service/access_token_fetcher.h" #include "components/autofill_assistant/browser/service/mock_access_token_fetcher.h" @@ -271,49 +273,6 @@ autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS); } -TEST_F(ServiceRequestSenderImplTest, - DoesNotCreateInstanceWhenFeatureNotEnabled) { - InitCupFeatures(false, false); - auto cup_factory = - std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>(); - auto loader_factory = - std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>(); - auto loader = std::make_unique<NiceMock<MockURLLoader>>(); - auto response_info = CreateResponseInfo(net::HTTP_OK, "OK"); - EXPECT_CALL(*loader_factory, OnCreateLoader(_, _)) - .WillOnce([&](::network::ResourceRequest* resource_request, - const ::net::NetworkTrafficAnnotationTag& annotation_tag) { - EXPECT_FALSE(resource_request->headers.HasHeader("Authorization")); - EXPECT_EQ(resource_request->url, - GURL("https://www.example.com/?key=fake_api_key")); - return std::move(loader); - }); - EXPECT_CALL(*loader, - AttachStringForUpload(std::string("request"), - std::string("application/x-protobuffer"))) - .Times(1); - EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _)) - .WillOnce(WithArgs<1>([&](auto&& callback) { - std::move(callback).Run(std::make_unique<std::string>("response")); - })); - EXPECT_CALL(*loader, ResponseInfo) - .WillRepeatedly(Return(response_info.get())); - EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response")); - - EXPECT_CALL(*cup_factory, CreateInstance(_)).Times(0); - ServiceRequestSenderImpl request_sender{ - &context_, - /* access_token_fetcher = */ nullptr, - std::move(cup_factory), - std::move(loader_factory), - std::string("fake_api_key"), - /* auth_enabled = */ false, - /* disable_auth_if_no_access_token = */ true}; - request_sender.SendRequest( - GURL("https://www.example.com"), std::string("request"), - mock_response_callback_.Get(), RpcType::GET_ACTIONS); -} - TEST_F(ServiceRequestSenderImplTest, SignsGetActionsRequestWhenFeatureEnabled) { InitCupFeatures(true, false); auto cup_factory = @@ -415,6 +374,288 @@ mock_response_callback_.Get(), autofill_assistant::RpcType::GET_ACTIONS); } +TEST_F(ServiceRequestSenderImplTest, RecordsCupSigningDisabledEvent) { + base::HistogramTester histogram_tester; + InitCupFeatures(false, false); + auto cup_factory = + std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>(); + auto loader_factory = + std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>(); + auto loader = std::make_unique<NiceMock<MockURLLoader>>(); + auto response_info = CreateResponseInfo(net::HTTP_OK, "OK"); + EXPECT_CALL(*loader_factory, OnCreateLoader(_, _)) + .WillOnce([&](::network::ResourceRequest* resource_request, + const ::net::NetworkTrafficAnnotationTag& annotation_tag) { + return std::move(loader); + }); + EXPECT_CALL(*loader, AttachStringForUpload(_, _)); + EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _)) + .WillOnce(RunOnceCallback<1>(std::make_unique<std::string>("response"))); + EXPECT_CALL(*loader, ResponseInfo) + .WillRepeatedly(Return(response_info.get())); + EXPECT_CALL(mock_access_token_fetcher_, OnFetchAccessToken) + .WillOnce(RunOnceCallback<0>(true, "access_token")); + + EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response")); + ServiceRequestSenderImpl request_sender{ + &context_, + /* access_token_fetcher = */ &mock_access_token_fetcher_, + std::move(cup_factory), + std::move(loader_factory), + /* api_key = */ std::string(""), + /* auth_enabled = */ true, + /* disable_auth_if_no_access_token = */ true}; + request_sender.SendRequest( + GURL("https://www.example.com"), std::string("request"), + mock_response_callback_.Get(), autofill_assistant::RpcType::GET_ACTIONS); + histogram_tester.ExpectUniqueSample( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::SIGNING_DISABLED, 1); +} + +TEST_F(ServiceRequestSenderImplTest, RecordsCupVerificationDisabledEvent) { + base::HistogramTester histogram_tester; + InitCupFeatures(true, false); + auto cup_factory = + std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>(); + auto cup = std::make_unique<NiceMock<autofill_assistant::cup::MockCUP>>(); + auto loader_factory = + std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>(); + auto loader = std::make_unique<NiceMock<MockURLLoader>>(); + auto response_info = CreateResponseInfo(net::HTTP_OK, "OK"); + EXPECT_CALL(*loader_factory, OnCreateLoader(_, _)) + .WillOnce([&](::network::ResourceRequest* resource_request, + const ::net::NetworkTrafficAnnotationTag& annotation_tag) { + return std::move(loader); + }); + EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _)) + .WillOnce(WithArgs<1>([&](auto&& callback) { + std::move(callback).Run(std::make_unique<std::string>("response")); + })); + EXPECT_CALL(*loader, ResponseInfo) + .WillRepeatedly(Return(response_info.get())); + EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response")); + + EXPECT_CALL(*cup_factory, + CreateInstance(autofill_assistant::RpcType::GET_ACTIONS)) + .WillOnce([&]() { return std::move(cup); }); + EXPECT_CALL(*cup, PackAndSignRequest("request")) + .WillOnce(Return(std::string("signed_request"))); + ServiceRequestSenderImpl request_sender{ + &context_, + /* access_token_fetcher = */ nullptr, + std::move(cup_factory), + std::move(loader_factory), + std::string("fake_api_key"), + /* auth_enabled = */ false, + /* disable_auth_if_no_access_token = */ true}; + request_sender.SendRequest( + GURL("https://www.example.com"), std::string("request"), + mock_response_callback_.Get(), RpcType::GET_ACTIONS); + histogram_tester.ExpectUniqueSample( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::VERIFICATION_DISABLED, 1); +} + +TEST_F(ServiceRequestSenderImplTest, RecordsHttpFailureEventWithCupEnabled) { + base::HistogramTester histogram_tester; + InitCupFeatures(true, true); + auto cup_factory = + std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>(); + auto cup = std::make_unique<NiceMock<autofill_assistant::cup::MockCUP>>(); + auto loader_factory = + std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>(); + auto loader = std::make_unique<NiceMock<MockURLLoader>>(); + auto response_info = CreateResponseInfo(net::HTTP_NOT_FOUND, "Not found"); + EXPECT_CALL(*loader_factory, OnCreateLoader(_, _)) + .WillOnce([&](::network::ResourceRequest* resource_request, + const ::net::NetworkTrafficAnnotationTag& annotation_tag) { + return std::move(loader); + }); + EXPECT_CALL(*loader, AttachStringForUpload(_, _)).Times(1); + EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _)) + .WillOnce(WithArgs<1>([&](auto&& callback) { + std::move(callback).Run( + std::make_unique<std::string>("packed_response")); + })); + EXPECT_CALL(*loader, ResponseInfo) + .WillRepeatedly(Return(response_info.get())); + EXPECT_CALL(mock_response_callback_, Run(net::HTTP_NOT_FOUND, "")); + EXPECT_CALL(*cup_factory, CreateInstance(_)).WillOnce([&]() { + return std::move(cup); + }); + EXPECT_CALL(*cup, PackAndSignRequest("request")).WillOnce([&]() { + return "signed_request"; + }); + + ServiceRequestSenderImpl request_sender{ + &context_, + /* access_token_fetcher = */ nullptr, + std::move(cup_factory), + std::move(loader_factory), + std::string("fake_api_key"), + /* auth_enabled = */ false, + /* disable_auth_if_no_access_token = */ true}; + request_sender.SendRequest( + GURL("https://www.example.com"), std::string("request"), + mock_response_callback_.Get(), autofill_assistant::RpcType::GET_ACTIONS); + + histogram_tester.ExpectBucketCount( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::HTTP_FAILED, 1); +} + +TEST_F(ServiceRequestSenderImplTest, RecordsHttpFailureEventWithCupDisabled) { + base::HistogramTester histogram_tester; + InitCupFeatures(false, false); + auto cup_factory = + std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>(); + auto cup = std::make_unique<NiceMock<autofill_assistant::cup::MockCUP>>(); + auto loader_factory = + std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>(); + auto loader = std::make_unique<NiceMock<MockURLLoader>>(); + auto response_info = CreateResponseInfo(net::HTTP_NOT_FOUND, "Not found"); + EXPECT_CALL(*loader_factory, OnCreateLoader(_, _)) + .WillOnce([&](::network::ResourceRequest* resource_request, + const ::net::NetworkTrafficAnnotationTag& annotation_tag) { + return std::move(loader); + }); + EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _)) + .WillOnce(WithArgs<1>([&](auto&& callback) { + std::move(callback).Run( + std::make_unique<std::string>("packed_response")); + })); + EXPECT_CALL(*loader, ResponseInfo) + .WillRepeatedly(Return(response_info.get())); + EXPECT_CALL(mock_response_callback_, Run(net::HTTP_NOT_FOUND, "")); + EXPECT_CALL(*cup_factory, CreateInstance(_)).WillOnce([&]() { + return std::move(cup); + }); + + ServiceRequestSenderImpl request_sender{ + &context_, + /* access_token_fetcher = */ nullptr, + std::move(cup_factory), + std::move(loader_factory), + std::string("fake_api_key"), + /* auth_enabled = */ false, + /* disable_auth_if_no_access_token = */ true}; + request_sender.SendRequest( + GURL("https://www.example.com"), std::string("request"), + mock_response_callback_.Get(), autofill_assistant::RpcType::GET_ACTIONS); + + histogram_tester.ExpectBucketCount( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::HTTP_FAILED, 1); +} + +TEST_F(ServiceRequestSenderImplTest, + DoesNotRecordCupDisabledEventIfVerificationPerformed) { + base::HistogramTester histogram_tester; + InitCupFeatures(true, true); + auto cup_factory = + std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>(); + auto cup = std::make_unique<NiceMock<autofill_assistant::cup::MockCUP>>(); + auto loader_factory = + std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>(); + auto loader = std::make_unique<NiceMock<MockURLLoader>>(); + auto response_info = CreateResponseInfo(net::HTTP_OK, "OK"); + EXPECT_CALL(*loader_factory, OnCreateLoader(_, _)) + .WillOnce([&](::network::ResourceRequest* resource_request, + const ::net::NetworkTrafficAnnotationTag& annotation_tag) { + return std::move(loader); + }); + EXPECT_CALL(*loader, AttachStringForUpload(_, _)); + EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _)) + .WillOnce(WithArgs<1>([&](auto&& callback) { + std::move(callback).Run( + std::make_unique<std::string>("packed_response")); + })); + EXPECT_CALL(*loader, ResponseInfo) + .WillRepeatedly(Return(response_info.get())); + EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response")); + EXPECT_CALL(*cup_factory, CreateInstance(_)).WillOnce([&]() { + return std::move(cup); + }); + EXPECT_CALL(*cup, PackAndSignRequest("request")).WillOnce([&]() { + return "signed_request"; + }); + EXPECT_CALL(*cup, UnpackResponse("packed_response")).WillOnce([&]() { + return "response"; + }); + + ServiceRequestSenderImpl request_sender{ + &context_, + /* access_token_fetcher = */ nullptr, + std::move(cup_factory), + std::move(loader_factory), + std::string("fake_api_key"), + /* auth_enabled = */ false, + /* disable_auth_if_no_access_token = */ true}; + request_sender.SendRequest( + GURL("https://www.example.com"), std::string("request"), + mock_response_callback_.Get(), autofill_assistant::RpcType::GET_ACTIONS); + + histogram_tester.ExpectUniqueSample( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::SIGNING_DISABLED, 0); + histogram_tester.ExpectUniqueSample( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::HTTP_FAILED, 0); + histogram_tester.ExpectBucketCount( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::VERIFICATION_DISABLED, 0); +} + +TEST_F(ServiceRequestSenderImplTest, DoesNotRecordCupEventForNonSupportedRpcs) { + base::HistogramTester histogram_tester; + InitCupFeatures(true, true); + auto cup_factory = + std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>(); + auto loader_factory = + std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>(); + auto loader = std::make_unique<NiceMock<MockURLLoader>>(); + auto response_info = CreateResponseInfo(net::HTTP_OK, "OK"); + EXPECT_CALL(*loader_factory, OnCreateLoader(_, _)) + .WillOnce([&](::network::ResourceRequest* resource_request, + const ::net::NetworkTrafficAnnotationTag& annotation_tag) { + return std::move(loader); + }); + EXPECT_CALL(*loader, AttachStringForUpload(_, _)); + EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _)) + .WillOnce(WithArgs<1>([&](auto&& callback) { + std::move(callback).Run(std::make_unique<std::string>("response")); + })); + EXPECT_CALL(*loader, ResponseInfo) + .WillRepeatedly(Return(response_info.get())); + EXPECT_CALL(mock_access_token_fetcher_, OnFetchAccessToken) + .WillOnce(RunOnceCallback<0>(true, "access_token")); + + EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response")); + ServiceRequestSenderImpl request_sender{ + &context_, + /* access_token_fetcher = */ &mock_access_token_fetcher_, + std::move(cup_factory), + std::move(loader_factory), + /* api_key = */ std::string(""), + /* auth_enabled = */ true, + /* disable_auth_if_no_access_token = */ true}; + request_sender.SendRequest(GURL("https://www.example.com"), + std::string("request"), + mock_response_callback_.Get(), + autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS); + + histogram_tester.ExpectUniqueSample( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::SIGNING_DISABLED, 0); + histogram_tester.ExpectUniqueSample( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::HTTP_FAILED, 0); + histogram_tester.ExpectBucketCount( + "Android.AutofillAssistant.CupRpcVerificationEvent", + Metrics::CupRpcVerificationEvent::VERIFICATION_DISABLED, 0); +} + // TODO(b/170934170): Add tests for full unit test coverage of // service_request_sender.
diff --git a/components/exo/ui_lock_controller.cc b/components/exo/ui_lock_controller.cc index 1d7383cd..f701c06e 100644 --- a/components/exo/ui_lock_controller.cc +++ b/components/exo/ui_lock_controller.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "ash/bluetooth_devices_observer.h" #include "ash/constants/app_types.h" #include "ash/constants/ash_features.h" #include "ash/public/cpp/keyboard/keyboard_controller.h" @@ -30,6 +31,7 @@ #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/events/devices/device_data_manager.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/gfx/paint_vector_icon.h" @@ -82,6 +84,31 @@ return false; } +// Return true if an external keyboard is attached to the device. +// +// Note: May mistakenly return true when certain non-keyboard devices are +// attached; see crbug/882410, crbug/884096. +// +// Copied from ash/keyboard/virtual_keyboard_controller.cc. +// TODO(cpelling): Refactor to avoid duplicating this logic. +bool HasExternalKeyboard() { + ui::DeviceDataManager* device_data_manager = + ui::DeviceDataManager::GetInstance(); + + ash::BluetoothDevicesObserver bluetooth(base::DoNothing()); + + for (const ui::InputDevice& device : + device_data_manager->GetKeyboardDevices()) { + ui::InputDeviceType type = device.type; + if (type == ui::InputDeviceType::INPUT_DEVICE_USB || + (type == ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH && + bluetooth.IsConnectedBluetoothDevice(device))) { + return true; + } + } + return false; +} + // Creates the separator view between bubble views of modifiers and key. std::unique_ptr<views::View> CreateIconView(const gfx::VectorIcon& icon) { constexpr int kIconSize = 28; @@ -181,13 +208,24 @@ views::Widget::ClosedReason::kUnspecified); } - if (ash::KeyboardController::Get()->AreTopRowKeysFunctionKeys()) { - pointer_capture_notification_ = - CreateEscNotification(window_, IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS, - {IDS_APP_SEARCH_KEY, IDS_APP_OVERVIEW_KEY}); + if (HasExternalKeyboard()) { + if (ash::KeyboardController::Get()->AreTopRowKeysFunctionKeys()) { + pointer_capture_notification_ = + CreateEscNotification(window_, IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS, + {IDS_APP_META_KEY, IDS_APP_F5_KEY}); + } else { + pointer_capture_notification_ = CreateEscNotification( + window_, IDS_PRESS_TO_EXIT_MOUSELOCK, {IDS_APP_F5_KEY}); + } } else { - pointer_capture_notification_ = CreateEscNotification( - window_, IDS_PRESS_TO_EXIT_MOUSELOCK, {IDS_APP_OVERVIEW_KEY}); + if (ash::KeyboardController::Get()->AreTopRowKeysFunctionKeys()) { + pointer_capture_notification_ = + CreateEscNotification(window_, IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS, + {IDS_APP_SEARCH_KEY, IDS_APP_OVERVIEW_KEY}); + } else { + pointer_capture_notification_ = CreateEscNotification( + window_, IDS_PRESS_TO_EXIT_MOUSELOCK, {IDS_APP_OVERVIEW_KEY}); + } } pointer_capture_notification_->Show(); @@ -281,14 +319,26 @@ } if (window_->GetProperty(chromeos::kUseOverviewToExitFullscreen)) { - if (ash::KeyboardController::Get()->AreTopRowKeysFunctionKeys()) { - fullscreen_esc_notification_ = CreateEscNotification( - window_, IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS, - {IDS_APP_SEARCH_KEY, IDS_APP_OVERVIEW_KEY}); + if (HasExternalKeyboard()) { + if (ash::KeyboardController::Get()->AreTopRowKeysFunctionKeys()) { + fullscreen_esc_notification_ = CreateEscNotification( + window_, IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS, + {IDS_APP_META_KEY, IDS_APP_F5_KEY}); + } else { + fullscreen_esc_notification_ = CreateEscNotification( + window_, IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN, + {IDS_APP_F5_KEY}); + } } else { - fullscreen_esc_notification_ = CreateEscNotification( - window_, IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN, - {IDS_APP_OVERVIEW_KEY}); + if (ash::KeyboardController::Get()->AreTopRowKeysFunctionKeys()) { + fullscreen_esc_notification_ = CreateEscNotification( + window_, IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS, + {IDS_APP_SEARCH_KEY, IDS_APP_OVERVIEW_KEY}); + } else { + fullscreen_esc_notification_ = CreateEscNotification( + window_, IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN, + {IDS_APP_OVERVIEW_KEY}); + } } } else { fullscreen_esc_notification_ = CreateEscNotification(
diff --git a/components/history_clusters/core/BUILD.gn b/components/history_clusters/core/BUILD.gn index fc926888..7628fda 100644 --- a/components/history_clusters/core/BUILD.gn +++ b/components/history_clusters/core/BUILD.gn
@@ -33,6 +33,8 @@ "history_clusters_types.h", "history_clusters_util.cc", "history_clusters_util.h", + "on_device_clustering_features.cc", + "on_device_clustering_features.h", "query_clusters_state.cc", "query_clusters_state.h", ] @@ -53,8 +55,6 @@ "noisy_cluster_finalizer.h", "on_device_clustering_backend.cc", "on_device_clustering_backend.h", - "on_device_clustering_features.cc", - "on_device_clustering_features.h", "on_device_clustering_util.cc", "on_device_clustering_util.h", "ranking_cluster_finalizer.cc",
diff --git a/components/history_clusters/core/clusterer.cc b/components/history_clusters/core/clusterer.cc index 2e56a4ac..1bd3a9f8 100644 --- a/components/history_clusters/core/clusterer.cc +++ b/components/history_clusters/core/clusterer.cc
@@ -5,6 +5,7 @@ #include "components/history_clusters/core/clusterer.h" #include "components/history/core/browser/history_types.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/on_device_clustering_features.h" namespace history_clusters { @@ -17,10 +18,10 @@ auto last_visit = cluster.visits.back(); if ((visit.annotated_visit.visit_row.visit_time - last_visit.annotated_visit.visit_row.visit_time) > - features::ClusterNavigationTimeCutoff()) { + GetConfig().cluster_navigation_time_cutoff) { return false; } - if (features::ShouldSplitClustersAtSearchVisits() && + if (GetConfig().split_clusters_at_search_visits && !visit.search_terms.empty()) { // If we want to split the clusters at search visits and we are at a search // visit, only add the visit to the cluster if the last visit was also a
diff --git a/components/history_clusters/core/config.cc b/components/history_clusters/core/config.cc index 8e0f7ce..14e950e5 100644 --- a/components/history_clusters/core/config.cc +++ b/components/history_clusters/core/config.cc
@@ -67,6 +67,130 @@ history_clusters_internals_page = base::FeatureList::IsEnabled(internal::kHistoryClustersInternalsPage); + + cluster_navigation_time_cutoff = + base::Minutes(GetFieldTrialParamByFeatureAsInt( + features::kOnDeviceClustering, "navigation_time_cutoff_minutes", + cluster_navigation_time_cutoff.InMinutes())); + + content_clustering_enabled = GetFieldTrialParamByFeatureAsBool( + features::kOnDeviceClustering, "content_clustering_enabled", + content_clustering_enabled); + + content_clustering_entity_similarity_weight = + GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, + "content_clustering_entity_similarity_weight", + content_clustering_entity_similarity_weight); + + content_clustering_category_similarity_weight = + GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, + "content_clustering_category_similarity_weight", + content_clustering_category_similarity_weight); + + content_clustering_similarity_threshold = GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, "content_clustering_similarity_threshold", + content_clustering_similarity_threshold); + // Ensure that the value is [0.0 and 1.0]. + DCHECK_GE(content_clustering_similarity_threshold, 0.0f); + DCHECK_LE(content_clustering_similarity_threshold, 1.0f); + + content_visibility_threshold = GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, "content_visibility_threshold", 0.7); + // Ensure that the value is [0.0 and 1.0]. + DCHECK_GE(content_visibility_threshold, 0.0f); + DCHECK_LE(content_visibility_threshold, 1.0f); + + std::string + min_page_topics_model_version_to_use_content_visibility_from_value_as_string = + GetFieldTrialParamValueByFeature( + features::kOnDeviceClustering, + "min_page_topics_model_version_for_visibility"); + int64_t value_as_int = 0; + if (!base::StringToInt64( + min_page_topics_model_version_to_use_content_visibility_from_value_as_string, + &value_as_int)) { + min_page_topics_model_version_to_use_content_visibility_from = INT64_MAX; + } else { + min_page_topics_model_version_to_use_content_visibility_from = value_as_int; + } + + should_hide_single_visit_clusters_on_prominent_ui_surfaces = + GetFieldTrialParamByFeatureAsBool( + features::kOnDeviceClustering, + "hide_single_visit_clusters_on_prominent_ui_surfaces", + should_hide_single_visit_clusters_on_prominent_ui_surfaces); + + should_dedupe_similar_visits = GetFieldTrialParamByFeatureAsBool( + features::kOnDeviceClustering, "dedupe_similar_visits", + should_dedupe_similar_visits); + + should_filter_noisy_clusters = GetFieldTrialParamByFeatureAsBool( + features::kOnDeviceClustering, "filter_noisy_clusters", + should_filter_noisy_clusters); + + noisy_cluster_visits_engagement_threshold = + GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, + "noisy_cluster_visit_engagement_threshold", + noisy_cluster_visits_engagement_threshold); + + number_interesting_visits_filter_threshold = GetFieldTrialParamByFeatureAsInt( + features::kOnDeviceClustering, "num_interesting_visits_filter_threshold", + number_interesting_visits_filter_threshold); + + visit_duration_ranking_weight = GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, "visit_duration_ranking_weight", + visit_duration_ranking_weight); + DCHECK_GE(visit_duration_ranking_weight, 0.0f); + + foreground_duration_ranking_weight = GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, "foreground_duration_ranking_weight", + foreground_duration_ranking_weight); + DCHECK_GE(foreground_duration_ranking_weight, 0.0f); + + bookmark_ranking_weight = GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, "bookmark_ranking_weight", + bookmark_ranking_weight); + DCHECK_GE(bookmark_ranking_weight, 0.0f); + + search_results_page_ranking_weight = GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, "search_results_page_ranking_weight", + search_results_page_ranking_weight); + DCHECK_GE(search_results_page_ranking_weight, 0.0f); + + has_page_title_ranking_weight = GetFieldTrialParamByFeatureAsDouble( + features::kOnDeviceClustering, "has_page_title_ranking_weight", + has_page_title_ranking_weight); + DCHECK_GE(has_page_title_ranking_weight, 0.0f); + + content_cluster_on_intersection_similarity = + GetFieldTrialParamByFeatureAsBool( + features::kOnDeviceClustering, + "use_content_clustering_intersection_similarity", + content_cluster_on_intersection_similarity); + + cluster_interaction_threshold = GetFieldTrialParamByFeatureAsInt( + features::kOnDeviceClustering, + "content_clustering_intersection_threshold", + cluster_interaction_threshold); + + should_include_categories_in_keywords = GetFieldTrialParamByFeatureAsBool( + features::kOnDeviceClustering, "include_categories_in_keywords", + should_include_categories_in_keywords); + + should_exclude_keywords_from_noisy_visits = GetFieldTrialParamByFeatureAsBool( + features::kOnDeviceClustering, "exclude_keywords_from_noisy_visits", + should_exclude_keywords_from_noisy_visits); + + clustering_tasks_batch_size = GetFieldTrialParamByFeatureAsInt( + features::kSplitClusteringTasksToSmallerBatches, + "clustering_task_batch_size", clustering_tasks_batch_size); + + split_clusters_at_search_visits = GetFieldTrialParamByFeatureAsBool( + features::kOnDeviceClustering, "split_clusters_at_search_visits", + split_clusters_at_search_visits); } Config::Config(const Config& other) = default;
diff --git a/components/history_clusters/core/config.h b/components/history_clusters/core/config.h index 8e27909..55208e1 100644 --- a/components/history_clusters/core/config.h +++ b/components/history_clusters/core/config.h
@@ -7,6 +7,8 @@ #include <string> +#include "base/time/time.h" + namespace history_clusters { // The default configuration. Always use |GetConfig()| to get the current @@ -83,6 +85,100 @@ // Enables the history clusters internals page. bool history_clusters_internals_page = false; + // Returns the maximum duration between navigations that + // a visit can be considered for the same cluster. + base::TimeDelta cluster_navigation_time_cutoff = base::Minutes(60); + + // Returns whether content clustering is enabled and + // should be performed by the clustering backend. + bool content_clustering_enabled = true; + + // Returns the weight that should be placed on entity similarity for + // determining if two clusters are similar enough to be combined into one. + float content_clustering_entity_similarity_weight = 1.0; + + // Returns the weight that should be placed on category similarity for + // determining if two clusters are similar enough to be combined into one. + float content_clustering_category_similarity_weight = 1.0; + + // Returns the similarity threshold, between 0 and 1, used to determine if + // two clusters are similar enough to be combined into + // a single cluster. + float content_clustering_similarity_threshold = 0.2; + + // Returns the threshold for which we should mark a cluster as being able to + // show on prominent UI surfaces. + float content_visibility_threshold = 0.7; + + // Returns the min page topics model version to honor the visibility score + // for. + int64_t min_page_topics_model_version_to_use_content_visibility_from = + INT64_MAX; + + // Whether to hide single-visit clusters on prominent UI surfaces. + bool should_hide_single_visit_clusters_on_prominent_ui_surfaces = true; + + // Whether to collapse visits within a cluster that will show on the UI in the + // same way. + bool should_dedupe_similar_visits = true; + + // Whether to filter clusters that are noisy from the UI. This will + // heuristically remove clusters that are unlikely to be "interesting". + bool should_filter_noisy_clusters = true; + + // Returns the threshold used to determine if a cluster, and its visits, has + // too high site engagement to be likely useful. + float noisy_cluster_visits_engagement_threshold = 15.0; + + // Returns the number of visits considered interesting, or not noisy, required + // to prevent the cluster from being filtered out (i.e., marked as not visible + // on the zero state UI). + size_t number_interesting_visits_filter_threshold = 1; + + // Returns the weight to use for the visit duration when ranking visits within + // a cluster. Will always be greater than or equal to 0. + float visit_duration_ranking_weight = 1.0; + + // Returns the weight to use for the foreground duration when ranking visits + // within a cluster. Will always be greater than or equal to 0. + float foreground_duration_ranking_weight = 1.5; + + // Returns the weight to use for bookmarked visits when ranking visits within + // a cluster. Will always be greater than or equal to 0. + float bookmark_ranking_weight = 1.0; + + // Returns the weight to use for visits that are search results pages ranking + // visits within a cluster. Will always be greater than or equal to 0. + float search_results_page_ranking_weight = 2.0; + + // Returns the weight to use for visits that have page titles ranking visits + // within a cluster. Will always be greater than or equal to 0. + float has_page_title_ranking_weight = 2.0; + + // Returns true if content clustering should use the intersection similarity + // score. Note, if this is used, the threshold used for clustering by content + // score should be < .5 (see ContentClusteringSimilarityThreshold above) or + // the weightings between entity and category content similarity scores should + // be adjusted. + bool content_cluster_on_intersection_similarity = true; + + // Returns the threshold, in terms of the number of overlapping keywords, to + // use when clustering based on intersection score. + int cluster_interaction_threshold = 2; + + // Whether to include category names in the keywords for a cluster. + bool should_include_categories_in_keywords = true; + + // Whether to exclude keywords from visits that may be considered "noisy" to + // the user (i.e. highly engaged, non-SRP). + bool should_exclude_keywords_from_noisy_visits = false; + + // Returns the default batch size for annotating visits when clustering. + size_t clustering_tasks_batch_size = 250; + + // Whether to split the clusters when a search visit is encountered. + bool split_clusters_at_search_visits = true; + Config(); Config(const Config& other); ~Config();
diff --git a/components/history_clusters/core/content_annotations_cluster_processor.cc b/components/history_clusters/core/content_annotations_cluster_processor.cc index 08f9075..2c681ca3 100644 --- a/components/history_clusters/core/content_annotations_cluster_processor.cc +++ b/components/history_clusters/core/content_annotations_cluster_processor.cc
@@ -7,6 +7,7 @@ #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" #include "base/strings/utf_string_conversions.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/on_device_clustering_features.h" namespace history_clusters { @@ -82,14 +83,14 @@ intersection_size++; } } - return intersection_size >= features::ClusterIntersectionThreshold() ? 1.0 - : 0.0; + return intersection_size >= GetConfig().cluster_interaction_threshold ? 1.0 + : 0.0; } // Returns the similarity score based on the configured similarity metric. float CalculateSimilarityScore(const base::flat_set<std::u16string>& cluster1, const base::flat_set<std::u16string>& cluster2) { - if (features::ContentClusterOnIntersectionSimilarity()) + if (GetConfig().content_cluster_on_intersection_similarity) return CalculateIntersectionSimilarity(cluster1, cluster2); return CalculateJaccardSimilarity(cluster1, cluster2); } @@ -98,19 +99,20 @@ // |entity_similarity| and |category_similarity|. Both |entity_similarity| and // |category_similarity| are expected to be between 0 and 1, inclusive. bool ShouldMergeClusters(float entity_similarity, float category_similarity) { - float max_score = features::ContentClusteringEntitySimilarityWeight() + - features::ContentClusteringEntitySimilarityWeight(); + float max_score = GetConfig().content_clustering_entity_similarity_weight + + GetConfig().content_clustering_category_similarity_weight; if (max_score == 0) return 0.0; float cluster_similarity_score = - (features::ContentClusteringEntitySimilarityWeight() * entity_similarity + - features::ContentClusteringCategorySimilarityWeight() * + (GetConfig().content_clustering_entity_similarity_weight * + entity_similarity + + GetConfig().content_clustering_category_similarity_weight * category_similarity) / max_score; float normalized_similarity_score = cluster_similarity_score > - features::ContentClusteringSimilarityThreshold(); + GetConfig().content_clustering_similarity_threshold; DCHECK(normalized_similarity_score >= 0 && normalized_similarity_score <= 1); return normalized_similarity_score; }
diff --git a/components/history_clusters/core/content_visibility_cluster_finalizer.cc b/components/history_clusters/core/content_visibility_cluster_finalizer.cc index b5bb47a..801cb3a 100644 --- a/components/history_clusters/core/content_visibility_cluster_finalizer.cc +++ b/components/history_clusters/core/content_visibility_cluster_finalizer.cc
@@ -5,6 +5,7 @@ #include "components/history_clusters/core/content_visibility_cluster_finalizer.h" #include "components/history_clusters/core/cluster_metrics_utils.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/on_device_clustering_features.h" #include "components/history_clusters/core/on_device_clustering_util.h" @@ -26,7 +27,7 @@ // visit wasn't evaluated for visibility. continue; } - if (visibility_score < features::ContentVisibilityThreshold()) { + if (visibility_score < GetConfig().content_visibility_threshold) { cluster.should_show_on_prominent_ui_surfaces = false; metrics_recorder.set_was_filtered(true); }
diff --git a/components/history_clusters/core/keyword_cluster_finalizer.cc b/components/history_clusters/core/keyword_cluster_finalizer.cc index 6fead35..2dbcca8 100644 --- a/components/history_clusters/core/keyword_cluster_finalizer.cc +++ b/components/history_clusters/core/keyword_cluster_finalizer.cc
@@ -7,6 +7,7 @@ #include "base/containers/flat_set.h" #include "base/strings/utf_string_conversions.h" #include "components/history/core/browser/history_types.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/on_device_clustering_features.h" #include "components/history_clusters/core/on_device_clustering_util.h" @@ -18,7 +19,7 @@ void KeywordClusterFinalizer::FinalizeCluster(history::Cluster& cluster) { base::flat_set<std::u16string> keywords_set; for (const auto& visit : cluster.visits) { - if (features::ShouldExcludeKeywordsFromNoisyVisits() && + if (GetConfig().should_exclude_keywords_from_noisy_visits && IsNoisyVisit(visit)) { // Do not put keywords if user visits the page a lot and it's not a // search-like visit. @@ -29,7 +30,7 @@ visit.annotated_visit.content_annotations.model_annotations.entities) { keywords_set.insert(base::UTF8ToUTF16(entity.id)); } - if (features::ShouldIncludeCategoriesInKeywords()) { + if (GetConfig().should_include_categories_in_keywords) { for (const auto& category : visit.annotated_visit.content_annotations .model_annotations.categories) { keywords_set.insert(base::UTF8ToUTF16(category.id));
diff --git a/components/history_clusters/core/noisy_cluster_finalizer.cc b/components/history_clusters/core/noisy_cluster_finalizer.cc index a46c2dc..2f6dc0f 100644 --- a/components/history_clusters/core/noisy_cluster_finalizer.cc +++ b/components/history_clusters/core/noisy_cluster_finalizer.cc
@@ -5,6 +5,7 @@ #include "components/history_clusters/core/noisy_cluster_finalizer.h" #include "components/history_clusters/core/cluster_metrics_utils.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/on_device_clustering_features.h" #include "components/history_clusters/core/on_device_clustering_util.h" @@ -22,7 +23,7 @@ interesting_visit_cnt += 1 + visit.duplicate_visits.size(); } if (interesting_visit_cnt >= - features::NumberInterestingVisitsFilterThreshold()) { + GetConfig().number_interesting_visits_filter_threshold) { return; } }
diff --git a/components/history_clusters/core/on_device_clustering_backend.cc b/components/history_clusters/core/on_device_clustering_backend.cc index dff99bb..dac27de 100644 --- a/components/history_clusters/core/on_device_clustering_backend.cc +++ b/components/history_clusters/core/on_device_clustering_backend.cc
@@ -18,6 +18,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/timer/elapsed_timer.h" #include "components/history/core/browser/history_types.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/content_annotations_cluster_processor.h" #include "components/history_clusters/core/content_visibility_cluster_finalizer.h" #include "components/history_clusters/core/features.h" @@ -223,7 +224,7 @@ // Entries in |annotated_visits| that have index greater than or equal to // |index_stop_batch_processing| should not be processed in this task loop. size_t index_stop_batch_processing = - index_to_process + features::GetClusteringTasksBatchSize(); + index_to_process + GetConfig().clustering_tasks_batch_size; // Process all entries in one go in certain cases. e.g., if // |clustering_request_source| is user blocking. @@ -322,7 +323,8 @@ } if (visit.content_annotations.model_annotations .page_topics_model_version < - features::GetMinPageTopicsModelVersionToUseContentVisibilityFrom()) { + GetConfig() + .min_page_topics_model_version_to_use_content_visibility_from) { // Override the visibility score to be as if the model was not evaluated // if the version of the model being used does not exceed the min // version that was not a random model. @@ -418,14 +420,14 @@ // The cluster finalizers to be run. std::vector<std::unique_ptr<ClusterFinalizer>> cluster_finalizers; - if (features::ContentClusteringEnabled()) { + if (GetConfig().content_clustering_enabled) { cluster_processors.push_back( std::make_unique<ContentAnnotationsClusterProcessor>()); } cluster_finalizers.push_back( std::make_unique<ContentVisibilityClusterFinalizer>()); - if (features::ShouldDedupeSimilarVisits()) { + if (GetConfig().should_dedupe_similar_visits) { cluster_finalizers.push_back( std::make_unique<SimilarVisitDeduperClusterFinalizer>()); } else { @@ -434,13 +436,13 @@ std::make_unique<UrlDeduperClusterFinalizer>()); } cluster_finalizers.push_back(std::make_unique<RankingClusterFinalizer>()); - if (features::ShouldHideSingleVisitClustersOnProminentUISurfaces()) { + if (GetConfig().should_hide_single_visit_clusters_on_prominent_ui_surfaces) { cluster_finalizers.push_back( std::make_unique<SingleVisitClusterFinalizer>()); } // Add feature to turn on/off site engagement score filter. if (engagement_score_provider_is_valid && - features::ShouldFilterNoisyClusters()) { + GetConfig().should_filter_noisy_clusters) { cluster_finalizers.push_back(std::make_unique<NoisyClusterFinalizer>()); } cluster_finalizers.push_back(std::make_unique<KeywordClusterFinalizer>());
diff --git a/components/history_clusters/core/on_device_clustering_backend_unittest.cc b/components/history_clusters/core/on_device_clustering_backend_unittest.cc index 693b017..c4c7290 100644 --- a/components/history_clusters/core/on_device_clustering_backend_unittest.cc +++ b/components/history_clusters/core/on_device_clustering_backend_unittest.cc
@@ -9,6 +9,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "components/history_clusters/core/clustering_test_utils.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/on_device_clustering_features.h" #include "components/optimization_guide/core/entity_metadata_provider.h" #include "components/search_engines/template_url_service.h" @@ -90,14 +91,13 @@ class OnDeviceClusteringWithoutContentBackendTest : public ::testing::Test { public: OnDeviceClusteringWithoutContentBackendTest() { - scoped_feature_list_.InitAndEnableFeatureWithParameters( - features::kOnDeviceClustering, - {{"content_clustering_enabled", "false"}, - {"dedupe_similar_visits", "false"}, - {"min_page_topics_model_version_for_visibility", "125"}, - {"include_categories_in_keywords", "true"}, - {"exclude_keywords_from_noisy_visits", "false"}, - {"split_clusters_at_search_visits", "false"}}); + config_.content_clustering_enabled = false; + config_.should_dedupe_similar_visits = false; + config_.min_page_topics_model_version_to_use_content_visibility_from = 125; + config_.should_include_categories_in_keywords = true; + config_.should_exclude_keywords_from_noisy_visits = false; + config_.split_clusters_at_search_visits = false; + SetConfigForTesting(config_); } void SetUp() override { @@ -139,7 +139,7 @@ base::test::TaskEnvironment task_environment_; private: - base::test::ScopedFeatureList scoped_feature_list_; + Config config_; TestSiteEngagementScoreProvider test_site_engagement_provider_; }; @@ -397,16 +397,15 @@ : public OnDeviceClusteringWithoutContentBackendTest { public: OnDeviceClusteringWithContentBackendTest() { - scoped_feature_list_.InitAndEnableFeatureWithParameters( - features::kOnDeviceClustering, - {{"content_clustering_enabled", "true"}, - {"dedupe_similar_visits", "false"}, - {"include_categories_in_keywords", "true"}, - {"exclude_keywords_from_noisy_visits", "false"}}); + config_.content_clustering_enabled = true; + config_.should_dedupe_similar_visits = false; + config_.should_include_categories_in_keywords = true; + config_.should_exclude_keywords_from_noisy_visits = false; + SetConfigForTesting(config_); } private: - base::test::ScopedFeatureList scoped_feature_list_; + Config config_; }; TEST_F(OnDeviceClusteringWithContentBackendTest, ClusterOnContent) { @@ -646,24 +645,19 @@ public ::testing::WithParamInterface<bool> { public: EngagementCacheOnDeviceClusteringWithoutContentBackendTest() { - const base::FieldTrialParams on_device_clustering_feature_parameters = { - {"content_clustering_enabled", "false"}, - {"dedupe_similar_visits", "false"}, - {"min_page_topics_model_version_for_visibility", "125"}, - {"include_categories_in_keywords", "true"}, - {"exclude_keywords_from_noisy_visits", "false"}}; + config_.content_clustering_enabled = false; + config_.should_dedupe_similar_visits = false; + config_.min_page_topics_model_version_to_use_content_visibility_from = 125; + config_.should_include_categories_in_keywords = true; + config_.should_exclude_keywords_from_noisy_visits = false; + SetConfigForTesting(config_); if (GetParam()) { - scoped_feature_list_.InitWithFeaturesAndParameters( - {{features::kOnDeviceClustering, - on_device_clustering_feature_parameters}, - {{features::kUseEngagementScoreCache}, {}}}, - {}); + scoped_feature_list_.InitAndEnableFeature( + features::kUseEngagementScoreCache); } else { - scoped_feature_list_.InitWithFeaturesAndParameters( - {{features::kOnDeviceClustering, - on_device_clustering_feature_parameters}}, - {features::kUseEngagementScoreCache}); + scoped_feature_list_.InitAndDisableFeature( + features::kUseEngagementScoreCache); } } @@ -671,6 +665,7 @@ private: base::test::ScopedFeatureList scoped_feature_list_; + Config config_; }; TEST_P(EngagementCacheOnDeviceClusteringWithoutContentBackendTest, @@ -722,15 +717,13 @@ std::tuple<bool, ClusteringRequestSource>> { public: BatchedClusteringTaskOnDeviceClusteringWithoutContentBackendTest() { - const base::FieldTrialParams on_device_clustering_feature_parameters = { - {"content_clustering_enabled", "false"}, - {"dedupe_similar_visits", "false"}, - {"min_page_topics_model_version_for_visibility", "125"}, - {"include_categories_in_keywords", "true"}, - {"exclude_keywords_from_noisy_visits", "false"}}; - - base::test::ScopedFeatureList::FeatureAndParams on_device_clustering( - features::kOnDeviceClustering, on_device_clustering_feature_parameters); + config_.content_clustering_enabled = false; + config_.should_dedupe_similar_visits = false; + config_.min_page_topics_model_version_to_use_content_visibility_from = 125; + config_.should_include_categories_in_keywords = true; + config_.should_exclude_keywords_from_noisy_visits = false; + config_.clustering_tasks_batch_size = 1; + SetConfigForTesting(config_); // expected_size_of_batches is 1. const base::FieldTrialParams batched_clustering_feature_parameters = { @@ -740,13 +733,11 @@ batched_clustering_feature_parameters); if (IsBatchingEnabled()) { - scoped_feature_list_.InitWithFeaturesAndParameters( - {{on_device_clustering, batched_clustering}}, {}); + scoped_feature_list_.InitWithFeaturesAndParameters({{batched_clustering}}, + {}); } else { - scoped_feature_list_.InitWithFeaturesAndParameters( - {{features::kOnDeviceClustering, - on_device_clustering_feature_parameters}}, - {features::kSplitClusteringTasksToSmallerBatches}); + scoped_feature_list_.InitAndDisableFeature( + features::kSplitClusteringTasksToSmallerBatches); } } @@ -758,6 +749,7 @@ private: base::test::ScopedFeatureList scoped_feature_list_; + Config config_; }; TEST_P(BatchedClusteringTaskOnDeviceClusteringWithoutContentBackendTest,
diff --git a/components/history_clusters/core/on_device_clustering_features.cc b/components/history_clusters/core/on_device_clustering_features.cc index ac827e3..d99cea6d 100644 --- a/components/history_clusters/core/on_device_clustering_features.cc +++ b/components/history_clusters/core/on_device_clustering_features.cc
@@ -24,140 +24,5 @@ "JourneysSplitClusteringTasksToSmallerBatches", base::FEATURE_DISABLED_BY_DEFAULT}; -base::TimeDelta ClusterNavigationTimeCutoff() { - return base::Minutes(GetFieldTrialParamByFeatureAsInt( - kOnDeviceClustering, "navigation_time_cutoff_minutes", 60)); -} - -bool ContentClusteringEnabled() { - return GetFieldTrialParamByFeatureAsBool(kOnDeviceClustering, - "content_clustering_enabled", true); -} - -float ContentClusteringEntitySimilarityWeight() { - return GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "content_clustering_entity_similarity_weight", 1.0); -} - -float ContentClusteringCategorySimilarityWeight() { - return GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "content_clustering_category_similarity_weight", - 1.0); -} - -float ContentClusteringSimilarityThreshold() { - float threshold = GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "content_clustering_similarity_threshold", 0.2); - // Ensure that the value is [0.0 and 1.0]. - return std::max(0.0f, std::min(1.0f, threshold)); -} - -float ContentVisibilityThreshold() { - float threshold = GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "content_visibility_threshold", 0.7); - // Ensure that the value is [0.0 and 1.0]. - return std::max(0.0f, std::min(1.0f, threshold)); -} - -int64_t GetMinPageTopicsModelVersionToUseContentVisibilityFrom() { - std::string value_as_string = GetFieldTrialParamValueByFeature( - kOnDeviceClustering, "min_page_topics_model_version_for_visibility"); - int64_t value_as_int = 0; - if (!base::StringToInt64(value_as_string, &value_as_int)) { - value_as_int = INT64_MAX; - } - return value_as_int; -} - -bool ShouldHideSingleVisitClustersOnProminentUISurfaces() { - return GetFieldTrialParamByFeatureAsBool( - kOnDeviceClustering, - "hide_single_visit_clusters_on_prominent_ui_surfaces", true); -} - -bool ShouldDedupeSimilarVisits() { - return GetFieldTrialParamByFeatureAsBool(kOnDeviceClustering, - "dedupe_similar_visits", true); -} - -bool ShouldFilterNoisyClusters() { - return GetFieldTrialParamByFeatureAsBool(kOnDeviceClustering, - "filter_noisy_clusters", true); -} - -float NoisyClusterVisitEngagementThreshold() { - float threshold = GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "noisy_cluster_visit_engagement_threshold", 15.0); - return threshold; -} - -size_t NumberInterestingVisitsFilterThreshold() { - int threshold = GetFieldTrialParamByFeatureAsInt( - kOnDeviceClustering, "num_interesting_visits_filter_threshold", 1); - return threshold; -} - -float VisitDurationRankingWeight() { - float weight = GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "visit_duration_ranking_weight", 1.0); - return std::max(0.f, weight); -} - -float ForegroundDurationRankingWeight() { - float weight = GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "foreground_duration_ranking_weight", 1.5); - return std::max(0.f, weight); -} - -float BookmarkRankingWeight() { - float weight = GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "bookmark_ranking_weight", 1.0); - return std::max(0.f, weight); -} - -float SearchResultsPageRankingWeight() { - float weight = GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "search_results_page_ranking_weight", 2.0); - return std::max(0.f, weight); -} - -float HasPageTitleRankingWeight() { - float weight = GetFieldTrialParamByFeatureAsDouble( - kOnDeviceClustering, "has_page_title_ranking_weight", 2.0); - return std::max(0.f, weight); -} - -bool ContentClusterOnIntersectionSimilarity() { - return GetFieldTrialParamByFeatureAsBool( - kOnDeviceClustering, "use_content_clustering_intersection_similarity", - true); -} - -int ClusterIntersectionThreshold() { - return GetFieldTrialParamByFeatureAsInt( - kOnDeviceClustering, "content_clustering_intersection_threshold", 2); -} - -bool ShouldIncludeCategoriesInKeywords() { - return GetFieldTrialParamByFeatureAsBool( - kOnDeviceClustering, "include_categories_in_keywords", true); -} - -bool ShouldExcludeKeywordsFromNoisyVisits() { - return GetFieldTrialParamByFeatureAsBool( - kOnDeviceClustering, "exclude_keywords_from_noisy_visits", false); -} - -size_t GetClusteringTasksBatchSize() { - return GetFieldTrialParamByFeatureAsInt( - features::kSplitClusteringTasksToSmallerBatches, - "clustering_task_batch_size", 250); -} - -bool ShouldSplitClustersAtSearchVisits() { - return GetFieldTrialParamByFeatureAsBool( - kOnDeviceClustering, "split_clusters_at_search_visits", true); -} - } // namespace features } // namespace history_clusters
diff --git a/components/history_clusters/core/on_device_clustering_features.h b/components/history_clusters/core/on_device_clustering_features.h index 4e0f676..4d70481 100644 --- a/components/history_clusters/core/on_device_clustering_features.h +++ b/components/history_clusters/core/on_device_clustering_features.h
@@ -23,98 +23,6 @@ // Splits clustering task into smaller batches. extern const base::Feature kSplitClusteringTasksToSmallerBatches; -// Returns the maximum duration between navigations that -// a visit can be considered for the same cluster. -base::TimeDelta ClusterNavigationTimeCutoff(); - -// Returns whether content clustering is enabled and -// should be performed by the clustering backend. -bool ContentClusteringEnabled(); - -// Returns the weight that should be placed on entity similarity for determining -// if two clusters are similar enough to be combined into one. -float ContentClusteringEntitySimilarityWeight(); - -// Returns the weight that should be placed on category similarity for -// determining if two clusters are similar enough to be combined into one. -float ContentClusteringCategorySimilarityWeight(); - -// Returns the similarity threshold, between 0 and 1, used to determine if -// two clusters are similar enough to be combined into -// a single cluster. -float ContentClusteringSimilarityThreshold(); - -// Returns the threshold for which we should mark a cluster as being able to -// show on prominent UI surfaces. -float ContentVisibilityThreshold(); - -// Returns the min page topics model version to honor the visibility score for. -int64_t GetMinPageTopicsModelVersionToUseContentVisibilityFrom(); - -// Whether to hide single-visit clusters on prominent UI surfaces. -bool ShouldHideSingleVisitClustersOnProminentUISurfaces(); - -// Whether to collapse visits within a cluster that will show on the UI in the -// same way. -bool ShouldDedupeSimilarVisits(); - -// Whether to filter clusters that are noisy from the UI. This will -// heuristically remove clusters that are unlikely to be "interesting". -bool ShouldFilterNoisyClusters(); - -// Returns the threshold used to determine if a cluster, and its visits, has -// too high site engagement to be likely useful. -float NoisyClusterVisitEngagementThreshold(); - -// Returns the number of visits considered interesting, or not noisy, required -// to prevent the cluster from being filtered out (i.e., marked as not visible -// on the zero state UI). -size_t NumberInterestingVisitsFilterThreshold(); - -// Returns the weight to use for the visit duration when ranking visits within a -// cluster. Will always be greater than or equal to 0. -float VisitDurationRankingWeight(); - -// Returns the weight to use for the foreground duration when ranking visits -// within a cluster. Will always be greater than or equal to 0. -float ForegroundDurationRankingWeight(); - -// Returns the weight to use for bookmarked visits when ranking visits within -// a cluster. Will always be greater than or equal to 0. -float BookmarkRankingWeight(); - -// Returns the weight to use for visits that are search results pages ranking -// visits within a cluster. Will always be greater than or equal to 0. -float SearchResultsPageRankingWeight(); - -// Returns the weight to use for visits that have page titles ranking visits -// within a cluster. Will always be greater than or equal to 0. -float HasPageTitleRankingWeight(); - -// Returns true if content clustering should use the intersection similarity -// score. Note, if this is used, the threshold used for clustering by content -// score should be < .5 (see ContentClusteringSimilarityThreshold above) or the -// weightings between entity and category content similarity scores should be -// adjusted. -bool ContentClusterOnIntersectionSimilarity(); - -// Returns the threshold, in terms of the number of overlapping keywords, to use -// when clustering based on intersection score. -int ClusterIntersectionThreshold(); - -// Whether to include category names in the keywords for a cluster. -bool ShouldIncludeCategoriesInKeywords(); - -// Whether to exclude keywords from visits that may be considered "noisy" to the -// user (i.e. highly engaged, non-SRP). -bool ShouldExcludeKeywordsFromNoisyVisits(); - -// Returns the default batch size for annotating visits when clustering. -size_t GetClusteringTasksBatchSize(); - -// Whether to split the clusters when a search visit is encountered. -bool ShouldSplitClustersAtSearchVisits(); - } // namespace features } // namespace history_clusters
diff --git a/components/history_clusters/core/on_device_clustering_util.cc b/components/history_clusters/core/on_device_clustering_util.cc index 296b069..430d1c0 100644 --- a/components/history_clusters/core/on_device_clustering_util.cc +++ b/components/history_clusters/core/on_device_clustering_util.cc
@@ -5,6 +5,7 @@ #include "components/history_clusters/core/on_device_clustering_util.h" #include "base/containers/contains.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/history_clusters_util.h" #include "components/history_clusters/core/on_device_clustering_features.h" @@ -100,7 +101,7 @@ bool IsNoisyVisit(const history::ClusterVisit& visit) { return visit.engagement_score > - features::NoisyClusterVisitEngagementThreshold() && + GetConfig().noisy_cluster_visits_engagement_threshold && visit.search_terms.empty(); }
diff --git a/components/history_clusters/core/ranking_cluster_finalizer.h b/components/history_clusters/core/ranking_cluster_finalizer.h index 844dada..9886b463 100644 --- a/components/history_clusters/core/ranking_cluster_finalizer.h +++ b/components/history_clusters/core/ranking_cluster_finalizer.h
@@ -6,6 +6,7 @@ #define COMPONENTS_HISTORY_CLUSTERS_CORE_RANKING_CLUSTER_FINALIZER_H_ #include "components/history_clusters/core/cluster_finalizer.h" +#include "components/history_clusters/core/config.h" #include "components/history_clusters/core/on_device_clustering_features.h" namespace history_clusters { @@ -21,12 +22,12 @@ // weightings between each. Note, this score is not between [0, 1] as // normalization will consider all visits within a cluster. float GetTotalScore() const { - return visit_duration_score_ * features::VisitDurationRankingWeight() + + return visit_duration_score_ * GetConfig().visit_duration_ranking_weight + foreground_duration_score_ * - features::ForegroundDurationRankingWeight() + - bookmark_score_ * features::BookmarkRankingWeight() + - srp_score_ * features::SearchResultsPageRankingWeight() + - page_title_score_ * features::HasPageTitleRankingWeight(); + GetConfig().foreground_duration_ranking_weight + + bookmark_score_ * GetConfig().bookmark_ranking_weight + + srp_score_ * GetConfig().search_results_page_ranking_weight + + page_title_score_ * GetConfig().has_page_title_ranking_weight; } void set_visit_duration_score(float score) { visit_duration_score_ = score; }
diff --git a/components/management_strings.grdp b/components/management_strings.grdp index dcb1d1a..40475e08 100644 --- a/components/management_strings.grdp +++ b/components/management_strings.grdp
@@ -123,7 +123,7 @@ Networking information such as addresses, interface configuration, and connection quality </message> <message name="IDS_MANAGEMENT_REPORT_DEVICE_HARDWARE_DATA" desc="Message stating that administrators see device hardware status."> - Device statistics such as CPU/RAM usage and hardware specifications + Device hardware specifications and statistics such as CPU/RAM utilization history </message> <message name="IDS_MANAGEMENT_REPORT_DEVICE_CRASH_REPORTS" desc="Message stating that administrators see the numbers and causes of the crashes that occurred on the device recently."> Numbers and causes of the crashes that occurred recently
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_HARDWARE_DATA.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_HARDWARE_DATA.png.sha1 index c3a44931..d2ff3a24 100644 --- a/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_HARDWARE_DATA.png.sha1 +++ b/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_HARDWARE_DATA.png.sha1
@@ -1 +1 @@ -b47e4323ab339253b680f0391d0270c69d3a325a \ No newline at end of file +10d7a0019187823ef7ccbae4b35250d1d37f4d19 \ No newline at end of file
diff --git a/components/metrics/content/content_stability_metrics_provider.h b/components/metrics/content/content_stability_metrics_provider.h index c58db13..f6069b5 100644 --- a/components/metrics/content/content_stability_metrics_provider.h +++ b/components/metrics/content/content_stability_metrics_provider.h
@@ -53,7 +53,7 @@ const ContentStabilityMetricsProvider&) = delete; ~ContentStabilityMetricsProvider() override; - // MetricsDataProvider: + // MetricsProvider: void OnRecordingEnabled() override; void OnRecordingDisabled() override; void ProvideStabilityMetrics(
diff --git a/components/metrics/drive_metrics_provider.h b/components/metrics/drive_metrics_provider.h index b30b0d6..5182fa0 100644 --- a/components/metrics/drive_metrics_provider.h +++ b/components/metrics/drive_metrics_provider.h
@@ -30,7 +30,7 @@ ~DriveMetricsProvider() override; - // metrics::MetricsDataProvider: + // metrics::MetricsProvider: void AsyncInit(base::OnceClosure done_callback) override; void ProvideSystemProfileMetrics( metrics::SystemProfileProto* system_profile_proto) override;
diff --git a/components/metrics/drive_metrics_provider_linux.cc b/components/metrics/drive_metrics_provider_linux.cc index 149405e..1beb726 100644 --- a/components/metrics/drive_metrics_provider_linux.cc +++ b/components/metrics/drive_metrics_provider_linux.cc
@@ -16,7 +16,6 @@ #include "build/build_config.h" namespace metrics { - namespace { // See http://www.kernel.org/doc/Documentation/devices.txt for more info.
diff --git a/components/metrics/file_metrics_provider.cc b/components/metrics/file_metrics_provider.cc index 59b5bc90..b0bf0bb 100644 --- a/components/metrics/file_metrics_provider.cc +++ b/components/metrics/file_metrics_provider.cc
@@ -37,7 +37,6 @@ #include "components/prefs/scoped_user_pref_update.h" namespace metrics { - namespace { // These structures provide values used to define how files are opened and
diff --git a/components/metrics/metrics_data_validation.cc b/components/metrics/metrics_data_validation.cc index d88752a..9920235 100644 --- a/components/metrics/metrics_data_validation.cc +++ b/components/metrics/metrics_data_validation.cc
@@ -9,7 +9,6 @@ #include "base/numerics/safe_conversions.h" namespace metrics { - namespace internal { // Used to assess the reliability of field trial data by injecting different @@ -52,4 +51,4 @@ base::Milliseconds(internal::kAdditiveFactor.Get()); } -} // namespace metrics \ No newline at end of file +} // namespace metrics
diff --git a/components/metrics/metrics_log_manager_unittest.cc b/components/metrics/metrics_log_manager_unittest.cc index a8b7986..89fa298 100644 --- a/components/metrics/metrics_log_manager_unittest.cc +++ b/components/metrics/metrics_log_manager_unittest.cc
@@ -20,7 +20,6 @@ #include "testing/gtest/include/gtest/gtest.h" namespace metrics { - namespace { class MetricsLogManagerTest : public testing::Test {
diff --git a/components/metrics/metrics_log_store_unittest.cc b/components/metrics/metrics_log_store_unittest.cc index 929c592..58f957ba 100644 --- a/components/metrics/metrics_log_store_unittest.cc +++ b/components/metrics/metrics_log_store_unittest.cc
@@ -12,7 +12,6 @@ #include "testing/gtest/include/gtest/gtest.h" namespace metrics { - namespace { const char kTestPrefName[] = "TestPref";
diff --git a/components/metrics/metrics_log_unittest.cc b/components/metrics/metrics_log_unittest.cc index 3f967cc..3305efd 100644 --- a/components/metrics/metrics_log_unittest.cc +++ b/components/metrics/metrics_log_unittest.cc
@@ -47,7 +47,6 @@ #endif namespace metrics { - namespace { const char kClientId[] = "bogus client ID";
diff --git a/components/metrics/metrics_scheduler.cc b/components/metrics/metrics_scheduler.cc index c3043f4..203fdad 100644 --- a/components/metrics/metrics_scheduler.cc +++ b/components/metrics/metrics_scheduler.cc
@@ -7,7 +7,6 @@ #include "build/build_config.h" namespace metrics { - namespace { // The delay, in seconds, after startup before sending the first log message.
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc index 185efee..8167d74 100644 --- a/components/metrics/metrics_service.cc +++ b/components/metrics/metrics_service.cc
@@ -167,7 +167,6 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) namespace metrics { - namespace { // Used to mark histogram samples as reported so that they are not included in
diff --git a/components/metrics/metrics_service_client.cc b/components/metrics/metrics_service_client.cc index f3fc1d5..ca6ed99 100644 --- a/components/metrics/metrics_service_client.cc +++ b/components/metrics/metrics_service_client.cc
@@ -16,7 +16,6 @@ #include "components/metrics/url_constants.h" namespace metrics { - namespace { // The minimum time in seconds between consecutive metrics report uploads.
diff --git a/components/metrics/metrics_service_client.h b/components/metrics/metrics_service_client.h index 63ef4017..68ad78e 100644 --- a/components/metrics/metrics_service_client.h +++ b/components/metrics/metrics_service_client.h
@@ -17,10 +17,6 @@ #include "third_party/metrics_proto/system_profile.pb.h" #include "url/gurl.h" -namespace base { -class FilePath; -} - namespace ukm { class UkmService; } @@ -129,9 +125,6 @@ // Called when loading state changed, e.g. start/stop loading. virtual void LoadingStateChanged(bool is_loading) {} - // Called on plugin loading errors. - virtual void OnPluginLoadingError(const base::FilePath& plugin_path) {} - // Called on renderer crashes in some embedders (e.g., those that do not use // //content and thus do not have //content's notification system available // as a mechanism for observing renderer crashes).
diff --git a/components/metrics/metrics_service_client_unittest.cc b/components/metrics/metrics_service_client_unittest.cc index d74fe31..d536bf5 100644 --- a/components/metrics/metrics_service_client_unittest.cc +++ b/components/metrics/metrics_service_client_unittest.cc
@@ -12,7 +12,6 @@ #include "testing/gtest/include/gtest/gtest.h" namespace metrics { - namespace { class MetricsServiceClientTest : public testing::Test {
diff --git a/components/metrics/metrics_upload_scheduler.cc b/components/metrics/metrics_upload_scheduler.cc index af64b42..ae9bb37 100644 --- a/components/metrics/metrics_upload_scheduler.cc +++ b/components/metrics/metrics_upload_scheduler.cc
@@ -14,7 +14,6 @@ #include "components/metrics/metrics_scheduler.h" namespace metrics { - namespace { // When uploading metrics to the server fails, we progressively wait longer and
diff --git a/components/metrics/single_sample_metrics.cc b/components/metrics/single_sample_metrics.cc index 9a262b4..954a77b0 100644 --- a/components/metrics/single_sample_metrics.cc +++ b/components/metrics/single_sample_metrics.cc
@@ -14,7 +14,6 @@ #include "mojo/public/cpp/bindings/self_owned_receiver.h" namespace metrics { - namespace { class MojoSingleSampleMetric : public mojom::SingleSampleMetric {
diff --git a/components/metrics/stability_metrics_helper.cc b/components/metrics/stability_metrics_helper.cc index 9e7ebae..ba03f870 100644 --- a/components/metrics/stability_metrics_helper.cc +++ b/components/metrics/stability_metrics_helper.cc
@@ -34,7 +34,6 @@ #endif namespace metrics { - namespace { enum RendererType {
diff --git a/components/metrics/stability_metrics_helper.h b/components/metrics/stability_metrics_helper.h index 66409d0..9f503577 100644 --- a/components/metrics/stability_metrics_helper.h +++ b/components/metrics/stability_metrics_helper.h
@@ -33,7 +33,7 @@ kLaunch = 15, kBrowserCrash = 16, // kIncompleteShutdown = 17, // Removed due to disuse and correctness issues. - kPluginCrash = 22, + // kPluginCrash = 22, // Removed due to plugin deprecation. kRendererFailedLaunch = 24, kExtensionRendererFailedLaunch = 25, kRendererLaunch = 26,
diff --git a/components/metrics_services_manager/metrics_services_manager.cc b/components/metrics_services_manager/metrics_services_manager.cc index eacceae..f010042d 100644 --- a/components/metrics_services_manager/metrics_services_manager.cc +++ b/components/metrics_services_manager/metrics_services_manager.cc
@@ -68,11 +68,6 @@ GetMetricsServiceClient()->LoadingStateChanged(is_loading); } -void MetricsServicesManager::OnPluginLoadingError( - const base::FilePath& plugin_path) { - GetMetricsServiceClient()->OnPluginLoadingError(plugin_path); -} - std::unique_ptr<const base::FieldTrial::EntropyProvider> MetricsServicesManager::CreateEntropyProviderForTesting() { return client_->GetMetricsStateManager()->CreateDefaultEntropyProvider();
diff --git a/components/metrics_services_manager/metrics_services_manager.h b/components/metrics_services_manager/metrics_services_manager.h index 8dab6fe..614df4c 100644 --- a/components/metrics_services_manager/metrics_services_manager.h +++ b/components/metrics_services_manager/metrics_services_manager.h
@@ -10,10 +10,6 @@ #include "base/metrics/field_trial.h" #include "base/threading/thread_checker.h" -namespace base { -class FilePath; -} - namespace metrics { class MetricsService; class MetricsServiceClient; @@ -66,9 +62,6 @@ // Called when loading state changed. void LoadingStateChanged(bool is_loading); - // Should be called when a plugin loading error occurs. - void OnPluginLoadingError(const base::FilePath& plugin_path); - // Update the managed services when permissions for uploading metrics change. void UpdateUploadPermissions(bool may_upload);
diff --git a/components/omnibox/browser/omnibox_metrics_provider.h b/components/omnibox/browser/omnibox_metrics_provider.h index ef5ff5a..840c3bc2 100644 --- a/components/omnibox/browser/omnibox_metrics_provider.h +++ b/components/omnibox/browser/omnibox_metrics_provider.h
@@ -21,7 +21,7 @@ OmniboxMetricsProvider(const OmniboxMetricsProvider&) = delete; OmniboxMetricsProvider& operator=(const OmniboxMetricsProvider&) = delete; - // metrics::MetricsDataProvider: + // metrics::MetricsProvider: void OnRecordingEnabled() override; void OnRecordingDisabled() override; void ProvideCurrentSessionData(
diff --git a/components/policy/core/common/policy_loader_common.cc b/components/policy/core/common/policy_loader_common.cc index e3852af..75bba5b 100644 --- a/components/policy/core/common/policy_loader_common.cc +++ b/components/policy/core/common/policy_loader_common.cc
@@ -56,7 +56,6 @@ key::kRestoreOnStartupURLs, key::kSafeBrowsingForTrustedSourcesEnabled, key::kSafeBrowsingEnabled, - key::kSafeBrowsingWhitelistDomains, key::kSafeBrowsingAllowlistDomains, };
diff --git a/components/policy/core/common/policy_service_impl.cc b/components/policy/core/common/policy_service_impl.cc index 8284c8b..ca435f5 100644 --- a/components/policy/core/common/policy_service_impl.cc +++ b/components/policy/core/common/policy_service_impl.cc
@@ -57,42 +57,22 @@ base::flat_set<std::string> policy_lists_to_merge = policy::ValueToStringSet(merge_list); const std::vector<std::pair<const char*, const char*>> renamed_policies = {{ - {policy::key::kSafeBrowsingWhitelistDomains, - policy::key::kSafeBrowsingAllowlistDomains}, - {policy::key::kSpellcheckLanguageBlacklist, - policy::key::kSpellcheckLanguageBlocklist}, {policy::key::kURLBlacklist, policy::key::kURLBlocklist}, {policy::key::kURLWhitelist, policy::key::kURLAllowlist}, #if !BUILDFLAG(IS_ANDROID) {policy::key::kAutoplayWhitelist, policy::key::kAutoplayAllowlist}, -#endif // !BUILDFLAG(IS_ANDROID) -#if BUILDFLAG(ENABLE_EXTENSIONS) - {policy::key::kExtensionInstallBlacklist, - policy::key::kExtensionInstallBlocklist}, - {policy::key::kExtensionInstallWhitelist, - policy::key::kExtensionInstallAllowlist}, - {policy::key::kNativeMessagingBlacklist, - policy::key::kNativeMessagingBlocklist}, - {policy::key::kNativeMessagingWhitelist, - policy::key::kNativeMessagingAllowlist}, -#endif // BUILDFLAG(ENABLE_EXTENSIONS) +#endif // !BUILDFLAG(OS_ANDROID) #if BUILDFLAG(IS_CHROMEOS) {policy::key::kAttestationExtensionWhitelist, policy::key::kAttestationExtensionAllowlist}, #endif // BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_CHROMEOS_ASH) - {policy::key::kExternalPrintServersWhitelist, - policy::key::kExternalPrintServersAllowlist}, {policy::key::kNativePrintersBulkBlacklist, policy::key::kPrintersBulkBlocklist}, {policy::key::kNativePrintersBulkWhitelist, policy::key::kPrintersBulkAllowlist}, - {policy::key::kPerAppTimeLimitsWhitelist, - policy::key::kPerAppTimeLimitsAllowlist}, {policy::key::kQuickUnlockModeWhitelist, policy::key::kQuickUnlockModeAllowlist}, - {policy::key::kNoteTakingAppsLockScreenWhitelist, - policy::key::kNoteTakingAppsLockScreenAllowlist}, #if defined(USE_CUPS) {policy::key::kPrintingAPIExtensionsWhitelist, policy::key::kPrintingAPIExtensionsAllowlist}, @@ -326,10 +306,9 @@ update_task_ptr_factory_.GetWeakPtr())); } -void PolicyServiceImpl::NotifyNamespaceUpdated( - const PolicyNamespace& ns, - const PolicyMap& previous, - const PolicyMap& current) { +void PolicyServiceImpl::NotifyNamespaceUpdated(const PolicyNamespace& ns, + const PolicyMap& previous, + const PolicyMap& current) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto iterator = observers_.find(ns.domain); if (iterator != observers_.end()) {
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index b5b3d8c..e381581 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -5180,7 +5180,7 @@ 'owners': ['file://components/policy/resources/OWNERS', 'rsorokin@chromium.org'], 'type': 'string', 'schema': { 'type': 'string' }, - 'supported_on': ['chrome.*:9-','android:46-','webview_android:49-','chrome_os:62-'], + 'supported_on': ['chrome.*:9-100','android:46-100','webview_android:49-100','chrome_os:62-100'], 'deprecated': True, 'features': { 'dynamic_refresh': False, @@ -5223,7 +5223,7 @@ 'owners': ['file://components/policy/resources/OWNERS', 'rsorokin@chromium.org'], 'type': 'string', 'schema': { 'type': 'string' }, - 'supported_on': ['chrome.*:9-','android:46-','chrome_os:62-'], + 'supported_on': ['chrome.*:9-100','android:46-100','chrome_os:62-100'], 'deprecated': True, 'features': { 'dynamic_refresh': False, @@ -5423,7 +5423,7 @@ 'type': 'array', 'items': { 'type': 'string' }, }, - 'supported_on': ['chrome.*:8-', 'chrome_os:11-'], + 'supported_on': ['chrome.*:8-100', 'chrome_os:11-100'], 'features': { 'dynamic_refresh': True, 'per_profile': True, @@ -5497,7 +5497,7 @@ 'type': 'array', 'items': { 'type': 'string' }, }, - 'supported_on': ['chrome.*:8-', 'chrome_os:11-'], + 'supported_on': ['chrome.*:8-100', 'chrome_os:11-100'], 'features': { 'dynamic_refresh': True, 'per_profile': True, @@ -8639,7 +8639,7 @@ 'type': 'array', 'items': { 'type': 'string' }, }, - 'supported_on': ['chrome.*:34-'], + 'supported_on': ['chrome.*:34-100'], 'deprecated': True, 'features': { 'dynamic_refresh': True, @@ -8692,7 +8692,7 @@ 'type': 'array', 'items': { 'type': 'string' }, }, - 'supported_on': ['chrome.*:34-'], + 'supported_on': ['chrome.*:34-100'], 'deprecated': True, 'features': { 'dynamic_refresh': True, @@ -19592,7 +19592,7 @@ 'items': { 'type': 'string' }, }, 'supported_on': [ - 'chrome_os:61-', + 'chrome_os:61-100', ], 'features': { 'dynamic_refresh': True, @@ -20402,7 +20402,7 @@ 'items': { 'type': 'string' } }, # Spell checking is provided by macOS, so can't be controlled on Mac. - 'supported_on': ['chrome.win:75-', 'chrome.linux:75-', 'chrome_os:75-'], + 'supported_on': ['chrome.win:75-100', 'chrome.linux:75-100', 'chrome_os:75-100'], 'deprecated': True, 'features': { 'can_be_recommended': False, @@ -20998,7 +20998,7 @@ 'type': 'array', 'items': { 'type': 'string' }, }, - 'supported_on': ['chrome.*:68-', 'chrome_os:68-'], + 'supported_on': ['chrome.*:68-100', 'chrome_os:68-100'], 'deprecated': True, 'features': { 'dynamic_refresh': True, @@ -25524,7 +25524,7 @@ { 'name': 'ExternalPrintServersWhitelist', 'owners': ['file://chromeos/printing/OWNERS', 'luum@chromium.org'], - 'supported_on': ['chrome_os:79-'], + 'supported_on': ['chrome_os:79-100'], 'id': 631, 'features': { 'dynamic_refresh': True, @@ -26400,7 +26400,7 @@ }, 'caption': '''Per-App Time Limits Whitelist''', 'tags': [], - 'supported_on': ['chrome_os: 80-'], + 'supported_on': ['chrome_os: 80-100'], 'desc': '''This policy specifies which applications and URLs should be whitelisted for per-app usage restrictions. The configured whitelist are applied to the apps installed on <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> for the given user with per-app time limits. The configured whitelist can only be applied to child user accounts and take effect when <ph name="PER_APP_TIME_LIMITS_POLICY_NAME">PerAppTimeLimits</ph> policy is set.
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc index 175c592..560ec91 100644 --- a/components/search/ntp_features.cc +++ b/components/search/ntp_features.cc
@@ -183,6 +183,18 @@ const base::FeatureParam<int> kNtpChromeCartModuleDiscountConsentNtpVariation{ &commerce::kDiscountConsentV2, kNtpChromeCartModuleDiscountConsentNtpVariationParam, 0}; +const char kNtpChromeCartModuleDiscountConsentReshowTimeParam[] = + "discount-consent-ntp-reshow-time"; +const base::FeatureParam<base::TimeDelta> + kNtpChromeCartModuleDiscountConsentReshowTime{ + &commerce::kDiscountConsentV2, + kNtpChromeCartModuleDiscountConsentReshowTimeParam, base::Days(28)}; +const char kNtpChromeCartModuleDiscountConsentMaxDismissalCountParam[] = + "discount-consent-ntp-max-dismiss-count"; +const base::FeatureParam<int> + kNtpChromeCartModuleDiscountConsentMaxDismissalCount{ + &commerce::kDiscountConsentV2, + kNtpChromeCartModuleDiscountConsentMaxDismissalCountParam, 1}; // String change variation params. const char kNtpChromeCartModuleDiscountConsentStringChangeContentParam[] = @@ -207,7 +219,7 @@ kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContent{ &commerce::kDiscountConsentV2, kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContentParam, - true}; + false}; const char kNtpChromeCartModuleDiscountConsentNtpStepOneStaticContentParam[] = "step-one-static-content"; const base::FeatureParam<std::string>
diff --git a/components/search/ntp_features.h b/components/search/ntp_features.h index ae4ffd25..8c82d1e 100644 --- a/components/search/ntp_features.h +++ b/components/search/ntp_features.h
@@ -124,6 +124,14 @@ extern const char kNtpChromeCartModuleDiscountConsentNtpVariationParam[]; extern const base::FeatureParam<int> kNtpChromeCartModuleDiscountConsentNtpVariation; +// The time interval, after the last dismissal, before reshowing the consent. +extern const char kNtpChromeCartModuleDiscountConsentReshowTimeParam[]; +extern const base::FeatureParam<base::TimeDelta> + kNtpChromeCartModuleDiscountConsentReshowTime; +// The max number of dismisses allowed. +extern const char kNtpChromeCartModuleDiscountConsentMaxDismissalCountParam[]; +extern const base::FeatureParam<int> + kNtpChromeCartModuleDiscountConsentMaxDismissalCount; // String change variation params. This string is replacing the content string // of the v1 consent.
diff --git a/components/signin/internal/identity_manager/BUILD.gn b/components/signin/internal/identity_manager/BUILD.gn index 08370fd..2933649 100644 --- a/components/signin/internal/identity_manager/BUILD.gn +++ b/components/signin/internal/identity_manager/BUILD.gn
@@ -13,6 +13,8 @@ "account_capabilities_constants.h", "account_capabilities_fetcher.cc", "account_capabilities_fetcher.h", + "account_capabilities_fetcher_gaia.cc", + "account_capabilities_fetcher_gaia.h", "account_fetcher_service.cc", "account_fetcher_service.h", "account_info_fetcher.cc",
diff --git a/components/signin/internal/identity_manager/account_capabilities_fetcher.cc b/components/signin/internal/identity_manager/account_capabilities_fetcher.cc index 61eeaf4..6734df35 100644 --- a/components/signin/internal/identity_manager/account_capabilities_fetcher.cc +++ b/components/signin/internal/identity_manager/account_capabilities_fetcher.cc
@@ -4,139 +4,18 @@ #include "components/signin/internal/identity_manager/account_capabilities_fetcher.h" -#include "base/metrics/histogram_functions.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "components/signin/internal/identity_manager/account_capabilities_constants.h" -#include "components/signin/internal/identity_manager/account_fetcher_service.h" -#include "components/signin/internal/identity_manager/account_info_util.h" -#include "components/signin/internal/identity_manager/profile_oauth2_token_service.h" -#include "google_apis/gaia/gaia_constants.h" -#include "google_apis/gaia/google_service_auth_error.h" -#include "google_apis/gaia/oauth2_access_token_consumer.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" - AccountCapabilitiesFetcher::AccountCapabilitiesFetcher( - ProfileOAuth2TokenService* token_service, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - AccountFetcherService* service, - const CoreAccountId& account_id) - : OAuth2AccessTokenManager::Consumer("account_capabilities_fetcher"), - token_service_(token_service), - url_loader_factory_(std::move(url_loader_factory)), - service_(service), - account_id_(account_id) { - TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("AccountFetcherService", - "AccountCapabilitiesFetcher", this, - "account_id", account_id.ToString()); + const CoreAccountId& account_id, + OnCompleteCallback on_complete_callback) + : account_id_(account_id), + on_complete_callback_(std::move(on_complete_callback)) { + DCHECK(on_complete_callback_); } -AccountCapabilitiesFetcher::~AccountCapabilitiesFetcher() { - TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService", - "AccountCapabilitiesFetcher", this); - RecordFetchResultAndDuration(FetchResult::kCancelled); -} +AccountCapabilitiesFetcher::~AccountCapabilitiesFetcher() = default; -void AccountCapabilitiesFetcher::Start() { - TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("AccountFetcherService", "GetAccessToken", - this); - fetch_start_time_ = base::TimeTicks::Now(); - OAuth2AccessTokenManager::ScopeSet scopes; - scopes.insert(GaiaConstants::kAccountCapabilitiesOAuth2Scope); - login_token_request_ = - token_service_->StartRequest(account_id_, scopes, this); -} - -void AccountCapabilitiesFetcher::OnGetTokenSuccess( - const OAuth2AccessTokenManager::Request* request, - const OAuth2AccessTokenConsumer::TokenResponse& token_response) { - TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService", "GetAccessToken", - this); - TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("AccountFetcherService", - "GetAccountCapabilities", this); - DCHECK_EQ(request, login_token_request_.get()); - login_token_request_.reset(); - - gaia_oauth_client_ = - std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory_); - const int kMaxRetries = 3; - gaia_oauth_client_->GetAccountCapabilities( - token_response.access_token, - AccountCapabilities::GetSupportedAccountCapabilityNames(), kMaxRetries, - this); -} - -void AccountCapabilitiesFetcher::OnGetTokenFailure( - const OAuth2AccessTokenManager::Request* request, - const GoogleServiceAuthError& error) { - TRACE_EVENT_NESTABLE_ASYNC_END1("AccountFetcherService", "GetAccessToken", - this, "error", error.ToString()); - VLOG(1) << "OnGetTokenFailure: " << error.ToString(); - DCHECK_EQ(request, login_token_request_.get()); - login_token_request_.reset(); - RecordFetchResultAndDuration(FetchResult::kGetTokenFailure); - service_->OnAccountCapabilitiesFetchFailure(account_id_); -} - -void AccountCapabilitiesFetcher::OnGetAccountCapabilitiesResponse( - std::unique_ptr<base::Value> account_capabilities) { - TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService", - "GetAccountCapabilities", this); - absl::optional<AccountCapabilities> parsed_capabilities = - AccountCapabilitiesFromValue(*account_capabilities); - if (!parsed_capabilities) { - VLOG(1) << "Failed to parse account capabilities for " << account_id_ - << ". Response body: " << account_capabilities->DebugString(); - RecordFetchResultAndDuration(FetchResult::kParseResponseFailure); - service_->OnAccountCapabilitiesFetchFailure(account_id_); - return; - } - - RecordFetchResultAndDuration(FetchResult::kSuccess); - service_->OnAccountCapabilitiesFetchSuccess(account_id_, - parsed_capabilities.value()); -} - -void AccountCapabilitiesFetcher::OnOAuthError() { - TRACE_EVENT_NESTABLE_ASYNC_END1("AccountFetcherService", - "GetAccountCapabilities", this, "error", - "OAuthError"); - VLOG(1) << "OnOAuthError"; - RecordFetchResultAndDuration(FetchResult::kOAuthError); - service_->OnAccountCapabilitiesFetchFailure(account_id_); -} - -void AccountCapabilitiesFetcher::OnNetworkError(int response_code) { - TRACE_EVENT_NESTABLE_ASYNC_END2( - "AccountFetcherService", "GetAccountCapabilities", this, "error", - "NetworkError", "response_code", response_code); - VLOG(1) << "OnNetworkError " << response_code; - RecordFetchResultAndDuration(FetchResult::kNetworkError); - service_->OnAccountCapabilitiesFetchFailure(account_id_); -} - -void AccountCapabilitiesFetcher::RecordFetchResultAndDuration( - FetchResult result) { - if (fetch_histograms_recorded_) { - // Record histograms only once. - return; - } - fetch_histograms_recorded_ = true; - - base::UmaHistogramEnumeration("Signin.AccountCapabilities.FetchResult", - result); - - if (fetch_start_time_.is_null()) { - // Cannot record duration for a fetch that hasn't started. - DCHECK_EQ(result, FetchResult::kCancelled); - return; - } - base::TimeDelta duration = base::TimeTicks::Now() - fetch_start_time_; - if (result == FetchResult::kSuccess) { - base::UmaHistogramMediumTimes( - "Signin.AccountCapabilities.FetchDuration.Success", duration); - } else { - base::UmaHistogramMediumTimes( - "Signin.AccountCapabilities.FetchDuration.Failure", duration); - } +void AccountCapabilitiesFetcher::CompleteFetchAndMaybeDestroySelf( + const absl::optional<AccountCapabilities>& capabilities) { + DCHECK(on_complete_callback_); + std::move(on_complete_callback_).Run(account_id_, capabilities); }
diff --git a/components/signin/internal/identity_manager/account_capabilities_fetcher.h b/components/signin/internal/identity_manager/account_capabilities_fetcher.h index b03aa32..661cfe33 100644 --- a/components/signin/internal/identity_manager/account_capabilities_fetcher.h +++ b/components/signin/internal/identity_manager/account_capabilities_fetcher.h
@@ -5,77 +5,40 @@ #ifndef COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_H_ #define COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_H_ -#include "base/memory/raw_ptr.h" -#include "base/memory/scoped_refptr.h" -#include "base/time/time.h" +#include "base/callback.h" +#include "components/signin/public/identity_manager/account_capabilities.h" #include "google_apis/gaia/core_account_id.h" -#include "google_apis/gaia/gaia_oauth_client.h" -#include "google_apis/gaia/oauth2_access_token_manager.h" +#include "third_party/abseil-cpp/absl/types/optional.h" -namespace network { -class SharedURLLoaderFactory; -} - -class AccountFetcherService; -class ProfileOAuth2TokenService; -class GoogleServiceAuthError; - -class AccountCapabilitiesFetcher : public OAuth2AccessTokenManager::Consumer, - public gaia::GaiaOAuthClient::Delegate { +class AccountCapabilitiesFetcher { public: - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. - enum class FetchResult { - kSuccess = 0, - kGetTokenFailure = 1, - kParseResponseFailure = 2, - kOAuthError = 3, - kNetworkError = 4, - kCancelled = 5, - kMaxValue = kCancelled - }; + using OnCompleteCallback = + base::OnceCallback<void(const CoreAccountId&, + const absl::optional<AccountCapabilities>&)>; - AccountCapabilitiesFetcher( - ProfileOAuth2TokenService* token_service, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - AccountFetcherService* service, - const CoreAccountId& account_id); - ~AccountCapabilitiesFetcher() override; + explicit AccountCapabilitiesFetcher(const CoreAccountId& account_id, + OnCompleteCallback on_complete_callback); + virtual ~AccountCapabilitiesFetcher(); AccountCapabilitiesFetcher(const AccountCapabilitiesFetcher&) = delete; AccountCapabilitiesFetcher& operator=(const AccountCapabilitiesFetcher&) = delete; // Start fetching account capabilities. - void Start(); + virtual void Start() = 0; - // OAuth2AccessTokenManager::Consumer: - void OnGetTokenSuccess( - const OAuth2AccessTokenManager::Request* request, - const OAuth2AccessTokenConsumer::TokenResponse& token_response) override; - void OnGetTokenFailure(const OAuth2AccessTokenManager::Request* request, - const GoogleServiceAuthError& error) override; + protected: + const CoreAccountId& account_id() { return account_id_; } - // gaia::GaiaOAuthClient::Delegate: - void OnGetAccountCapabilitiesResponse( - std::unique_ptr<base::Value> account_capabilities) override; - void OnOAuthError() override; - void OnNetworkError(int response_code) override; + // Completes the fetch by calling `on_complete_callback_`. Must be called no + // more than once per object lifetime. + // `this` may be destroyed after calling this function. + void CompleteFetchAndMaybeDestroySelf( + const absl::optional<AccountCapabilities>& capabilities); private: - void RecordFetchResultAndDuration(FetchResult result); - - raw_ptr<ProfileOAuth2TokenService> token_service_; - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - raw_ptr<AccountFetcherService> service_; const CoreAccountId account_id_; - - std::unique_ptr<OAuth2AccessTokenManager::Request> login_token_request_; - std::unique_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_; - - // Used for metrics: - base::TimeTicks fetch_start_time_; - bool fetch_histograms_recorded_ = false; + OnCompleteCallback on_complete_callback_; }; #endif // COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_H_
diff --git a/components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.cc b/components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.cc new file mode 100644 index 0000000..f923938 --- /dev/null +++ b/components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.cc
@@ -0,0 +1,138 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.h" + +#include "base/metrics/histogram_functions.h" +#include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "components/signin/internal/identity_manager/account_capabilities_constants.h" +#include "components/signin/internal/identity_manager/account_info_util.h" +#include "components/signin/internal/identity_manager/profile_oauth2_token_service.h" +#include "google_apis/gaia/gaia_constants.h" +#include "google_apis/gaia/google_service_auth_error.h" +#include "google_apis/gaia/oauth2_access_token_consumer.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +AccountCapabilitiesFetcherGaia::AccountCapabilitiesFetcherGaia( + ProfileOAuth2TokenService* token_service, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const CoreAccountId& account_id, + AccountCapabilitiesFetcher::OnCompleteCallback on_complete_callback) + : AccountCapabilitiesFetcher(account_id, std::move(on_complete_callback)), + OAuth2AccessTokenManager::Consumer("account_capabilities_fetcher"), + token_service_(token_service), + url_loader_factory_(std::move(url_loader_factory)) { + TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("AccountFetcherService", + "AccountCapabilitiesFetcherGaia", this, + "account_id", account_id.ToString()); +} + +AccountCapabilitiesFetcherGaia::~AccountCapabilitiesFetcherGaia() { + TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService", + "AccountCapabilitiesFetcherGaia", this); + RecordFetchResultAndDuration(FetchResult::kCancelled); +} + +void AccountCapabilitiesFetcherGaia::Start() { + TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("AccountFetcherService", "GetAccessToken", + this); + fetch_start_time_ = base::TimeTicks::Now(); + OAuth2AccessTokenManager::ScopeSet scopes; + scopes.insert(GaiaConstants::kAccountCapabilitiesOAuth2Scope); + login_token_request_ = + token_service_->StartRequest(account_id(), scopes, this); +} + +void AccountCapabilitiesFetcherGaia::OnGetTokenSuccess( + const OAuth2AccessTokenManager::Request* request, + const OAuth2AccessTokenConsumer::TokenResponse& token_response) { + TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService", "GetAccessToken", + this); + TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("AccountFetcherService", + "GetAccountCapabilities", this); + DCHECK_EQ(request, login_token_request_.get()); + login_token_request_.reset(); + + gaia_oauth_client_ = + std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory_); + const int kMaxRetries = 3; + gaia_oauth_client_->GetAccountCapabilities( + token_response.access_token, + {kCanOfferExtendedChromeSyncPromosCapabilityName}, kMaxRetries, this); +} + +void AccountCapabilitiesFetcherGaia::OnGetTokenFailure( + const OAuth2AccessTokenManager::Request* request, + const GoogleServiceAuthError& error) { + TRACE_EVENT_NESTABLE_ASYNC_END1("AccountFetcherService", "GetAccessToken", + this, "error", error.ToString()); + VLOG(1) << "OnGetTokenFailure: " << error.ToString(); + DCHECK_EQ(request, login_token_request_.get()); + login_token_request_.reset(); + RecordFetchResultAndDuration(FetchResult::kGetTokenFailure); + CompleteFetchAndMaybeDestroySelf(absl::nullopt); +} + +void AccountCapabilitiesFetcherGaia::OnGetAccountCapabilitiesResponse( + std::unique_ptr<base::Value> account_capabilities) { + TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService", + "GetAccountCapabilities", this); + absl::optional<AccountCapabilities> parsed_capabilities = + AccountCapabilitiesFromValue(*account_capabilities); + FetchResult result = FetchResult::kSuccess; + if (!parsed_capabilities) { + VLOG(1) << "Failed to parse account capabilities for " << account_id() + << ". Response body: " << account_capabilities->DebugString(); + result = FetchResult::kParseResponseFailure; + } + + RecordFetchResultAndDuration(result); + CompleteFetchAndMaybeDestroySelf(parsed_capabilities); +} + +void AccountCapabilitiesFetcherGaia::OnOAuthError() { + TRACE_EVENT_NESTABLE_ASYNC_END1("AccountFetcherService", + "GetAccountCapabilities", this, "error", + "OAuthError"); + VLOG(1) << "OnOAuthError"; + RecordFetchResultAndDuration(FetchResult::kOAuthError); + CompleteFetchAndMaybeDestroySelf(absl::nullopt); +} + +void AccountCapabilitiesFetcherGaia::OnNetworkError(int response_code) { + TRACE_EVENT_NESTABLE_ASYNC_END2( + "AccountFetcherService", "GetAccountCapabilities", this, "error", + "NetworkError", "response_code", response_code); + VLOG(1) << "OnNetworkError " << response_code; + RecordFetchResultAndDuration(FetchResult::kNetworkError); + CompleteFetchAndMaybeDestroySelf(absl::nullopt); +} + +void AccountCapabilitiesFetcherGaia::RecordFetchResultAndDuration( + FetchResult result) { + if (fetch_histograms_recorded_) { + // Record histograms only once. + return; + } + fetch_histograms_recorded_ = true; + + base::UmaHistogramEnumeration("Signin.AccountCapabilities.FetchResult", + result); + + if (fetch_start_time_.is_null()) { + // Cannot record duration for a fetch that hasn't started. + DCHECK_EQ(result, FetchResult::kCancelled); + return; + } + base::TimeDelta duration = base::TimeTicks::Now() - fetch_start_time_; + if (result == FetchResult::kSuccess) { + base::UmaHistogramMediumTimes( + "Signin.AccountCapabilities.FetchDuration.Success", duration); + } else { + base::UmaHistogramMediumTimes( + "Signin.AccountCapabilities.FetchDuration.Failure", duration); + } +}
diff --git a/components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.h b/components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.h new file mode 100644 index 0000000..9054ff6 --- /dev/null +++ b/components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.h
@@ -0,0 +1,82 @@ +// 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 COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_GAIA_H_ +#define COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_GAIA_H_ + +#include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" +#include "base/time/time.h" +#include "components/signin/internal/identity_manager/account_capabilities_fetcher.h" +#include "google_apis/gaia/core_account_id.h" +#include "google_apis/gaia/gaia_oauth_client.h" +#include "google_apis/gaia/oauth2_access_token_manager.h" + +namespace network { +class SharedURLLoaderFactory; +} + +class ProfileOAuth2TokenService; +class GoogleServiceAuthError; + +class AccountCapabilitiesFetcherGaia + : public AccountCapabilitiesFetcher, + public OAuth2AccessTokenManager::Consumer, + public gaia::GaiaOAuthClient::Delegate { + public: + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + enum class FetchResult { + kSuccess = 0, + kGetTokenFailure = 1, + kParseResponseFailure = 2, + kOAuthError = 3, + kNetworkError = 4, + kCancelled = 5, + kMaxValue = kCancelled + }; + + AccountCapabilitiesFetcherGaia( + ProfileOAuth2TokenService* token_service, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const CoreAccountId& account_id, + AccountCapabilitiesFetcher::OnCompleteCallback on_complete_callback); + ~AccountCapabilitiesFetcherGaia() override; + + AccountCapabilitiesFetcherGaia(const AccountCapabilitiesFetcherGaia&) = + delete; + AccountCapabilitiesFetcherGaia& operator=( + const AccountCapabilitiesFetcherGaia&) = delete; + + // AccountCapabilitiesFetcher: + void Start() override; + + // OAuth2AccessTokenManager::Consumer: + void OnGetTokenSuccess( + const OAuth2AccessTokenManager::Request* request, + const OAuth2AccessTokenConsumer::TokenResponse& token_response) override; + void OnGetTokenFailure(const OAuth2AccessTokenManager::Request* request, + const GoogleServiceAuthError& error) override; + + // gaia::GaiaOAuthClient::Delegate: + void OnGetAccountCapabilitiesResponse( + std::unique_ptr<base::Value> account_capabilities) override; + void OnOAuthError() override; + void OnNetworkError(int response_code) override; + + private: + void RecordFetchResultAndDuration(FetchResult result); + + raw_ptr<ProfileOAuth2TokenService> token_service_; + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + + std::unique_ptr<OAuth2AccessTokenManager::Request> login_token_request_; + std::unique_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_; + + // Used for metrics: + base::TimeTicks fetch_start_time_; + bool fetch_histograms_recorded_ = false; +}; + +#endif // COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_GAIA_H_
diff --git a/components/signin/internal/identity_manager/account_fetcher_service.cc b/components/signin/internal/identity_manager/account_fetcher_service.cc index daab73e..11dd8df 100644 --- a/components/signin/internal/identity_manager/account_fetcher_service.cc +++ b/components/signin/internal/identity_manager/account_fetcher_service.cc
@@ -20,6 +20,7 @@ #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/signin/internal/identity_manager/account_capabilities_fetcher.h" +#include "components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.h" #include "components/signin/internal/identity_manager/account_info_fetcher.h" #include "components/signin/internal/identity_manager/account_tracker_service.h" #include "components/signin/internal/identity_manager/profile_oauth2_token_service.h" @@ -259,9 +260,11 @@ std::unique_ptr<AccountCapabilitiesFetcher>& request = account_capabilities_requests_[account_id]; if (!request) { - request = std::make_unique<AccountCapabilitiesFetcher>( - token_service_, signin_client_->GetURLLoaderFactory(), this, - account_id); + request = std::make_unique<AccountCapabilitiesFetcherGaia>( + token_service_, signin_client_->GetURLLoaderFactory(), account_id, + base::BindOnce( + &AccountFetcherService::OnAccountCapabilitiesFetchComplete, + base::Unretained(this))); request->Start(); } } @@ -383,17 +386,13 @@ user_info_requests_.erase(account_id); } -void AccountFetcherService::OnAccountCapabilitiesFetchSuccess( +void AccountFetcherService::OnAccountCapabilitiesFetchComplete( const CoreAccountId& account_id, - const AccountCapabilities& account_capabilities) { - account_tracker_service_->SetAccountCapabilities(account_id, - account_capabilities); - account_capabilities_requests_.erase(account_id); -} - -void AccountFetcherService::OnAccountCapabilitiesFetchFailure( - const CoreAccountId& account_id) { - VLOG(1) << "Failed to get AccountCapabilities for " << account_id; + const absl::optional<AccountCapabilities>& account_capabilities) { + if (account_capabilities.has_value()) { + account_tracker_service_->SetAccountCapabilities(account_id, + *account_capabilities); + } // |account_id| is owned by the request. Cannot be used after this line. account_capabilities_requests_.erase(account_id); }
diff --git a/components/signin/internal/identity_manager/account_fetcher_service.h b/components/signin/internal/identity_manager/account_fetcher_service.h index ac05e5f..be2d230f 100644 --- a/components/signin/internal/identity_manager/account_fetcher_service.h +++ b/components/signin/internal/identity_manager/account_fetcher_service.h
@@ -20,6 +20,7 @@ #include "build/build_config.h" #include "components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h" #include "components/signin/public/base/persistent_repeating_timer.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class AccountCapabilities; class AccountCapabilitiesFetcher; @@ -117,7 +118,6 @@ private: friend class AccountInfoFetcher; - friend class AccountCapabilitiesFetcher; void RefreshAllAccountInfo(bool only_fetch_if_invalid); @@ -154,10 +154,9 @@ void OnUserInfoFetchFailure(const CoreAccountId& account_id); // Called by AccountCapabilitiesFetcher. - void OnAccountCapabilitiesFetchSuccess( + void OnAccountCapabilitiesFetchComplete( const CoreAccountId& account_id, - const AccountCapabilities& account_capabilities); - void OnAccountCapabilitiesFetchFailure(const CoreAccountId& account_id); + const absl::optional<AccountCapabilities>& account_capabilities); image_fetcher::ImageFetcherImpl* GetOrCreateImageFetcher();
diff --git a/components/signin/internal/identity_manager/account_tracker_service_unittest.cc b/components/signin/internal/identity_manager/account_tracker_service_unittest.cc index e13add3..6ba0371 100644 --- a/components/signin/internal/identity_manager/account_tracker_service_unittest.cc +++ b/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
@@ -22,6 +22,7 @@ #include "components/prefs/testing_pref_service.h" #include "components/signin/internal/identity_manager/account_capabilities_constants.h" #include "components/signin/internal/identity_manager/account_capabilities_fetcher.h" +#include "components/signin/internal/identity_manager/account_capabilities_fetcher_gaia.h" #include "components/signin/internal/identity_manager/account_fetcher_service.h" #include "components/signin/internal/identity_manager/account_tracker_service.h" #include "components/signin/internal/identity_manager/fake_profile_oauth2_token_service.h" @@ -619,9 +620,9 @@ 1); tester.ExpectTotalCount("Signin.AccountCapabilities.FetchDuration.Failure", 0); - tester.ExpectUniqueSample("Signin.AccountCapabilities.FetchResult", - AccountCapabilitiesFetcher::FetchResult::kSuccess, - 1); + tester.ExpectUniqueSample( + "Signin.AccountCapabilities.FetchResult", + AccountCapabilitiesFetcherGaia::FetchResult::kSuccess, 1); } TEST_F(AccountTrackerServiceTest, TokenAvailable_AccountCapabilitiesFailed) { @@ -645,7 +646,7 @@ 1); tester.ExpectUniqueSample( "Signin.AccountCapabilities.FetchResult", - AccountCapabilitiesFetcher::FetchResult::kOAuthError, 1); + AccountCapabilitiesFetcherGaia::FetchResult::kOAuthError, 1); } TEST_F(AccountTrackerServiceTest, @@ -668,7 +669,7 @@ 1); tester.ExpectUniqueSample( "Signin.AccountCapabilities.FetchResult", - AccountCapabilitiesFetcher::FetchResult::kGetTokenFailure, 1); + AccountCapabilitiesFetcherGaia::FetchResult::kGetTokenFailure, 1); } TEST_F(AccountTrackerServiceTest, TokenAvailable_AccountCapabilitiesCancelled) { @@ -691,9 +692,9 @@ 0); tester.ExpectTotalCount("Signin.AccountCapabilities.FetchDuration.Failure", 1); - tester.ExpectUniqueSample("Signin.AccountCapabilities.FetchResult", - AccountCapabilitiesFetcher::FetchResult::kCancelled, - 1); + tester.ExpectUniqueSample( + "Signin.AccountCapabilities.FetchResult", + AccountCapabilitiesFetcherGaia::FetchResult::kCancelled, 1); } TEST_F(AccountTrackerServiceTest,
diff --git a/components/signin/public/identity_manager/account_capabilities.cc b/components/signin/public/identity_manager/account_capabilities.cc index ef47e7f..1fe703d1 100644 --- a/components/signin/public/identity_manager/account_capabilities.cc +++ b/components/signin/public/identity_manager/account_capabilities.cc
@@ -22,8 +22,8 @@ // static const std::vector<std::string>& AccountCapabilities::GetSupportedAccountCapabilityNames() { - static base::NoDestructor<std::vector<std::string>> kCapabilityNames( - {kCanOfferExtendedChromeSyncPromosCapabilityName}); + static base::NoDestructor<std::vector<std::string>> kCapabilityNames{ + {kCanOfferExtendedChromeSyncPromosCapabilityName}}; return *kCapabilityNames; }
diff --git a/components/spellcheck/common/spellcheck_common.cc b/components/spellcheck/common/spellcheck_common.cc index 3ea09e9..5a8f6b1 100644 --- a/components/spellcheck/common/spellcheck_common.cc +++ b/components/spellcheck/common/spellcheck_common.cc
@@ -135,18 +135,18 @@ {"sh", "-4-0"}, {"sr", "-4-0"}, - // January 2020: Update en-* and fa-IR dictionaries from upstream. - {"en-AU", "-9-0"}, - {"en-CA", "-9-0"}, - {"en-GB", "-9-0"}, - {"en-US", "-9-0"}, + // January 2020: Update fa-IR dictionaries from upstream. {"fa-IR", "-9-0"}, // March 2020: Update uk-UA dictionary from upstream. {"uk-UA", "-4-0"}, - // June 2020: Add the en-GB-oxendict dictionary. - {"en-GB-oxendict", "-9-0"}, + // March 2022: Update en-* dictionaries from upstream. + {"en-AU", "-10-0"}, + {"en-CA", "-10-0"}, + {"en-GB", "-10-0"}, + {"en-GB-oxendict", "-10-0"}, + {"en-US", "-10-0"}, }; // Generate the bdict file name using default version string or special
diff --git a/components/viz/common/hit_test/aggregated_hit_test_region.h b/components/viz/common/hit_test/aggregated_hit_test_region.h index 222ab14..6134698 100644 --- a/components/viz/common/hit_test/aggregated_hit_test_region.h +++ b/components/viz/common/hit_test/aggregated_hit_test_region.h
@@ -15,10 +15,6 @@ namespace viz { -namespace mojom { -class AggregatedHitTestRegionDataView; -} - // A AggregatedHitTestRegion element with child_count of kEndOfList indicates // the last element and end of the list. constexpr int32_t kEndOfList = -1; @@ -44,7 +40,8 @@ async_hit_test_reasons(async_hit_test_reasons), rect(rect), child_count(child_count), - transform_(transform) { + // NOLINTNEXTLINE(build/include_what_you_use). See crbug.com/1301129. + transform(transform) { DCHECK_EQ(!!(flags & HitTestRegionFlags::kHitTestAsk), !!async_hit_test_reasons); } @@ -67,39 +64,18 @@ // to move to the next entry. int32_t child_count = 0; - // gfx::Transform is backed by skia::Matrix44. skia::Matrix44 has a mutable - // attribute which can be changed even during a const function call (e.g. - // skia::Matrix44::getType()). This means that when HitTestQuery reads the - // transform in the read-only shared memory segment created (and populated) by - // HitTestAggregator, if it attempts to perform any operation on the - // transform (e.g. use Transform::IsIdentity()), skia will attempt to write to - // the read-only shared memory segment, causing exception in HitTestQuery. - // For this reason, it is necessary for the HitTestQuery to make a copy of the - // transform before using it. To enforce this, the |transform_| attribute is - // made private here, and exposed through an accessor which always makes a - // copy. - gfx::Transform transform() const { return transform_; } - void set_transform(const gfx::Transform& transform) { - transform_ = transform; - } + gfx::Transform transform; bool operator==(const AggregatedHitTestRegion& rhs) const { return (frame_sink_id == rhs.frame_sink_id && flags == rhs.flags && async_hit_test_reasons == rhs.async_hit_test_reasons && rect == rhs.rect && child_count == rhs.child_count && - transform_ == rhs.transform()); + transform == rhs.transform); } bool operator!=(const AggregatedHitTestRegion& other) const { return !(*this == other); } - - private: - friend struct mojo::StructTraits<mojom::AggregatedHitTestRegionDataView, - AggregatedHitTestRegion>; - - // The transform applied to the rect in parent region's coordinate space. - gfx::Transform transform_; }; } // namespace viz
diff --git a/components/viz/host/hit_test/hit_test_query.cc b/components/viz/host/hit_test/hit_test_query.cc index 25496aa..e703c39 100644 --- a/components/viz/host/hit_test/hit_test_query.cc +++ b/components/viz/host/hit_test/hit_test_query.cc
@@ -190,7 +190,7 @@ // HasPerspective() is checked for the transform because the point will not // be transformed correctly for a plane with a different normal. // See https://crbug.com/854247. - if (hit_test_data_[region_index].transform().HasPerspective()) { + if (hit_test_data_[region_index].transform.HasPerspective()) { target->frame_sink_id = hit_test_data_[region_index].frame_sink_id; target->location_in_target = gfx::PointF(); target->flags = HitTestRegionFlags::kHitTestAsk; @@ -200,7 +200,7 @@ return true; } - hit_test_data_[region_index].transform().TransformPoint( + hit_test_data_[region_index].transform.TransformPoint( &location_transformed); if (!gfx::RectF(hit_test_data_[region_index].rect) .Contains(location_transformed)) { @@ -295,7 +295,7 @@ size_t target_ancestor, size_t region_index, gfx::PointF* location_in_target) const { - hit_test_data_[region_index].transform().TransformPoint(location_in_target); + hit_test_data_[region_index].transform.TransformPoint(location_in_target); if (!target_ancestor) return true; @@ -333,7 +333,7 @@ // TODO(crbug.com/966944): Cache the matrix product such that the transform // can be found immediately. if (hit_test_data_[region_index].frame_sink_id == target) { - *transform = hit_test_data_[region_index].transform(); + *transform = hit_test_data_[region_index].transform; return true; } @@ -349,7 +349,7 @@ gfx::Transform transform_to_child; if (GetTransformToTargetRecursively(target, child_region, &transform_to_child)) { - gfx::Transform region_transform(hit_test_data_[region_index].transform()); + gfx::Transform region_transform(hit_test_data_[region_index].transform); *transform = transform_to_child * region_transform; return true; } @@ -409,7 +409,7 @@ std::string s; std::stringstream transform_ss; - transform_ss << htr.transform().ToString() << '\n'; + transform_ss << htr.transform.ToString() << '\n'; while (getline(transform_ss, s)) { oss << tabs << s << '\n';
diff --git a/components/viz/service/display/ca_layer_overlay.cc b/components/viz/service/display/ca_layer_overlay.cc index a6f96ee..2c47575 100644 --- a/components/viz/service/display/ca_layer_overlay.cc +++ b/components/viz/service/display/ca_layer_overlay.cc
@@ -144,9 +144,9 @@ // transformation that flips the contents of the layer without changing its // frame is the composition of a vertical flip about the anchor point, and a // translation by the height of the layer. - ca_layer_overlay->shared_state->transform.preTranslate( - 0, ca_layer_overlay->bounds_rect.height(), 0); - ca_layer_overlay->shared_state->transform.preScale(1, -1, 1); + ca_layer_overlay->shared_state->transform.Translate( + 0, ca_layer_overlay->bounds_rect.height()); + ca_layer_overlay->shared_state->transform.Scale(1, -1); } ca_layer_overlay->contents_resource_id = resource_id; ca_layer_overlay->contents_rect = @@ -273,7 +273,7 @@ most_recent_overlay_shared_state_->opacity = quad->shared_quad_state->opacity; most_recent_overlay_shared_state_->transform = - quad->shared_quad_state->quad_to_target_transform.matrix(); + quad->shared_quad_state->quad_to_target_transform; } ca_layer_overlay->shared_state = most_recent_overlay_shared_state_;
diff --git a/components/viz/service/display/ca_layer_overlay.h b/components/viz/service/display/ca_layer_overlay.h index 0016f0b..7d3dacb 100644 --- a/components/viz/service/display/ca_layer_overlay.h +++ b/components/viz/service/display/ca_layer_overlay.h
@@ -13,12 +13,12 @@ #include "components/viz/common/quads/compositor_render_pass.h" #include "components/viz/service/viz_service_export.h" #include "gpu/command_buffer/common/mailbox.h" -#include "skia/ext/skia_matrix_44.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "ui/gfx/ca_layer_result.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/rrect_f.h" +#include "ui/gfx/geometry/transform.h" #include "ui/gfx/video_types.h" #include "ui/gl/ca_renderer_layer_params.h" @@ -46,8 +46,7 @@ // The opacity property for the CAayer. float opacity = 1; // The transform to apply to the CALayer. - skia::Matrix44 transform = - skia::Matrix44(skia::Matrix44::kIdentity_Constructor); + gfx::Transform transform; private: friend class base::RefCountedThreadSafe<CALayerOverlaySharedState>;
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc index 11df6a6..553c3be 100644 --- a/components/viz/service/display/gl_renderer.cc +++ b/components/viz/service/display/gl_renderer.cc
@@ -3913,7 +3913,7 @@ GLint sorting_context_id = ca_layer_overlay.shared_state->sorting_context_id; GLfloat transform[16]; - ca_layer_overlay.shared_state->transform.asColMajorf(transform); + ca_layer_overlay.shared_state->transform.matrix().asColMajorf(transform); unsigned filter = ca_layer_overlay.filter; if (ca_layer_overlay.shared_state != shared_state) { @@ -3954,7 +3954,7 @@ const gfx::Rect& content_rect = dc_layer_overlay.content_rect; const gfx::Rect& quad_rect = dc_layer_overlay.quad_rect; DCHECK(dc_layer_overlay.transform.IsFlat()); - const skia::Matrix44& transform = dc_layer_overlay.transform.matrix(); + const auto& matrix = dc_layer_overlay.transform.matrix(); bool is_clipped = dc_layer_overlay.clip_rect.has_value(); const gfx::Rect& clip_rect = dc_layer_overlay.clip_rect.value_or(gfx::Rect()); @@ -3965,9 +3965,9 @@ texture_ids[0], texture_ids[1], z_order, content_rect.x(), content_rect.y(), content_rect.width(), content_rect.height(), quad_rect.x(), quad_rect.y(), quad_rect.width(), quad_rect.height(), - transform.rc(0, 0), transform.rc(0, 1), transform.rc(1, 0), - transform.rc(1, 1), transform.rc(0, 3), transform.rc(1, 3), is_clipped, - clip_rect.x(), clip_rect.y(), clip_rect.width(), clip_rect.height(), + matrix.rc(0, 0), matrix.rc(0, 1), matrix.rc(1, 0), matrix.rc(1, 1), + matrix.rc(0, 3), matrix.rc(1, 3), is_clipped, clip_rect.x(), + clip_rect.y(), clip_rect.width(), clip_rect.height(), protected_video_type); } } @@ -4270,9 +4270,8 @@ ca_layer_overlay->shared_state->rounded_corner_bounds.GetSimpleRadius()}; GLint sorting_context_id = ca_layer_overlay->shared_state->sorting_context_id; - skia::Matrix44 transform = ca_layer_overlay->shared_state->transform; GLfloat gl_transform[16]; - transform.asColMajorf(gl_transform); + ca_layer_overlay->shared_state->transform.matrix().asColMajorf(gl_transform); unsigned filter = ca_layer_overlay->filter; // The alpha has already been applied when copying the RPDQ to an IOSurface.
diff --git a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc index fefda076..e52ca63 100644 --- a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc +++ b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
@@ -3,12 +3,12 @@ // found in the LICENSE file. #include "components/viz/service/hit_test/hit_test_aggregator.h" -#include "base/memory/raw_ptr.h" #include <map> #include <memory> #include <utility> +#include "base/memory/raw_ptr.h" #include "components/viz/common/hit_test/hit_test_region_list.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/surface_id.h" @@ -689,9 +689,8 @@ EXPECT_EQ(region.child_count, 2); gfx::Point point(300, 300); - gfx::Transform transform(region.transform()); - transform.TransformPointReverse(&point); - EXPECT_TRUE(point == gfx::Point(100, 200)); + EXPECT_TRUE(region.transform.TransformPointReverse(&point)); + EXPECT_EQ(gfx::Point(100, 200), point); region = host_regions()[2]; EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
diff --git a/content/browser/BACK_FORWARD_CACHE_OWNERS b/content/browser/BACK_FORWARD_CACHE_OWNERS new file mode 100644 index 0000000..1807156 --- /dev/null +++ b/content/browser/BACK_FORWARD_CACHE_OWNERS
@@ -0,0 +1,3 @@ +altimin@chromium.org +fergal@chromium.org +rakina@chromium.org
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 92537e5..064051cc 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -2674,6 +2674,8 @@ "media/cdm_file_impl.h", "media/cdm_storage_impl.cc", "media/cdm_storage_impl.h", + "media/media_license_database.cc", + "media/media_license_database.h", "media/media_license_manager.cc", "media/media_license_manager.h", "media/media_license_quota_client.cc",
diff --git a/content/browser/OWNERS b/content/browser/OWNERS index 3c7e36c..4c4e4855 100644 --- a/content/browser/OWNERS +++ b/content/browser/OWNERS
@@ -44,9 +44,7 @@ per-file ppapi_plugin_sandboxed_process_launcher_delegate.*=file://sandbox/OWNERS # BackForwardCache -per-file back_forward_cache*=arthursonzogni@chromium.org -per-file back_forward_cache*=altimin@chromium.org -per-file back_forward_cache*=rakina@chromium.org +per-file back_forward_cache*=file://content/browser/BACK_FORWARD_CACHE_OWNERS # Storage API dependencies. per-file storage_partition*=file://storage/OWNERS
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc index e675502..93ca692 100644 --- a/content/browser/attribution_reporting/attributions_browsertest.cc +++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -648,48 +648,6 @@ } IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest, - EventSourceImpressionConversion_ReportSent) { - // Expected reports must be registered before the server starts. - // 123 in the `registerConversion` call below is sanitized to 1 in - // the report's `trigger_data`. - ExpectedReportWaiter expected_report( - GURL("https://a.test/.well-known/attribution-reporting/" - "report-event-attribution"), - /*attribution_destination=*/"https://b.test", - /*source_event_id=*/"7", /*source_type=*/"event", /*trigger_data=*/"1", - https_server()); - ASSERT_TRUE(https_server()->Start()); - - GURL impression_url = https_server()->GetURL( - "a.test", "/attribution_reporting/page_with_impression_creator.html"); - EXPECT_TRUE(NavigateToURL(web_contents(), impression_url)); - - // Create an anchor tag with impression attributes. - GURL conversion_url = https_server()->GetURL( - "b.test", "/attribution_reporting/page_with_conversion_redirect.html"); - EXPECT_TRUE( - ExecJs(web_contents(), - JsReplace(R"( - createImpressionTag({id: 'link', - url: $1, - data: '7', - destination: $2, - registerAttributionSource: true});)", - conversion_url, url::Origin::Create(conversion_url)))); - - EXPECT_TRUE(NavigateToURL(web_contents(), conversion_url)); - - // Register a conversion with the original page as the reporting origin. - EXPECT_TRUE( - ExecJs(web_contents(), JsReplace(R"(registerConversion({data: 0, - origin: $1, - eventSourceTriggerData: 123});)", - url::Origin::Create(impression_url)))); - - expected_report.WaitForReport(); -} - -IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest, EventSourceImpressionWithDebugKeyConversion_ReportSent) { // Expected reports must be registered before the server starts. ExpectedReportWaiter expected_report( @@ -731,64 +689,6 @@ } IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest, - EventSourceImpressionTwoConversions_OneReportSent) { - // Expected reports must be registered before the server starts. - // 123 in the `registerConversion` call below is sanitized to 1 in - // the report's `trigger_data`. - ExpectedReportWaiter expected_report( - GURL("https://a.test/.well-known/attribution-reporting/" - "report-event-attribution"), - /*attribution_destination=*/"https://b.test", - /*source_event_id=*/"7", /*source_type=*/"event", /*trigger_data=*/"1", - https_server()); - ExpectedReportWaiter expected_report_not_sent( - GURL("https://a.test/.well-known/attribution-reporting/" - "report-event-attribution"), - /*body=*/base::Value(), https_server()); - ASSERT_TRUE(https_server()->Start()); - - GURL impression_url = https_server()->GetURL( - "a.test", "/attribution_reporting/page_with_impression_creator.html"); - EXPECT_TRUE(NavigateToURL(web_contents(), impression_url)); - - // Create an anchor tag with impression attributes. - GURL conversion_url = https_server()->GetURL( - "b.test", "/attribution_reporting/page_with_conversion_redirect.html"); - EXPECT_TRUE( - ExecJs(web_contents(), - JsReplace(R"( - createImpressionTag({id: 'link', - url: $1, - data: '7', - destination: $2, - registerAttributionSource: true});)", - conversion_url, url::Origin::Create(conversion_url)))); - - EXPECT_TRUE(NavigateToURL(web_contents(), conversion_url)); - - // Register two conversions with the original page as the reporting origin. - for (int i = 0; i < 2; i++) { - EXPECT_TRUE( - ExecJs(web_contents(), JsReplace(R"(registerConversion({data: 0, - origin: $1, - eventSourceTriggerData: 123});)", - url::Origin::Create(impression_url)))); - } - - expected_report.WaitForReport(); - - // Since we want to verify that a report _isn't_ sent, we can't really wait on - // any event here. The best thing we can do is just impose a short delay and - // verify the browser didn't send anything. Worst case, this should start - // flakily failing if the logic breaks. - base::RunLoop run_loop; - base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(100)); - run_loop.Run(); - EXPECT_FALSE(expected_report_not_sent.HasRequest()); -} - -IN_PROC_BROWSER_TEST_F(AttributionsBrowserTest, EventSourceImpressionConversionFromJS_ReportSent) { // Expected reports must be registered before the server starts. // 123 in the `registerConversion` call below is sanitized to 1 in
diff --git a/content/browser/attribution_reporting/common_source_info.h b/content/browser/attribution_reporting/common_source_info.h index 7cc28b3..c3d81010 100644 --- a/content/browser/attribution_reporting/common_source_info.h +++ b/content/browser/attribution_reporting/common_source_info.h
@@ -29,9 +29,7 @@ enum class SourceType { // An impression which was associated with a top-level navigation. kNavigation = 0, - // An impression which was not associated with a navigation, such as an - // impression for an anchor element with the registerattributionsource - // attribute set. + // An impression which was not associated with a navigation. kEvent = 1, kMaxValue = kEvent, };
diff --git a/content/browser/attribution_reporting/source_declaration_browsertest.cc b/content/browser/attribution_reporting/source_declaration_browsertest.cc index 88cf306a..dc95be02 100644 --- a/content/browser/attribution_reporting/source_declaration_browsertest.cc +++ b/content/browser/attribution_reporting/source_declaration_browsertest.cc
@@ -668,94 +668,6 @@ "Conversions.UniqueReportingOriginsPerPage.Impressions", 2, 1); } -IN_PROC_BROWSER_TEST_F( - AttributionSourceDeclarationBrowserTest, - ImpressionTagWithRegisterAttributionSource_ImpressionReceived) { - EXPECT_TRUE(NavigateToURL( - shell(), - https_server()->GetURL("b.test", "/page_with_impression_creator.html"))); - - base::RunLoop loop; - MockAttributionHost host(web_contents()); - EXPECT_CALL(host, RegisterImpression( - Field(&blink::Impression::impression_data, 200UL))) - .WillOnce([&]() { loop.Quit(); }); - - EXPECT_TRUE(ExecJs(web_contents(), R"( - createImpressionTag({id: 'link', - url: 'page_with_conversion_redirect.html', - data: '200', - destination: 'https://a.com', - registerAttributionSource: true});)")); - loop.Run(); - - EXPECT_TRUE(ExecJs(web_contents(), R"( - document.getElementById("link").removeAttribute("registerattributionsource");)")); - - // Conversion mojo messages are sent on the same message pipe as navigation - // messages. Because the conversion would have been sequenced prior to the - // navigation message, it would be observed before the NavigateToURL() call - // finishes. - EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank"))); -} - -IN_PROC_BROWSER_TEST_F( - AttributionSourceDeclarationBrowserTest, - ImpressionTagWithRegisterAttributionSource_ImpressionReceivedWithNewData) { - EXPECT_TRUE(NavigateToURL( - shell(), - https_server()->GetURL("b.test", "/page_with_impression_creator.html"))); - - base::RunLoop loop1, loop2; - MockAttributionHost host(web_contents()); - EXPECT_CALL(host, RegisterImpression( - Field(&blink::Impression::impression_data, 200UL))) - .WillOnce([&]() { loop1.Quit(); }); - EXPECT_CALL(host, RegisterImpression( - Field(&blink::Impression::impression_data, 300UL))) - .WillOnce([&]() { loop2.Quit(); }); - - EXPECT_TRUE(ExecJs(web_contents(), R"( - createImpressionTag({id: 'link', - url: 'page_with_conversion_redirect.html', - data: '200', - destination: 'https://a.com', - registerAttributionSource: true});)")); - loop1.Run(); - - EXPECT_TRUE(ExecJs(web_contents(), R"( - let link = document.getElementById("link"); - link.removeAttribute("registerattributionsource"); - link.setAttribute("attributionsourceeventid", "300"); - link.setAttribute("registerattributionsource", "");)")); - - loop2.Run(); -} - -IN_PROC_BROWSER_TEST_F( - AttributionSourceDeclarationBrowserTest, - RegisterAttributionSourceInSubFrameWithoutPermissionsPolicy_NotReceived) { - GURL page_url = https_server()->GetURL("b.test", "/page_with_iframe.html"); - EXPECT_TRUE(NavigateToURL(web_contents(), page_url)); - - GURL subframe_url = - https_server()->GetURL("c.test", "/page_with_impression_creator.html"); - NavigateIframeToURL(web_contents(), "test_iframe", subframe_url); - - MockAttributionHost host(web_contents()); - EXPECT_CALL(host, RegisterImpression).Times(0); - - RenderFrameHost* subframe = ChildFrameAt(web_contents()->GetMainFrame(), 0); - EXPECT_TRUE(ExecJs(subframe, R"( - createImpressionTag({id: 'link', - url: 'page_with_conversion_redirect.html', - data: '200', - destination: 'https://a.com', - registerAttributionSource: true});)")); - - EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank"))); -} - IN_PROC_BROWSER_TEST_F(AttributionSourceDeclarationBrowserTest, WindowOpenImpression_ImpressionReceived) { SourceObserver source_observer(web_contents());
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 67ea617..ac5f80a 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -987,17 +987,15 @@ // ShellBrowserMainParts initializes a ShellBrowserContext with user data // directory only in PreMainMessageLoopRun(). FirstPartySetsUtil needs to // access this directory, hence triggering after this stage has run. - if (GetContentClient()->browser()->IsFirstPartySetsEnabled()) { - FirstPartySetsUtil::GetInstance()->SendAndUpdatePersistedSets( - GetContentClient()->browser()->GetFirstPartySetsDirectory(), - /*send_sets=*/ - base::BindOnce([](base::OnceCallback<void(const std::string&)> callback, - const std::string& sets) { - content::GetNetworkService() - ->SetPersistedFirstPartySetsAndGetCurrentSets( - sets, std::move(callback)); - })); - } + FirstPartySetsUtil::GetInstance()->SendAndUpdatePersistedSets( + GetContentClient()->browser()->GetFirstPartySetsDirectory(), + /*send_sets=*/ + base::BindOnce([](base::OnceCallback<void(const std::string&)> callback, + const std::string& sets) { + content::GetNetworkService() + ->SetPersistedFirstPartySetsAndGetCurrentSets(sets, + std::move(callback)); + })); variations::MaybeScheduleFakeCrash();
diff --git a/content/browser/file_system/file_system_url_loader_factory.cc b/content/browser/file_system/file_system_url_loader_factory.cc index 11cb59b..9c00edb 100644 --- a/content/browser/file_system/file_system_url_loader_factory.cc +++ b/content/browser/file_system/file_system_url_loader_factory.cc
@@ -524,9 +524,7 @@ } void ReadMoreFileData() { - int64_t bytes_to_read = std::min( - static_cast<int64_t>(kDefaultFileSystemUrlPipeSize), remaining_bytes_); - if (bytes_to_read == 0) { + if (remaining_bytes_ == 0) { if (consumer_handle_.is_valid()) { // This was an empty file; make sure to call OnReceiveResponse and // OnStartLoadingResponseBody regardless. @@ -534,9 +532,11 @@ mojo::ScopedDataPipeConsumerHandle()); client_->OnStartLoadingResponseBody(std::move(consumer_handle_)); } - OnFileWritten(MOJO_RESULT_OK); + OnFileWritten(net::OK); return; } + const int64_t bytes_to_read = std::min( + static_cast<int64_t>(kDefaultFileSystemUrlPipeSize), remaining_bytes_); net::CompletionRepeatingCallback read_callback = base::BindRepeating( &FileSystemFileURLLoader::DidReadMoreFileData, base::AsWeakPtr(this)); const int rv = @@ -549,8 +549,15 @@ } void DidReadMoreFileData(int result) { - if (result <= 0) { - OnFileWritten(result); + if (result < 0) { + OnFileWritten(static_cast<net::Error>(result)); + return; + } + if (result == 0) { + // If `remaining_bytes_` is 0, then we should've called OnFileWritten in + // ReadMoreFileData. + DCHECK_NE(remaining_bytes_, 0); + OnFileWritten(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); return; } @@ -587,20 +594,20 @@ } void OnFileDataWritten(MojoResult result) { - if (result != MOJO_RESULT_OK || remaining_bytes_ == 0) { - OnFileWritten(result); + if (result != MOJO_RESULT_OK) { + OnFileWritten(net::ERR_FAILED); return; } ReadMoreFileData(); } - void OnFileWritten(MojoResult result) { + void OnFileWritten(net::Error net_error) { // All the data has been written now. Close the data pipe. The consumer will // be notified that there will be no more data to read from now. data_producer_.reset(); file_data_ = nullptr; - OnClientComplete(result == MOJO_RESULT_OK ? net::OK : net::ERR_FAILED); + OnClientComplete(net_error); } int64_t remaining_bytes_ = 0;
diff --git a/content/browser/first_party_sets/first_party_sets_util.cc b/content/browser/first_party_sets/first_party_sets_util.cc index 80aa677..e93b6b7 100644 --- a/content/browser/first_party_sets/first_party_sets_util.cc +++ b/content/browser/first_party_sets/first_party_sets_util.cc
@@ -61,6 +61,7 @@ const std::string&)> send_sets) { if (user_data_dir.empty()) { VLOG(1) << "Empty path. Failed loading serialized First-Party Sets file."; + SendPersistedSets(std::move(send_sets), base::FilePath(), ""); return; } @@ -80,9 +81,11 @@ void FirstPartySetsUtil::OnGetUpdatedSets(const base::FilePath& path, const std::string& sets) { - base::ThreadPool::PostTask( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&MaybeWriteSetsToDisk, path, sets)); + if (!path.empty()) { + base::ThreadPool::PostTask( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&MaybeWriteSetsToDisk, path, sets)); + } } void FirstPartySetsUtil::SendPersistedSets(
diff --git a/content/browser/first_party_sets/first_party_sets_util_unittest.cc b/content/browser/first_party_sets/first_party_sets_util_unittest.cc index c804bca2..0728e23 100644 --- a/content/browser/first_party_sets/first_party_sets_util_unittest.cc +++ b/content/browser/first_party_sets/first_party_sets_util_unittest.cc
@@ -35,6 +35,23 @@ base::test::TaskEnvironment env_; }; +TEST_F(FirstPartySetsUtilTest, SendAndUpdatePersistedSets_NoUserDataDir) { + bool sent_sets = false; + FirstPartySetsUtil::GetInstance()->SendAndUpdatePersistedSets( + base::FilePath(), + /*send_sets=*/ + base::BindLambdaForTesting( + [&](base::OnceCallback<void(const std::string&)> callback, + const std::string& got) { + EXPECT_EQ(got, ""); + sent_sets = true; + std::move(callback).Run("current sets"); + })); + + env_.RunUntilIdle(); + EXPECT_TRUE(sent_sets); +} + TEST_F(FirstPartySetsUtilTest, SendAndUpdatePersistedSets_FileNotExist) { SEQUENCE_CHECKER(sequence_checker); const std::string expected_updated_sets = "updated first party sets";
diff --git a/content/browser/loader/cors_origin_pattern_setter_browsertest.cc b/content/browser/loader/cors_origin_pattern_setter_browsertest.cc index 6bce9ba..bdc59d43 100644 --- a/content/browser/loader/cors_origin_pattern_setter_browsertest.cc +++ b/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
@@ -197,14 +197,7 @@ // Tests if complete allow list set does not allow a host with a different port // to pass. -// Flaky on Win/Mac. crbug.com/1188675 -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) -#define MAYBE_BlockDifferentPort DISABLED_BlockDifferentPort -#else -#define MAYBE_BlockDifferentPort BlockDifferentPort -#endif -IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, - MAYBE_BlockDifferentPort) { +IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, BlockDifferentPort) { SetAllowList("http", kTestHost, kDisallowSubdomains); std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
diff --git a/content/browser/media/cdm_file_impl.cc b/content/browser/media/cdm_file_impl.cc index 147a869..6373e92 100644 --- a/content/browser/media/cdm_file_impl.cc +++ b/content/browser/media/cdm_file_impl.cc
@@ -9,14 +9,21 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/feature_list.h" #include "base/logging.h" #include "base/metrics/histogram_functions.h" +#include "base/notreached.h" #include "base/strings/strcat.h" #include "base/strings/string_util.h" +#include "content/browser/media/media_license_storage_host.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "content/public/common/content_features.h" #include "media/base/bind_to_current_loop.h" #include "media/cdm/cdm_type.h" +#include "media/mojo/mojom/cdm_storage.mojom.h" +#include "mojo/public/cpp/bindings/pending_associated_receiver.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "storage/browser/file_system/file_stream_reader.h" @@ -391,6 +398,25 @@ } CdmFileImpl::CdmFileImpl( + MediaLicenseStorageHost* host, + const media::CdmType& cdm_type, + const std::string& file_name, + mojo::PendingAssociatedReceiver<media::mojom::CdmFile> pending_receiver) + : file_name_(file_name), cdm_type_(cdm_type), host_(host) { + DVLOG(3) << __func__ << " " << file_name_; + DCHECK(IsValidName(file_name_)); + DCHECK(host_); + DCHECK(base::FeatureList::IsEnabled(features::kMediaLicenseBackend)); + + receiver_.Bind(std::move(pending_receiver)); + receiver_.set_disconnect_handler(base::BindOnce( + &CdmFileImpl::OnReceiverDisconnect, weak_factory_.GetWeakPtr())); + + // The MediaLicenseStorageHost handles file locking. + file_locked_ = true; +} + +CdmFileImpl::CdmFileImpl( const std::string& file_name, const url::Origin& origin, const media::CdmType& cdm_type, @@ -404,6 +430,7 @@ file_system_context_(file_system_context) { DVLOG(3) << __func__ << " " << file_name_; DCHECK(IsValidName(file_name_)); + DCHECK(!base::FeatureList::IsEnabled(features::kMediaLicenseBackend)); } CdmFileImpl::~CdmFileImpl() { @@ -453,6 +480,11 @@ read_callback_ = std::move(callback); start_time_ = base::TimeTicks::Now(); + if (host_) { + ReadUsingMediaLicenseStorageDelegate(); + return; + } + // As reading is done on the IO thread, when it's done ReadDone() needs to be // called back on this thread. auto read_done_cb = media::BindToCurrentLoop( @@ -523,6 +555,11 @@ return; } + if (host_) { + WriteUsingMediaLicenseStorageDelegate(data); + return; + } + // Copy |data| into a net::IOBuffer. int bytes_to_write = base::checked_cast<int>(data.size()); auto buffer = base::MakeRefCounted<CdmFileIOBuffer>(data); @@ -679,6 +716,11 @@ DCHECK(!file_writer_); DCHECK(write_callback_); + if (host_) { + DeleteUsingMediaLicenseStorageDelegate(); + return; + } + storage::FileSystemURL file_url = CreateFileSystemURL(file_name_); storage::AsyncFileUtil* file_util = file_system_context_->GetAsyncFileUtil( storage::kFileSystemTypePluginPrivate); @@ -724,11 +766,23 @@ } bool CdmFileImpl::AcquireFileLock(const std::string& file_name) { + if (host_) { + // The MediaLicenseStorageHost handles file locking and will not call the + // `Initialize()` method which acquires file locks. + NOTREACHED(); + return true; + } + FileLockKey file_lock_key(origin_, cdm_type_, file_name); return GetFileLockMap()->AcquireFileLock(file_lock_key); } void CdmFileImpl::ReleaseFileLock(const std::string& file_name) { + if (host_) { + // The MediaLicenseStorageHost handles file locking. + return; + } + FileLockKey file_lock_key(origin_, cdm_type_, file_name); GetFileLockMap()->ReleaseFileLock(file_lock_key); } @@ -737,14 +791,119 @@ static const char kIncognito[] = ".Incognito"; static const char kNormal[] = ".Normal"; + bool is_incognito = + host_ ? host_->in_memory() : file_system_context_->is_incognito(); + // This records the time taken to the base histogram as well as splitting it // out by incognito or normal mode. auto time_taken = base::TimeTicks::Now() - start_time_; base::UmaHistogramTimes(uma_name, time_taken); base::UmaHistogramTimes( - base::StrCat({uma_name, file_system_context_->is_incognito() ? kIncognito - : kNormal}), + base::StrCat({uma_name, is_incognito ? kIncognito : kNormal}), time_taken); } +void CdmFileImpl::ReadUsingMediaLicenseStorageDelegate() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + DCHECK(file_locked_); + DCHECK(read_callback_); + DCHECK(host_); + + host_->ReadFile( + cdm_type_, file_name_, + base::BindOnce(&CdmFileImpl::DidReadUsingMediaLicenseStorageDelegate, + weak_factory_.GetWeakPtr())); +} + +void CdmFileImpl::DidReadUsingMediaLicenseStorageDelegate( + absl::optional<std::vector<uint8_t>> data) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(file_locked_); + DCHECK(read_callback_); + DCHECK(host_); + + if (!data.has_value()) { + std::move(read_callback_).Run(Status::kFailure, {}); + return; + } + + // Only report reading time for successful reads. + ReportFileOperationTimeUMA(kReadTimeUmaName); + std::move(read_callback_).Run(Status::kSuccess, std::move(data.value())); +} + +void CdmFileImpl::WriteUsingMediaLicenseStorageDelegate( + const std::vector<uint8_t>& data) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(file_locked_); + DCHECK(write_callback_); + DCHECK(host_); + + host_->WriteFile( + cdm_type_, file_name_, data, + base::BindOnce(&CdmFileImpl::DidWriteUsingMediaLicenseStorageDelegate, + weak_factory_.GetWeakPtr())); +} + +void CdmFileImpl::DidWriteUsingMediaLicenseStorageDelegate(bool success) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(file_locked_); + DCHECK(write_callback_); + DCHECK(host_); + + if (!success) { + DLOG(WARNING) << "Unable to write to file " << file_name_; + std::move(write_callback_).Run(Status::kFailure); + return; + } + + // Only report writing time for successful writes. + ReportFileOperationTimeUMA(kWriteTimeUmaName); + std::move(write_callback_).Run(Status::kSuccess); +} + +void CdmFileImpl::DeleteUsingMediaLicenseStorageDelegate() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(file_locked_); + DCHECK(write_callback_); + DCHECK(host_); + + if (!host_) { + std::move(write_callback_).Run(Status::kFailure); + return; + } + + host_->DeleteFile( + cdm_type_, file_name_, + base::BindOnce(&CdmFileImpl::DidDeleteUsingMediaLicenseStorageDelegate, + weak_factory_.GetWeakPtr())); +} + +void CdmFileImpl::DidDeleteUsingMediaLicenseStorageDelegate(bool success) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(file_locked_); + DCHECK(write_callback_); + DCHECK(host_); + + if (!success) { + DLOG(WARNING) << "Unable to delete file " << file_name_; + std::move(write_callback_).Run(Status::kFailure); + return; + } + + // Only report writing time for successful deletions. + ReportFileOperationTimeUMA(kDeleteTimeUmaName); + std::move(write_callback_).Run(Status::kSuccess); +} + +void CdmFileImpl::OnReceiverDisconnect() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(host_); + + // May delete `this`. + host_->OnFileReceiverDisconnect(file_name_, cdm_type_, + base::PassKey<CdmFileImpl>()); +} + } // namespace content
diff --git a/content/browser/media/cdm_file_impl.h b/content/browser/media/cdm_file_impl.h index 713c6de..d79faadd 100644 --- a/content/browser/media/cdm_file_impl.h +++ b/content/browser/media/cdm_file_impl.h
@@ -17,6 +17,7 @@ #include "base/time/time.h" #include "media/cdm/cdm_type.h" #include "media/mojo/mojom/cdm_storage.mojom.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" #include "storage/browser/file_system/async_file_util.h" #include "url/origin.h" @@ -26,6 +27,7 @@ } // namespace storage namespace content { +class MediaLicenseStorageHost; // This class implements the media::mojom::CdmFile interface. It uses the same // mojo pipe as CdmStorageImpl, to enforce message dispatch order. @@ -35,6 +37,15 @@ // false otherwise. static bool IsValidName(const std::string& name); + // This "file" is actually just an entry in a custom backend for CDM, uniquely + // identified by a storage key, CDM type, and file name. File operations are + // routed through `host` which is owned by the storage partition. + CdmFileImpl( + MediaLicenseStorageHost* host, + const media::CdmType& cdm_type, + const std::string& file_name, + mojo::PendingAssociatedReceiver<media::mojom::CdmFile> pending_receiver); + CdmFileImpl(const std::string& file_name, const url::Origin& origin, const media::CdmType& cdm_type, @@ -91,6 +102,19 @@ // Report operation time to UMA. void ReportFileOperationTimeUMA(const std::string& uma_name); + void ReadUsingMediaLicenseStorageDelegate(); + void DidReadUsingMediaLicenseStorageDelegate( + absl::optional<std::vector<uint8_t>> data); + void WriteUsingMediaLicenseStorageDelegate(const std::vector<uint8_t>& data); + void DidWriteUsingMediaLicenseStorageDelegate(bool success); + void DeleteUsingMediaLicenseStorageDelegate(); + void DidDeleteUsingMediaLicenseStorageDelegate(bool success); + + void OnReceiverDisconnect(); + + // This receiver is associated with the CdmStorage receiver which creates it. + mojo::AssociatedReceiver<media::mojom::CdmFile> receiver_{this}; + // Names of the files this class represents. const std::string file_name_; const std::string temp_file_name_; @@ -123,6 +147,10 @@ // Time when the read or write operation starts. base::TimeTicks start_time_; + // Backing store which CDM file operations are routed through. + // Owned by MediaLicenseManager. + const raw_ptr<MediaLicenseStorageHost> host_ = nullptr; + THREAD_CHECKER(thread_checker_); base::WeakPtrFactory<CdmFileImpl> weak_factory_{this}; };
diff --git a/content/browser/media/cdm_storage_impl_unittest.cc b/content/browser/media/cdm_storage_impl_unittest.cc index 9b89e73..89989eb 100644 --- a/content/browser/media/cdm_storage_impl_unittest.cc +++ b/content/browser/media/cdm_storage_impl_unittest.cc
@@ -310,11 +310,6 @@ } TEST_P(CdmStorageTest, WriteThenReadFile) { - if (base::FeatureList::IsEnabled(features::kMediaLicenseBackend)) { - // TODO(crbug.com/1231162): Implement read and write for the new backend. - return; - } - const char kFileName[] = "test_file_name"; mojo::AssociatedRemote<CdmFile> cdm_file; EXPECT_TRUE(Open(kFileName, cdm_file)); @@ -330,11 +325,6 @@ } TEST_P(CdmStorageTest, ReadThenWriteEmptyFile) { - if (base::FeatureList::IsEnabled(features::kMediaLicenseBackend)) { - // TODO(crbug.com/1231162): Implement read and write for the new backend. - return; - } - const char kFileName[] = "empty_file_name"; mojo::AssociatedRemote<CdmFile> cdm_file; EXPECT_TRUE(Open(kFileName, cdm_file)); @@ -354,11 +344,6 @@ } TEST_P(CdmStorageTest, ParallelRead) { - if (base::FeatureList::IsEnabled(features::kMediaLicenseBackend)) { - // TODO(crbug.com/1231162): Implement read and write for the new backend. - return; - } - const char kFileName[] = "duplicate_read_file_name"; mojo::AssociatedRemote<CdmFile> cdm_file; EXPECT_TRUE(Open(kFileName, cdm_file)); @@ -376,11 +361,6 @@ } TEST_P(CdmStorageTest, ParallelWrite) { - if (base::FeatureList::IsEnabled(features::kMediaLicenseBackend)) { - // TODO(crbug.com/1231162): Implement read and write for the new backend. - return; - } - const char kFileName[] = "duplicate_write_file_name"; mojo::AssociatedRemote<CdmFile> cdm_file; EXPECT_TRUE(Open(kFileName, cdm_file));
diff --git a/content/browser/media/media_license_database.cc b/content/browser/media/media_license_database.cc new file mode 100644 index 0000000..bc28ea0 --- /dev/null +++ b/content/browser/media/media_license_database.cc
@@ -0,0 +1,194 @@ +// 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 "content/browser/media/media_license_database.h" + +#include "base/files/file.h" +#include "base/files/file_util.h" +#include "sql/database.h" +#include "sql/meta_table.h" +#include "sql/statement.h" + +namespace content { + +namespace { + +static const int kVersionNumber = 1; + +} // namespace + +MediaLicenseDatabase::MediaLicenseDatabase(const base::FilePath& path) + : path_(path), + // Use a smaller cache, since access will be fairly infrequent and random. + // Given the expected record sizes (~100s of bytes) and key sizes (<100 + // bytes) and that we'll typically only be pulling one file at a time + // (playback), specify a large page size to allow inner nodes can pack + // many keys, to keep the index B-tree flat. + db_(sql::DatabaseOptions{.exclusive_locking = true, + .page_size = 32768, + .cache_size = 8}) {} + +bool MediaLicenseDatabase::OpenFile(const media::CdmType& cdm_type, + const std::string& file_name) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!OpenDatabase()) + return false; + + // The media license code doesn't distinguish between an empty file and a + // file which does not exist, so don't bother inserting an empty row into + // the database. + return true; +} + +absl::optional<std::vector<uint8_t>> MediaLicenseDatabase::ReadFile( + const media::CdmType& cdm_type, + const std::string& file_name) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!db_.is_open()) + return absl::nullopt; + + static constexpr char kSelectSql[] = + "SELECT data FROM licenses WHERE cdm_type=? AND file_name=?"; + DCHECK(db_.IsSQLValid(kSelectSql)); + + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql)); + statement.BindString(0, cdm_type.id.ToString()); + statement.BindString(1, file_name); + + if (!statement.Step()) { + // Failing here is expected if the "file" has not yet been written to and + // the row does not yet exist. The media license code doesn't distinguish + // between an empty file and a file which does not exist, so just return + // an empty file without erroring. + return std::vector<uint8_t>(); + } + + std::vector<uint8_t> data; + if (!statement.ColumnBlobAsVector(0, &data)) { + DVLOG(1) << "Error reading media license data."; + return absl::nullopt; + } + + return data; +} + +bool MediaLicenseDatabase::WriteFile(const media::CdmType& cdm_type, + const std::string& file_name, + const std::vector<uint8_t>& data) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!db_.is_open()) + return false; + + static constexpr char kInsertSql[] = + // clang-format off + "INSERT OR REPLACE INTO licenses(cdm_type,file_name,data) " + "VALUES(?,?,?)"; + // clang-format on + DCHECK(db_.IsSQLValid(kInsertSql)); + + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kInsertSql)); + statement.BindString(0, cdm_type.id.ToString()); + statement.BindString(1, file_name); + statement.BindBlob(2, data); + bool success = statement.Run(); + + if (!success) + DVLOG(1) << "Error writing media license data."; + + return success; +} + +bool MediaLicenseDatabase::DeleteFile(const media::CdmType& cdm_type, + const std::string& file_name) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!db_.is_open()) + return false; + + static constexpr char kDeleteSql[] = + "DELETE FROM licenses WHERE cdm_type=? AND file_name=?"; + DCHECK(db_.IsSQLValid(kDeleteSql)); + + sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kDeleteSql)); + statement.BindString(0, cdm_type.id.ToString()); + statement.BindString(1, file_name); + bool success = statement.Run(); + + if (!success) + DVLOG(1) << "Error writing media license data."; + + return success; +} + +// Opens and sets up a database if one is not already set up. +bool MediaLicenseDatabase::OpenDatabase(bool is_retry) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Open the database if it isn't open already. + if (!db_.is_open()) { + bool success = false; + if (path_.empty()) { + success = db_.OpenInMemory(); + } else { + // Ensure `path`'s parent directory exists. + base::File::Error error = base::File::Error::FILE_OK; + if (!base::CreateDirectoryAndGetError(path_.DirName(), &error)) { + DVLOG(1) << "Failed to open CDM database: " + << base::File::ErrorToString(error); + return false; + } + DCHECK_EQ(error, base::File::Error::FILE_OK); + + success = db_.Open(path_); + } + + if (!success) { + DVLOG(1) << "Failed to open CDM database: " << db_.GetErrorMessage(); + return false; + } + } + + sql::MetaTable meta_table; + if (!meta_table.Init(&db_, kVersionNumber, kVersionNumber)) { + DVLOG(1) << "Could not initialize Media License database metadata table."; + // Wipe the database and start over. If we've already wiped the database and + // are still failing, just return false. + db_.Raze(); + return is_retry ? false : OpenDatabase(/*is_retry=*/true); + } + + if (meta_table.GetCompatibleVersionNumber() > kVersionNumber) { + // This should only happen if the user downgrades the Chrome channel (for + // example, from Beta to Stable). If that results in an incompatible schema, + // we need to wipe the database and start over. + DVLOG(1) << "Media License database is too new, kVersionNumber" + << kVersionNumber << ", GetCompatibleVersionNumber=" + << meta_table.GetCompatibleVersionNumber(); + db_.Raze(); + return is_retry ? false : OpenDatabase(/*is_retry=*/true); + } + + // Set up the table. + static constexpr char kCreateTableSql[] = + // clang-format off + "CREATE TABLE IF NOT EXISTS licenses(" + "cdm_type TEXT NOT NULL," + "file_name TEXT NOT NULL," + "data BLOB NOT NULL," + "PRIMARY KEY(cdm_type,file_name))"; + // clang-format on + DCHECK(db_.IsSQLValid(kCreateTableSql)); + + if (!db_.Execute(kCreateTableSql)) { + DVLOG(1) << "Failed to execute " << kCreateTableSql; + return false; + } + + return true; +} + +} // namespace content
diff --git a/content/browser/media/media_license_database.h b/content/browser/media/media_license_database.h new file mode 100644 index 0000000..0361a87 --- /dev/null +++ b/content/browser/media/media_license_database.h
@@ -0,0 +1,45 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEDIA_MEDIA_LICENSE_DATABASE_H_ +#define CONTENT_BROWSER_MEDIA_MEDIA_LICENSE_DATABASE_H_ + +#include "base/sequence_checker.h" +#include "media/cdm/cdm_type.h" +#include "sql/database.h" + +namespace content { + +// Helper class which encapsulates all database logic for storing media license +// data. +// +// This class must be constructed and used on a sequence which allows blocking. +class MediaLicenseDatabase { + public: + // The database will be in-memory if `path` is empty. + explicit MediaLicenseDatabase(const base::FilePath& path); + + bool OpenFile(const media::CdmType& cdm_type, const std::string& file_name); + absl::optional<std::vector<uint8_t>> ReadFile(const media::CdmType& cdm_type, + const std::string& file_name); + bool WriteFile(const media::CdmType& cdm_type, + const std::string& file_name, + const std::vector<uint8_t>& data); + bool DeleteFile(const media::CdmType& cdm_type, const std::string& file_name); + + private: + // Opens and sets up a database if one is not already set up. + bool OpenDatabase(bool is_retry = false); + + SEQUENCE_CHECKER(sequence_checker_); + + // Empty if the database is in-memory. + const base::FilePath path_; + + sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEDIA_MEDIA_LICENSE_DATABASE_H_
diff --git a/content/browser/media/media_license_manager.cc b/content/browser/media/media_license_manager.cc index 69439b1..ab03beb 100644 --- a/content/browser/media/media_license_manager.cc +++ b/content/browser/media/media_license_manager.cc
@@ -12,6 +12,8 @@ #include "base/notreached.h" #include "base/sequence_checker.h" #include "base/strings/string_number_conversions.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "base/threading/sequenced_task_runner_handle.h" #include "components/services/storage/public/cpp/buckets/constants.h" #include "components/services/storage/public/cpp/constants.h" @@ -20,11 +22,34 @@ namespace content { +namespace { + +// Creates a task runner suitable for running SQLite database operations. +scoped_refptr<base::SequencedTaskRunner> CreateDatabaseTaskRunner() { + // We use a SequencedTaskRunner so that there is a global ordering to a + // storage key's directory operations. + return base::ThreadPool::CreateSequencedTaskRunner({ + // Needed for file I/O. + base::MayBlock(), + + // Reasonable compromise, given that a few database operations are + // blocking, while most operations are not. We should be able to do better + // when we get scheduling APIs on the Web Platform. + base::TaskPriority::USER_VISIBLE, + + // Needed to allow for clearing site data on shutdown. + base::TaskShutdownBehavior::BLOCK_SHUTDOWN, + }); +} + +} // namespace + MediaLicenseManager::MediaLicenseManager( const base::FilePath& bucket_base_path, scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) - : bucket_base_path_(bucket_base_path), + : db_runner_(CreateDatabaseTaskRunner()), + bucket_base_path_(bucket_base_path), special_storage_policy_(std::move(special_storage_policy)), quota_manager_proxy_(std::move(quota_manager_proxy)), // Using a raw pointer is safe since `quota_client_` is owned by
diff --git a/content/browser/media/media_license_manager.h b/content/browser/media/media_license_manager.h index a65008d..a7ec8f41 100644 --- a/content/browser/media/media_license_manager.h +++ b/content/browser/media/media_license_manager.h
@@ -10,6 +10,8 @@ #include "base/callback_forward.h" #include "base/containers/flat_map.h" #include "base/files/file_path.h" +#include "base/memory/scoped_refptr.h" +#include "base/task/sequenced_task_runner.h" #include "base/types/pass_key.h" #include "content/browser/media/media_license_quota_client.h" #include "content/common/content_export.h" @@ -65,12 +67,30 @@ MediaLicenseStorageHost* host, base::PassKey<MediaLicenseStorageHost> pass_key); + const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return quota_manager_proxy_; + } + + const scoped_refptr<base::SequencedTaskRunner>& db_runner() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return db_runner_; + } + + bool in_memory() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return bucket_base_path_.empty(); + } + private: void DidGetBucket(const blink::StorageKey& storage_key, storage::QuotaErrorOr<storage::BucketInfo> result); SEQUENCE_CHECKER(sequence_checker_); + // Task runner which all database operations are routed through. + const scoped_refptr<base::SequencedTaskRunner> db_runner_; + // Root path of the storage bucket associated with the StoragePartition which // owns this class. If `bucket_base_path_` is empty, the profile is in-memory. const base::FilePath bucket_base_path_;
diff --git a/content/browser/media/media_license_storage_host.cc b/content/browser/media/media_license_storage_host.cc index 878170a..6e2c84b 100644 --- a/content/browser/media/media_license_storage_host.cc +++ b/content/browser/media/media_license_storage_host.cc
@@ -4,21 +4,39 @@ #include "content/browser/media/media_license_storage_host.h" +#include <algorithm> +#include <memory> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/containers/contains.h" #include "base/notreached.h" #include "base/sequence_checker.h" #include "base/types/pass_key.h" #include "components/services/storage/public/cpp/buckets/bucket_locator.h" #include "content/browser/media/cdm_file_impl.h" +#include "content/browser/media/media_license_database.h" #include "content/browser/media/media_license_manager.h" +#include "media/cdm/cdm_type.h" +#include "media/mojo/mojom/cdm_storage.mojom.h" +#include "mojo/public/cpp/bindings/pending_associated_remote.h" #include "storage/browser/file_system/file_system_context.h" #include "third_party/blink/public/common/storage_key/storage_key.h" namespace content { +MediaLicenseStorageHost::CdmFileId::CdmFileId(const std::string& name, + const media::CdmType& cdm_type) + : name(name), cdm_type(cdm_type) {} +MediaLicenseStorageHost::CdmFileId::~CdmFileId() = default; + MediaLicenseStorageHost::MediaLicenseStorageHost( MediaLicenseManager* manager, const storage::BucketLocator& bucket_locator) - : manager_(manager), bucket_locator_(bucket_locator) { + : manager_(manager), + bucket_locator_(bucket_locator), + db_(manager_->db_runner(), manager_->GetDatabasePath(bucket_locator_)) { DCHECK(manager_); // base::Unretained is safe here because this MediaLicenseStorageHost owns @@ -28,7 +46,9 @@ &MediaLicenseStorageHost::OnReceiverDisconnect, base::Unretained(this))); } -MediaLicenseStorageHost::~MediaLicenseStorageHost() = default; +MediaLicenseStorageHost::~MediaLicenseStorageHost() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} void MediaLicenseStorageHost::Open(const std::string& file_name, OpenCallback callback) { @@ -45,24 +65,14 @@ return; } - // TODO(crbug.com/1231162): Modify CdmFileImpl to route operations through - // this class. + // TODO(crbug.com/1231162): Notify the quota system of a write. + const BindingContext& binding_context = receivers_.current_context(); - auto cdm_file_impl = std::make_unique<CdmFileImpl>( - file_name, binding_context.storage_key.origin(), binding_context.cdm_type, - /*file_system_root_uri_=*/"", nullptr); - - if (!cdm_file_impl->Initialize()) { - // Unable to initialize with the file requested. - std::move(callback).Run(Status::kInUse, mojo::NullAssociatedRemote()); - return; - } - - // File was opened successfully, so create the binding and return success. - mojo::PendingAssociatedRemote<media::mojom::CdmFile> cdm_file; - cdm_file_receivers_.Add(std::move(cdm_file_impl), - cdm_file.InitWithNewEndpointAndPassReceiver()); - std::move(callback).Run(Status::kSuccess, std::move(cdm_file)); + db_.AsyncCall(&MediaLicenseDatabase::OpenFile) + .WithArgs(binding_context.cdm_type, file_name) + .Then(base::BindOnce(&MediaLicenseStorageHost::DidOpenFile, + weak_factory_.GetWeakPtr(), file_name, + binding_context, std::move(callback))); } void MediaLicenseStorageHost::BindReceiver( @@ -74,6 +84,76 @@ receivers_.Add(this, std::move(receiver), binding_context); } +void MediaLicenseStorageHost::DidOpenFile(const std::string& file_name, + BindingContext binding_context, + OpenCallback callback, + bool success) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!success) { + std::move(callback).Run(Status::kFailure, mojo::NullAssociatedRemote()); + return; + } + + // Check whether this CDM file is in-use. + CdmFileId id(file_name, binding_context.cdm_type); + if (base::Contains(cdm_files_, id)) { + std::move(callback).Run(Status::kInUse, mojo::NullAssociatedRemote()); + return; + } + + // File was opened successfully, so create the binding and return success. + mojo::PendingAssociatedRemote<media::mojom::CdmFile> cdm_file; + + // `this` is safe here since `cdm_file_impl` is owned by this instance. + cdm_files_.emplace(id, std::make_unique<CdmFileImpl>( + this, binding_context.cdm_type, file_name, + cdm_file.InitWithNewEndpointAndPassReceiver())); + + // TODO(crbug.com/1231162): Notify the quota system of a write. + // We don't actually touch the database here, but notify the quota system + // anyways since conceptually we're creating an empty file. + + std::move(callback).Run(Status::kSuccess, std::move(cdm_file)); +} + +void MediaLicenseStorageHost::ReadFile(const media::CdmType& cdm_type, + const std::string& file_name, + ReadFileCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // TODO(crbug.com/1231162): Notify the quota system of a read. + + db_.AsyncCall(&MediaLicenseDatabase::ReadFile) + .WithArgs(cdm_type, file_name) + .Then(std::move(callback)); +} + +void MediaLicenseStorageHost::WriteFile(const media::CdmType& cdm_type, + const std::string& file_name, + const std::vector<uint8_t>& data, + 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(std::move(callback)); +} + +void MediaLicenseStorageHost::DeleteFile(const media::CdmType& cdm_type, + const std::string& file_name, + 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)); +} + void MediaLicenseStorageHost::OnReceiverDisconnect() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -82,4 +162,14 @@ base::PassKey<MediaLicenseStorageHost>()); } +void MediaLicenseStorageHost::OnFileReceiverDisconnect( + const std::string& name, + const media::CdmType& cdm_type, + base::PassKey<CdmFileImpl> /*pass_key*/) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + auto count = cdm_files_.erase(CdmFileId(name, cdm_type)); + DCHECK_GT(count, 0u); +} + } // namespace content \ No newline at end of file
diff --git a/content/browser/media/media_license_storage_host.h b/content/browser/media/media_license_storage_host.h index 7425995..bc7ea2de 100644 --- a/content/browser/media/media_license_storage_host.h +++ b/content/browser/media/media_license_storage_host.h
@@ -8,6 +8,7 @@ #include "base/containers/unique_ptr_adapters.h" #include "base/files/file_path.h" #include "base/thread_annotations.h" +#include "base/threading/sequence_bound.h" #include "base/types/pass_key.h" #include "components/services/storage/public/cpp/buckets/bucket_locator.h" #include "components/services/storage/public/mojom/quota_client.mojom.h" @@ -19,6 +20,8 @@ #include "third_party/blink/public/common/storage_key/storage_key.h" namespace content { +class CdmFileImpl; +class MediaLicenseDatabase; // Per-storage-key backend for media license (CDM) files. MediaLicenseManager // owns an instance of this class for each storage key that is actively using @@ -27,6 +30,10 @@ class CONTENT_EXPORT MediaLicenseStorageHost : public media::mojom::CdmStorage { public: using BindingContext = MediaLicenseManager::BindingContext; + using ReadFileCallback = + base::OnceCallback<void(absl::optional<std::vector<uint8_t>>)>; + using WriteFileCallback = base::OnceCallback<void(bool)>; + using DeleteFileCallback = base::OnceCallback<void(bool)>; MediaLicenseStorageHost(MediaLicenseManager* manager, const storage::BucketLocator& bucket_locator); @@ -38,10 +45,26 @@ void BindReceiver(const BindingContext& binding_context, mojo::PendingReceiver<media::mojom::CdmStorage> receiver); + // CDM file operations. + void ReadFile(const media::CdmType& cdm_type, + const std::string& file_name, + ReadFileCallback callback); + void WriteFile(const media::CdmType& cdm_type, + const std::string& file_name, + const std::vector<uint8_t>& data, + WriteFileCallback callback); + void DeleteFile(const media::CdmType& cdm_type, + const std::string& file_name, + DeleteFileCallback callback); + + void OnFileReceiverDisconnect(const std::string& name, + const media::CdmType& cdm_type, + base::PassKey<CdmFileImpl> pass_key); + // True if there are no receivers connected to this host. // - // The MediaLicenseManager that owns this host is expected to destroy the host - // when it isn't serving any receivers. + // The MediaLicenseManagerImpl that owns this host is expected to destroy the + // host when it isn't serving any receivers. bool has_empty_receiver_set() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return receivers_.empty(); @@ -49,9 +72,36 @@ const blink::StorageKey& storage_key() { return bucket_locator_.storage_key; } + bool in_memory() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return manager_->in_memory(); + } + private: + // A CDM file for a given storage key can be uniquely identified by its name + // and CDM type. + struct CdmFileId { + CdmFileId(const std::string& name, const media::CdmType& cdm_type); + ~CdmFileId(); + + bool operator==(const CdmFileId& rhs) const { + return (name == rhs.name) && (cdm_type == rhs.cdm_type); + } + bool operator<(const CdmFileId& rhs) const { + return std::tie(name, cdm_type) < std::tie(rhs.name, rhs.cdm_type); + } + + const std::string name; + const media::CdmType cdm_type; + }; + void OnReceiverDisconnect(); + void DidOpenFile(const std::string& file_name, + BindingContext binding_context, + OpenCallback callback, + bool success); + SEQUENCE_CHECKER(sequence_checker_); // MediaLicenseManager instance which owns this object. @@ -60,7 +110,9 @@ const storage::BucketLocator bucket_locator_; - // TODO: hold SequenceBound sql::Database to run operations through. + // All file operations are run through this member. + base::SequenceBound<MediaLicenseDatabase> db_ + GUARDED_BY_CONTEXT(sequence_checker_); // All receivers for frames and workers whose storage key is `storage_key()`. mojo::ReceiverSet<media::mojom::CdmStorage, BindingContext> receivers_ @@ -69,10 +121,11 @@ // Keep track of all media::mojom::CdmFile receivers, as each CdmFileImpl // object keeps a reference to |this|. If |this| goes away unexpectedly, // all remaining CdmFile receivers will be closed. - mojo::UniqueAssociatedReceiverSet<media::mojom::CdmFile> cdm_file_receivers_ + std::map<CdmFileId, std::unique_ptr<CdmFileImpl>> cdm_files_ GUARDED_BY_CONTEXT(sequence_checker_); - base::WeakPtrFactory<MediaLicenseStorageHost> weak_factory_{this}; + base::WeakPtrFactory<MediaLicenseStorageHost> weak_factory_ + GUARDED_BY_CONTEXT(sequence_checker_){this}; }; } // namespace content
diff --git a/content/browser/net/sandboxed_nqe_browsertest.cc b/content/browser/net/sandboxed_nqe_browsertest.cc index 81a9bcb..f8a47077 100644 --- a/content/browser/net/sandboxed_nqe_browsertest.cc +++ b/content/browser/net/sandboxed_nqe_browsertest.cc
@@ -11,10 +11,48 @@ #include "content/public/test/content_browser_test.h" #include "sandbox/features.h" #include "sandbox/policy/features.h" +#include "services/network/public/cpp/network_quality_tracker.h" +#include "services/network/public/mojom/network_service_test.mojom.h" namespace content { namespace { +class TestNetworkQualityObserver + : public network::NetworkQualityTracker::EffectiveConnectionTypeObserver { + public: + TestNetworkQualityObserver() = default; + + // NetworkQualityTracker::EffectiveConnectionTypeObserver implementation: + void OnEffectiveConnectionTypeChanged( + net::EffectiveConnectionType type) override { + effective_connection_type_ = type; + if (effective_connection_type_ != run_loop_wait_effective_connection_type_) + return; + run_loop_->Quit(); + } + + void WaitForNotification( + net::EffectiveConnectionType run_loop_wait_effective_connection_type) { + if (effective_connection_type_ == run_loop_wait_effective_connection_type) + return; + run_loop_wait_effective_connection_type_ = + run_loop_wait_effective_connection_type; + run_loop_ = std::make_unique<base::RunLoop>(); + run_loop_->Run(); + } + + net::EffectiveConnectionType EffectiveConnectionType() const { + return effective_connection_type_; + } + + private: + std::unique_ptr<base::RunLoop> run_loop_; + net::EffectiveConnectionType run_loop_wait_effective_connection_type_ = + net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN; + net::EffectiveConnectionType effective_connection_type_ = + net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN; +}; + class SandboxedNQEBrowserTest : public ContentBrowserTest { public: SandboxedNQEBrowserTest() { @@ -47,15 +85,61 @@ ContentBrowserTest::SetUp(); } + // Simulates a network quality change. + void SimulateNetworkQualityChange(net::EffectiveConnectionType type) { + mojo::ScopedAllowSyncCallForTesting allow_sync_call; + DCHECK(content::GetNetworkService()); + + mojo::Remote<network::mojom::NetworkServiceTest> network_service_test; + content::GetNetworkService()->BindTestInterface( + network_service_test.BindNewPipeAndPassReceiver()); + base::RunLoop run_loop; + network_service_test->SimulateNetworkQualityChange(type, + run_loop.QuitClosure()); + run_loop.Run(); + } + private: base::test::ScopedFeatureList scoped_feature_list_; }; +// NetworkQualityEstimater used to call android syscall to gather device info +// in the constructor, which has been removed. This test confirms that. IN_PROC_BROWSER_TEST_F(SandboxedNQEBrowserTest, GetNetworkService) { EXPECT_TRUE(GetNetworkService()); } -// TODO(yoichio): Add more tests. +// Simulate EffectiveConnectionType change in NetworkQualityEstimator and +// reports it to mojo client. +IN_PROC_BROWSER_TEST_F(SandboxedNQEBrowserTest, NetworkQualityTracker) { + // Change the network quality to UNKNOWN to prevent any spurious + // notifications. + SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN); + + std::unique_ptr<network::NetworkQualityTracker> tracker = + std::make_unique<network::NetworkQualityTracker>( + base::BindRepeating(&GetNetworkService)); + TestNetworkQualityObserver network_quality_observer; + tracker->AddEffectiveConnectionTypeObserver(&network_quality_observer); + + SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_4G); + network_quality_observer.WaitForNotification( + net::EFFECTIVE_CONNECTION_TYPE_4G); + EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_4G, + network_quality_observer.EffectiveConnectionType()); + + SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_3G); + network_quality_observer.WaitForNotification( + net::EFFECTIVE_CONNECTION_TYPE_3G); + EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_3G, + network_quality_observer.EffectiveConnectionType()); + + // Typical RTT and downlink values when effective connection type is 3G. Taken + // from net::NetworkQualityEstimatorParams. + EXPECT_EQ(base::Milliseconds(450), tracker->GetHttpRTT()); + EXPECT_EQ(base::Milliseconds(400), tracker->GetTransportRTT()); + EXPECT_EQ(400, tracker->GetDownstreamThroughputKbps()); +} } // namespace } // namespace content
diff --git a/content/browser/renderer_host/OWNERS b/content/browser/renderer_host/OWNERS index 2c6d46c9..05fb123 100644 --- a/content/browser/renderer_host/OWNERS +++ b/content/browser/renderer_host/OWNERS
@@ -34,9 +34,7 @@ # DirectWrite font code. per-file dwrite_*=drott@chromium.org -# BackForwardCache. -per-file back_forward_cache*=altimin@chromium.org -per-file back_forward_cache*=rakina@chromium.org +per-file back_forward_cache*=file://content/browser/BACK_FORWARD_CACHE_OWNERS # Clipboard per-file *clipboard_host_impl*=mek@chromium.org
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc index abae855..1ffa17f 100644 --- a/content/browser/renderer_host/frame_tree_node.cc +++ b/content/browser/renderer_host/frame_tree_node.cc
@@ -782,7 +782,8 @@ } void FrameTreeNode::WriteIntoTrace( - perfetto::TracedProto<perfetto::protos::pbzero::FrameTreeNodeInfo> proto) { + perfetto::TracedProto<perfetto::protos::pbzero::FrameTreeNodeInfo> proto) + const { proto->set_is_main_frame(IsMainFrame()); proto->set_frame_tree_node_id(frame_tree_node_id()); proto->set_has_speculative_render_frame_host(
diff --git a/content/browser/renderer_host/frame_tree_node.h b/content/browser/renderer_host/frame_tree_node.h index 7da255e..2383cde 100644 --- a/content/browser/renderer_host/frame_tree_node.h +++ b/content/browser/renderer_host/frame_tree_node.h
@@ -121,6 +121,9 @@ Navigator& navigator() { return frame_tree()->navigator(); } RenderFrameHostManager* render_manager() { return &render_manager_; } + const RenderFrameHostManager* render_manager() const { + return &render_manager_; + } int frame_tree_node_id() const { return frame_tree_node_id_; } const std::string& frame_name() const { return render_manager_.current_replication_state().name; @@ -456,7 +459,8 @@ // Write a representation of this object into a trace. void WriteIntoTrace(perfetto::TracedValue context) const; void WriteIntoTrace( - perfetto::TracedProto<perfetto::protos::pbzero::FrameTreeNodeInfo> proto); + perfetto::TracedProto<perfetto::protos::pbzero::FrameTreeNodeInfo> proto) + const; // Returns true the node is navigating, i.e. it has an associated // NavigationRequest.
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc index 185bbdc1..1430b7c9 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -692,7 +692,7 @@ void RenderWidgetHostViewChildFrame::NotifyHitTestRegionUpdated( const viz::AggregatedHitTestRegion& region) { gfx::RectF screen_rect(region.rect); - if (!region.transform().TransformRectReverse(&screen_rect)) { + if (!region.transform.TransformRectReverse(&screen_rect)) { last_stable_screen_rect_ = gfx::RectF(); screen_rect_stable_since_ = base::TimeTicks::Now(); return;
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index eef64c7..53ab55c 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -300,6 +300,10 @@ storage::QuotaClientType::kServiceWorker, {blink::mojom::StorageType::kTemporary}); } + + registry_->GetRegisteredStorageKeys( + base::BindOnce(&ServiceWorkerContextCore::DidGetRegisteredStorageKeys, + AsWeakPtr(), base::TimeTicks::Now())); } ServiceWorkerContextCore::ServiceWorkerContextCore( @@ -326,6 +330,13 @@ &ServiceWorkerContextCore::OnContainerHostReceiverDisconnected, base::Unretained(this))); quota_client_->ResetContext(*this); + + // Uma (ServiceWorker.Storage.RegisteredStorageKeyCacheInitialization.Time) + // shouldn't be recorded when ServiceWorkerContextCore is recreated. Hence we + // specify a null TimeTicks here. + registry_->GetRegisteredStorageKeys( + base::BindOnce(&ServiceWorkerContextCore::DidGetRegisteredStorageKeys, + AsWeakPtr(), base::TimeTicks())); } ServiceWorkerContextCore::~ServiceWorkerContextCore() { @@ -635,6 +646,27 @@ container_host.GetClientType()); } +bool ServiceWorkerContextCore::MaybeHasRegistrationForStorageKey( + const blink::StorageKey& key) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!registrations_initialized_) { + return true; + } + if (registered_storage_keys_.find(key) != registered_storage_keys_.end()) { + return true; + } + return false; +} + +void ServiceWorkerContextCore::WaitForRegistrationsInitializedForTest() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (registrations_initialized_) + return; + base::RunLoop loop; + on_registrations_initialized_for_test_ = loop.QuitClosure(); + loop.Run(); +} + void ServiceWorkerContextCore::RegistrationComplete( const GURL& scope, const blink::StorageKey& key, @@ -916,6 +948,7 @@ const GURL& scope, const blink::StorageKey& key) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + registered_storage_keys_.insert(key); observer_list_->Notify( FROM_HERE, &ServiceWorkerContextCoreObserver::OnRegistrationStored, registration_id, scope, key); @@ -924,6 +957,7 @@ void ServiceWorkerContextCore::NotifyAllRegistrationsDeletedForStorageKey( const blink::StorageKey& key) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + registered_storage_keys_.erase(key); observer_list_->Notify( FROM_HERE, &ServiceWorkerContextCoreObserver::OnAllRegistrationsDeletedForStorageKey, @@ -1122,4 +1156,25 @@ CheckFetchHandlerOfInstalledServiceWorker(std::move(callback), registration); } +void ServiceWorkerContextCore::DidGetRegisteredStorageKeys( + base::TimeTicks start_time, + const std::vector<blink::StorageKey>& storage_keys) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + for (const blink::StorageKey& storage_key : storage_keys) + registered_storage_keys_.insert(storage_key); + + DCHECK(!registrations_initialized_); + registrations_initialized_ = true; + + if (on_registrations_initialized_for_test_) + std::move(on_registrations_initialized_for_test_).Run(); + + if (!start_time.is_null()) { + base::UmaHistogramMediumTimes( + "ServiceWorker.Storage.RegisteredStorageKeyCacheInitialization.Time", + base::TimeTicks::Now() - start_time); + } +} + } // namespace content
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h index 856a240..1bac459b 100644 --- a/content/browser/service_worker/service_worker_context_core.h +++ b/content/browser/service_worker/service_worker_context_core.h
@@ -376,6 +376,13 @@ void NotifyClientIsExecutionReady( const ServiceWorkerContainerHost& container_host); + bool MaybeHasRegistrationForStorageKey(const blink::StorageKey& key); + + // This method waits for service worker registrations to be initialized, and + // depends on |on_registrations_initialized_| and |registrations_initialized_| + // which are called in InitializeRegisteredOrigins(). + void WaitForRegistrationsInitializedForTest(); + private: friend class ServiceWorkerContextCoreTest; FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextCoreTest, FailureInfo); @@ -424,6 +431,12 @@ ServiceWorkerContext::CheckHasServiceWorkerCallback callback, scoped_refptr<ServiceWorkerRegistration> registration); + // This is used as a callback of GetRegisteredStorageKeys when initialising to + // store a list of storage keys that have registered service workers. + void DidGetRegisteredStorageKeys( + base::TimeTicks start_time, + const std::vector<blink::StorageKey>& storage_keys); + // It's safe to store a raw pointer instead of a scoped_refptr to |wrapper_| // because the Wrapper::Shutdown call that hops threads to destroy |this| uses // Bind() to hold a reference to |wrapper_| until |this| is fully destroyed. @@ -484,6 +497,13 @@ std::unique_ptr<mojo::Receiver<storage::mojom::QuotaClient>> quota_client_receiver_; + // A set of StorageKeys that have at least one registration. + // TODO(http://crbug.com/824858): This can be removed when service workers are + // fully converted to running on the UI thread. + std::set<blink::StorageKey> registered_storage_keys_; + bool registrations_initialized_ = false; + base::OnceClosure on_registrations_initialized_for_test_; + base::WeakPtrFactory<ServiceWorkerContextCore> weak_factory_{this}; };
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index d079ede7..4ff63cc 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -259,10 +259,6 @@ quota_manager_proxy, special_storage_policy, std::move(non_network_pending_loader_factory_bundle_for_update_check), core_observer_list_.get(), this); - - context()->registry()->GetRegisteredStorageKeys( - base::BindOnce(&ServiceWorkerContextWrapper::DidGetRegisteredStorageKeys, - this, base::TimeTicks::Now())); } void ServiceWorkerContextWrapper::Shutdown() { @@ -319,9 +315,6 @@ const GURL& scope, const blink::StorageKey& key) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - registered_storage_keys_.insert(key); - for (auto& observer : observer_list_) observer.OnRegistrationStored(registration_id, scope); } @@ -329,7 +322,6 @@ void ServiceWorkerContextWrapper::OnAllRegistrationsDeletedForStorageKey( const blink::StorageKey& key) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - registered_storage_keys_.erase(key); } void ServiceWorkerContextWrapper::OnErrorReported( @@ -575,13 +567,7 @@ bool ServiceWorkerContextWrapper::MaybeHasRegistrationForStorageKey( const blink::StorageKey& key) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!registrations_initialized_) { - return true; - } - if (registered_storage_keys_.find(key) != registered_storage_keys_.end()) { - return true; - } - return false; + return context() ? context()->MaybeHasRegistrationForStorageKey(key) : true; } void ServiceWorkerContextWrapper::GetAllOriginsInfo( @@ -1610,30 +1596,6 @@ std::move(loader_factory_bundle_info)); } -void ServiceWorkerContextWrapper::WaitForRegistrationsInitializedForTest() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (registrations_initialized_) - return; - base::RunLoop loop; - on_registrations_initialized_for_test_ = loop.QuitClosure(); - loop.Run(); -} - -void ServiceWorkerContextWrapper::DidGetRegisteredStorageKeys( - base::TimeTicks start_time, - const std::vector<blink::StorageKey>& storage_keys) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - for (const blink::StorageKey& storage_key : storage_keys) - registered_storage_keys_.insert(storage_key); - registrations_initialized_ = true; - if (on_registrations_initialized_for_test_) - std::move(on_registrations_initialized_for_test_).Run(); - - base::UmaHistogramMediumTimes( - "ServiceWorker.Storage.RegisteredStorageKeyCacheInitialization.Time", - base::TimeTicks::Now() - start_time); -} - void ServiceWorkerContextWrapper::ClearRunningServiceWorkers() { DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h index c4bcb6c..b88e2809 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.h +++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -362,11 +362,6 @@ // DeleteAndStartOver fails. ServiceWorkerContextCore* context(); - // This method waits for service worker registrations to be initialized, and - // depends on |on_registrations_initialized_| and |registrations_initialized_| - // which are called in InitializeRegisteredOrigins(). - void WaitForRegistrationsInitializedForTest(); - void SetLoaderFactoryForUpdateCheckForTest( scoped_refptr<network::SharedURLLoaderFactory> loader_factory); // Returns nullptr on failure. @@ -469,12 +464,6 @@ CreateNonNetworkPendingURLLoaderFactoryBundleForUpdateCheck( BrowserContext* browser_context); - // This is used as a callback of GetRegisteredStorageKeys when initialising to - // store a list of storage keys that have registered service workers. - void DidGetRegisteredStorageKeys( - base::TimeTicks start_time, - const std::vector<blink::StorageKey>& storage_keys); - // TODO(https://crbug.com/1295029): Remove. Temporary workaround. void StartServiceWorkerAndDispatchMessageOnUIThread( const GURL& scope, @@ -517,13 +506,6 @@ base::flat_map<int64_t /* version_id */, ServiceWorkerRunningInfo> running_service_workers_; - // A set of StorageKeys that have at least one registration. - // TODO(http://crbug.com/824858): This can be removed when service workers are - // fully converted to running on the UI thread. - std::set<blink::StorageKey> registered_storage_keys_; - bool registrations_initialized_ = false; - base::OnceClosure on_registrations_initialized_for_test_; - std::unique_ptr<ServiceWorkerIdentifiabilityMetrics> identifiability_metrics_; // TODO(crbug.com/1055677): Remove `storage_control_` when
diff --git a/content/browser/service_worker/service_worker_context_wrapper_unittest.cc b/content/browser/service_worker/service_worker_context_wrapper_unittest.cc index c5f0d8f..2ef074b 100644 --- a/content/browser/service_worker/service_worker_context_wrapper_unittest.cc +++ b/content/browser/service_worker/service_worker_context_wrapper_unittest.cc
@@ -150,7 +150,7 @@ InitWrapper(); // Now test that registrations are recognized. - wrapper_->WaitForRegistrationsInitializedForTest(); + wrapper_->context()->WaitForRegistrationsInitializedForTest(); EXPECT_TRUE(wrapper_->MaybeHasRegistrationForStorageKey(key)); EXPECT_FALSE(wrapper_->MaybeHasRegistrationForStorageKey( blink::StorageKey(url::Origin::Create(GURL("https://example.org"))))); @@ -162,7 +162,7 @@ // key, and should only return FALSE when ALL registrations for that key // have been deleted from storage. TEST_F(ServiceWorkerContextWrapperTest, DeleteRegistrationsForSameKey) { - wrapper_->WaitForRegistrationsInitializedForTest(); + wrapper_->context()->WaitForRegistrationsInitializedForTest(); // Make two registrations for same origin. GURL scope1("https://example1.com/abc/"); @@ -216,7 +216,7 @@ scope_feature_list_.InitAndEnableFeature( blink::features::kThirdPartyStoragePartitioning); - wrapper_->WaitForRegistrationsInitializedForTest(); + wrapper_->context()->WaitForRegistrationsInitializedForTest(); // Make two registrations for same origin, but different top-level site. GURL scope("https://example1.com/abc/"); @@ -270,7 +270,7 @@ // registrations may exist, MaybeHasRegistrationForStorageKey correctly returns // FALSE since the registrations do not exist in storage. TEST_F(ServiceWorkerContextWrapperTest, DeleteRegistration) { - wrapper_->WaitForRegistrationsInitializedForTest(); + wrapper_->context()->WaitForRegistrationsInitializedForTest(); // Make registration. GURL scope1("https://example2.com/");
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index 3b7c2b29..08c725e 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -7000,8 +7000,8 @@ gfx::QuadF TransformRectToQuadF( const viz::AggregatedHitTestRegion& hit_test_region) { - return TransformRectToQuadF(hit_test_region.rect, - hit_test_region.transform(), false); + return TransformRectToQuadF(hit_test_region.rect, hit_test_region.transform, + false); } bool ApproximatelyEqual(const gfx::PointF& p1, const gfx::PointF& p2) const { @@ -7018,9 +7018,9 @@ gfx::Rect AxisAlignedLayoutRectFromHitTest( const viz::AggregatedHitTestRegion& hit_test_region) { - DCHECK(hit_test_region.transform().Preserves2dAxisAlignment()); + DCHECK(hit_test_region.transform.Preserves2dAxisAlignment()); gfx::RectF rect(hit_test_region.rect); - hit_test_region.transform().TransformRect(&rect); + hit_test_region.transform.TransformRect(&rect); return gfx::ToEnclosingRect(rect); } @@ -7087,7 +7087,7 @@ AxisAlignedLayoutRectFromHitTest(hit_test_data[2]), base::ClampRound(device_scale_factor) + 2)); EXPECT_TRUE( - expected_transform.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(expected_flags, hit_test_data[2].flags); } @@ -7122,7 +7122,7 @@ EXPECT_TRUE(expected_region.ApproximatelyEqual(hit_test_data[2].rect, 1 + device_scale_factor)); EXPECT_TRUE( - expected_transform.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags); } @@ -7168,12 +7168,12 @@ // Since iframe is clipped into an octagon, we expect to do slow path hit // test on the iframe. DCHECK(hit_test_data.size() >= 3); - EXPECT_TRUE(expected_region1.ApproximatelyEqual(hit_test_data[2].rect, - 1 + device_scale_factor) || - expected_region2.ApproximatelyEqual(hit_test_data[2].rect, - 1 + device_scale_factor)); + EXPECT_TRUE(expected_region1.ApproximatelyEqual(hit_test_data[2].rect, + 1 + device_scale_factor) || + expected_region2.ApproximatelyEqual(hit_test_data[2].rect, + 1 + device_scale_factor)); EXPECT_TRUE( - expected_transform.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags); } @@ -7200,7 +7200,7 @@ expected_region2.ApproximatelyEqual(hit_test_data[2].rect, 1 + device_scale_factor)); EXPECT_TRUE( - expected_transform.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags); } @@ -7221,11 +7221,11 @@ DCHECK(hit_test_data.size() >= 4); EXPECT_EQ(expected_region.ToString(), hit_test_data[3].rect.ToString()); EXPECT_TRUE( - expected_transform1.ApproximatelyEqual(hit_test_data[3].transform())); + expected_transform1.ApproximatelyEqual(hit_test_data[3].transform)); EXPECT_EQ(kSlowHitTestFlags, hit_test_data[3].flags); EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString()); EXPECT_TRUE( - expected_transform2.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform2.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags); } @@ -7243,7 +7243,7 @@ DCHECK(hit_test_data.size() >= 3); EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString()); EXPECT_TRUE( - expected_transform.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags); } @@ -7261,7 +7261,7 @@ DCHECK(hit_test_data.size() >= 3); EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString()); EXPECT_TRUE( - expected_transform.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags); } @@ -7288,13 +7288,13 @@ DCHECK(hit_test_data.size() == 4); EXPECT_EQ(expected_region2.ToString(), hit_test_data[3].rect.ToString()); EXPECT_TRUE( - expected_transform2.ApproximatelyEqual(hit_test_data[3].transform())); + expected_transform2.ApproximatelyEqual(hit_test_data[3].transform)); EXPECT_EQ(flags | viz::HitTestRegionFlags::kHitTestIgnore, hit_test_data[3].flags); EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString()); EXPECT_TRUE( - expected_transform.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(flags, hit_test_data[2].flags); FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) @@ -7324,12 +7324,12 @@ ASSERT_EQ(4u, hit_test_data.size()); EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString()); EXPECT_TRUE( - expected_transform.ApproximatelyEqual(hit_test_data[2].transform())); + expected_transform.ApproximatelyEqual(hit_test_data[2].transform)); EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags); EXPECT_EQ(expected_region2.ToString(), hit_test_data[3].rect.ToString()); EXPECT_TRUE( - expected_transform2.ApproximatelyEqual(hit_test_data[3].transform())); + expected_transform2.ApproximatelyEqual(hit_test_data[3].transform)); // Hit test region with pointer-events: none is marked as kHitTestIgnore. The // JavaScript above sets the element's pointer-events to 'auto' therefore // kHitTestIgnore should be removed from the flag.
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc index a7377fb..ddfd35c 100644 --- a/content/browser/web_contents/web_contents_view_android.cc +++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -426,9 +426,9 @@ return true; } -// TODO(paulmeyer): The drag-and-drop calls on GetRenderViewHost()->GetWidget() -// in the following functions will need to be targeted to specific -// RenderWidgetHosts in order to work with OOPIFs. See crbug.com/647249. +// TODO(crbug.com/1301905): does not work for OOPIFs. The drag-and-drop calls +// on GetRenderViewHost()->GetWidget() in the following functions will need to +// be targeted to specific RenderWidgetHosts. void WebContentsViewAndroid::OnDragEntered( const std::vector<DropData::Metadata>& metadata,
diff --git a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc index e14f70b..592b7fe5 100644 --- a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc +++ b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
@@ -1896,6 +1896,19 @@ RegisterRequestHandler(embedded_test_server()); RegisterRequestHandler(data_server.get()); + + // Prefetch requests for alternate SXG should be made with no-cors, + // regardless of the crossorigin attribute of Link:rel=preload header that + // triggered the prefetch. + embedded_test_server()->RegisterRequestMonitor( + base::BindRepeating([](const net::test_server::HttpRequest& request) { + if (!base::EndsWith(request.relative_url, "_data.sxg")) + return; + auto it = request.headers.find("Sec-Fetch-Mode"); + ASSERT_TRUE(it != request.headers.end()); + EXPECT_EQ(it->second, "no-cors"); + })); + ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(data_server->Start());
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index 4e95076c..68ec2ed 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -427,7 +427,6 @@ } } - endpoints_.idp = ResolveManifestUrl(endpoints.idp); endpoints_.token = ResolveManifestUrl(endpoints.token); endpoints_.accounts = ResolveManifestUrl(endpoints.accounts); endpoints_.client_metadata = ResolveManifestUrl(endpoints.client_metadata);
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc index 239fa13..042358f 100644 --- a/content/browser/webid/federated_auth_request_impl_unittest.cc +++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -68,7 +68,7 @@ constexpr bool kNotPreferAutoSignIn = false; constexpr char kRpTestOrigin[] = "https://rp.example"; constexpr char kIdpTestOrigin[] = "https://idp.example"; -constexpr char kIdpEndpoint[] = "https://idp.example/webid"; +constexpr char kProviderUrl[] = "https://idp.example"; constexpr char kAccountsEndpoint[] = "https://idp.example/accounts"; constexpr char kCrossOriginAccountsEndpoint[] = "https://idp2.example/accounts"; constexpr char kTokenEndpoint[] = "https://idp.example/token"; @@ -125,7 +125,6 @@ const char* token; absl::optional<FetchStatus> manifest_fetch_status; absl::optional<MockClientIdConfiguration> client_metadata; - const char* idp_endpoint; const char* accounts_endpoint; const char* token_endpoint; const char* client_metadata_endpoint; @@ -168,7 +167,7 @@ {RequestIdTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, kEmptyToken}, - {kToken, FetchStatus::kInvalidResponseError, absl::nullopt, kIdpEndpoint, + {kToken, FetchStatus::kInvalidResponseError, absl::nullopt, kAccountsEndpoint, "", kClientMetadataEndpoint, kMediatedNoop}}, {"Error parsing FedCM manifest for Mediated mode missing accounts endpoint", @@ -176,15 +175,15 @@ {RequestIdTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, kEmptyToken}, - {kToken, FetchStatus::kSuccess, absl::nullopt, kIdpEndpoint, "", - kTokenEndpoint, kClientMetadataEndpoint, kMediatedNoop}}, + {kToken, FetchStatus::kSuccess, absl::nullopt, "", kTokenEndpoint, + kClientMetadataEndpoint, kMediatedNoop}}, {"Error due to accounts endpoint in different origin than identity " "provider", {kIdpTestOrigin, kClientId, kNonce}, {RequestIdTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, kEmptyToken}, - {kToken, FetchStatus::kSuccess, absl::nullopt, kIdpEndpoint, + {kToken, FetchStatus::kSuccess, absl::nullopt, kCrossOriginAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, kMediatedNoop}}, @@ -196,7 +195,6 @@ {kEmptyToken, FetchStatus::kSuccess, kSuccessfulClientId, - "", kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, @@ -210,7 +208,6 @@ {kToken, FetchStatus::kSuccess, kSuccessfulClientId, - "", kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, @@ -223,7 +220,6 @@ {kToken, FetchStatus::kSuccess, kSuccessfulClientId, - "", kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, @@ -234,7 +230,7 @@ {RequestIdTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingClientMetadataHttpNotFound, kEmptyToken}, - {kToken, FetchStatus::kSuccess, kClientMetadataHttpNotFound, "", + {kToken, FetchStatus::kSuccess, kClientMetadataHttpNotFound, kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, kMediatedNoop}}, @@ -243,7 +239,7 @@ {RequestIdTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingClientMetadataNoResponse, kEmptyToken}, - {kToken, FetchStatus::kSuccess, kClientMetadataNoResponse, "", + {kToken, FetchStatus::kSuccess, kClientMetadataNoResponse, kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, kMediatedNoop}}, @@ -252,7 +248,7 @@ {RequestIdTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingClientMetadataInvalidResponse, kEmptyToken}, - {kToken, FetchStatus::kSuccess, kClientMetadataInvalidResponse, "", + {kToken, FetchStatus::kSuccess, kClientMetadataInvalidResponse, kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, kMediatedNoop}}, }; @@ -449,7 +445,7 @@ RevokeStatus PerformRevokeRequest(const char* account_id) { RevokeRequestCallbackHelper revoke_helper; - request_remote_->Revoke(GURL(kIdpEndpoint), kClientId, account_id, + request_remote_->Revoke(GURL(kProviderUrl), kClientId, account_id, revoke_helper.callback()); revoke_helper.WaitForCallback(); return revoke_helper.status(); @@ -523,7 +519,6 @@ [&](absl::optional<int>, absl::optional<int>, IdpNetworkRequestManager::FetchManifestCallback callback) { IdpNetworkRequestManager::Endpoints endpoints; - endpoints.idp = test_case.config.idp_endpoint; endpoints.accounts = test_case.config.accounts_endpoint; endpoints.token = test_case.config.token_endpoint; endpoints.client_metadata = @@ -822,7 +817,6 @@ {kToken, FetchStatus::kSuccess, kSuccessfulClientId, - "", kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, @@ -836,7 +830,6 @@ {kToken, FetchStatus::kSuccess, kSuccessfulClientId, - "", kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, @@ -850,7 +843,6 @@ {kToken, FetchStatus::kSuccess, kSuccessfulClientId, - "", kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, @@ -1080,7 +1072,7 @@ TEST_F(FederatedAuthRequestImplTest, Revoke) { constexpr char kAccountId[] = "foo@bar.com"; - auto& auth_request = CreateAuthRequest(GURL(kIdpEndpoint)); + auto& auth_request = CreateAuthRequest(GURL(kProviderUrl)); auth_request.SetRequestPermissionDelegateForTests( mock_request_permission_delegate_.get()); @@ -1131,7 +1123,7 @@ TEST_F(FederatedAuthRequestImplTest, RevokeNoPermission) { constexpr char kAccountId[] = "foo@bar.com"; - auto& auth_request = CreateAuthRequest(GURL(kIdpEndpoint)); + auto& auth_request = CreateAuthRequest(GURL(kProviderUrl)); auth_request.SetRequestPermissionDelegateForTests( mock_request_permission_delegate_.get()); @@ -1261,7 +1253,6 @@ {kToken, FetchStatus::kSuccess, kSuccessfulClientId, - "", kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint, @@ -1369,7 +1360,6 @@ {kToken, FetchStatus::kSuccess, kSuccessfulClientId, - "", kAccountsEndpoint, kTokenEndpoint, kClientMetadataEndpoint,
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc index 99f3d6e..044b16b6 100644 --- a/content/browser/webid/idp_network_request_manager.cc +++ b/content/browser/webid/idp_network_request_manager.cc
@@ -39,7 +39,6 @@ // referenced here. // fedcm.json configuration keys. -constexpr char kIdpEndpointKey[] = "idp_endpoint"; constexpr char kTokenEndpointKey[] = "id_token_endpoint"; constexpr char kAccountsEndpointKey[] = "accounts_endpoint"; constexpr char kClientMetadataEndpointKey[] = "client_metadata_endpoint"; @@ -623,7 +622,6 @@ }; Endpoints endpoints; - endpoints.idp = ExtractEndpoint(kIdpEndpointKey); endpoints.token = ExtractEndpoint(kTokenEndpointKey); endpoints.accounts = ExtractEndpoint(kAccountsEndpointKey); endpoints.client_metadata = ExtractEndpoint(kClientMetadataEndpointKey);
diff --git a/content/browser/webid/idp_network_request_manager.h b/content/browser/webid/idp_network_request_manager.h index cb54378..b5257e1 100644 --- a/content/browser/webid/idp_network_request_manager.h +++ b/content/browser/webid/idp_network_request_manager.h
@@ -92,7 +92,6 @@ ~Endpoints(); Endpoints(const Endpoints&); - std::string idp; std::string token; std::string accounts; std::string client_metadata;
diff --git a/content/test/data/attribution_reporting/register_impression.js b/content/test/data/attribution_reporting/register_impression.js index 8f7bcbb0..4c2cbcd 100644 --- a/content/test/data/attribution_reporting/register_impression.js +++ b/content/test/data/attribution_reporting/register_impression.js
@@ -27,7 +27,6 @@ reportOrigin, expiry, priority, - registerAttributionSource = false, left, top, } = {}) { @@ -49,9 +48,6 @@ if (priority !== undefined) anchor.setAttribute('attributionsourcepriority', priority); - if (registerAttributionSource) - anchor.setAttribute('registerattributionsource', ''); - if (left !== undefined && top !== undefined) { const style = 'position: absolute; left: ' + (left - 10) + 'px; top: ' + (top - 10) + 'px; width: 20px; height: 20px;';
diff --git a/device/vr/android/arcore/arcore_impl.cc b/device/vr/android/arcore/arcore_impl.cc index 7385288..e102131 100644 --- a/device/vr/android/arcore/arcore_impl.cc +++ b/device/vr/android/arcore/arcore_impl.cc
@@ -19,7 +19,6 @@ #include "device/vr/android/arcore/type_converters.h" #include "device/vr/public/mojom/pose.h" #include "device/vr/public/mojom/vr_service.mojom.h" -#include "skia/ext/skia_matrix_44.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h"
diff --git a/docs/android_emulator.md b/docs/android_emulator.md index a1b4126..0b17623c 100644 --- a/docs/android_emulator.md +++ b/docs/android_emulator.md
@@ -34,15 +34,15 @@ | `generic_android29.textpb` | 10 (Q) | google_apis | N/A | | `generic_android30.textpb` | 11 (R) | google_apis | [android-11-x86-rel][android-11-x86-rel] | | `generic_playstore_android30.textpb` | 11 (R) | google_apis_playstore | [android-11-x86-rel][android-11-x86-rel] | -| `generic_android31.textpb` | 12 (S) | google_apis | [android-12-x64-fyi-rel][android-12-x64-fyi-rel] | -| `generic_playstore_android31.textpb` | 12 (S) | google_apis_playstore | [android-12-x64-fyi-rel][android-12-x64-fyi-rel] | +| `generic_android31.textpb` | 12 (S) | google_apis | [android-12-x64-rel][android-12-x64-rel] | +| `generic_playstore_android31.textpb` | 12 (S) | google_apis_playstore | [android-12-x64-rel][android-12-x64-rel] | You can use these configuration files to run the same emulator images locally. [android-marshmallow-x86-rel]: https://ci.chromium.org/p/chromium/builders/ci/android-marshmallow-x86-rel [android-pie-x86-rel]: https://ci.chromium.org/p/chromium/builders/ci/android-pie-x86-rel [android-11-x86-rel]: https://ci.chromium.org/p/chromium/builders/ci/android-11-x86-rel -[android-12-x64-fyi-rel]: https://ci.chromium.org/p/chromium/builders/ci/android-12-x64-fyi-rel +[android-12-x64-rel]: https://ci.chromium.org/p/chromium/builders/ci/android-12-x64-rel #### Prerequisite
diff --git a/docs/security/sheriff.md b/docs/security/sheriff.md index c1501bd2..1c08d25 100644 --- a/docs/security/sheriff.md +++ b/docs/security/sheriff.md
@@ -222,6 +222,9 @@ 100% of the test case. If not, use a disposable virtual machine. If you're inside Google, a good way to do this is using [Redshell](https://goto.google.com/redshell-for-chrome-sheriffs). +* [Instructions for using an Android emulator can be found + here](/docs/android_emulator.md). If you're inside Google, we have a + [guide for testing using Google infrastructure](https://goto.google.com/android-for-chrome-sheriffs). * When you can't just build from a specific branch locally, check out [https://dev.chromium.org/getting-involved/dev-channel](https://dev.chromium.org/getting-involved/dev-channel) or
diff --git a/extensions/browser/view_type_utils.cc b/extensions/browser/view_type_utils.cc index a307a97a..f668561 100644 --- a/extensions/browser/view_type_utils.cc +++ b/extensions/browser/view_type_utils.cc
@@ -6,6 +6,7 @@ #include "base/lazy_instance.h" #include "content/public/browser/web_contents.h" +#include "extensions/browser/extension_web_contents_observer.h" #include "extensions/browser/extensions_browser_client.h" using content::WebContents; @@ -43,6 +44,17 @@ std::make_unique<ViewTypeUserData>(type)); ExtensionsBrowserClient::Get()->AttachExtensionTaskManagerTag(tab, type); + + auto send_view_type_to_renderer = [](ExtensionWebContentsObserver* ewco, + mojom::ViewType type, + content::RenderFrameHost* frame_host) { + if (mojom::LocalFrame* local_frame = ewco->GetLocalFrame(frame_host)) + local_frame->NotifyRenderViewType(type); + }; + if (auto* ewco = ExtensionWebContentsObserver::GetForWebContents(tab)) { + tab->ForEachRenderFrameHost( + base::BindRepeating(send_view_type_to_renderer, ewco, type)); + } } } // namespace extensions
diff --git a/gpu/vulkan/generate_bindings.py b/gpu/vulkan/generate_bindings.py index d9ca37e..6b506da2 100755 --- a/gpu/vulkan/generate_bindings.py +++ b/gpu/vulkan/generate_bindings.py
@@ -389,6 +389,8 @@ #include <vulkan/vulkan.h> +#include <memory> + #include "base/compiler_specific.h" #include "base/component_export.h" #include "base/containers/flat_map.h"
diff --git a/gpu/vulkan/vulkan_function_pointers.h b/gpu/vulkan/vulkan_function_pointers.h index 8a824a2..f6b0556 100644 --- a/gpu/vulkan/vulkan_function_pointers.h +++ b/gpu/vulkan/vulkan_function_pointers.h
@@ -13,6 +13,8 @@ #include <vulkan/vulkan.h> +#include <memory> + #include "base/compiler_specific.h" #include "base/component_export.h" #include "base/containers/flat_map.h"
diff --git a/infra/config/generated/builders/ci/android-12-x64-fyi-rel/properties.json b/infra/config/generated/builders/ci/android-12-x64-fyi-rel/properties.json index b6e2921..c6534f7 100644 --- a/infra/config/generated/builders/ci/android-12-x64-fyi-rel/properties.json +++ b/infra/config/generated/builders/ci/android-12-x64-fyi-rel/properties.json
@@ -1,8 +1,9 @@ { - "$build/reclient": { - "instance": "rbe-chromium-trusted", - "jobs": 250, - "metrics_project": "chromium-reclient-metrics" + "$build/goma": { + "enable_ats": true, + "rpc_extra_params": "?prod", + "server_host": "goma.chromium.org", + "use_luci_auth": true }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git a/infra/config/generated/builders/ci/android-12-x64-rel/properties.json b/infra/config/generated/builders/ci/android-12-x64-rel/properties.json new file mode 100644 index 0000000..8252801 --- /dev/null +++ b/infra/config/generated/builders/ci/android-12-x64-rel/properties.json
@@ -0,0 +1,19 @@ +{ + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 500, + "metrics_project": "chromium-reclient-metrics" + }, + "$recipe_engine/resultdb/test_presentation": { + "column_keys": [], + "grouping_keys": [ + "status", + "v.test_suite" + ] + }, + "builder_group": "chromium.android", + "recipe": "chromium", + "sheriff_rotations": [ + "android" + ] +} \ No newline at end of file
diff --git a/infra/config/generated/builders/try/android-12-x64-fyi-rel/properties.json b/infra/config/generated/builders/try/android-12-x64-rel-compilator/properties.json similarity index 67% rename from infra/config/generated/builders/try/android-12-x64-fyi-rel/properties.json rename to infra/config/generated/builders/try/android-12-x64-rel-compilator/properties.json index d90599c..dc7af2f 100644 --- a/infra/config/generated/builders/try/android-12-x64-fyi-rel/properties.json +++ b/infra/config/generated/builders/try/android-12-x64-rel-compilator/properties.json
@@ -1,6 +1,7 @@ { "$build/goma": { "enable_ats": true, + "jobs": 300, "rpc_extra_params": "?prod", "server_host": "goma.chromium.org", "use_luci_auth": true @@ -13,5 +14,9 @@ ] }, "builder_group": "tryserver.chromium.android", - "recipe": "chromium_trybot" + "orchestrator": { + "builder_group": "tryserver.chromium.android", + "builder_name": "android-12-x64-rel" + }, + "recipe": "chromium/compilator" } \ No newline at end of file
diff --git a/infra/config/generated/builders/try/android-12-x64-rel/properties.json b/infra/config/generated/builders/try/android-12-x64-rel/properties.json new file mode 100644 index 0000000..7fef7c8 --- /dev/null +++ b/infra/config/generated/builders/try/android-12-x64-rel/properties.json
@@ -0,0 +1,15 @@ +{ + "$build/chromium_orchestrator": { + "compilator": "android-12-x64-rel-compilator", + "compilator_watcher_git_revision": "c49f1d02dec735eb0e8f03121d3fab2840c2c954" + }, + "$recipe_engine/resultdb/test_presentation": { + "column_keys": [], + "grouping_keys": [ + "status", + "v.test_suite" + ] + }, + "builder_group": "tryserver.chromium.android", + "recipe": "chromium/orchestrator" +} \ No newline at end of file
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index b1b68bae..8703708 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -285,7 +285,11 @@ includable_only: true } builders { - name: "chromium/try/android-12-x64-fyi-rel" + name: "chromium/try/android-12-x64-rel" + includable_only: true + } + builders { + name: "chromium/try/android-12-x64-rel-compilator" includable_only: true } builders {
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 86d66cc2..b5154dc4 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -22426,7 +22426,89 @@ ' "led_builder_is_bootstrapped": true,' ' "recipe": "chromium"' '}' - execution_timeout_secs: 21600 + execution_timeout_secs: 10800 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "ci_test_results" + test_results {} + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "gpu_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+" + } + } + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "blink_web_tests_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://[^/]*blink_web_tests/.+" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { + name: "android-12-x64-rel" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-18.04" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:0" + exe { + cipd_package: "infra/chromium/bootstrapper/${platform}" + cipd_version: "latest" + cmd: "bootstrapper" + } + properties: + '{' + ' "$bootstrap/exe": {' + ' "exe": {' + ' "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",' + ' "cipd_version": "refs/heads/main",' + ' "cmd": [' + ' "luciexe"' + ' ]' + ' }' + ' },' + ' "$bootstrap/properties": {' + ' "properties_file": "infra/config/generated/builders/ci/android-12-x64-rel/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "chromium.android",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chromium",' + ' "sheriff_rotations": [' + ' "android"' + ' ]' + '}' + execution_timeout_secs: 14400 build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" experiments { @@ -47054,14 +47136,13 @@ } } builders { - name: "android-12-x64-fyi-rel" + name: "android-12-x64-rel" swarming_host: "chromium-swarm.appspot.com" - dimensions: "builderless:1" - dimensions: "cores:8" + dimensions: "builder:android-12-x64-rel" + dimensions: "cores:4" dimensions: "cpu:x86-64" dimensions: "os:Ubuntu-18.04" dimensions: "pool:luci.chromium.try" - dimensions: "ssd:0" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" cipd_version: "latest" @@ -47079,7 +47160,7 @@ ' }' ' },' ' "$bootstrap/properties": {' - ' "properties_file": "infra/config/generated/builders/try/android-12-x64-fyi-rel/properties.json",' + ' "properties_file": "infra/config/generated/builders/try/android-12-x64-rel/properties.json",' ' "top_level_project": {' ' "ref": "refs/heads/main",' ' "repo": {' @@ -47090,7 +47171,98 @@ ' },' ' "builder_group": "tryserver.chromium.android",' ' "led_builder_is_bootstrapped": true,' - ' "recipe": "chromium_trybot"' + ' "recipe": "chromium/orchestrator"' + '}' + execution_timeout_secs: 14400 + expiration_secs: 7200 + grace_period { + seconds: 120 + } + caches { + name: "win_toolchain" + path: "win_toolchain" + } + build_numbers: YES + service_account: "chromium-orchestrator@chops-service-accounts.iam.gserviceaccount.com" + task_template_canary_percentage { + value: 5 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "try_test_results" + test_results {} + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "gpu_try_test_results" + test_results { + predicate { + test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+" + } + } + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "blink_web_tests_try_test_results" + test_results { + predicate { + test_id_regexp: "ninja://[^/]*blink_web_tests/.+" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + description_html: "This is the orchestrator half of an orchestrator + compilator pair of builders. The compilator is <a href=\"https://ci.chromium.org/p/chromium/builders/try/android-12-x64-rel-compilator\">android-12-x64-rel-compilator</a>." + } + builders { + name: "android-12-x64-rel-compilator" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builder:android-12-x64-rel-compilator" + dimensions: "cores:32" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-18.04" + dimensions: "pool:luci.chromium.try" + dimensions: "ssd:1" + exe { + cipd_package: "infra/chromium/bootstrapper/${platform}" + cipd_version: "latest" + cmd: "bootstrapper" + } + properties: + '{' + ' "$bootstrap/exe": {' + ' "exe": {' + ' "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",' + ' "cipd_version": "refs/heads/main",' + ' "cmd": [' + ' "luciexe"' + ' ]' + ' }' + ' },' + ' "$bootstrap/properties": {' + ' "properties_file": "infra/config/generated/builders/try/android-12-x64-rel-compilator/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "tryserver.chromium.android",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chromium/compilator"' '}' execution_timeout_secs: 14400 expiration_secs: 7200 @@ -47142,6 +47314,7 @@ use_invocation_timestamp: true } } + description_html: "This is the compilator half of an orchestrator + compilator pair of builders. The orchestrator is <a href=\"https://ci.chromium.org/p/chromium/builders/try/android-12-x64-rel\">android-12-x64-rel</a>." } builders { name: "android-angle-chromium-try"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index bf56e432..e14b9fa1 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -2409,6 +2409,12 @@ name: "buildbucket/luci.chromium.try/android-11-x86-rel-compilator" } builders { + name: "buildbucket/luci.chromium.try/android-12-x64-rel" + } + builders { + name: "buildbucket/luci.chromium.try/android-12-x64-rel-compilator" + } + builders { name: "buildbucket/luci.chromium.try/android-binary-size" } builders { @@ -3276,6 +3282,11 @@ short_name: "p-cov" } builders { + name: "buildbucket/luci.chromium.ci/android-12-x64-rel" + category: "builder_tester|x64" + short_name: "12" + } + builders { name: "buildbucket/luci.chromium.ci/android-11-x86-rel" category: "builder_tester|x86" short_name: "11" @@ -14124,7 +14135,10 @@ name: "buildbucket/luci.chromium.try/android-12-x64-dbg" } builders { - name: "buildbucket/luci.chromium.try/android-12-x64-fyi-rel" + name: "buildbucket/luci.chromium.try/android-12-x64-rel" + } + builders { + name: "buildbucket/luci.chromium.try/android-12-x64-rel-compilator" } builders { name: "buildbucket/luci.chromium.try/android-angle-chromium-try" @@ -15247,7 +15261,10 @@ name: "buildbucket/luci.chromium.try/android-12-x64-dbg" } builders { - name: "buildbucket/luci.chromium.try/android-12-x64-fyi-rel" + name: "buildbucket/luci.chromium.try/android-12-x64-rel" + } + builders { + name: "buildbucket/luci.chromium.try/android-12-x64-rel-compilator" } builders { name: "buildbucket/luci.chromium.try/android-asan"
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg index 39826a8..398a6697 100644 --- a/infra/config/generated/luci/luci-scheduler.cfg +++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -4005,13 +4005,13 @@ } } job { - id: "android-12-x64-fyi-rel" + id: "android-12-x64-rel" realm: "ci" acl_sets: "ci" buildbucket { server: "cr-buildbucket.appspot.com" bucket: "ci" - builder: "android-12-x64-fyi-rel" + builder: "android-12-x64-rel" } } job { @@ -7178,7 +7178,7 @@ triggers: "Windows deterministic" triggers: "android-10-arm64-rel" triggers: "android-11-x86-rel" - triggers: "android-12-x64-fyi-rel" + triggers: "android-12-x64-rel" triggers: "android-angle-arm64-builder" triggers: "android-angle-chromium-arm64-builder" triggers: "android-annotator-rel"
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.fyi.star b/infra/config/subprojects/chromium/ci/chromium.android.fyi.star index b37152b0..ae6271c 100644 --- a/infra/config/subprojects/chromium/ci/chromium.android.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.android.fyi.star
@@ -170,14 +170,10 @@ category = "emulator|12|x64", short_name = "rel", ), - # Bump to 6h for now since compile on x64 seems slower than x86. It could - # take 3h on Android-12 (For example ci.chromium.org/b/8841892751541698720) - # vs 1h on Android-11 (For example ci.chromium.org/b/8841899947736889024) - # TODO(crbug.com/1229245): Look into ways to improve the compile time. - execution_timeout = 6 * time.hour, - goma_backend = None, - reclient_jobs = rbe_jobs.DEFAULT, - reclient_instance = rbe_instance.DEFAULT, + # Set to an empty list to avoid chromium-gitiles-trigger triggering new + # builds. Also we don't set any `schedule` since this builder is for + # reference only and should not run any new builds. + triggered_by = [], ) ci.builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star index 4ba978b..fe13f52 100644 --- a/infra/config/subprojects/chromium/ci/chromium.android.star +++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -578,6 +578,18 @@ ) ci.builder( + name = "android-12-x64-rel", + console_view_entry = consoles.console_view_entry( + category = "builder_tester|x64", + short_name = "12", + ), + execution_timeout = 4 * time.hour, + goma_backend = None, + reclient_instance = rbe_instance.DEFAULT, + reclient_jobs = rbe_jobs.HIGH_JOBS_FOR_CI, +) + +ci.builder( name = "android-weblayer-10-x86-rel-tests", console_view_entry = consoles.console_view_entry( category = "tester|weblayer",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star index 8f7e154..20fb923e 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
@@ -55,8 +55,19 @@ name = "android-12-x64-dbg", ) -try_.builder( - name = "android-12-x64-fyi-rel", +try_.orchestrator_builder( + name = "android-12-x64-rel", + compilator = "android-12-x64-rel-compilator", + # TODO(crbug.com/1225851): Enable it on branch after running on CQ + # branch_selector = branches.STANDARD_MILESTONE, + main_list_view = "try", +) + +try_.compilator_builder( + name = "android-12-x64-rel-compilator", + # TODO(crbug.com/1225851): Enable it on branch after running on CQ + # branch_selector = branches.STANDARD_MILESTONE, + main_list_view = "try", ) try_.builder(
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 7f8b6f3..2ac47a4 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2900,7 +2900,7 @@ Search Recent Tabs </message> <message name="IDS_IOS_TABS_SEARCH_SUGGESTED_ACTION_SEARCH_WEB" desc="Title for a suggested action presented at the end of search results to search the web for the same search term."> - Search on the Web + Search on Web </message> <message name="IDS_IOS_TERMS_OF_SERVICE" desc="The label to access the terms of service, displayed in the application settings, with no product name. [Length: 30em] [iOS only]"> Terms of Service
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TABS_SEARCH_SUGGESTED_ACTION_SEARCH_WEB.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TABS_SEARCH_SUGGESTED_ACTION_SEARCH_WEB.png.sha1 index 106d0a3..1bd3aa4 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TABS_SEARCH_SUGGESTED_ACTION_SEARCH_WEB.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TABS_SEARCH_SUGGESTED_ACTION_SEARCH_WEB.png.sha1
@@ -1 +1 @@ -d48936067e52e43d71b487e4546630c570aaab55 \ No newline at end of file +131b99de923967255e66de42d7c2ff5766521b21 \ No newline at end of file
diff --git a/ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h b/ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h index ecdcc84..feac85a 100644 --- a/ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h +++ b/ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h
@@ -49,7 +49,7 @@ ~IOSChromeStabilityMetricsProvider() override; - // metrics::MetricsDataProvider: + // metrics::MetricsProvider: void OnRecordingEnabled() override; void OnRecordingDisabled() override; void ProvideStabilityMetrics(
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm index 4104cef..72faf43 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -662,20 +662,28 @@ self.onDeviceEncryptionStateInModel = newState; TableViewModel* model = self.tableViewModel; - NSInteger passwordCheckSectionIndex = - [model sectionForSectionIdentifier:SectionIdentifierPasswordCheck]; + // Index of the OnDeviceEncryption section if it exists. + // Index where it should be added if it does not exists. + NSInteger sectionIdentifierOnDeviceEncryptionIndex = + [model sectionForSectionIdentifier:SectionIdentifierPasswordCheck] + 1; + NSIndexSet* sectionIdentifierOnDeviceEncryptionIndexSet = + [NSIndexSet indexSetWithIndex:sectionIdentifierOnDeviceEncryptionIndex]; if (newState == OnDeviceEncryptionStateNotShown) { // Previous state was not `OnDeviceEncryptionStateNotShown`, wich mean the // section `SectionIdentifierOnDeviceEncryption` exists and must be removed. + // It also mean the table view is not yet shown and thus should not be + // updated. + DCHECK(!updateTableView); [self clearSectionWithIdentifier:SectionIdentifierOnDeviceEncryption - withRowAnimation:UITableViewRowAnimationFade]; + withRowAnimation:UITableViewRowAnimationAutomatic]; return; } if (oldState == OnDeviceEncryptionStateNotShown) { - [model insertSectionWithIdentifier:SectionIdentifierOnDeviceEncryption - atIndex:(passwordCheckSectionIndex + 1)]; + [model + insertSectionWithIdentifier:SectionIdentifierOnDeviceEncryption + atIndex:sectionIdentifierOnDeviceEncryptionIndex]; } [model deleteAllItemsFromSectionWithIdentifier: @@ -710,20 +718,15 @@ toSectionWithIdentifier:SectionIdentifierOnDeviceEncryption]; } - if (updateTableView) { - if (oldState == OnDeviceEncryptionStateNotShown) { - [self.tableView - insertSections:[NSIndexSet - indexSetWithIndex:(passwordCheckSectionIndex + - 1)] - withRowAnimation:UITableViewRowAnimationAutomatic]; - } else { - [self.tableView - reloadSections:[NSIndexSet - indexSetWithIndex:(passwordCheckSectionIndex + - 1)] - withRowAnimation:UITableViewRowAnimationAutomatic]; - } + if (!updateTableView) { + return; + } + if (oldState == OnDeviceEncryptionStateNotShown) { + [self.tableView insertSections:sectionIdentifierOnDeviceEncryptionIndexSet + withRowAnimation:UITableViewRowAnimationAutomatic]; + } else { + [self.tableView reloadSections:sectionIdentifierOnDeviceEncryptionIndexSet + withRowAnimation:UITableViewRowAnimationAutomatic]; } }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm index 1bed922f..a0b105a5 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm
@@ -150,7 +150,8 @@ } } - if ([self.contextMenuDelegate respondsToSelector:@selector(selectTabs)]) { + if (scenario != MenuScenario::kTabGridSearchResult && + [self.contextMenuDelegate respondsToSelector:@selector(selectTabs)]) { [menuElements addObject:[actionFactory actionToSelectTabsWithBlock:^{ [self.contextMenuDelegate selectTabs]; }]];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm index 528b632..4629192 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm
@@ -301,7 +301,8 @@ [self setItems:@[ _leadingButton, _iconButtonAdditionalSpaceItem, _searchButton, _spaceItem, centralItem, _spaceItem, trailingButton - ]]; + ] + animated:YES]; return; } @@ -405,7 +406,7 @@ // create a custom cancel button. _searchBar.showsCancelButton = NO; _cancelSearchButton = [[UIBarButtonItem alloc] init]; - _cancelSearchButton.style = UIBarButtonItemStyleDone; + _cancelSearchButton.style = UIBarButtonItemStylePlain; _cancelSearchButton.tintColor = UIColorFromRGB(kTabGridToolbarTextButtonColor); _cancelSearchButton.accessibilityIdentifier =
diff --git a/ios/chrome/browser/ui/webui/version_handler.cc b/ios/chrome/browser/ui/webui/version_handler.cc index b761327..b63df3f 100644 --- a/ios/chrome/browser/ui/webui/version_handler.cc +++ b/ios/chrome/browser/ui/webui/version_handler.cc
@@ -16,14 +16,13 @@ VersionHandler::~VersionHandler() {} void VersionHandler::RegisterMessages() { - web_ui()->RegisterDeprecatedMessageCallback2( + web_ui()->RegisterMessageCallback( version_ui::kRequestVariationInfo, base::BindRepeating(&VersionHandler::HandleRequestVariationInfo, base::Unretained(this))); } -void VersionHandler::HandleRequestVariationInfo( - base::Value::ConstListView args) { +void VersionHandler::HandleRequestVariationInfo(const base::Value::List& args) { // Respond with the variations info immediately. CHECK_EQ(2U, args.size()); std::string callback_id = args[0].GetString();
diff --git a/ios/chrome/browser/ui/webui/version_handler.h b/ios/chrome/browser/ui/webui/version_handler.h index 6effbc9..027bb4e3d 100644 --- a/ios/chrome/browser/ui/webui/version_handler.h +++ b/ios/chrome/browser/ui/webui/version_handler.h
@@ -23,7 +23,7 @@ // Callback for the "requestVariationInfo" message. This responds immediately // with the list of variations. - void HandleRequestVariationInfo(base::Value::ConstListView args); + void HandleRequestVariationInfo(const base::Value::List& args); }; #endif // IOS_CHROME_BROWSER_UI_WEBUI_VERSION_HANDLER_H_
diff --git a/ios/chrome/common/credential_provider/memory_credential_store.mm b/ios/chrome/common/credential_provider/memory_credential_store.mm index 8b625c4..d5aaf78 100644 --- a/ios/chrome/common/credential_provider/memory_credential_store.mm +++ b/ios/chrome/common/credential_provider/memory_credential_store.mm
@@ -78,7 +78,7 @@ DCHECK(recordIdentifier.length) << "Invalid |recordIdentifier| was passed."; dispatch_barrier_async(self.workingQueue, ^{ DCHECK(self.memoryStorage[recordIdentifier]) - << "Credential doesn't exist in the storage"; + << "Credential doesn't exist in the storage, " << recordIdentifier; self.memoryStorage[recordIdentifier] = nil; }); }
diff --git a/ios/chrome/credential_provider_extension/ui/new_password_mediator.mm b/ios/chrome/credential_provider_extension/ui/new_password_mediator.mm index d934e1a..022d733 100644 --- a/ios/chrome/credential_provider_extension/ui/new_password_mediator.mm +++ b/ios/chrome/credential_provider_extension/ui/new_password_mediator.mm
@@ -110,7 +110,7 @@ // Checks whether a credential already exists with the given username. - (BOOL)credentialExistsForUsername:(NSString*)username { - NSURL* url = [NSURL URLWithString:self.serviceIdentifier.identifier]; + NSURL* url = [NSURL URLWithString:[self currentIdentifier]]; NSString* recordIdentifier = RecordIdentifierForData(url, username); return [self.existingCredentials @@ -120,19 +120,7 @@ // Creates a new credential but doesn't add it to any stores. - (ArchivableCredential*)createNewCredentialWithUsername:(NSString*)username password:(NSString*)password { - NSString* identifier = self.serviceIdentifier.identifier; - - // According to Apple - // (https://developer.apple.com/documentation/xcode/supporting-associated-domains). - // associated domains must have an https:// scheme, and to autofill passwords - // an associated domain is needed - // (https://developer.apple.com/documentation/security/password_autofill/). - // Also iOS strips https:// from passed identifier, Chrome restores it here to - // save a valid URL. - if (self.serviceIdentifier.type == ASCredentialServiceIdentifierTypeDomain && - ![identifier hasPrefix:@"https://"]) { - identifier = [@"https://" stringByAppendingString:identifier]; - } + NSString* identifier = [self currentIdentifier]; NSURL* url = [NSURL URLWithString:identifier]; NSString* recordIdentifier = RecordIdentifierForData(url, username); @@ -184,4 +172,21 @@ completionHandler:nil]; } +- (NSString*)currentIdentifier { + NSString* identifier = self.serviceIdentifier.identifier; + + // According to Apple + // (https://developer.apple.com/documentation/xcode/supporting-associated-domains). + // associated domains must have an https:// scheme, and to autofill passwords + // an associated domain is needed + // (https://developer.apple.com/documentation/security/password_autofill/). + // Also iOS strips https:// from passed identifier, Chrome restores it here to + // save a valid URL. + if (self.serviceIdentifier.type == ASCredentialServiceIdentifierTypeDomain && + ![identifier hasPrefix:@"https://"]) { + identifier = [@"https://" stringByAppendingString:identifier]; + } + return identifier; +} + @end
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index 23bbe254..3e3e705d 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -64a561ba8314904b646303daca3280fa91843058 \ No newline at end of file +cd6542a66a3c307fa0a0a0aa88b49ddafb8ded7f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index a8210e3..b80ef65 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -760fb9cd718242c7232237f67d4180f8b7612856 \ No newline at end of file +4770e31ad0de99d1e3b0497cb241bf2b1907a20a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 9790d4c..df3720b 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -433fd594a645200e0ae148b6bec85149b36ea2c5 \ No newline at end of file +e62f7a91d9f30ce6b5594ad39972f491eca2db07 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 75bf7c9..3164ede2 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -f8f773745196a6b0ffd8ce877bcff7318156ddf0 \ No newline at end of file +ecf6fdee6e94d0d89990adae9fe78de0810c21d3 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index 3455243..a6205c1 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -175b5c319ebe32939236c1e03f7d33513f399dc1 \ No newline at end of file +8fef0ae7223faaa4c555a5a9d03145efe9c7327a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index e75cd72..61e4b53 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -c9f2afcee32d6408175f02a32c3d342310bbf0d0 \ No newline at end of file +29f97144df53280e5e00d0d99d16905e08a97efe \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 72d7bbb..ec21ebe 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -aa92b31fcddb2ef7a364ba012e4f1ea1abece71b \ No newline at end of file +b751970fec98f5d271e3f3e6f221124bd28da073 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index 75e66d1..1582d4e1 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -8cf6ff9c3fe3cab2b01b8717119998df83069f11 \ No newline at end of file +192c0555a9b2ce728c06ac5902e8caa600f43c25 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index 8ca38cf..212837d 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -d19a5d2fb06a4283c8283fd92fe0319ade4e9d07 \ No newline at end of file +4cb5eff38eb3373dcd8e53ded193e0078e9a4517 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 132f5531..c7020dc 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -0e04e5bd2e9e67bb694f2fa677ed951d26c45f57 \ No newline at end of file +9354349c0fcfb1a2f1b0eddb00cea390e910c65e \ No newline at end of file
diff --git a/ios/web/public/webui/web_ui_ios.h b/ios/web/public/webui/web_ui_ios.h index e2f0c97..3e219f7 100644 --- a/ios/web/public/webui/web_ui_ios.h +++ b/ios/web/public/webui/web_ui_ios.h
@@ -42,10 +42,15 @@ virtual void AddMessageHandler( std::unique_ptr<WebUIIOSMessageHandler> handler) = 0; - // TODO(crbug.com/1300095): new version of DeprecatedMessageCallback2 that - // takes base::Value::List as a parameter needs to be introduced. Afterwards - // existing callers of RegisterDeprecatedMessageCallback2() should be migrated - // to the new RegisterMessageCallback() (not yet introduced) version. + // Used by WebUIMessageHandlers. If the given message is already registered, + // the call has no effect. + using MessageCallback = + base::RepeatingCallback<void(const base::Value::List&)>; + virtual void RegisterMessageCallback(const std::string& message, + MessageCallback callback) = 0; + + // TODO(crbug.com/1300095): Instances of RegisterDeprecatedMessageCallback2() + // should be migrated to RegisterMessageCallback(). // // Used by WebUIIOSMessageHandlers. If the given message is already // registered, the call has no effect. @@ -55,10 +60,8 @@ const std::string& message, DeprecatedMessageCallback2 callback) = 0; - // TODO(crbug.com/1300095): new version of DeprecatedMessageCallback that - // takes base::Value::List as a parameter needs to be introduced. Afterwards - // existing callers of RegisterDeprecatedMessageCallback() should be migrated - // to the new RegisterMessageCallback() (not yet introduced) version. + // TODO(crbug.com/1300095): Instances of RegisterDeprecatedMessageCallback() + // should be migrated to RegisterMessageCallback(). // // Used by WebUIIOSMessageHandlers. If the given message is already // registered, the call has no effect.
diff --git a/ios/web/webui/web_ui_ios_impl.h b/ios/web/webui/web_ui_ios_impl.h index 882e8f3c..90f6e06 100644 --- a/ios/web/webui/web_ui_ios_impl.h +++ b/ios/web/webui/web_ui_ios_impl.h
@@ -37,6 +37,8 @@ void SetController(std::unique_ptr<WebUIIOSController> controller) override; void AddMessageHandler( std::unique_ptr<WebUIIOSMessageHandler> handler) override; + void RegisterMessageCallback(const std::string& message, + MessageCallback callback) override; void RegisterDeprecatedMessageCallback2( const std::string& message, DeprecatedMessageCallback2 callback) override; @@ -66,11 +68,19 @@ void ExecuteJavascript(const std::u16string& javascript); // A map of message name -> message handling callback. + using MessageCallbackMap = std::map<std::string, MessageCallback>; + MessageCallbackMap message_callbacks_; + + // A map of message name -> message handling callback. + // TODO(crbug.com/1300095): Remove once RegisterDeprecatedMessageCallback2() + // instances are migrated to RegisterMessageCallback(). using DeprecatedMessageCallback2Map = std::map<std::string, DeprecatedMessageCallback2>; DeprecatedMessageCallback2Map deprecated_message_callbacks_2_; // A map of message name -> message handling callback. + // TODO(crbug.com/1300095): Remove once RegisterDeprecatedMessageCallback() + // instances are migrated to RegisterMessageCallback(). using DeprecatedMessageCallbackMap = std::map<std::string, DeprecatedMessageCallback>; DeprecatedMessageCallbackMap deprecated_message_callbacks_;
diff --git a/ios/web/webui/web_ui_ios_impl.mm b/ios/web/webui/web_ui_ios_impl.mm index ce82ea7..fe915b3 100644 --- a/ios/web/webui/web_ui_ios_impl.mm +++ b/ios/web/webui/web_ui_ios_impl.mm
@@ -108,6 +108,11 @@ GetJavascriptCall("cr.webUIListenerCallback", modified_args)); } +void WebUIIOSImpl::RegisterMessageCallback(const std::string& message, + MessageCallback callback) { + message_callbacks_.emplace(message, std::move(callback)); +} + void WebUIIOSImpl::RegisterDeprecatedMessageCallback2( const std::string& message, DeprecatedMessageCallback2 callback) { @@ -154,6 +159,14 @@ return; // Look up the callback for this message. + auto message_callback_it = message_callbacks_.find(message); + if (message_callback_it != message_callbacks_.end()) { + // Forward this message and content on. + message_callback_it->second.Run(args.GetList()); + return; + } + + // Look up the deprecated callback for this message. auto deprecated_message_callback_2_it = deprecated_message_callbacks_2_.find(message); if (deprecated_message_callback_2_it !=
diff --git a/ios/web_view/internal/app/application_context.h b/ios/web_view/internal/app/application_context.h index 15962ad..641e3f3 100644 --- a/ios/web_view/internal/app/application_context.h +++ b/ios/web_view/internal/app/application_context.h
@@ -14,6 +14,10 @@ #include "mojo/public/cpp/bindings/remote.h" #include "services/network/public/mojom/network_service.mojom.h" +namespace component_updater { +class ComponentUpdateService; +} + namespace net { class NetLog; class URLRequestContextGetter; @@ -61,6 +65,9 @@ // Gets the NetLog. net::NetLog* GetNetLog(); + // Gets the ComponentUpdateService. + component_updater::ComponentUpdateService* GetComponentUpdateService(); + // Creates state tied to application threads. It is expected this will be // called from web::WebMainParts::PreCreateThreads. void PreCreateThreads(); @@ -101,6 +108,8 @@ std::unique_ptr<network::NetworkChangeManager> network_change_manager_; std::unique_ptr<network::NetworkConnectionTracker> network_connection_tracker_; + + std::unique_ptr<component_updater::ComponentUpdateService> component_updater_; }; } // namespace ios_web_view
diff --git a/ios/web_view/internal/app/application_context.mm b/ios/web_view/internal/app/application_context.mm index f8d251d9..7bac0968 100644 --- a/ios/web_view/internal/app/application_context.mm +++ b/ios/web_view/internal/app/application_context.mm
@@ -9,6 +9,8 @@ #include "base/no_destructor.h" #include "base/path_service.h" #include "base/task/post_task.h" +#include "components/component_updater/component_updater_service.h" +#include "components/component_updater/timer_update_scheduler.h" #include "components/flags_ui/pref_service_flags_storage.h" #include "components/prefs/json_pref_store.h" #include "components/prefs/pref_registry_simple.h" @@ -17,10 +19,12 @@ #include "components/proxy_config/pref_proxy_config_tracker_impl.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/translate/core/browser/translate_download_manager.h" +#include "components/update_client/update_client.h" #include "components/variations/net/variations_http_headers.h" #include "ios/web/public/thread/web_task_traits.h" #include "ios/web/public/thread/web_thread.h" #include "ios/web_view/internal/app/web_view_io_thread.h" +#import "ios/web_view/internal/component_updater/web_view_component_updater_configurator.h" #import "ios/web_view/internal/cwv_flags_internal.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "net/log/net_log.h" @@ -29,6 +33,7 @@ #include "services/network/public/cpp/network_connection_tracker.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/network_context.mojom.h" +#include "ui/base/device_form_factor.h" #include "ui/base/l10n/l10n_util_mac.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -99,6 +104,8 @@ flags_ui::PrefServiceFlagsStorage::RegisterPrefs(pref_registry.get()); PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get()); signin::IdentityManager::RegisterLocalStatePrefs(pref_registry.get()); + component_updater::RegisterComponentUpdateServicePrefs(pref_registry.get()); + update_client::RegisterPrefs(pref_registry.get()); base::FilePath local_state_path; base::PathService::Get(base::DIR_APP_DATA, &local_state_path); @@ -184,6 +191,22 @@ return net::NetLog::Get(); } +component_updater::ComponentUpdateService* +ApplicationContext::GetComponentUpdateService() { + if (!component_updater_) { + // TODO(crbug.com/1298671): Brand code should be configurable. + std::string brand_code = + ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET ? "APLB" + : "APLA"; + component_updater_ = component_updater::ComponentUpdateServiceFactory( + MakeComponentUpdaterConfigurator( + base::CommandLine::ForCurrentProcess()), + std::make_unique<component_updater::TimerUpdateScheduler>(), + brand_code); + } + return component_updater_.get(); +} + WebViewIOThread* ApplicationContext::GetWebViewIOThread() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(web_view_io_thread_.get());
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm index 4805430..091a27b 100644 --- a/ios/web_view/internal/cwv_web_view.mm +++ b/ios/web_view/internal/cwv_web_view.mm
@@ -525,6 +525,18 @@ } } +- (web::WebState*)webState:(web::WebState*)webState + openURLWithParams:(const web::WebState::OpenURLParams&)params { + web::NavigationManager::WebLoadParams load_params(params.url); + load_params.referrer = params.referrer; + load_params.transition_type = params.transition; + load_params.is_renderer_initiated = params.is_renderer_initiated; + load_params.virtual_url = params.virtual_url; + _webState->GetNavigationManager()->LoadURLWithParams(load_params); + [self updateCurrentURLs]; + return _webState.get(); +} + - (web::JavaScriptDialogPresenter*)javaScriptDialogPresenterForWebState: (web::WebState*)webState { return _javaScriptDialogPresenter.get();
diff --git a/ios/web_view/internal/web_view_web_main_delegate.mm b/ios/web_view/internal/web_view_web_main_delegate.mm index 8b7e185..bb50039e 100644 --- a/ios/web_view/internal/web_view_web_main_delegate.mm +++ b/ios/web_view/internal/web_view_web_main_delegate.mm
@@ -4,8 +4,10 @@ #import "ios/web_view/internal/web_view_web_main_delegate.h" +#include "base/base_paths.h" #include "base/logging.h" #import "base/mac/bundle_locations.h" +#include "components/component_updater/component_updater_paths.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -30,6 +32,9 @@ // Sets up logging so logging levels can be controlled. logging::InitLogging(logging::LoggingSettings()); + + component_updater::RegisterPathProvider( + base::DIR_APP_DATA, base::DIR_APP_DATA, base::DIR_APP_DATA); } } // namespace ios_web_view
diff --git a/ios/web_view/internal/web_view_web_main_parts.mm b/ios/web_view/internal/web_view_web_main_parts.mm index 1c78921f..f6a80877 100644 --- a/ios/web_view/internal/web_view_web_main_parts.mm +++ b/ios/web_view/internal/web_view_web_main_parts.mm
@@ -11,6 +11,7 @@ #include "base/strings/string_util.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_payments_features.h" +#include "components/component_updater/installer_policies/safety_tips_component_installer.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/sync/base/features.h" #include "components/variations/variations_ids_provider.h" @@ -79,6 +80,10 @@ web::WebUIIOSControllerFactory::RegisterFactory( WebViewWebUIIOSControllerFactory::GetInstance()); + + component_updater::ComponentUpdateService* cus = + ApplicationContext::GetInstance()->GetComponentUpdateService(); + RegisterSafetyTipsComponent(cus); } void WebViewWebMainParts::PostMainMessageLoopRun() {
diff --git a/media/cdm/cdm_type.h b/media/cdm/cdm_type.h index daf0127..6b5f2fe 100644 --- a/media/cdm/cdm_type.h +++ b/media/cdm/cdm_type.h
@@ -5,6 +5,7 @@ #ifndef MEDIA_CDM_CDM_TYPE_H_ #define MEDIA_CDM_CDM_TYPE_H_ +#include "base/strings/string_piece_forward.h" #include "base/token.h" #include "media/base/media_export.h" // nogncheck @@ -29,13 +30,16 @@ const char* legacy_file_system_id = ""; bool operator==(const CdmType& other) const { - return (this->id == other.id) && (strcmp(this->legacy_file_system_id, - other.legacy_file_system_id) == 0); + return (id == other.id) && (base::StringPiece(legacy_file_system_id) == + base::StringPiece(other.legacy_file_system_id)); } bool operator<(const CdmType& other) const { - return (this->id < other.id) || (strcmp(this->legacy_file_system_id, - other.legacy_file_system_id) < 0); + // Create some local variables, since std::tie needs an lvalue. Casting to a + // StringPiece allows for string comparison rather than pointer comparison. + const base::StringPiece fs_id(legacy_file_system_id); + const base::StringPiece other_fs_id(other.legacy_file_system_id); + return std::tie(id, fs_id) < std::tie(other.id, other_fs_id); } };
diff --git a/mojo/public/rust/BUILD.gn b/mojo/public/rust/BUILD.gn index 34a20d0..c29b2dc 100644 --- a/mojo/public/rust/BUILD.gn +++ b/mojo/public/rust/BUILD.gn
@@ -5,6 +5,7 @@ import("//build/config/rust.gni") import("//build/rust/rust_static_library.gni") import("//build/rust/rust_unit_test.gni") +import("//build/rust/rust_unit_tests_group.gni") # Meta target to build everything group("rust") { @@ -12,8 +13,7 @@ } # Meta target to build test binaries, if supported. -group("tests") { - testonly = true +rust_unit_tests_group("mojo_rust_tests") { deps = [] if (build_rust_unit_tests) { deps += [ ":mojo_rust_unittests" ]
diff --git a/pdf/ui/thumbnail.cc b/pdf/ui/thumbnail.cc index b45225e..b3b794d 100644 --- a/pdf/ui/thumbnail.cc +++ b/pdf/ui/thumbnail.cc
@@ -38,7 +38,7 @@ // Maximum CSS dimensions are set to match UX specifications. // These constants should be kept in sync with `PORTRAIT_WIDTH` and // `LANDSCAPE_WIDTH` in -// chrome/browser/resources/pdf/elements/viewer-thumbnail.js. +// chrome/browser/resources/pdf/elements/viewer-thumbnail.ts. constexpr int kMaxWidthPortraitPx = 108; constexpr int kMaxWidthLandscapePx = 140;
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc index 38ffc1c..9728d0b 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -205,7 +205,8 @@ #endif // BUILDFLAG(IS_ANDROID) ), Allow()) - .Default(CrashSIGSYSPrctl()); + .Default( + If(option == PR_SET_PTRACER, Error(EPERM)).Else(CrashSIGSYSPrctl())); } ResultExpr RestrictIoctl() {
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h index 348970b..86d55ca 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -23,7 +23,10 @@ // Crash if anything else is attempted. SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictCloneToThreadsAndEPERMFork(); -// Allow PR_SET_NAME, PR_SET_DUMPABLE, PR_GET_DUMPABLE. +// Allow PR_GET_NAME, PR_SET_NAME, PR_SET_DUMPABLE, PR_GET_DUMPABLE. +// On Android allows a few other options. +// Returns EPERM for PR_SET_PTRACER to allow crashpad to try to set itself as +// ptracer at crash time, if it hasn't yet been able to. // Crash if anything else is attempted. SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrctl();
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index 6201f8f..ee35ded8 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc
@@ -2290,9 +2290,12 @@ // Send empty body to the real URLLoaderClient. mojo::ScopedDataPipeProducerHandle producer_handle; mojo::ScopedDataPipeConsumerHandle consumer_handle; - CHECK_EQ(mojo::CreateDataPipe(kBlockedBodyAllocationSize, producer_handle, - consumer_handle), - MOJO_RESULT_OK); + MojoResult result = mojo::CreateDataPipe(kBlockedBodyAllocationSize, + producer_handle, consumer_handle); + if (result != MOJO_RESULT_OK) { + NotifyCompleted(net::ERR_INSUFFICIENT_RESOURCES); + return kWillCancelRequest; + } producer_handle.reset(); if (base::FeatureList::IsEnabled(features::kCombineResponseBody)) {
diff --git a/services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.cc b/services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.cc index d972d4c..2cabc13 100644 --- a/services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.cc +++ b/services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.cc
@@ -12,7 +12,7 @@ Read(viz::mojom::AggregatedHitTestRegionDataView data, viz::AggregatedHitTestRegion* out) { if (!data.ReadFrameSinkId(&out->frame_sink_id) || - !data.ReadRect(&out->rect) || !data.ReadTransform(&out->transform_)) { + !data.ReadRect(&out->rect) || !data.ReadTransform(&out->transform)) { return false; } out->flags = data.flags();
diff --git a/services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.h b/services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.h index 8debca7..3e7a656f 100644 --- a/services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.h +++ b/services/viz/public/cpp/hit_test/aggregated_hit_test_region_mojom_traits.h
@@ -38,8 +38,10 @@ return region.child_count; } - static gfx::Transform transform(const viz::AggregatedHitTestRegion& region) { - return region.transform(); + // NOLINTNEXTLINE(build/include_what_you_use). See crbug.com/1301129. + static const gfx::Transform& transform( + const viz::AggregatedHitTestRegion& region) { + return region.transform; } static bool Read(viz::mojom::AggregatedHitTestRegionDataView data,
diff --git a/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc b/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc index 5f1f82a..a4efd5d 100644 --- a/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc +++ b/services/viz/public/cpp/hit_test/mojom_traits_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cstring> + #include "components/viz/common/hit_test/aggregated_hit_test_region.h" #include "components/viz/common/hit_test/hit_test_region_list.h" #include "mojo/public/cpp/test_support/test_utils.h" @@ -33,7 +35,7 @@ EXPECT_EQ(input.flags, output.flags); EXPECT_EQ(input.async_hit_test_reasons, output.async_hit_test_reasons); EXPECT_EQ(input.rect, output.rect); - EXPECT_EQ(input.transform(), output.transform()); + EXPECT_EQ(input.transform, output.transform); EXPECT_EQ(input.child_count, output.child_count); } @@ -68,4 +70,14 @@ EXPECT_EQ(input->regions[0].transform, output->regions[0].transform); } +// Ensures gfx::Transform doesn't mutate itself when its const methods are +// called, to ensure it won't change in the read-only shared memory segment. +TEST(StructTraitsTest, TransformImmutable) { + gfx::Transform t1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + gfx::Transform t2; + std::memcpy(&t2, &t1, sizeof(t1)); + EXPECT_FALSE(t2.IsIdentity()); + EXPECT_EQ(0, std::memcmp(&t1, &t2, sizeof(t1))); +} + } // namespace viz
diff --git a/testing/PRESUBMIT.py b/testing/PRESUBMIT.py index 7d4e79a..c907602 100644 --- a/testing/PRESUBMIT.py +++ b/testing/PRESUBMIT.py
@@ -35,12 +35,14 @@ input_api, output_api, files_to_skip=[r'gmock.*', r'gtest.*', - r'buildbot.*', r'trigger_scripts.*'])) + r'buildbot.*', r'merge_scripts.*', r'trigger_scripts.*'])) # Pylint2.7 is run on subdirs whose presubmit checks are migrated to Python3 output.extend(input_api.canned_checks.RunPylint( input_api, output_api, - files_to_check=[r'buildbot.*\.py$', r'trigger_scripts.*\.py$'], + files_to_check=[r'buildbot.*\.py$', + r'merge_scripts.*\.py$', + r'trigger_scripts.*\.py$'], version='2.7')) return output
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index b24685c..52225aa 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -210,4805 +210,6 @@ } ] }, - "android-12-x64-fyi-rel": { - "gtest_tests": [ - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "absl_hardening_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "absl_hardening_tests", - "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "android_browsertests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "android_browsertests", - "test_id_prefix": "ninja://chrome/test:android_browsertests/" - }, - { - "args": [ - "--test-launcher-batch-limit=1", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "android_sync_integration_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "android_sync_integration_tests", - "test_id_prefix": "ninja://chrome/test:android_sync_integration_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "android_webview_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "android_webview_unittests", - "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/" - }, - { - "args": [ - "angle_unittests", - "-v", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "angle_unittests", - "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/", - "use_isolated_scripts_api": true - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter", - "--gtest_filter=-ModuleCacheTest.CheckAgainstProcMaps" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "base_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "base_unittests", - "test_id_prefix": "ninja://base:base_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "blink_common_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "blink_common_unittests", - "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "blink_heap_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "blink_heap_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "blink_platform_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "blink_platform_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.blink_unittests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webkit_unit_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "webkit_unit_tests", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 6 - }, - "test": "blink_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "boringssl_crypto_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "boringssl_crypto_tests", - "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "boringssl_ssl_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "boringssl_ssl_tests", - "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "breakpad_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "breakpad_unittests", - "test_id_prefix": "ninja://third_party/breakpad:breakpad_unittests/" - }, - { - "args": [ - "--gtest_filter=-*UsingRealWebcam*", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "capture_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "capture_unittests", - "test_id_prefix": "ninja://media/capture:capture_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "cast_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "cast_unittests", - "test_id_prefix": "ninja://media/cast:cast_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "cc_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "cc_unittests", - "test_id_prefix": "ninja://cc:cc_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_smoke_test" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "chrome_public_smoke_test", - "test_id_prefix": "ninja://chrome/android:chrome_public_smoke_test/" - }, - { - "args": [ - "--gtest_filter=-org.chromium.chrome.browser.contextualsearch.ContextualSearchManagerTest.test*ExternalNavigationWithUserGesture*:org.chromium.chrome.browser.externalnav.UrlOverridingTest.test*UserGesture*:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallback:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackAndShortTimeout:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackInSubFrame:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testRedirectionFromIntent*", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--git-revision=${got_revision}", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.chrome_public_test_apk.filter", - "--timeout-scale=2.0" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 20 - }, - "test": "chrome_public_test_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/" - }, - { - "args": [ - "--gtest_filter=org.chromium.chrome.browser.contextualsearch.ContextualSearchManagerTest.test*ExternalNavigationWithUserGesture*:org.chromium.chrome.browser.externalnav.UrlOverridingTest.test*UserGesture*:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallback:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackAndShortTimeout:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackInSubFrame:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testRedirectionFromIntent*", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--git-revision=${got_revision}", - "--avd-config=../../tools/android/avd/proto/generic_playstore_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_apk_with_playstore" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "chrome_public_test_apk_with_playstore", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_playstore_android31", - "path": ".android_emulator/generic_playstore_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_playstore_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "chrome_public_test_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--git-revision=${got_revision}" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_unit_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "chrome_public_unit_test_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "components_browsertests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "components_browsertests", - "test_id_prefix": "ninja://components:components_browsertests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--gtest_filter=-FieldFormatterTest.DifferentLocales" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "components_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 6 - }, - "test": "components_unittests", - "test_id_prefix": "ninja://components:components_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.content_browsertests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "content_browsertests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 20 - }, - "test": "content_browsertests", - "test_id_prefix": "ninja://content/test:content_browsertests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.content_shell_test_apk.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "content_shell_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 - }, - "test": "content_shell_test_apk", - "test_id_prefix": "ninja://content/shell/android:content_shell_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "content_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 - }, - "test": "content_unittests", - "test_id_prefix": "ninja://content/test:content_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.crashpad_tests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "crashpad_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "crashpad_tests", - "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "crypto_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "crypto_unittests", - "test_id_prefix": "ninja://crypto:crypto_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.device_unittests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "device_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "device_unittests", - "test_id_prefix": "ninja://device:device_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "display_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "display_unittests", - "test_id_prefix": "ninja://ui/display:display_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "events_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "events_unittests", - "test_id_prefix": "ninja://ui/events:events_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gcm_unit_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gcm_unit_tests", - "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gfx_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gfx_unittests", - "test_id_prefix": "ninja://ui/gfx:gfx_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gin_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gin_unittests", - "test_id_prefix": "ninja://gin:gin_unittests/" - }, - { - "args": [ - "--use-cmd-decoder=validating", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.gl_tests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gl_tests_validating" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "gl_tests_validating", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gl_tests", - "test_id_prefix": "ninja://gpu:gl_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.gl_unittests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gl_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gl_unittests", - "test_id_prefix": "ninja://ui/gl:gl_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "google_apis_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "google_apis_unittests", - "test_id_prefix": "ninja://google_apis:google_apis_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gpu_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gpu_unittests", - "test_id_prefix": "ninja://gpu:gpu_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "gwp_asan_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "gwp_asan_unittests", - "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "ipc_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "ipc_tests", - "test_id_prefix": "ninja://ipc:ipc_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "latency_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "latency_unittests", - "test_id_prefix": "ninja://ui/latency:latency_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "libjingle_xmpp_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "libjingle_xmpp_unittests", - "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "liburlpattern_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "liburlpattern_unittests", - "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.media_unittests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "media_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "media_unittests", - "test_id_prefix": "ninja://media:media_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "midi_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "midi_unittests", - "test_id_prefix": "ninja://media/midi:midi_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "mojo_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "mojo_test_apk", - "test_id_prefix": "ninja://mojo/public/java/system:mojo_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "mojo_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "mojo_unittests", - "test_id_prefix": "ninja://mojo:mojo_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "monochrome_public_bundle_smoke_test" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "monochrome_public_bundle_smoke_test", - "test_id_prefix": "ninja://chrome/android:monochrome_public_bundle_smoke_test/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "monochrome_public_smoke_test" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "monochrome_public_smoke_test", - "test_id_prefix": "ninja://chrome/android:monochrome_public_smoke_test/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--gtest_filter=-MimeUtilTest.ExtensionTest" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "net_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 3 - }, - "test": "net_unittests", - "test_id_prefix": "ninja://net:net_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--gtest_filter=-ScopedDirTest.CloseOutOfScope" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "perfetto_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "perfetto_unittests", - "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.sandbox_linux_unittests.filter" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "sandbox_linux_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "sandbox_linux_unittests", - "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--gtest_filter=-PacLibraryTest.ActualPacMyIpAddress*" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "services_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "services_unittests", - "test_id_prefix": "ninja://services:services_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "shell_dialogs_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "shell_dialogs_unittests", - "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "skia_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "skia_unittests", - "test_id_prefix": "ninja://skia:skia_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "sql_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "sql_unittests", - "test_id_prefix": "ninja://sql:sql_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "storage_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "storage_unittests", - "test_id_prefix": "ninja://storage:storage_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "system_webview_shell_layout_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "system_webview_shell_layout_test_apk", - "test_id_prefix": "ninja://android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "ui_android_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "ui_android_unittests", - "test_id_prefix": "ninja://ui/android:ui_android_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "ui_base_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "ui_base_unittests", - "test_id_prefix": "ninja://ui/base:ui_base_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "ui_touch_selection_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "ui_touch_selection_unittests", - "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "unit_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 - }, - "test": "unit_tests", - "test_id_prefix": "ninja://chrome/test:unit_tests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "url_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "url_unittests", - "test_id_prefix": "ninja://url:url_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "viz_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "viz_unittests", - "test_id_prefix": "ninja://components/viz:viz_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--gtest_filter=-DownloadBrowserTest.OverrideDownloadDirectory" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "weblayer_browsertests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "weblayer_browsertests", - "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "weblayer_bundle_test" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "weblayer_bundle_test", - "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_bundle_test/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "weblayer_instrumentation_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "weblayer_instrumentation_test_apk", - "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--gtest_filter=-org.chromium.weblayer.test.BrowserControlsTest.testTopExpandedOnLoadWhenOnlyExpandAtTop" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "weblayer_private_instrumentation_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "weblayer_private_instrumentation_test_apk", - "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_private_instrumentation_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "weblayer_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "weblayer_unittests", - "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", - "--gtest_filter=-org.chromium.android_webview.test.devui.HomeFragmentTest.testLongPressCopy*" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_instrumentation_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 7 - }, - "test": "webview_instrumentation_test_apk", - "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_ui_test_app_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "webview_ui_test_app_test_apk", - "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "wtf_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "wtf_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "zlib_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "device_os": null, - "device_type": null, - "machine_type": "e2-standard-8", - "os": "Ubuntu-16.04|Ubuntu-18.04", - "pool": "chromium.tests.avd" - } - ], - "named_caches": [ - { - "name": "generic_android31", - "path": ".android_emulator/generic_android31" - } - ], - "optional_dimensions": { - "60": [ - { - "caches": "generic_android31" - } - ] - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "zlib_unittests", - "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/" - } - ] - }, "android-annotator-rel": { "scripts": [ {
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 80539ba..637ebbda 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -14863,6 +14863,4807 @@ } ] }, + "android-12-x64-rel": { + "gtest_tests": [ + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "absl_hardening_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "absl_hardening_tests", + "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "android_browsertests", + "test_id_prefix": "ninja://chrome/test:android_browsertests/" + }, + { + "args": [ + "--test-launcher-batch-limit=1", + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_sync_integration_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "android_sync_integration_tests", + "test_id_prefix": "ninja://chrome/test:android_sync_integration_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "android_webview_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "android_webview_unittests", + "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/" + }, + { + "args": [ + "angle_unittests", + "-v", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "angle_unittests", + "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/", + "use_isolated_scripts_api": true + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter", + "--gtest_filter=-ModuleCacheTest.CheckAgainstProcMaps" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "base_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "base_unittests", + "test_id_prefix": "ninja://base:base_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_common_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "blink_common_unittests", + "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_heap_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "blink_heap_unittests", + "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "blink_platform_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "blink_platform_unittests", + "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.blink_unittests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webkit_unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "name": "webkit_unit_tests", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 6 + }, + "test": "blink_unittests", + "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "boringssl_crypto_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "boringssl_crypto_tests", + "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "boringssl_ssl_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "boringssl_ssl_tests", + "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "breakpad_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "breakpad_unittests", + "test_id_prefix": "ninja://third_party/breakpad:breakpad_unittests/" + }, + { + "args": [ + "--gtest_filter=-*UsingRealWebcam*", + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "capture_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "capture_unittests", + "test_id_prefix": "ninja://media/capture:capture_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cast_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cast_unittests", + "test_id_prefix": "ninja://media/cast:cast_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cc_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cc_unittests", + "test_id_prefix": "ninja://cc:cc_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_smoke_test" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "chrome_public_smoke_test", + "test_id_prefix": "ninja://chrome/android:chrome_public_smoke_test/" + }, + { + "args": [ + "--gtest_filter=-org.chromium.chrome.browser.contextualsearch.ContextualSearchManagerTest.test*ExternalNavigationWithUserGesture*:org.chromium.chrome.browser.externalnav.UrlOverridingTest.test*UserGesture*:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallback:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackAndShortTimeout:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackInSubFrame:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testRedirectionFromIntent*", + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--git-revision=${got_revision}", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.chrome_public_test_apk.filter", + "--timeout-scale=2.0" + ], + "ci_only": true, + "experiment_percentage": 100, + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "chrome_public_test_apk", + "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/" + }, + { + "args": [ + "--gtest_filter=org.chromium.chrome.browser.contextualsearch.ContextualSearchManagerTest.test*ExternalNavigationWithUserGesture*:org.chromium.chrome.browser.externalnav.UrlOverridingTest.test*UserGesture*:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallback:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackAndShortTimeout:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testNavigationFromXHRCallbackInSubFrame:org.chromium.chrome.browser.externalnav.UrlOverridingTest.testRedirectionFromIntent*", + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--git-revision=${got_revision}", + "--avd-config=../../tools/android/avd/proto/generic_playstore_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_test_apk_with_playstore" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "name": "chrome_public_test_apk_with_playstore", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_playstore_android31", + "path": ".android_emulator/generic_playstore_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_playstore_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "chrome_public_test_apk", + "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--git-revision=${got_revision}" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_unit_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "chrome_public_unit_test_apk", + "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "components_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "components_browsertests", + "test_id_prefix": "ninja://components:components_browsertests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--gtest_filter=-FieldFormatterTest.DifferentLocales" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "components_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 6 + }, + "test": "components_unittests", + "test_id_prefix": "ninja://components:components_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.content_browsertests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "content_browsertests", + "test_id_prefix": "ninja://content/test:content_browsertests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.content_shell_test_apk.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_shell_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 + }, + "test": "content_shell_test_apk", + "test_id_prefix": "ninja://content/shell/android:content_shell_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "content_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 + }, + "test": "content_unittests", + "test_id_prefix": "ninja://content/test:content_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.crashpad_tests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "crashpad_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "crashpad_tests", + "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "crypto_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "crypto_unittests", + "test_id_prefix": "ninja://crypto:crypto_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.device_unittests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "device_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "device_unittests", + "test_id_prefix": "ninja://device:device_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "display_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "display_unittests", + "test_id_prefix": "ninja://ui/display:display_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "events_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "events_unittests", + "test_id_prefix": "ninja://ui/events:events_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gcm_unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gcm_unit_tests", + "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gfx_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gfx_unittests", + "test_id_prefix": "ninja://ui/gfx:gfx_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gin_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gin_unittests", + "test_id_prefix": "ninja://gin:gin_unittests/" + }, + { + "args": [ + "--use-cmd-decoder=validating", + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.gl_tests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gl_tests_validating" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "name": "gl_tests_validating", + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gl_tests", + "test_id_prefix": "ninja://gpu:gl_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.gl_unittests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gl_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gl_unittests", + "test_id_prefix": "ninja://ui/gl:gl_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "google_apis_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "google_apis_unittests", + "test_id_prefix": "ninja://google_apis:google_apis_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gpu_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gpu_unittests", + "test_id_prefix": "ninja://gpu:gpu_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "gwp_asan_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gwp_asan_unittests", + "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ipc_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ipc_tests", + "test_id_prefix": "ninja://ipc:ipc_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "latency_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "latency_unittests", + "test_id_prefix": "ninja://ui/latency:latency_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "libjingle_xmpp_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "libjingle_xmpp_unittests", + "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "liburlpattern_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "liburlpattern_unittests", + "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.media_unittests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "media_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "media_unittests", + "test_id_prefix": "ninja://media:media_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "midi_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "midi_unittests", + "test_id_prefix": "ninja://media/midi:midi_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "mojo_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "mojo_test_apk", + "test_id_prefix": "ninja://mojo/public/java/system:mojo_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "mojo_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "mojo_unittests", + "test_id_prefix": "ninja://mojo:mojo_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "monochrome_public_bundle_smoke_test" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "monochrome_public_bundle_smoke_test", + "test_id_prefix": "ninja://chrome/android:monochrome_public_bundle_smoke_test/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "monochrome_public_smoke_test" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "monochrome_public_smoke_test", + "test_id_prefix": "ninja://chrome/android:monochrome_public_smoke_test/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--gtest_filter=-MimeUtilTest.ExtensionTest" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "net_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 + }, + "test": "net_unittests", + "test_id_prefix": "ninja://net:net_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--gtest_filter=-ScopedDirTest.CloseOutOfScope" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "perfetto_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "perfetto_unittests", + "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.sandbox_linux_unittests.filter" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "sandbox_linux_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "sandbox_linux_unittests", + "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--gtest_filter=-PacLibraryTest.ActualPacMyIpAddress*" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "services_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "services_unittests", + "test_id_prefix": "ninja://services:services_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "shell_dialogs_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "shell_dialogs_unittests", + "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "skia_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "skia_unittests", + "test_id_prefix": "ninja://skia:skia_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "sql_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "sql_unittests", + "test_id_prefix": "ninja://sql:sql_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "storage_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "storage_unittests", + "test_id_prefix": "ninja://storage:storage_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "system_webview_shell_layout_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "system_webview_shell_layout_test_apk", + "test_id_prefix": "ninja://android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_android_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ui_android_unittests", + "test_id_prefix": "ninja://ui/android:ui_android_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_base_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ui_base_unittests", + "test_id_prefix": "ninja://ui/base:ui_base_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "ui_touch_selection_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ui_touch_selection_unittests", + "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "unit_tests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "unit_tests", + "test_id_prefix": "ninja://chrome/test:unit_tests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "url_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "url_unittests", + "test_id_prefix": "ninja://url:url_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "viz_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "viz_unittests", + "test_id_prefix": "ninja://components/viz:viz_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--gtest_filter=-DownloadBrowserTest.OverrideDownloadDirectory" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "weblayer_browsertests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_browsertests", + "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "weblayer_bundle_test" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_bundle_test", + "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_bundle_test/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "weblayer_instrumentation_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_instrumentation_test_apk", + "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--gtest_filter=-org.chromium.weblayer.test.BrowserControlsTest.testTopExpandedOnLoadWhenOnlyExpandAtTop" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "weblayer_private_instrumentation_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_private_instrumentation_test_apk", + "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_private_instrumentation_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "weblayer_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_unittests", + "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb", + "--gtest_filter=-org.chromium.android_webview.test.devui.HomeFragmentTest.testLongPressCopy*" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webview_instrumentation_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 7 + }, + "test": "webview_instrumentation_test_apk", + "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webview_ui_test_app_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "webview_ui_test_app_test_apk", + "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "wtf_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "wtf_unittests", + "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android31.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "zlib_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true, + "has_native_resultdb_integration": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "e2-standard-8", + "os": "Ubuntu-16.04|Ubuntu-18.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "generic_android31", + "path": ".android_emulator/generic_android31" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "generic_android31" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "zlib_unittests", + "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/" + } + ] + }, "android-arm64-proguard-rel": { "additional_compile_targets": [ "all"
diff --git a/testing/buildbot/chromium.rust.json b/testing/buildbot/chromium.rust.json index 6aee39c..a3d05ad 100644 --- a/testing/buildbot/chromium.rust.json +++ b/testing/buildbot/chromium.rust.json
@@ -82,8 +82,7 @@ "linux-rust-intree-x64-rel": { "additional_compile_targets": [ "mojo_rust", - "mojo_rust_extra_tests", - "mojo_rust_unittests", + "mojo_rust_tests", "rust_build_tests" ], "gtest_tests": [ @@ -152,14 +151,27 @@ }, "test": "build_rust_tests", "test_id_prefix": "ninja://build/rust/tests:build_rust_tests/" + }, + { + "isolate_name": "mojo_rust_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "mojo_rust_tests", + "swarming": { + "can_use_on_swarming_builders": true, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "mojo_rust_tests", + "test_id_prefix": "ninja://mojo/public/rust:mojo_rust_tests/" } ] }, "linux-rust-x64-rel": { "additional_compile_targets": [ "mojo_rust", - "mojo_rust_extra_tests", - "mojo_rust_unittests", + "mojo_rust_tests", "rust_build_tests" ], "gtest_tests": [ @@ -228,6 +240,20 @@ }, "test": "build_rust_tests", "test_id_prefix": "ninja://build/rust/tests:build_rust_tests/" + }, + { + "isolate_name": "mojo_rust_tests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "mojo_rust_tests", + "swarming": { + "can_use_on_swarming_builders": true, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "mojo_rust_tests", + "test_id_prefix": "ninja://mojo/public/rust:mojo_rust_tests/" } ] }
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 89b563c..8d8574b 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1283,17 +1283,9 @@ # coverage. "type": "additional_compile_target", }, - "mojo_rust_unittests": { - "label": "//mojo/public/rust:mojo_rust_unittests", - # We don't yet support running Rust test binaries. For now, at least build - # the target. TODO(https://crbug.com/1260120): make this a test. - "type": "additional_compile_target", - }, - "mojo_rust_extra_tests": { - "label": "//mojo/public/rust:mojo_rust", - # We don't yet support running Rust test binaries. For now, at least build - # the target. TODO(https://crbug.com/1260120): make this a test. - "type": "additional_compile_target", + "mojo_rust_tests": { + "label": "//mojo/public/rust:mojo_rust_tests", + "type": "generated_script", }, "mojo_test_apk": { "label": "//mojo/public/java/system:mojo_test_apk",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index bd1f0f84..8ba88a9 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -147,7 +147,7 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.base_unittests.filter', '--gtest_filter=-ModuleCacheTest.CheckAgainstProcMaps', # crbug.com/1260521 @@ -811,7 +811,7 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { # https://crbug.com/1039860 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.cc_unittests.filter', @@ -934,11 +934,15 @@ 'ci_only': True, 'experiment_percentage': 100, }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.chrome_public_test_apk.filter', '--timeout-scale=2.0', ], + # TODO(crbug.com/1225851): Remove experiment and ci_only + # once the test suite is stable. + 'ci_only': True, + 'experiment_percentage': 100, }, 'android-arm64-proguard-rel': { 'swarming': { @@ -1005,7 +1009,7 @@ ], }, }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--avd-config=../../tools/android/avd/proto/generic_playstore_android31.textpb', ], @@ -1156,7 +1160,7 @@ '--gtest_filter=-FieldFormatterTest.DifferentLocales', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ # TODO(crbug.com/1192348): Fix the test failure '--gtest_filter=-FieldFormatterTest.DifferentLocales', @@ -1299,7 +1303,7 @@ ], }, }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.content_browsertests.filter', ], @@ -1435,7 +1439,7 @@ '--timeout-scale=2.0', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.content_shell_test_apk.filter', ], @@ -1507,7 +1511,7 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11.crashpad_tests.filter', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.crashpad_tests.filter', ], @@ -1535,7 +1539,7 @@ }, 'device_unittests': { 'modifications': { - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.device_unittests.filter', ], @@ -1751,7 +1755,7 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11.gl_tests.filter', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.gl_tests.filter', ], @@ -1783,7 +1787,7 @@ 'Linux MSan Tests', ], 'modifications': { - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.gl_unittests.filter', ], @@ -2138,7 +2142,7 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.media_unittests.filter', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11_12.media_unittests.filter', ], @@ -2369,7 +2373,7 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_11.net_unittests.filter', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ # TODO(crbug.com/1191793): Fix the test failure '--gtest_filter=-MimeUtilTest.ExtensionTest', @@ -2531,7 +2535,7 @@ }, 'perfetto_unittests': { 'modifications': { - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ # TODO(crbug.com/1260440): Fix the failed test '--gtest_filter=-ScopedDirTest.CloseOutOfScope', @@ -2727,7 +2731,7 @@ }, 'sandbox_linux_unittests': { 'modifications': { - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_12.sandbox_linux_unittests.filter', ] @@ -2815,7 +2819,7 @@ '--gtest_filter=-PacLibraryTest.ActualPacMyIpAddress*' ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ # TODO(crbug.com/1264654): Fix the failed tests '--gtest_filter=-PacLibraryTest.ActualPacMyIpAddress*' @@ -3547,7 +3551,7 @@ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.blink_unittests.filter', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.blink_unittests.filter', ], @@ -3567,7 +3571,7 @@ '--gtest_filter=-DownloadBrowserTest.OverrideDownloadDirectory', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ # TODO(crbug.com/1191784): Fix the test failure '--gtest_filter=-DownloadBrowserTest.OverrideDownloadDirectory', @@ -3634,7 +3638,7 @@ '--gtest_filter=-org.chromium.weblayer.test.MediaCaptureTest.*', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ # crbug.com/1275200 '--gtest_filter=-org.chromium.weblayer.test.BrowserControlsTest.testTopExpandedOnLoadWhenOnlyExpandAtTop', @@ -3657,7 +3661,7 @@ }, 'webview_64_cts_tests': { 'remove_from': [ - 'android-12-x64-fyi-rel', # crbug.com/1260194 + 'android-12-x64-rel', # crbug.com/1260194 ], 'modifications': { 'android-pie-arm64-rel': { @@ -3727,7 +3731,7 @@ '--gtest_filter=-org.chromium.net.NetworkChangeNotifierTest.testNetworkChangeNotifierJavaObservers', ], }, - 'android-12-x64-fyi-rel': { + 'android-12-x64-rel': { 'args': [ # crbug.com/1292197 '--gtest_filter=-org.chromium.android_webview.test.devui.HomeFragmentTest.testLongPressCopy*',
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index a274b43..be9f2f5 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -4438,6 +4438,10 @@ 'swarming': {}, 'test': 'build_rust_tests', }, + 'mojo_rust_tests': { + 'swarming': {}, + 'test': 'mojo_rust_tests', + }, }, 'site_isolation_android_fyi_gtests': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 73d61c47..0300447 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -701,6 +701,19 @@ 'gtest_tests': 'android_11_emulator_gtests', } }, + 'android-12-x64-rel': { + 'mixins': [ + '12-x64-emulator', + 'emulator-8-cores', + 'has_native_resultdb_integration', + 'linux-xenial-or-bionic', + 'x86-64', + ], + 'os_type': 'android', + 'test_suites': { + 'gtest_tests': 'android_12_emulator_gtests', + } + }, 'android-arm64-proguard-rel': { 'additional_compile_targets': [ 'all', @@ -1163,19 +1176,6 @@ 'gtest_tests': 'android_12_dbg_emulator_gtests', } }, - 'android-12-x64-fyi-rel': { - 'mixins': [ - '12-x64-emulator', - 'emulator-8-cores', - 'has_native_resultdb_integration', - 'linux-xenial-or-bionic', - 'x86-64', - ], - 'os_type': 'android', - 'test_suites': { - 'gtest_tests': 'android_12_emulator_gtests', - } - }, 'android-annotator-rel': { 'test_suites': { 'scripts': 'test_traffic_annotation_auditor_script', @@ -5494,8 +5494,7 @@ 'linux-rust-intree-x64-rel' : { 'additional_compile_targets': [ 'mojo_rust', - 'mojo_rust_extra_tests', - 'mojo_rust_unittests', + 'mojo_rust_tests', 'rust_build_tests', ], 'test_suites': { @@ -5506,8 +5505,7 @@ 'linux-rust-x64-rel' : { 'additional_compile_targets': [ 'mojo_rust', - 'mojo_rust_extra_tests', - 'mojo_rust_unittests', + 'mojo_rust_tests', 'rust_build_tests', ], 'test_suites': {
diff --git a/testing/merge_scripts/PRESUBMIT.py b/testing/merge_scripts/PRESUBMIT.py index 3c01237..c29cbf5 100644 --- a/testing/merge_scripts/PRESUBMIT.py +++ b/testing/merge_scripts/PRESUBMIT.py
@@ -12,7 +12,8 @@ def CommonChecks(input_api, output_api): return input_api.canned_checks.RunUnitTestsInDirectory( - input_api, output_api, '.', [ r'^.+_test\.py$']) + input_api, output_api, '.', [ r'^.+_test\.py$'], + skip_shebang_check = True) def CheckChangeOnUpload(input_api, output_api): return CommonChecks(input_api, output_api)
diff --git a/testing/merge_scripts/code_coverage/merge_js_lib.py b/testing/merge_scripts/code_coverage/merge_js_lib.py index 92c32614..19fbd6bb 100644 --- a/testing/merge_scripts/code_coverage/merge_js_lib.py +++ b/testing/merge_scripts/code_coverage/merge_js_lib.py
@@ -102,6 +102,7 @@ stack = [] segments = [] + # pylint: disable=unsupported-assignment-operation def _append(end, count): """Append a new range segment to |segments|. @@ -148,7 +149,9 @@ _append(top['endOffset'], top['count']) return segments + # pylint: enable=unsupported-assignment-operation +# pylint: disable=unsupported-assignment-operation def _merge_segments(segments_a, segments_b): """Merges 2 lists of disjoint segments into one @@ -200,6 +203,7 @@ j += 1 return segments +# pylint: enable=unsupported-assignment-operation def _get_paths_with_suffix(input_dir, suffix): @@ -233,14 +237,14 @@ if not json_files: logging.info('No JavaScript coverage files found in %s', coverage_dir) - return + return None for file_path in json_files: coverage_data = _parse_json_file(file_path) if 'result' not in coverage_data: raise RuntimeError('%r does not have a result field' % - json_file_path) + file_path) for script_coverage in coverage_data['result']: script_url = script_coverage['url']
diff --git a/testing/merge_scripts/code_coverage/merge_js_results.py b/testing/merge_scripts/code_coverage/merge_js_results.py index cebf8bf..e8d48e7 100755 --- a/testing/merge_scripts/code_coverage/merge_js_results.py +++ b/testing/merge_scripts/code_coverage/merge_js_results.py
@@ -60,7 +60,7 @@ javascript_merger.merge_istanbul_reports( istanbul_coverage_dir, parsed_scripts, coverage_file_path) except RuntimeError as e: - logging.warn('Failed executing istanbul tasks: %s', e.message) + logging.warn('Failed executing istanbul tasks: %s', e) # Ensure JavaScript coverage dir exists. if not os.path.exists(params.javascript_coverage_dir):
diff --git a/testing/merge_scripts/code_coverage/merge_lib_test.py b/testing/merge_scripts/code_coverage/merge_lib_test.py index 97c1fbef..ff60fd9 100755 --- a/testing/merge_scripts/code_coverage/merge_lib_test.py +++ b/testing/merge_scripts/code_coverage/merge_lib_test.py
@@ -15,9 +15,11 @@ class MergeLibTest(unittest.TestCase): + # pylint: disable=super-with-arguments def __init__(self, *args, **kwargs): super(MergeLibTest, self).__init__(*args, **kwargs) self.maxDiff = None + # pylint: enable=super-with-arguments @mock.patch.object(subprocess, 'check_output') def test_validate_and_convert_profraw(self, mock_cmd):
diff --git a/testing/merge_scripts/code_coverage/merge_results_test.py b/testing/merge_scripts/code_coverage/merge_results_test.py index 1f064e9..9454af3 100755 --- a/testing/merge_scripts/code_coverage/merge_results_test.py +++ b/testing/merge_scripts/code_coverage/merge_results_test.py
@@ -19,9 +19,11 @@ class MergeProfilesTest(unittest.TestCase): + # pylint: disable=super-with-arguments def __init__(self, *args, **kwargs): super(MergeProfilesTest, self).__init__(*args, **kwargs) self.maxDiff = None + # pylint: enable=super-with-arguments def test_merge_script_api_parameters(self): """Test the step-level merge front-end."""
diff --git a/testing/merge_scripts/common_merge_script_tests.py b/testing/merge_scripts/common_merge_script_tests.py index fd56905..cb2e3cf 100644 --- a/testing/merge_scripts/common_merge_script_tests.py +++ b/testing/merge_scripts/common_merge_script_tests.py
@@ -10,10 +10,11 @@ class CommandLineTest(unittest.TestCase): - + # pylint: disable=super-with-arguments def __init__(self, methodName, module): super(CommandLineTest, self).__init__(methodName) self._module = module + # pylint: disable=super-with-arguments def setUp(self): self.temp_dir = tempfile.mkdtemp(prefix='common_merge_script_tests') @@ -48,4 +49,4 @@ '--output-json', output_json, shard0_json, ] - self.assertEquals(0, self._module.main(raw_args)) + self.assertEqual(0, self._module.main(raw_args))
diff --git a/testing/merge_scripts/noop_merge.py b/testing/merge_scripts/noop_merge.py index f7a93cd..d906bc7 100755 --- a/testing/merge_scripts/noop_merge.py +++ b/testing/merge_scripts/noop_merge.py
@@ -3,6 +3,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from __future__ import print_function + import argparse import json import shutil @@ -21,8 +23,8 @@ jsons_to_merge: A list of paths to JSON files. """ if len(jsons_to_merge) > 1: - print >> sys.stderr, ( - 'Multiple JSONs provided: %s' % ','.join(jsons_to_merge)) + print('Multiple JSONs provided: %s' % (','.join(jsons_to_merge)), + file=sys.stderr) return 1 if jsons_to_merge: shutil.copyfile(jsons_to_merge[0], output_json)
diff --git a/testing/merge_scripts/noop_merge_test.py b/testing/merge_scripts/noop_merge_test.py index 4cda1bf..bc913523 100755 --- a/testing/merge_scripts/noop_merge_test.py +++ b/testing/merge_scripts/noop_merge_test.py
@@ -21,13 +21,17 @@ class NoopMergeTest(unittest.TestCase): + # pylint: disable=super-with-arguments def setUp(self): super(NoopMergeTest, self).setUp() self.temp_dir = tempfile.mkdtemp() + # pylint: enable=super-with-arguments + # pylint: disable=super-with-arguments def tearDown(self): shutil.rmtree(self.temp_dir) super(NoopMergeTest, self).tearDown() + # pylint: enable=super-with-arguments def test_copies_first_json(self): input_json = os.path.join(self.temp_dir, 'input.json') @@ -60,10 +64,10 @@ class CommandLineTest(common_merge_script_tests.CommandLineTest): - + # pylint: disable=super-with-arguments def __init__(self, methodName='runTest'): super(CommandLineTest, self).__init__(methodName, noop_merge) - + # pylint: enable=super-with-arguments if __name__ == '__main__': unittest.main()
diff --git a/testing/merge_scripts/results_merger.py b/testing/merge_scripts/results_merger.py index 3c05dfe..4bb9f636 100755 --- a/testing/merge_scripts/results_merger.py +++ b/testing/merge_scripts/results_merger.py
@@ -69,8 +69,8 @@ if 'seconds_since_epoch' in shard_results_list[0]: return _merge_json_test_result_format(shard_results_list) - else: - return _merge_simplified_json_format(shard_results_list) + + return _merge_simplified_json_format(shard_results_list) def _merge_simplified_json_format(shard_results_list): @@ -261,8 +261,8 @@ try: dest[key] = merge_func(source[key], dest[key]) except MergeException as e: - e.message = "MergeFailure for %s\n%s" % (key, e.message) - e.args = tuple([e.message] + list(e.args[1:])) + message = "MergeFailure for %s\n%s" % (key, e.args[0]) + e.args = (message,) + e.args[1:] raise del source[key]
diff --git a/testing/merge_scripts/results_merger_test.py b/testing/merge_scripts/results_merger_test.py index e01f789..461a83f49 100755 --- a/testing/merge_scripts/results_merger_test.py +++ b/testing/merge_scripts/results_merger_test.py
@@ -5,6 +5,7 @@ import copy import os +import six import sys import unittest @@ -162,13 +163,13 @@ maxDiff = None # Show full diff if assertion fail def test_merge_tries(self): - self.assertEquals( + self.assertEqual( {'a': 'A', 'b': {'c': 'C'}}, results_merger.merge_tries( {'a': 'A', 'b': {}}, {'b': {'c': 'C'}})) def test_merge_tries_unmergable(self): - with self.assertRaisesRegexp(results_merger.MergeException, "a:b"): + with six.assertRaisesRegex(self, results_merger.MergeException, "a:b"): results_merger.merge_tries( {'a': {'b': 'A'}}, {'a': {'b': 'C'}}) @@ -178,7 +179,7 @@ merged_results = results_merger.merge_test_results( [extend(GOOD_JSON_TEST_RESULT_0, metadata1), extend(GOOD_JSON_TEST_RESULT_1, metadata2)]) - self.assertEquals( + self.assertEqual( merged_results['metadata']['tags'], ['foo', 'bat']) def test_merge_json_test_results_nop(self): @@ -190,8 +191,8 @@ for j in good_json_results: # Clone so we can check the input dictionaries are not modified a = copy.deepcopy(j) - self.assertEquals(results_merger.merge_test_results([a]), j) - self.assertEquals(a, j) + self.assertEqual(results_merger.merge_test_results([a]), j) + self.assertEqual(a, j) def test_merge_json_test_results_invalid_version(self): with self.assertRaises(results_merger.MergeException): @@ -242,7 +243,7 @@ ]) def test_merge_json_test_results_multiple(self): - self.assertEquals( + self.assertEqual( results_merger.merge_test_results([ GOOD_JSON_TEST_RESULT_0, GOOD_JSON_TEST_RESULT_1, @@ -251,7 +252,7 @@ GOOD_JSON_TEST_RESULT_MERGED) def test_merge_json_test_results_optional_matches(self): - self.assertEquals( + self.assertEqual( results_merger.merge_test_results([ extend(GOOD_JSON_TEST_RESULT_0, {'path_delimiter': '.'}), extend(GOOD_JSON_TEST_RESULT_1, {'path_delimiter': '.'}), @@ -268,7 +269,7 @@ ]) def test_merge_json_test_results_optional_count(self): - self.assertEquals( + self.assertEqual( results_merger.merge_test_results([ extend(GOOD_JSON_TEST_RESULT_0, {'fixable': 1}), extend(GOOD_JSON_TEST_RESULT_1, {'fixable': 2}), @@ -277,7 +278,7 @@ extend(GOOD_JSON_TEST_RESULT_MERGED, {'fixable': 6})) def test_merge_nothing(self): - self.assertEquals( + self.assertEqual( results_merger.merge_test_results([]), {})
diff --git a/testing/merge_scripts/standard_gtest_merge.py b/testing/merge_scripts/standard_gtest_merge.py index 5a3729f..a93edde 100755 --- a/testing/merge_scripts/standard_gtest_merge.py +++ b/testing/merge_scripts/standard_gtest_merge.py
@@ -145,7 +145,7 @@ if not matching_json_files: print('shard %s test output missing' % index, file=sys.stderr) return (None, 'shard %s test output was missing' % index) - elif len(matching_json_files) > 1: + if len(matching_json_files) > 1: print('duplicate test output for shard %s' % index, file=sys.stderr) return (None, 'shard %s test output was duplicated' % index) @@ -183,7 +183,7 @@ output_json, summary_json, jsons_to_merge): output = merge_shard_results(summary_json, jsons_to_merge) - with open(output_json, 'wb') as f: + with open(output_json, 'w') as f: json.dump(output, f) return 0
diff --git a/testing/merge_scripts/standard_gtest_merge_test.py b/testing/merge_scripts/standard_gtest_merge_test.py index 2de820c4..40bc5f4a 100755 --- a/testing/merge_scripts/standard_gtest_merge_test.py +++ b/testing/merge_scripts/standard_gtest_merge_test.py
@@ -3,11 +3,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import cStringIO import json import logging import os import shutil +import six import sys import tempfile import unittest @@ -428,10 +428,12 @@ class MergeShardResultsTest(_StandardGtestMergeTest): """Tests for merge_shard_results function.""" + # pylint: disable=super-with-arguments def setUp(self): super(MergeShardResultsTest, self).setUp() self.summary = None self.test_files = [] + # pylint: enable=super-with-arguments def stage(self, summary, files): self.summary = self._write_temp_file('summary.json', summary) @@ -440,7 +442,7 @@ self.test_files.append(abs_path) def call(self): - stdout = cStringIO.StringIO() + stdout = six.StringIO() with mock.patch('sys.stdout', stdout): merged = standard_gtest_merge.merge_shard_results( self.summary, self.test_files) @@ -600,8 +602,10 @@ class CommandLineTest(common_merge_script_tests.CommandLineTest): + # pylint: disable=super-with-arguments def __init__(self, methodName='runTest'): super(CommandLineTest, self).__init__(methodName, standard_gtest_merge) + # pylint: enable=super-with-arguments if __name__ == '__main__':
diff --git a/testing/merge_scripts/standard_isolated_script_merge.py b/testing/merge_scripts/standard_isolated_script_merge.py index b4e49b9..61b1692 100755 --- a/testing/merge_scripts/standard_isolated_script_merge.py +++ b/testing/merge_scripts/standard_isolated_script_merge.py
@@ -7,6 +7,7 @@ import json import os +import six import sys import merge_api @@ -47,8 +48,9 @@ with open(output_path) as f: try: json_contents = json.load(f) - except ValueError: - raise ValueError('Failed to parse JSON from %s' % j) + except ValueError as e: + six.raise_from(ValueError( + 'Failed to parse JSON from %s' % output_path), e) shard_results_list.append(json_contents) merged_results = results_merger.merge_test_results(shard_results_list) @@ -85,7 +87,7 @@ if not matching_json_files: print('shard %s test output missing' % index, file=sys.stderr) return None - elif len(matching_json_files) > 1: + if len(matching_json_files) > 1: print('duplicate test output for shard %s' % index, file=sys.stderr) return None
diff --git a/testing/merge_scripts/standard_isolated_script_merge_test.py b/testing/merge_scripts/standard_isolated_script_merge_test.py index 131199a..2f95c64 100755 --- a/testing/merge_scripts/standard_isolated_script_merge_test.py +++ b/testing/merge_scripts/standard_isolated_script_merge_test.py
@@ -35,9 +35,11 @@ self.test_files = [] self.summary = None + # pylint: disable=super-with-arguments def tearDown(self): shutil.rmtree(self.temp_dir) super(StandardIsolatedScriptMergeTest, self).tearDown() + # pylint: enable=super-with-arguments def _write_temp_file(self, path, content): abs_path = os.path.join(self.temp_dir, path.replace('/', os.sep)) @@ -103,6 +105,7 @@ self.assertEquals(results['missing_shards'], [1]) class InputParsingTest(StandardIsolatedScriptMergeTest): + # pylint: disable=super-with-arguments def setUp(self): super(InputParsingTest, self).setUp() @@ -121,6 +124,7 @@ side_effect=mock_merge_test_results) m.start() self.addCleanup(m.stop) + # pylint: enable=super-with-arguments def test_simple(self): self._stage(TWO_COMPLETED_SHARDS, @@ -173,9 +177,11 @@ class CommandLineTest(common_merge_script_tests.CommandLineTest): + # pylint: disable=super-with-arguments def __init__(self, methodName='runTest'): super(CommandLineTest, self).__init__( methodName, standard_isolated_script_merge) + # pylint: enable=super-with-arguments if __name__ == '__main__':
diff --git a/testing/scripts/rust/main_program_unittests.py b/testing/scripts/rust/main_program_unittests.py index 9719574..7f40acf 100755 --- a/testing/scripts/rust/main_program_unittests.py +++ b/testing/scripts/rust/main_program_unittests.py
@@ -37,11 +37,14 @@ def test_basic_scenario(self): with tempfile.TemporaryDirectory() as tmpdirname: # Prepare simulated inputs. - test_list = ['test_foo', 'test_bar', 'test_foobar'] + test_list = [ + 'test_foo', 'test_bar', 'test_foobar', 'module/test_foo' + ] test_results = [ TestResult('test_foo', 'PASS'), TestResult('test_bar', 'PASS'), - TestResult('test_foobar', 'FAILED') + TestResult('test_foobar', 'FAILED'), + TestResult('module/test_foo', 'PASS') ] fake_executable_wrapper = FakeTestExecutableWrapper( test_list, test_results) @@ -62,7 +65,7 @@ # yapf: disable expected_json_output = { 'interrupted': False, - 'path_delimiter': '/', + 'path_delimiter': '//', #'seconds_since_epoch': 1635974313.8388052, 'version': 3, 'tests': { @@ -77,9 +80,13 @@ 'test_foobar': { 'expected': 'PASS', 'actual': 'FAILED' + }, + 'module/test_foo': { + 'expected': 'PASS', + 'actual': 'PASS' }}, 'num_failures_by_type': { - 'PASS': 2, + 'PASS': 3, 'FAILED': 1 } }
diff --git a/testing/scripts/rust/rust_main_program.py b/testing/scripts/rust/rust_main_program.py index 224ebc3..080dd2b 100644 --- a/testing/scripts/rust/rust_main_program.py +++ b/testing/scripts/rust/rust_main_program.py
@@ -18,14 +18,17 @@ def _format_test_name(test_executable_name, test_case_name): - assert "/" not in test_executable_name + assert "//" not in test_executable_name assert "/" not in test_case_name - return "{}/{}".format(test_executable_name, test_case_name) + test_case_name = "/".join(test_case_name.split("::")) + return "{}//{}".format(test_executable_name, test_case_name) -def _split_test_name(test_name): - assert "/" in test_name - test_executable_name, test_case_name = test_name.split("/", 1) +def _parse_test_name(test_name): + assert "//" in test_name + assert "::" not in test_name + test_executable_name, test_case_name = test_name.split("//", 1) + test_case_name = "::".join(test_case_name.split("/")) return test_executable_name, test_case_name @@ -74,7 +77,7 @@ A list of test_results.TestResult objects. """ results = [] - regex = re.compile(r'^test (\w+) \.\.\. (\w+)') + regex = re.compile(r'^test ([:\w]+) \.\.\. (\w+)') for line in output.splitlines(): match = regex.match(line.strip()) if not match: @@ -87,6 +90,10 @@ actual_test_result = match.group(2) if actual_test_result == 'ok': actual_test_result = 'PASS' + elif actual_test_result == 'FAILED': + actual_test_result = 'FAIL' + elif actual_test_result == 'ignored': + actual_test_result = 'SKIP' test_name = _format_test_name(test_executable_name, test_case_name) results.append(test_results.TestResult(test_name, actual_test_result)) @@ -96,7 +103,7 @@ def _get_exe_specific_tests(expected_test_executable_name, list_of_test_names): results = [] for test_name in list_of_test_names: - actual_test_executable_name, test_case_name = _split_test_name( + actual_test_executable_name, test_case_name = _parse_test_name( test_name) if actual_test_executable_name != expected_test_executable_name: continue
diff --git a/testing/scripts/rust/rust_main_program_unittests.py b/testing/scripts/rust/rust_main_program_unittests.py index 8af5d6c1..d354e61 100755 --- a/testing/scripts/rust/rust_main_program_unittests.py +++ b/testing/scripts/rust/rust_main_program_unittests.py
@@ -11,6 +11,8 @@ from test_results import TestResult +from rust_main_program import _format_test_name +from rust_main_program import _parse_test_name from rust_main_program import _get_exe_specific_tests from rust_main_program import _scrape_test_list from rust_main_program import _scrape_test_results @@ -19,14 +21,30 @@ class Tests(fake_filesystem_unittest.TestCase): + def test_format_test_name(self): + self.assertEqual('test_exe//test_bar', + _format_test_name('test_exe', 'test_bar')) + self.assertEqual('test_exe//foo/test_foo', + _format_test_name('test_exe', 'foo::test_foo')) + + def test_parse_test_name(self): + self.assertEqual(('test_exe', 'test_bar'), + _parse_test_name('test_exe//test_bar')) + self.assertEqual(('test_exe', 'foo::test_foo'), + _parse_test_name('test_exe//foo/test_foo')) + def test_scrape_test_list(self): test_input = """ test_foo: test test_bar: test +foo::test_in_mod: test test_benchmark: benchmark """.strip() actual_results = _scrape_test_list(test_input, 'test_exe_name') - expected_results = ['test_exe_name/test_foo', 'test_exe_name/test_bar'] + expected_results = [ + 'test_exe_name//test_foo', 'test_exe_name//test_bar', + 'test_exe_name//foo/test_in_mod' + ] self.assertEqual(actual_results, expected_results) # https://crbug.com/1281664 meant that Rust executables might @@ -48,6 +66,7 @@ running 3 tests test test_foo ... ok test test_bar ... ok +test foo::test_in_mod ... ok test test_foobar ... FAILED failures: @@ -62,15 +81,18 @@ failures: test_foobar -test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s +test result: FAILED. 3 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s """.strip() - list_of_expected_test_names = ['test_foo', 'test_bar', 'test_foobar'] + list_of_expected_test_names = [ + 'test_foo', 'test_bar', 'foo::test_in_mod', 'test_foobar' + ] actual_results = _scrape_test_results(test_input, 'test_exe_name', list_of_expected_test_names) expected_results = [ - TestResult('test_exe_name/test_foo', 'PASS'), - TestResult('test_exe_name/test_bar', 'PASS'), - TestResult('test_exe_name/test_foobar', 'FAILED') + TestResult('test_exe_name//test_foo', 'PASS'), + TestResult('test_exe_name//test_bar', 'PASS'), + TestResult('test_exe_name//foo/test_in_mod', 'PASS'), + TestResult('test_exe_name//test_foobar', 'FAIL') ] self.assertEqual(actual_results, expected_results) @@ -84,7 +106,8 @@ def test_get_exe_specific_tests(self): result = _get_exe_specific_tests( - "exe_name", ["exe_name/foo1", "exe_name/foo2", "other_exe/foo3"]) + "exe_name", + ["exe_name//foo1", "exe_name//foo2", "other_exe//foo3"]) self.assertEqual(['foo1', 'foo2'], result) def test_executable_wrapper_basic_construction(self):
diff --git a/testing/scripts/rust/test_filtering_unittests.py b/testing/scripts/rust/test_filtering_unittests.py index aa908995..5390469 100755 --- a/testing/scripts/rust/test_filtering_unittests.py +++ b/testing/scripts/rust/test_filtering_unittests.py
@@ -21,6 +21,7 @@ t = _TestFilter('foo') self.assertTrue(t.is_match('foo')) self.assertFalse(t.is_match('foobar')) + self.assertFalse(t.is_match('foo/bar')) self.assertFalse(t.is_match('fo')) self.assertFalse(t.is_exclusion_filter()) @@ -28,6 +29,7 @@ t = _TestFilter('foo*') self.assertTrue(t.is_match('foo')) self.assertTrue(t.is_match('foobar')) + self.assertTrue(t.is_match('foo/bar')) self.assertFalse(t.is_match('fo')) self.assertFalse(t.is_exclusion_filter()) @@ -35,6 +37,7 @@ t = _TestFilter('-foo') self.assertTrue(t.is_match('foo')) self.assertFalse(t.is_match('foobar')) + self.assertFalse(t.is_match('foo/bar')) self.assertFalse(t.is_match('fo')) self.assertTrue(t.is_exclusion_filter()) @@ -42,6 +45,7 @@ t = _TestFilter('-foo*') self.assertTrue(t.is_match('foo')) self.assertTrue(t.is_match('foobar')) + self.assertTrue(t.is_match('foo/bar')) self.assertFalse(t.is_match('fo')) self.assertTrue(t.is_exclusion_filter())
diff --git a/testing/scripts/rust/test_results.py b/testing/scripts/rust/test_results.py index 8e208ea8..52e40ea7 100644 --- a/testing/scripts/rust/test_results.py +++ b/testing/scripts/rust/test_results.py
@@ -100,7 +100,7 @@ old_count = num_failures_by_type.get(res.actual_test_result, 0) num_failures_by_type[res.actual_test_result] = old_count + 1 - path = res.test_name.split('/') + path = res.test_name.split('//') group = tests for group_name in path[:-1]: if not group_name in group: @@ -114,7 +114,7 @@ return { 'interrupted': False, - 'path_delimiter': '/', + 'path_delimiter': '//', 'seconds_since_epoch': seconds_since_epoch, 'version': 3, 'tests': tests,
diff --git a/testing/scripts/rust/test_results_unittests.py b/testing/scripts/rust/test_results_unittests.py index 767a26b..df55385e 100755 --- a/testing/scripts/rust/test_results_unittests.py +++ b/testing/scripts/rust/test_results_unittests.py
@@ -40,14 +40,14 @@ class BuildJsonDataTests(unittest.TestCase): def test_grouping_of_tests(self): - t1 = TestResult('group1/foo', 'PASS') - t2 = TestResult('group1/bar', 'FAILED') - t3 = TestResult('group2/baz', 'FAILED') + t1 = TestResult('group1//foo', 'PASS') + t2 = TestResult('group1//bar', 'FAIL') + t3 = TestResult('group2//baz', 'FAIL') actual_result = _build_json_data([t1, t2, t3], 123) # yapf: disable expected_result = { 'interrupted': False, - 'path_delimiter': '/', + 'path_delimiter': '//', 'seconds_since_epoch': 123, 'version': 3, 'tests': { @@ -58,16 +58,16 @@ }, 'bar': { 'expected': 'PASS', - 'actual': 'FAILED' + 'actual': 'FAIL' }}, 'group2': { 'baz': { 'expected': 'PASS', - 'actual': 'FAILED' + 'actual': 'FAIL' }}}, 'num_failures_by_type': { 'PASS': 1, - 'FAILED': 2 + 'FAIL': 2 } } # yapf: enable
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index f955a3b9..36eadec4 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -185,6 +185,21 @@ ] } ], + "AndroidMessagesNotificationBlocked": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled_2022-03-02", + "enable_features": [ + "MessagesForAndroidNotificationBlocked" + ] + } + ] + } + ], "AndroidMessagesSaveCard": [ { "platforms": [ @@ -816,6 +831,28 @@ ] } ], + "AutofillFixServerQueriesIfPasswordManagerIsEnabled": [ + { + "platforms": [ + "android", + "android_webview", + "chromeos", + "chromeos_lacros", + "ios", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AutofillFixServerQueriesIfPasswordManagerIsEnabled" + ] + } + ] + } + ], "AutofillIgnoreAutocompleteForImport": [ { "platforms": [ @@ -1314,6 +1351,28 @@ "CPSS-Geolocation": [ { "platforms": [ + "chromeos", + "chromeos_lacros", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled_20210817", + "params": { + "holdback_chance": "0.3" + }, + "enable_features": [ + "PermissionGeolocationPredictions" + ] + } + ] + } + ], + "CPSS-OnDeviceNotificationPredictions": [ + { + "platforms": [ "android", "chromeos", "chromeos_lacros", @@ -1323,12 +1382,13 @@ ], "experiments": [ { - "name": "Enabled__20210817", + "name": "Enabled_20220221", "params": { "holdback_chance": "0.3" }, "enable_features": [ - "PermissionGeolocationPredictions" + "OptimizationHints", + "PermissionOnDeviceNotificationPredictions" ] } ] @@ -2188,6 +2248,23 @@ ] } ], + "CrashReportBreadcrumbs": [ + { + "platforms": [ + "windows", + "mac", + "linux" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "LogBreadcrumbs" + ] + } + ] + } + ], "CredentialProviderExtensionPromo": [ { "platforms": [
diff --git a/third_party/blink/perf_tests/webcodecs/video-encoding.js b/third_party/blink/perf_tests/webcodecs/video-encoding.js index 53468df..408f629 100644 --- a/third_party/blink/perf_tests/webcodecs/video-encoding.js +++ b/third_party/blink/perf_tests/webcodecs/video-encoding.js
@@ -25,7 +25,8 @@ let support = await VideoEncoder.isConfigSupported(encoder_config); if (!support.supported) { - testRunner.notifyDone(); + PerfTestRunner.log("Skipping test. Unsupported encoder config" + + JSON.stringify(encoder_config)); return; }
diff --git a/third_party/blink/perf_tests/webcodecs/videoFrame-texImage2d.html b/third_party/blink/perf_tests/webcodecs/videoFrame-texImage2d.html index 1124428..5c9198f4 100644 --- a/third_party/blink/perf_tests/webcodecs/videoFrame-texImage2d.html +++ b/third_party/blink/perf_tests/webcodecs/videoFrame-texImage2d.html
@@ -5,6 +5,7 @@ </head> <body> <script src="../resources/runner.js"></script> +<script src="videoFrame-utils.js"></script> <canvas id="canvas" width="1280" height="720"></canvas> <script id="fragment-shader" type="glsl"> @@ -25,35 +26,7 @@ <script> (async function() { - const config = { - codec: "avc1.64001f", - codedWidth: 1280, - codedHeight: 720 - }; - - const support = await VideoDecoder.isConfigSupported(config); - if (!support.supported) { - testRunner.notifyDone(); - return; - } - - const result = await fetch("resources/720p.h264"); - const buf = await result.arrayBuffer(); - const chunk = new EncodedVideoChunk({ - timestamp: 0, - type: "key", - data: buf - }); - - let frame = null; - const decoder = new VideoDecoder({ - output: f => frame = f, - error: e => PerfTestRunner.log("Decode error:" + e) - }); - decoder.configure(config); - decoder.decode(chunk); - await decoder.flush(); - + let frame = await createDecodedFrame(); if (frame == null) { PerfTestRunner.logFatalError("No frame decoded"); return;
diff --git a/third_party/blink/perf_tests/webcodecs/videoFrame-utils.js b/third_party/blink/perf_tests/webcodecs/videoFrame-utils.js index 73be8de..383c500 100644 --- a/third_party/blink/perf_tests/webcodecs/videoFrame-utils.js +++ b/third_party/blink/perf_tests/webcodecs/videoFrame-utils.js
@@ -26,7 +26,8 @@ const support = await VideoDecoder.isConfigSupported(config); if (!support.supported) { - testRunner.notifyDone(); + PerfTestRunner.logFatalError("Skipping test. Unsupported decoder config:" + + JSON.stringify(config)); return null; }
diff --git a/third_party/blink/public/mojom/conversions/conversions.mojom b/third_party/blink/public/mojom/conversions/conversions.mojom index 3b7d6d7..1a770d92 100644 --- a/third_party/blink/public/mojom/conversions/conversions.mojom +++ b/third_party/blink/public/mojom/conversions/conversions.mojom
@@ -83,10 +83,8 @@ // browsing context. RegisterConversion(Conversion conversion); - // Registers an impression. Triggered by the registerattributionsource - // attribute being added to an anchor element alongside other API attributes, - // or by the registerAttributionSource JS method. These impressions are not - // associated with a browser navigation. + // Registers an impression. Triggered by the registerAttributionSource JS + // method. These impressions are not associated with a browser navigation. RegisterImpression(Impression impression); // Registers a new data host which can register a source or trigger.
diff --git a/third_party/blink/renderer/core/frame/attribution_response_parsing.cc b/third_party/blink/renderer/core/frame/attribution_response_parsing.cc index 9c0fd2d1..3465e70 100644 --- a/third_party/blink/renderer/core/frame/attribution_response_parsing.cc +++ b/third_party/blink/renderer/core/frame/attribution_response_parsing.cc
@@ -4,17 +4,23 @@ #include "third_party/blink/renderer/core/frame/attribution_response_parsing.h" +#include <stdint.h> + #include <memory> #include <utility> #include "base/check.h" +#include "base/memory/scoped_refptr.h" +#include "base/time/time.h" #include "third_party/blink/public/common/attribution_reporting/constants.h" #include "third_party/blink/public/mojom/conversions/attribution_data_host.mojom-blink.h" #include "third_party/blink/renderer/platform/json/json_parser.h" #include "third_party/blink/renderer/platform/json/json_values.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/text/ascii_ctype.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" namespace blink::attribution_response_parsing { @@ -62,6 +68,55 @@ return mojom::blink::AttributionAggregatableKey::New(high_bits, low_bits); } +bool ParseAttributionFilterData( + JSONValue* value, + mojom::blink::AttributionFilterData& filter_data) { + if (!value) + return true; + + JSONObject* object = JSONObject::Cast(value); + if (!object) + return false; + + const wtf_size_t num_filters = object->size(); + if (num_filters > kMaxAttributionFiltersPerSource) + return false; + + for (wtf_size_t i = 0; i < num_filters; ++i) { + JSONObject::Entry entry = object->at(i); + + if (entry.first.CharactersSizeInBytes() > + kMaxBytesPerAttributionFilterString) { + return false; + } + + JSONArray* array = JSONArray::Cast(entry.second); + if (!array) + return false; + + const wtf_size_t num_values = array->size(); + if (num_values > kMaxValuesPerAttributionFilter) + return false; + + WTF::Vector<String> values; + + for (wtf_size_t j = 0; j < num_values; ++j) { + String value; + if (!array->at(j)->AsString(&value)) + return false; + + if (value.CharactersSizeInBytes() > kMaxBytesPerAttributionFilterString) + return false; + + values.push_back(std::move(value)); + } + + filter_data.filter_values.insert(entry.first, std::move(values)); + } + + return true; +} + } // namespace ResponseParseResult<mojom::blink::AttributionAggregatableSources> @@ -120,6 +175,74 @@ ResponseParseStatus::kSuccess, std::move(sources)); } +bool ParseSourceRegistrationHeader( + const AtomicString& json_string, + mojom::blink::AttributionSourceData& source_data) { + // TODO(apaseltiner): Consider applying a max stack depth to this. + std::unique_ptr<JSONValue> json = ParseJSON(json_string); + + if (!json) + return false; + + JSONObject* object = JSONObject::Cast(json.get()); + if (!object) + return false; + + String event_id_string; + if (!object->GetString("source_event_id", &event_id_string)) + return false; + bool event_id_is_valid = false; + uint64_t event_id = event_id_string.ToUInt64Strict(&event_id_is_valid); + + // For source registrations where there is no mechanism to raise an error, + // such as on an img element, it is more useful to log the source with + // default data so that a reporting origin can learn the failure mode. + source_data.source_event_id = event_id_is_valid ? event_id : 0; + + String destination_string; + if (!object->GetString("destination", &destination_string)) + return false; + scoped_refptr<const SecurityOrigin> destination = + SecurityOrigin::CreateFromString(destination_string); + if (!destination->IsPotentiallyTrustworthy()) + return false; + source_data.destination = std::move(destination); + + // Treat invalid expiry, priority, and debug key as if they were not set. + String priority_string; + if (object->GetString("priority", &priority_string)) { + bool priority_is_valid = false; + int64_t priority = priority_string.ToInt64Strict(&priority_is_valid); + if (priority_is_valid) + source_data.priority = priority; + } + + String expiry_string; + if (object->GetString("expiry", &expiry_string)) { + bool expiry_is_valid = false; + int64_t expiry = expiry_string.ToInt64Strict(&expiry_is_valid); + if (expiry_is_valid) + source_data.expiry = base::Seconds(expiry); + } + + String debug_key_string; + if (object->GetString("debug_key", &debug_key_string)) { + bool debug_key_is_valid = false; + uint64_t debug_key = debug_key_string.ToUInt64Strict(&debug_key_is_valid); + if (debug_key_is_valid) { + source_data.debug_key = mojom::blink::AttributionDebugKey::New(debug_key); + } + } + + source_data.filter_data = mojom::blink::AttributionFilterData::New(); + if (!ParseAttributionFilterData(object->Get("filter_data"), + *source_data.filter_data)) { + return false; + } + + return true; +} + bool ParseEventTriggerData( const AtomicString& json_string, WTF::Vector<mojom::blink::EventTriggerDataPtr>& event_trigger_data) {
diff --git a/third_party/blink/renderer/core/frame/attribution_response_parsing.h b/third_party/blink/renderer/core/frame/attribution_response_parsing.h index ceb65b6dc..128b636 100644 --- a/third_party/blink/renderer/core/frame/attribution_response_parsing.h +++ b/third_party/blink/renderer/core/frame/attribution_response_parsing.h
@@ -48,6 +48,10 @@ CORE_EXPORT ResponseParseResult<mojom::blink::AttributionAggregatableSources> ParseAttributionAggregatableSources(const AtomicString& json_string); +CORE_EXPORT bool ParseSourceRegistrationHeader( + const AtomicString& json_string, + mojom::blink::AttributionSourceData& source_data); + // Parses event trigger data header of the form: // // [{
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 82dd4341..755fa0e 100644 --- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc +++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -6,11 +6,9 @@ #include <utility> -#include "base/time/time.h" +#include "base/memory/scoped_refptr.h" #include "services/network/public/mojom/referrer_policy.mojom-blink.h" -#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" -#include "third_party/blink/public/common/attribution_reporting/constants.h" #include "third_party/blink/public/mojom/conversions/attribution_data_host.mojom-blink.h" #include "third_party/blink/public/mojom/conversions/conversions.mojom-blink.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" @@ -20,8 +18,6 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/html/html_image_element.h" -#include "third_party/blink/renderer/platform/json/json_parser.h" -#include "third_party/blink/renderer/platform/json/json_values.h" #include "third_party/blink/renderer/platform/loader/cors/cors.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h" @@ -36,65 +32,10 @@ #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/referrer.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/weborigin/security_policy.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { -namespace { - -bool ParseAttributionFilterData( - JSONValue* value, - mojom::blink::AttributionFilterData& filter_data) { - if (!value) - return true; - - JSONObject* object = JSONObject::Cast(value); - if (!object) - return false; - - const wtf_size_t num_filters = object->size(); - if (num_filters > kMaxAttributionFiltersPerSource) - return false; - - for (wtf_size_t i = 0; i < num_filters; ++i) { - JSONObject::Entry entry = object->at(i); - - if (entry.first.CharactersSizeInBytes() > - kMaxBytesPerAttributionFilterString) { - return false; - } - - JSONArray* array = JSONArray::Cast(entry.second); - if (!array) - return false; - - const wtf_size_t num_values = array->size(); - if (num_values > kMaxValuesPerAttributionFilter) - return false; - - WTF::Vector<String> values; - - for (wtf_size_t j = 0; j < num_values; ++j) { - String value; - if (!array->at(j)->AsString(&value)) - return false; - - if (value.CharactersSizeInBytes() > kMaxBytesPerAttributionFilterString) - return false; - - values.push_back(std::move(value)); - } - - filter_data.filter_values.insert(entry.first, std::move(values)); - } - - return true; -} - -} // namespace - AttributionSrcLoader::AttributionSrcLoader(LocalFrame* frame) : local_frame_(frame) {} @@ -235,7 +176,6 @@ mojom::blink::AttributionSourceDataPtr source_data = mojom::blink::AttributionSourceData::New(); - source_data->filter_data = mojom::blink::AttributionFilterData::New(); // Verify the current url is trustworthy and capable of registering sources. scoped_refptr<const SecurityOrigin> reporting_origin = @@ -245,69 +185,10 @@ source_data->reporting_origin = SecurityOrigin::Create(response.CurrentRequestUrl()); - // Populate attribution data from provided JSON. - // TODO(apaseltiner): Consider applying a max stack depth to this. - std::unique_ptr<JSONValue> json = ParseJSON(response.HttpHeaderField( - http_names::kAttributionReportingRegisterSource)); - - // TODO(johnidel): Log a devtools issues if JSON parsing fails and on - // individual early exits below. - if (!json) - return; - - JSONObject* object = JSONObject::Cast(json.get()); - if (!object) - return; - - String event_id_string; - if (!object->GetString("source_event_id", &event_id_string)) - return; - bool event_id_is_valid = false; - uint64_t event_id = event_id_string.ToUInt64Strict(&event_id_is_valid); - - // For source registrations where there is no mechanism to raise an error, - // such as on an img element, it is more useful to log the source with - // default data so that a reporting origin can learn the failure mode. - source_data->source_event_id = event_id_is_valid ? event_id : 0; - - String destination_string; - if (!object->GetString("destination", &destination_string)) - return; - scoped_refptr<const SecurityOrigin> destination = - SecurityOrigin::CreateFromString(destination_string); - if (!destination->IsPotentiallyTrustworthy()) - return; - source_data->destination = std::move(destination); - - // Treat invalid expiry, priority, and debug key as if they were not set. - String priority_string; - if (object->GetString("priority", &priority_string)) { - bool priority_is_valid = false; - int64_t priority = priority_string.ToInt64Strict(&priority_is_valid); - if (priority_is_valid) - source_data->priority = priority; - } - - String expiry_string; - if (object->GetString("expiry", &expiry_string)) { - bool expiry_is_valid = false; - int64_t expiry = expiry_string.ToInt64Strict(&expiry_is_valid); - if (expiry_is_valid) - source_data->expiry = base::Seconds(expiry); - } - - String debug_key_string; - if (object->GetString("debug_key", &debug_key_string)) { - bool debug_key_is_valid = false; - uint64_t debug_key = debug_key_string.ToUInt64Strict(&debug_key_is_valid); - if (debug_key_is_valid) { - source_data->debug_key = - mojom::blink::AttributionDebugKey::New(debug_key); - } - } - - if (!ParseAttributionFilterData(object->Get("filter_data"), - *source_data->filter_data)) { + if (!attribution_response_parsing::ParseSourceRegistrationHeader( + response.HttpHeaderField( + http_names::kAttributionReportingRegisterSource), + *source_data)) { return; }
diff --git a/third_party/blink/renderer/core/html/forms/resources/calendar_picker.js b/third_party/blink/renderer/core/html/forms/resources/calendar_picker.js index 2f421d8..39b33ce 100644 --- a/third_party/blink/renderer/core/html/forms/resources/calendar_picker.js +++ b/third_party/blink/renderer/core/html/forms/resources/calendar_picker.js
@@ -2358,130 +2358,135 @@ // Mixin containing utilities for identifying and navigating between // valid day/week/month ranges. -var DateRangeManager = { - _setValidDateConfig(config) { - this.config = {}; +function dateRangeManagerMixin(baseClass) { + class DateRangeManager extends baseClass { + _setValidDateConfig(config) { + this.config = {}; - this.config.minimum = (typeof config.min !== 'undefined' && config.min) ? - parseDateString(config.min) : - this._dateTypeConstructor.Minimum; - this.config.maximum = (typeof config.max !== 'undefined' && config.max) ? - parseDateString(config.max) : - this._dateTypeConstructor.Maximum; - this.config.minimumValue = this.config.minimum.valueOf(); - this.config.maximumValue = this.config.maximum.valueOf(); - this.config.step = (typeof config.step !== 'undefined') ? - Number(config.step) : - this._dateTypeConstructor.DefaultStep; - this.config.stepBase = (typeof config.stepBase !== 'undefined') ? - Number(config.stepBase) : - this._dateTypeConstructor.DefaultStepBase; - }, - - _isValidForStep(value) { - // nextAllowedValue is the time closest (looking forward) to value that is - // within the interval specified by the step and the stepBase. This may - // be equal to value. - var nextAllowedValue = - (Math.ceil((value - this.config.stepBase) / this.config.step) * - this.config.step) + - this.config.stepBase; - // If the nextAllowedValue is between value and the next nearest possible time - // for this control type (determined by adding the smallest time interval, given - // by DefaultStep, to value) then we consider it to be valid. - return nextAllowedValue < (value + this._dateTypeConstructor.DefaultStep); - }, - - /** - * @param {!number} value - * @return {!boolean} - */ - _outOfRange(value) { - return value < this.config.minimumValue || value > this.config.maximumValue; - }, - - /** - * @param {!DateType} dayOrWeekOrMonth - * @return {!boolean} - */ - isValid(dayOrWeekOrMonth) { - var value = dayOrWeekOrMonth.valueOf(); - return dayOrWeekOrMonth instanceof this._dateTypeConstructor && - !this._outOfRange(value) && this._isValidForStep(value); - }, - - /** - * @param {!DayOrWeekOrMonth} dayOrWeekOrMonth - * @return {?DayOrWeekOrMonth} - */ - getNearestValidRangeLookingForward(dayOrWeekOrMonth) { - if (dayOrWeekOrMonth < this.config.minimumValue) { - // Performance optimization: avoid wasting lots of time in the below - // loop if dayOrWeekOrMonth is significantly less than the min. - dayOrWeekOrMonth = - this._dateTypeConstructor.createFromValue(this.config.minimumValue); + this.config.minimum = (typeof config.min !== 'undefined' && config.min) ? + parseDateString(config.min) : + this._dateTypeConstructor.Minimum; + this.config.maximum = (typeof config.max !== 'undefined' && config.max) ? + parseDateString(config.max) : + this._dateTypeConstructor.Maximum; + this.config.minimumValue = this.config.minimum.valueOf(); + this.config.maximumValue = this.config.maximum.valueOf(); + this.config.step = (typeof config.step !== 'undefined') ? + Number(config.step) : + this._dateTypeConstructor.DefaultStep; + this.config.stepBase = (typeof config.stepBase !== 'undefined') ? + Number(config.stepBase) : + this._dateTypeConstructor.DefaultStepBase; } - while (!this.isValid(dayOrWeekOrMonth) && - dayOrWeekOrMonth < this.config.maximumValue) { - dayOrWeekOrMonth = dayOrWeekOrMonth.next(); + _isValidForStep(value) { + // nextAllowedValue is the time closest (looking forward) to value that is + // within the interval specified by the step and the stepBase. This may + // be equal to value. + var nextAllowedValue = + (Math.ceil((value - this.config.stepBase) / this.config.step) * + this.config.step) + + this.config.stepBase; + // If the nextAllowedValue is between value and the next nearest possible + // time for this control type (determined by adding the smallest time + // interval, given by DefaultStep, to value) then we consider it to be + // valid. + return nextAllowedValue < (value + this._dateTypeConstructor.DefaultStep); } - return this.isValid(dayOrWeekOrMonth) ? dayOrWeekOrMonth : null; - }, - - /** - * @param {!DayOrWeekOrMonth} dayOrWeekOrMonth - * @return {?DayOrWeekOrMonth} - */ - getNearestValidRangeLookingBackward(dayOrWeekOrMonth) { - if (dayOrWeekOrMonth > this.config.maximumValue) { - // Performance optimization: avoid wasting lots of time in the below - // loop if dayOrWeekOrMonth is significantly greater than the max. - dayOrWeekOrMonth = - this._dateTypeConstructor.createFromValue(this.config.maximumValue); + /** + * @param {!number} value + * @return {!boolean} + */ + _outOfRange(value) { + return value < this.config.minimumValue || + value > this.config.maximumValue; } - while (!this.isValid(dayOrWeekOrMonth) && - dayOrWeekOrMonth > this.config.minimumValue) { - dayOrWeekOrMonth = dayOrWeekOrMonth.previous(); + /** + * @param {!DateType} dayOrWeekOrMonth + * @return {!boolean} + */ + isValid(dayOrWeekOrMonth) { + var value = dayOrWeekOrMonth.valueOf(); + return dayOrWeekOrMonth instanceof this._dateTypeConstructor && + !this._outOfRange(value) && this._isValidForStep(value); } - return this.isValid(dayOrWeekOrMonth) ? dayOrWeekOrMonth : null; - }, - - /** - * @param {!DayOrWeekOrMonth} dayOrWeekOrMonth - * @param {!boolean} lookForwardFirst - * @return {?DayOrWeekOrMonth} - */ - getNearestValidRange(dayOrWeekOrMonth, lookForwardFirst) { - var result = null; - if (lookForwardFirst) { - if (!(result = - this.getNearestValidRangeLookingForward(dayOrWeekOrMonth))) { - result = this.getNearestValidRangeLookingBackward(dayOrWeekOrMonth); + /** + * @param {!DayOrWeekOrMonth} dayOrWeekOrMonth + * @return {?DayOrWeekOrMonth} + */ + getNearestValidRangeLookingForward(dayOrWeekOrMonth) { + if (dayOrWeekOrMonth < this.config.minimumValue) { + // Performance optimization: avoid wasting lots of time in the below + // loop if dayOrWeekOrMonth is significantly less than the min. + dayOrWeekOrMonth = + this._dateTypeConstructor.createFromValue(this.config.minimumValue); } - } else { - if (!(result = - this.getNearestValidRangeLookingBackward(dayOrWeekOrMonth))) { - result = this.getNearestValidRangeLookingForward(dayOrWeekOrMonth); + + while (!this.isValid(dayOrWeekOrMonth) && + dayOrWeekOrMonth < this.config.maximumValue) { + dayOrWeekOrMonth = dayOrWeekOrMonth.next(); } + + return this.isValid(dayOrWeekOrMonth) ? dayOrWeekOrMonth : null; } - return result; - }, + /** + * @param {!DayOrWeekOrMonth} dayOrWeekOrMonth + * @return {?DayOrWeekOrMonth} + */ + getNearestValidRangeLookingBackward(dayOrWeekOrMonth) { + if (dayOrWeekOrMonth > this.config.maximumValue) { + // Performance optimization: avoid wasting lots of time in the below + // loop if dayOrWeekOrMonth is significantly greater than the max. + dayOrWeekOrMonth = + this._dateTypeConstructor.createFromValue(this.config.maximumValue); + } - /** - * @param {!Day} day - * @param {!boolean} lookForwardFirst - * @return {?DayOrWeekOrMonth} - */ - getValidRangeNearestToDay(day, lookForwardFirst) { - var dayOrWeekOrMonth = this._dateTypeConstructor.createFromDay(day); - return this.getNearestValidRange(dayOrWeekOrMonth, lookForwardFirst); + while (!this.isValid(dayOrWeekOrMonth) && + dayOrWeekOrMonth > this.config.minimumValue) { + dayOrWeekOrMonth = dayOrWeekOrMonth.previous(); + } + + return this.isValid(dayOrWeekOrMonth) ? dayOrWeekOrMonth : null; + } + + /** + * @param {!DayOrWeekOrMonth} dayOrWeekOrMonth + * @param {!boolean} lookForwardFirst + * @return {?DayOrWeekOrMonth} + */ + getNearestValidRange(dayOrWeekOrMonth, lookForwardFirst) { + var result = null; + if (lookForwardFirst) { + if (!(result = + this.getNearestValidRangeLookingForward(dayOrWeekOrMonth))) { + result = this.getNearestValidRangeLookingBackward(dayOrWeekOrMonth); + } + } else { + if (!(result = + this.getNearestValidRangeLookingBackward(dayOrWeekOrMonth))) { + result = this.getNearestValidRangeLookingForward(dayOrWeekOrMonth); + } + } + + return result; + } + + /** + * @param {!Day} day + * @param {!boolean} lookForwardFirst + * @return {?DayOrWeekOrMonth} + */ + getValidRangeNearestToDay(day, lookForwardFirst) { + var dayOrWeekOrMonth = this._dateTypeConstructor.createFromDay(day); + return this.getNearestValidRange(dayOrWeekOrMonth, lookForwardFirst); + } } -}; + return DateRangeManager; +} /** * @constructor @@ -2606,7 +2611,9 @@ }; } -class YearListView extends ListView { +// clang-format off +class YearListView extends dateRangeManagerMixin(ListView) { + // clang-format on /** * @param {!Month} minimumMonth * @param {!Month} maximumMonth @@ -3193,8 +3200,6 @@ } } -Object.assign(YearListView.prototype, DateRangeManager); - /** * @constructor * @extends View @@ -4307,7 +4312,9 @@ // ---------------------------------------------------------------- -class CalendarPicker extends View { +// clang-format off +class CalendarPicker extends dateRangeManagerMixin(View) { + // clang-format on /** * @param {!Object} config */ @@ -5011,8 +5018,6 @@ } } -Object.assign(CalendarPicker.prototype, DateRangeManager); - // ---------------------------------------------------------------- if (window.dialogArguments) {
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc index 1c39125..99d9887 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.cc +++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -26,14 +26,10 @@ #include "base/metrics/histogram_macros.h" #include "base/time/time.h" -#include "mojo/public/cpp/bindings/associated_remote.h" -#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/common/features.h" -#include "third_party/blink/public/mojom/conversions/conversions.mojom-blink.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h" #include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-blink.h" -#include "third_party/blink/public/platform/impression_conversions.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_prescient_networking.h" #include "third_party/blink/renderer/core/editing/editing_utilities.h" @@ -228,19 +224,6 @@ void HTMLAnchorElement::AttributeChanged( const AttributeModificationParams& params) { HTMLElement::AttributeChanged(params); - if (params.name == html_names::kRegisterattributionsourceAttr && - !params.new_value.IsNull() && HasImpression()) { - absl::optional<WebImpression> impression = GetImpressionForAnchor(this); - if (impression) { - mojo::AssociatedRemote<mojom::blink::ConversionHost> conversion_host; - GetDocument() - .GetFrame() - ->GetRemoteNavigationAssociatedInterfaces() - ->GetInterface(&conversion_host); - conversion_host->RegisterImpression( - ConvertWebImpressionToImpression(*impression)); - } - } if (params.reason != AttributeModificationReason::kDirectly) return;
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 c7c31dafe..93d30b4 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.idl +++ b/third_party/blink/renderer/core/html/html_anchor_element.idl
@@ -40,7 +40,6 @@ [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute USVString attributionDestination; [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute USVString attributionReportTo; [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute DOMString attributionExpiry; - [RuntimeEnabled=ConversionMeasurementEventSources, CEReactions,Reflect] attribute boolean registerAttributionSource; [RuntimeEnabled=ConversionMeasurement, CEReactions,Reflect] attribute DOMString attributionSourcePriority; // obsolete members
diff --git a/third_party/blink/renderer/core/html/html_attribute_names.json5 b/third_party/blink/renderer/core/html/html_attribute_names.json5 index a35a7126..669a9fd 100644 --- a/third_party/blink/renderer/core/html/html_attribute_names.json5 +++ b/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -292,7 +292,6 @@ "pseudo", "readonly", "referrerpolicy", - "registerattributionsource", "rel", "required", "resources",
diff --git a/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc b/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc index 317d892..68cbfca 100644 --- a/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc +++ b/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc
@@ -59,6 +59,8 @@ ScriptController()->GetScriptState()); WorkletGlobalScope::Dispose(); + + NotifyContextDestroyed(); } // https://drafts.css-houdini.org/css-layout-api/#dom-layoutworkletglobalscope-registerlayout
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc index 6915d2a..f1f5bf1 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
@@ -42,10 +42,10 @@ NGFragmentItems::NGFragmentItems(NGFragmentItemsBuilder* builder) : text_content_(std::move(builder->text_content_)), first_line_text_content_(std::move(builder->first_line_text_content_)), - const_size_(builder->items_.size()), + size_(builder->items_.size()), size_of_earlier_fragments_(0) { NGFragmentItemsBuilder::ItemWithOffsetList& source_items = builder->items_; - for (wtf_size_t i = 0; i < const_size_; ++i) { + for (wtf_size_t i = 0; i < size_; ++i) { // Call the move constructor to move without |AddRef|. Items in // |NGFragmentItemsBuilder| are not used after |this| was constructed. new (&items_[i]) NGFragmentItem(std::move(source_items[i].item)); @@ -55,9 +55,9 @@ NGFragmentItems::NGFragmentItems(const NGFragmentItems& other) : text_content_(other.text_content_), first_line_text_content_(other.first_line_text_content_), - const_size_(other.const_size_), + size_(other.size_), size_of_earlier_fragments_(other.size_of_earlier_fragments_) { - for (wtf_size_t i = 0; i < const_size_; ++i) { + for (wtf_size_t i = 0; i < size_; ++i) { const auto& other_item = other.items_[i]; new (&items_[i]) NGFragmentItem(other_item); @@ -71,7 +71,7 @@ } NGFragmentItems::~NGFragmentItems() { - for (unsigned i = 0; i < const_size_; ++i) + for (wtf_size_t i = 0; i < size_; ++i) items_[i].~NGFragmentItem(); }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h index 1c35a78..c66e710 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h
@@ -27,17 +27,17 @@ explicit NGFragmentItems(NGFragmentItemsBuilder* builder); ~NGFragmentItems(); - wtf_size_t Size() const { return const_size_; } + wtf_size_t Size() const { return size_; } using Span = base::span<const NGFragmentItem>; - Span Items() const { return base::make_span(ItemsData(), const_size_); } + Span Items() const { return base::make_span(ItemsData(), size_); } bool Equals(const Span& span) const { return ItemsData() == span.data() && Size() == span.size(); } bool IsSubSpan(const Span& span) const; const NGFragmentItem& front() const { - CHECK_GE(const_size_, 1u); + CHECK_GE(size_, 1u); return items_[0]; } @@ -59,9 +59,7 @@ wtf_size_t SizeOfEarlierFragments() const { return size_of_earlier_fragments_; } - wtf_size_t EndItemIndex() const { - return size_of_earlier_fragments_ + const_size_; - } + wtf_size_t EndItemIndex() const { return size_of_earlier_fragments_ + size_; } bool HasItemIndex(wtf_size_t index) const { return index >= SizeOfEarlierFragments() && index < EndItemIndex(); } @@ -123,7 +121,9 @@ String text_content_; String first_line_text_content_; - const wtf_size_t const_size_; + // Note: To make |Trace()| handles flexible array |items_| correctly, |size_| + // must be an immutable. + const wtf_size_t size_; // Total size of |NGFragmentItem| in earlier fragments when block fragmented. // 0 for the first |NGFragmentItems|.
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc index 05f213a..38c73c54 100644 --- a/third_party/blink/renderer/core/loader/preload_helper.cc +++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -658,6 +658,11 @@ // used by the next navigation only when they requested the same URL // with the same association mapping. change_rel_to_prefetch = true; + // Prefetch requests for alternate SXG should be made with no-cors, + // regardless of the crossorigin attribute of Link:rel=preload header + // that triggered the prefetch. See step 19.6.8 of + // https://wicg.github.io/webpackage/loading.html#mp-link-type-prefetch. + params.cross_origin = kCrossOriginAttributeNotSet; } }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc b/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc index 641823a..ad6b4d1 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc
@@ -4,10 +4,12 @@ #include "third_party/blink/renderer/core/paint/paint_property_tree_printer.h" +#include "third_party/blink/renderer/core/document_transition/document_transition_supplement.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/paint/object_paint_properties.h" @@ -52,6 +54,8 @@ } void CollectNodes(const LayoutObject& object) { + Traits::AddSharedElementTransitionProperties(object, *this); + for (const auto* fragment = &object.FirstFragment(); fragment; fragment = fragment->NextFragment()) { if (const auto* properties = fragment->PaintProperties()) @@ -86,6 +90,9 @@ printer.AddNode(properties.ScrollTranslation()); printer.AddNode(properties.TransformIsolationNode()); } + static void AddSharedElementTransitionProperties( + const LayoutObject& object, + PropertyTreePrinter<TransformPaintPropertyNodeOrAlias>& printer) {} static void AddOtherProperties( const FrameView& frame_view, PropertyTreePrinter<TransformPaintPropertyNodeOrAlias>& printer) {} @@ -110,6 +117,9 @@ printer.AddNode(properties.OverflowClip()); printer.AddNode(properties.ClipIsolationNode()); } + static void AddSharedElementTransitionProperties( + const LayoutObject& object, + PropertyTreePrinter<ClipPaintPropertyNodeOrAlias>& printer) {} static void AddOtherProperties( const LocalFrameView& frame_view, PropertyTreePrinter<ClipPaintPropertyNodeOrAlias>& printer) {} @@ -136,6 +146,19 @@ printer.AddNode(properties.EffectIsolationNode()); } + static void AddSharedElementTransitionProperties( + const LayoutObject& object, + PropertyTreePrinter<EffectPaintPropertyNodeOrAlias>& printer) { + auto* supplement = + DocumentTransitionSupplement::FromIfExists(object.GetDocument()); + if (!supplement || + !supplement->GetTransition()->IsTransitionParticipant(object)) { + return; + } + + printer.AddNode(supplement->GetTransition()->GetEffect(object)); + } + static void AddOtherProperties( const LocalFrameView& frame_view, PropertyTreePrinter<EffectPaintPropertyNodeOrAlias>& printer) { @@ -158,6 +181,9 @@ printer.AddNode(properties.Scroll()); } + static void AddSharedElementTransitionProperties( + const LayoutObject& object, + PropertyTreePrinter<ScrollPaintPropertyNode>& printer) {} static void AddOtherProperties( const LocalFrameView& frame_view, PropertyTreePrinter<ScrollPaintPropertyNode>& printer) {}
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h index b1dccd8..d9d12b67 100644 --- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h +++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
@@ -64,7 +64,7 @@ // Transfer the ArrayBuffer if it is detachable, otherwise make a copy and // transfer that. - bool Transfer(v8::Isolate*, ArrayBufferContents& result); + virtual bool Transfer(v8::Isolate*, ArrayBufferContents& result); // Share the ArrayBuffer, even if it is non-shared. Such sharing is necessary // for e.g. WebAudio which uses a separate thread for processing the
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc index 2acf0a5..817795e 100644 --- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc +++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -257,6 +257,14 @@ void WorkerOrWorkletGlobalScope::CountUse(WebFeature feature) { DCHECK(IsContextThread()); + + // `reporting_proxy_` should outlive `this` but there seems a situation where + // the assumption is broken. Don't count features while the context is + // destroyed. + // TODO(https://crbug.com/1298450): Fix the lifetime of WorkerReportingProxy. + if (IsContextDestroyed()) + return; + DCHECK_NE(WebFeature::kOBSOLETE_PageDestruction, feature); DCHECK_GT(WebFeature::kNumberOfFeatures, feature); if (used_features_[static_cast<size_t>(feature)])
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc index aa19afd..df8078f 100644 --- a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc +++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc
@@ -147,6 +147,12 @@ ScriptController()->GetScriptState()); } WorkletGlobalScope::Dispose(); + + if (WTF::IsMainThread()) { + // For off-the-main-thread paint worklet, this will be called in + // WorkerThread::PrepareForShutdownOnWorkerThread(). + NotifyContextDestroyed(); + } } void PaintWorkletGlobalScope::registerPaint(const ScriptState* script_state,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc index 7df3f82..bf3df8e 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
@@ -76,6 +76,33 @@ GPUMappedDOMArrayBuffer(GPUBuffer* owner, ArrayBufferContents contents) : DOMArrayBuffer(std::move(contents)), owner_(owner) {} + ~GPUMappedDOMArrayBuffer() override = default; + + // Override Transfer such that a copy of the contents is always made. The + // backing store will still be detached for this ArrayBuffer, but the + // result will be a copy of the contents, not a reference to + // the same backing store. This is required by the WebGPU specification so + // that the mapped backing store may not be shared cross-thread. + bool Transfer(v8::Isolate* isolate, ArrayBufferContents& result) override { + // Transfer into |contents| which will detach |this| and all views of + // |this|. + ArrayBufferContents contents; + bool did_detach = DOMArrayBuffer::Transfer(isolate, contents); + if (!did_detach) { + return false; + } + + // Copy the contents into the result. + contents.CopyTo(result); + return true; + } + + bool DetachContents(v8::Isolate* isolate) { + // Detach the array buffer by transferring the contents out and dropping + // them. + ArrayBufferContents contents; + return DOMArrayBuffer::Transfer(isolate, contents); + } void Trace(Visitor* visitor) const override { DOMArrayBuffer::Trace(visitor); @@ -365,23 +392,7 @@ GPUMappedDOMArrayBuffer* array_buffer = mapped_array_buffer.Release(); DCHECK(array_buffer->IsDetachable(isolate)); - // Detach the array buffer by transferring the contents out and dropping - // them. - ArrayBufferContents contents; - bool did_detach = array_buffer->Transfer(isolate, contents); - - // |did_detach| would be false if the buffer were already detached. - // Crash if it was, as this indicates that unmapping could alias the - // backing store, or possibly even free it out from under the - // ArrayBuffer. It might be difficult to be 100% certain about this - // invariant, so we CHECK, even in release builds. (Actually, it would be - // fine if the ArrayBuffer was detached without being transferred, but - // this isn't a common case, so it can be revisited if needed.) - // TODO(crbug.com/1243842): This CHECK can currently be hit easily by JS - // code. We need to validate against this case by preventing the - // ArrayBuffer from being transferred/detached by outside code. - CHECK(did_detach) - << "An ArrayBuffer from getMappedRange() was detached before unmap()"; + array_buffer->DetachContents(isolate); DCHECK(array_buffer->IsDetached()); } mapped_array_buffers_.clear();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc index 07b295b..d12e6c1 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -40,7 +40,6 @@ #include "third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.h" #include "third_party/blink/renderer/modules/webgpu/gpu_validation_error.h" #include "third_party/blink/renderer/platform/bindings/microtask.h" -#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc index c47bd18..7fee352 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc +++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
@@ -28,7 +28,6 @@ #include "third_party/blink/renderer/modules/webgpu/gpu_command_buffer.h" #include "third_party/blink/renderer/modules/webgpu/gpu_device.h" #include "third_party/blink/renderer/modules/webgpu/gpu_texture.h" -#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h" #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" @@ -98,27 +97,25 @@ } } -bool IsValidCopyTextureForBrowserFormats(SkColorType src_color_type, - WGPUTextureFormat dst_texture_format) { - // CopyTextureForBrowser only supports RGBA8Unorm and BGRA8Unorm src texture. - // TODO(crbug.com/dawn/856): Cover more source formats if needed. - if ((src_color_type == SkColorType::kRGBA_8888_SkColorType || - src_color_type == SkColorType::kBGRA_8888_SkColorType) && - (dst_texture_format == WGPUTextureFormat_R8Unorm || - dst_texture_format == WGPUTextureFormat_R16Float || - dst_texture_format == WGPUTextureFormat_R32Float || - dst_texture_format == WGPUTextureFormat_RG8Unorm || - dst_texture_format == WGPUTextureFormat_RG16Float || - dst_texture_format == WGPUTextureFormat_RG32Float || - dst_texture_format == WGPUTextureFormat_RGBA8Unorm || - dst_texture_format == WGPUTextureFormat_BGRA8Unorm || - dst_texture_format == WGPUTextureFormat_RGB10A2Unorm || - dst_texture_format == WGPUTextureFormat_RGBA16Float || - dst_texture_format == WGPUTextureFormat_RGBA32Float)) { - return true; +WGPUTextureFormat SkColorTypeToDawnColorFormat(SkColorType sk_color_type) { + switch (sk_color_type) { + case SkColorType::kRGBA_8888_SkColorType: + return WGPUTextureFormat_RGBA8Unorm; + case SkColorType::kBGRA_8888_SkColorType: + return WGPUTextureFormat_BGRA8Unorm; + default: + NOTREACHED(); + return WGPUTextureFormat_Undefined; } +} - return false; +static constexpr uint64_t kDawnBytesPerRowAlignmentBits = 8; + +// Calculate bytes per row for T2B/B2T copy +// TODO(shaobo.yan@intel.com): Using Dawn's constants once they are exposed +uint64_t AlignBytesPerRow(uint64_t bytesPerRow) { + return (((bytesPerRow - 1) >> kDawnBytesPerRowAlignmentBits) + 1) + << kDawnBytesPerRowAlignmentBits; } scoped_refptr<Image> GetImageFromExternalImage( @@ -498,150 +495,38 @@ "({width|height|depthOrArrayLayers} equals to 0)."); } - // Try GPU path first and delegate noop copy to CPU path. - if (static_bitmap_image->IsTextureBacked()) { // Try GPU uploading path. - if (CopyContentFromGPU( - static_bitmap_image.get(), origin_in_external_image, dawn_copy_size, - dawn_destination, destination->texture()->Format(), - destination->premultipliedAlpha(), copyImage->flipY())) { - return; - } - } - // GPU path failed, fallback to CPU path - static_bitmap_image = static_bitmap_image->MakeUnaccelerated(); - DCHECK_EQ(static_bitmap_image->IsOriginTopLeft(), true); - - // CPU path is the fallback path and should always work. - if (!CopyContentFromCPU( + if (!UploadContentToTexture( static_bitmap_image.get(), origin_in_external_image, dawn_copy_size, - dawn_destination, destination->texture()->Format(), - destination->premultipliedAlpha(), copyImage->flipY())) { + dawn_destination, destination->premultipliedAlpha(), + copyImage->flipY())) { exception_state.ThrowTypeError( "Failed to copy content from external image."); return; } } -bool GPUQueue::CopyContentFromCPU(StaticBitmapImage* image, - const WGPUOrigin3D& origin, - const WGPUExtent3D& copy_size, - const WGPUImageCopyTexture& destination, - const WGPUTextureFormat dest_texture_format, - bool dst_premultiplied_alpha, - bool flipY) { - // Prepare for uploading CPU data. - gfx::Rect image_data_rect(origin.x, origin.y, copy_size.width, - copy_size.height); +bool GPUQueue::UploadContentToTexture(StaticBitmapImage* image, + const WGPUOrigin3D& origin, + const WGPUExtent3D& copy_size, + const WGPUImageCopyTexture& destination, + bool dst_premultiplied_alpha, + bool flipY) { + PaintImage paint_image = image->PaintImageForCurrentFrame(); + SkColorType source_color_type = paint_image.GetSkImageInfo().colorType(); - WebGPUImageUploadSizeInfo info = ComputeImageBitmapWebGPUUploadSizeInfo( - image_data_rect, dest_texture_format); - - bool isNoopCopy = - info.size_in_bytes == 0 || copy_size.depthOrArrayLayers == 0; - - // Create a mapped buffer to receive image bitmap contents - WGPUBufferDescriptor buffer_desc = {}; - buffer_desc.usage = WGPUBufferUsage_CopySrc; - buffer_desc.size = info.size_in_bytes; - buffer_desc.mappedAtCreation = !isNoopCopy; - - if (buffer_desc.size > uint64_t(std::numeric_limits<size_t>::max())) { - return false; - } - size_t size = static_cast<size_t>(buffer_desc.size); - - WGPUBuffer buffer = - GetProcs().deviceCreateBuffer(device_->GetHandle(), &buffer_desc); - - bool isExternalImageOriginTopLeft = IsExternalImageOriginTopLeft(image); - - // Bypass extract source content in noop copy but follow the copy path - // for validation. - if (!isNoopCopy) { - void* data = GetProcs().bufferGetMappedRange(buffer, 0, size); - - if (!CopyBytesFromImageBitmapForWebGPU( - image, base::span<uint8_t>(static_cast<uint8_t*>(data), size), - image_data_rect, dest_texture_format, dst_premultiplied_alpha, - isExternalImageOriginTopLeft == flipY)) { - // Release the buffer. - GetProcs().bufferRelease(buffer); - return false; - } - - GetProcs().bufferUnmap(buffer); - } - - // Start a B2T copy to move contents from buffer to destination texture - WGPUImageCopyBuffer dawn_intermediate = {}; - dawn_intermediate.nextInChain = nullptr; - dawn_intermediate.buffer = buffer; - dawn_intermediate.layout.offset = 0; - dawn_intermediate.layout.bytesPerRow = info.wgpu_bytes_per_row; - dawn_intermediate.layout.rowsPerImage = image->height(); - - WGPUCommandEncoder encoder = - GetProcs().deviceCreateCommandEncoder(device_->GetHandle(), nullptr); - GetProcs().commandEncoderCopyBufferToTexture(encoder, &dawn_intermediate, - &destination, ©_size); - WGPUCommandBuffer commands = - GetProcs().commandEncoderFinish(encoder, nullptr); - - // Don't need to add fence after this submit. Because if user want to use the - // texture to do copy or render, it will trigger another queue submit. Dawn - // will insert the necessary resource transitions. - GetProcs().queueSubmit(GetHandle(), 1, &commands); - - // Release intermediate resources. - GetProcs().commandBufferRelease(commands); - GetProcs().commandEncoderRelease(encoder); - GetProcs().bufferRelease(buffer); - - return true; -} - -bool GPUQueue::CopyContentFromGPU(StaticBitmapImage* image, - const WGPUOrigin3D& origin, - const WGPUExtent3D& copy_size, - const WGPUImageCopyTexture& destination, - const WGPUTextureFormat dest_texture_format, - bool dst_premultiplied_alpha, - bool flipY) { - // Check src/dst texture formats are supported by CopyTextureForBrowser - SkImageInfo image_info = image->PaintImageForCurrentFrame().GetSkImageInfo(); - if (!IsValidCopyTextureForBrowserFormats(image_info.colorType(), - dest_texture_format)) { + // TODO(crbug.com/dawn/856): Expand copyTextureForBrowser to support any + // non-depth, non-stencil, non-compressed texture format pair copy. + if (source_color_type != SkColorType::kRGBA_8888_SkColorType && + source_color_type != SkColorType::kBGRA_8888_SkColorType) { return false; } - // Keep mailbox generation in noop copy to catch possible issue. - // TODO(crbug.com/1197369): config color space based on image - scoped_refptr<WebGPUMailboxTexture> mailbox_texture = - WebGPUMailboxTexture::FromStaticBitmapImage( - GetDawnControlClient(), device_->GetHandle(), - static_cast<WGPUTextureUsage>(WGPUTextureUsage_CopyDst | - WGPUTextureUsage_CopySrc | - WGPUTextureUsage_TextureBinding), - image, PredefinedColorSpace::kSRGB, image_info.colorType()); - - // Fail to associate staticBitmapImage to dawn resource. - if (!mailbox_texture) { - return false; - } - - WGPUTexture src_texture = mailbox_texture->GetTexture(); - DCHECK(src_texture != nullptr); - - WGPUImageCopyTexture src = {}; - src.texture = src_texture; - src.origin = origin; - - bool isExternalImageOriginTopLeft = IsExternalImageOriginTopLeft(image); - + // Set options for CopyTextureForBrowser except flipY. The possible + // image->MakeUnaccelerated() call changes the source orientation, so we set + // the flipY option when we need to issue CopyTextureForBrowser() to ensure + // the correctness. WGPUCopyTextureForBrowserOptions options = {}; - options.flipY = (isExternalImageOriginTopLeft == flipY); - options.srcAlphaMode = image->IsPremultiplied() ? WGPUAlphaMode_Premultiplied : WGPUAlphaMode_Unpremultiplied; @@ -649,10 +534,151 @@ ? WGPUAlphaMode_Premultiplied : WGPUAlphaMode_Unpremultiplied; + // Handling GPU resource. + if (image->IsTextureBacked()) { + // TODO(crbug.com/1197369): Delegate color space conversion to + // copyTextureForBrowser(). + scoped_refptr<WebGPUMailboxTexture> mailbox_texture = + WebGPUMailboxTexture::FromStaticBitmapImage( + GetDawnControlClient(), device_->GetHandle(), + static_cast<WGPUTextureUsage>(WGPUTextureUsage_CopyDst | + WGPUTextureUsage_CopySrc | + WGPUTextureUsage_TextureBinding), + image, PredefinedColorSpace::kSRGB, source_color_type); + + if (mailbox_texture != nullptr) { + WGPUImageCopyTexture src = {}; + src.texture = mailbox_texture->GetTexture(); + src.origin = origin; + + bool is_external_image_origin_top_left = + IsExternalImageOriginTopLeft(image); + options.flipY = (is_external_image_origin_top_left == flipY); + + GetProcs().queueCopyTextureForBrowser(GetHandle(), &src, &destination, + ©_size, &options); + return true; + } + } + + // Call MakeUnaccelerated() to ensure image is CPU back resource. + // This path will handle all CPU backend resource StaticBitmapImage or the one + // with texture backed resource but fail to associate staticBitmapImage to + // dawn resource. + scoped_refptr<StaticBitmapImage> unaccelerated_image = + image->MakeUnaccelerated(); + image = unaccelerated_image.get(); + + // Handling CPU resource. + // Source type is SkColorType::kRGBA_8888_SkColorType or + // SkColorType::kBGRA_8888_SkColorType. + uint64_t bytes_per_pixel = 4; + + gfx::Rect source_image_rect = image->Rect(); + base::CheckedNumeric<uint32_t> bytes_per_row = + AlignBytesPerRow(image->width() * bytes_per_pixel); + + // Static cast to uint64_t to catch overflow during multiplications and use + // base::CheckedNumeric to catch this overflow. + base::CheckedNumeric<size_t> size_in_bytes = + bytes_per_row * static_cast<uint64_t>(image->height()); + + // Overflow happens when calculating size or row bytes. + if (!size_in_bytes.IsValid()) { + return false; + } + + uint32_t wgpu_bytes_per_row = bytes_per_row.ValueOrDie(); + + // Create a mapped buffer to receive external image contents + WGPUBufferDescriptor buffer_desc = {}; + buffer_desc.usage = WGPUBufferUsage_CopySrc; + buffer_desc.size = size_in_bytes.ValueOrDie(); + buffer_desc.mappedAtCreation = true; + + WGPUBuffer intermediate_buffer = + GetProcs().deviceCreateBuffer(device_->GetHandle(), &buffer_desc); + + size_t size = static_cast<size_t>(buffer_desc.size); + void* data = GetProcs().bufferGetMappedRange(intermediate_buffer, 0, size); + + auto dest_pixels = base::span<uint8_t>(static_cast<uint8_t*>(data), size); + + // TODO(crbug.com/1197369): Delegate color space conversion to + // copyTextureForBrowser(). + SkImageInfo info = SkImageInfo::Make( + image->width(), image->height(), source_color_type, + image->IsPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType, + SkColorSpace::MakeSRGB()); + + bool success = paint_image.readPixels( + paint_image.GetSkImageInfo(), dest_pixels.data(), wgpu_bytes_per_row, + source_image_rect.x(), source_image_rect.y()); + if (!success) { + // Release the buffer. + GetProcs().bufferRelease(intermediate_buffer); + return false; + } + + GetProcs().bufferUnmap(intermediate_buffer); + + uint32_t source_image_width = static_cast<uint32_t>(image->width()); + uint32_t source_image_height = static_cast<uint32_t>(image->height()); + + // Create intermediate texture as input for CopyTextureForBrowser(). + WGPUTextureDescriptor texture_desc = {}; + texture_desc.usage = WGPUTextureUsage_CopySrc | WGPUTextureUsage_CopyDst | + WGPUTextureUsage_TextureBinding; + texture_desc.dimension = WGPUTextureDimension_2D; + texture_desc.size = {source_image_width, source_image_height, 1}; + texture_desc.format = SkColorTypeToDawnColorFormat(source_color_type); + texture_desc.mipLevelCount = 1; + texture_desc.sampleCount = 1; + + WGPUTexture intermediate_texture = + GetProcs().deviceCreateTexture(device_->GetHandle(), &texture_desc); + + // Start a B2T copy to move contents from buffer to intermediate texture + WGPUImageCopyBuffer dawn_intermediate_buffer = {}; + dawn_intermediate_buffer.buffer = intermediate_buffer; + dawn_intermediate_buffer.layout.bytesPerRow = wgpu_bytes_per_row; + dawn_intermediate_buffer.layout.rowsPerImage = source_image_height; + + WGPUImageCopyTexture dawn_intermediate_texture = {}; + dawn_intermediate_texture.texture = intermediate_texture; + dawn_intermediate_texture.aspect = WGPUTextureAspect_All; + + WGPUExtent3D source_image_copy_size = {source_image_width, + source_image_height, 1}; + + WGPUCommandEncoder encoder = + GetProcs().deviceCreateCommandEncoder(device_->GetHandle(), nullptr); + GetProcs().commandEncoderCopyBufferToTexture( + encoder, &dawn_intermediate_buffer, &dawn_intermediate_texture, + &source_image_copy_size); + WGPUCommandBuffer commands = + GetProcs().commandEncoderFinish(encoder, nullptr); + + GetProcs().queueSubmit(GetHandle(), 1, &commands); + + // Release intermediate resources. + GetProcs().commandBufferRelease(commands); + GetProcs().commandEncoderRelease(encoder); + GetProcs().bufferRelease(intermediate_buffer); + + WGPUImageCopyTexture src = {}; + src.texture = intermediate_texture; + src.origin = origin; + + // MakeUnaccelerated() call might change the StaticBitmapImage orientation so + // we need to query the orientation again. + bool is_external_image_origin_top_left = IsExternalImageOriginTopLeft(image); + options.flipY = (is_external_image_origin_top_left == flipY); GetProcs().queueCopyTextureForBrowser(GetHandle(), &src, &destination, ©_size, &options); + // Release intermediate texture. + GetProcs().textureRelease(intermediate_texture); return true; } - } // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.h b/third_party/blink/renderer/modules/webgpu/gpu_queue.h index 0cda6d9..e516257 100644 --- a/third_party/blink/renderer/modules/webgpu/gpu_queue.h +++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.h
@@ -78,20 +78,12 @@ void OnWorkDoneCallback(ScriptPromiseResolver* resolver, WGPUQueueWorkDoneStatus status); - bool CopyContentFromCPU(StaticBitmapImage* image, - const WGPUOrigin3D& origin, - const WGPUExtent3D& copy_size, - const WGPUImageCopyTexture& destination, - const WGPUTextureFormat dest_texture_format, - bool premultiplied_alpha, - bool flipY = false); - bool CopyContentFromGPU(StaticBitmapImage* image, - const WGPUOrigin3D& origin, - const WGPUExtent3D& copy_size, - const WGPUImageCopyTexture& destination, - const WGPUTextureFormat dest_texture_format, - bool premultiplied_alpha, - bool flipY = false); + bool UploadContentToTexture(StaticBitmapImage* image, + const WGPUOrigin3D& origin, + const WGPUExtent3D& copy_size, + const WGPUImageCopyTexture& destination, + bool dst_premultiplied_alpha, + bool flipY = false); void WriteBufferImpl(GPUBuffer* buffer, uint64_t buffer_offset, uint64_t data_byte_length,
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 18322f4..4ced8312 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -935,8 +935,6 @@ "graphics/gpu/shared_gpu_context.h", "graphics/gpu/webgl_image_conversion.cc", "graphics/gpu/webgl_image_conversion.h", - "graphics/gpu/webgpu_image_bitmap_handler.cc", - "graphics/gpu/webgpu_image_bitmap_handler.h", "graphics/gpu/webgpu_mailbox_texture.cc", "graphics/gpu/webgpu_mailbox_texture.h", "graphics/gpu/webgpu_resource_provider_cache.cc", @@ -2059,7 +2057,6 @@ "graphics/gpu/drawing_buffer_test.cc", "graphics/gpu/shared_gpu_context_test.cc", "graphics/gpu/webgl_image_conversion_test.cc", - "graphics/gpu/webgpu_image_bitmap_handler_test.cc", "graphics/gpu/webgpu_resource_provider_cache_test.cc", "graphics/gpu/webgpu_swap_buffer_provider_test.cc", "graphics/graphics_context_test.cc",
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.cc deleted file mode 100644 index cf00a3d68..0000000 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.cc +++ /dev/null
@@ -1,215 +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 "third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h" - -#include "gpu/command_buffer/client/shared_image_interface.h" -#include "gpu/command_buffer/client/webgpu_interface.h" -#include "gpu/command_buffer/common/shared_image_usage.h" -#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" - -namespace blink { - -namespace { -static constexpr uint64_t kDawnBytesPerRowAlignmentBits = 8; - -// Calculate bytes per row for T2B/B2T copy -// TODO(shaobo.yan@intel.com): Using Dawn's constants once they are exposed -uint64_t AlignWebGPUBytesPerRow(uint64_t bytesPerRow) { - return (((bytesPerRow - 1) >> kDawnBytesPerRowAlignmentBits) + 1) - << kDawnBytesPerRowAlignmentBits; -} - -bool IsPaintImageReadAllChannels(WGPUTextureFormat dawn_format) { - switch (dawn_format) { - case WGPUTextureFormat_R8Unorm: - case WGPUTextureFormat_R16Float: - case WGPUTextureFormat_R32Float: - case WGPUTextureFormat_RG32Float: - return false; - default: - return true; - } -} - -// SkImageInfo doesn't support R8Unorm, R16Float, R32Float and RG32Float. -// So we config these formats to the 2 or 4 channel compatible ones to read -// pixels. -WGPUTextureFormat DawnColorTypeToCreateSkImageInfo( - WGPUTextureFormat dawn_format) { - switch (dawn_format) { - case WGPUTextureFormat_R32Float: - case WGPUTextureFormat_RG32Float: - return WGPUTextureFormat_RGBA32Float; - case WGPUTextureFormat_R8Unorm: - return WGPUTextureFormat_RG8Unorm; - case WGPUTextureFormat_R16Float: - return WGPUTextureFormat_RG16Float; - default: - return dawn_format; - } -} - -SkColorType DawnColorTypeToSkColorType(WGPUTextureFormat dawn_format) { - switch (dawn_format) { - case WGPUTextureFormat_RGBA8Unorm: - // According to WebGPU spec, format with -srgb suffix will do color - // space conversion when reading and writing in shader. In this uploading - // path, we should keep the conversion happening in canvas color space and - // leave the srgb color space conversion to the GPU. - case WGPUTextureFormat_RGBA8UnormSrgb: - return SkColorType::kRGBA_8888_SkColorType; - case WGPUTextureFormat_BGRA8Unorm: - case WGPUTextureFormat_BGRA8UnormSrgb: - return SkColorType::kBGRA_8888_SkColorType; - case WGPUTextureFormat_RGB10A2Unorm: - return SkColorType::kRGBA_1010102_SkColorType; - case WGPUTextureFormat_RGBA16Float: - return SkColorType::kRGBA_F16_SkColorType; - case WGPUTextureFormat_RGBA32Float: - return SkColorType::kRGBA_F32_SkColorType; - case WGPUTextureFormat_RG8Unorm: - return SkColorType::kR8G8_unorm_SkColorType; - case WGPUTextureFormat_RG16Float: - return SkColorType::kR16G16_float_SkColorType; - default: - return SkColorType::kUnknown_SkColorType; - } -} - -} // anonymous namespace - -WebGPUImageUploadSizeInfo ComputeImageBitmapWebGPUUploadSizeInfo( - const gfx::Rect& rect, - const WGPUTextureFormat& destination_format) { - WebGPUImageUploadSizeInfo info; - - uint64_t bytes_per_pixel = DawnTextureFormatBytesPerPixel(destination_format); - DCHECK_NE(bytes_per_pixel, 0u); - - uint64_t bytes_per_row = - AlignWebGPUBytesPerRow(rect.width() * bytes_per_pixel); - - // Currently, bytes per row for buffer copy view in WebGPU is an uint32_t type - // value and the maximum value is std::numeric_limits<uint32_t>::max(). - DCHECK(bytes_per_row <= std::numeric_limits<uint32_t>::max()); - - info.wgpu_bytes_per_row = static_cast<uint32_t>(bytes_per_row); - info.size_in_bytes = bytes_per_row * rect.height(); - - return info; -} - -bool CopyBytesFromImageBitmapForWebGPU( - scoped_refptr<StaticBitmapImage> image, - base::span<uint8_t> dst, - const gfx::Rect& rect, - const WGPUTextureFormat destination_format, - bool dst_premultiplied_alpha, - bool flipY) { - DCHECK(image); - DCHECK_GT(dst.size(), static_cast<size_t>(0)); - DCHECK(image->width() - rect.x() >= rect.width()); - DCHECK(image->height() - rect.y() >= rect.height()); - DCHECK(rect.width()); - DCHECK(rect.height()); - - WebGPUImageUploadSizeInfo dst_info = - ComputeImageBitmapWebGPUUploadSizeInfo(rect, destination_format); - DCHECK_EQ(static_cast<uint64_t>(dst.size()), dst_info.size_in_bytes); - - // Prepare extract data from SkImage. - SkColorType sk_color_type = DawnColorTypeToSkColorType( - DawnColorTypeToCreateSkImageInfo(destination_format)); - if (sk_color_type == kUnknown_SkColorType) { - return false; - } - PaintImage paint_image = image->PaintImageForCurrentFrame(); - - bool read_all_channels = IsPaintImageReadAllChannels(destination_format); - - // Read pixel request dst info. - // TODO(crbug.com/1217153): Convert to user-provided color space. - SkImageInfo info = SkImageInfo::Make( - rect.width(), rect.height(), sk_color_type, - dst_premultiplied_alpha ? kPremul_SkAlphaType : kUnpremul_SkAlphaType, - paint_image.GetSkImageInfo().refColorSpace()); - - if (!flipY && read_all_channels) { - return paint_image.readPixels(info, dst.data(), dst_info.wgpu_bytes_per_row, - rect.x(), rect.y()); - } else { - // Calculate size info if the destination format has been converted to the - // compatible ones. - WGPUTextureFormat compatible_dawn_format = - DawnColorTypeToCreateSkImageInfo(destination_format); - WebGPUImageUploadSizeInfo pixel_info = - ComputeImageBitmapWebGPUUploadSizeInfo(rect, compatible_dawn_format); - - std::vector<uint8_t> paint_image_content; - paint_image_content.resize(pixel_info.wgpu_bytes_per_row * rect.height()); - if (!paint_image.readPixels(info, paint_image_content.data(), - pixel_info.wgpu_bytes_per_row, rect.x(), - rect.y())) { - return false; - } - // Do flipY for the bottom left image. - if (flipY && read_all_channels) { - for (int i = 0; i < rect.height(); ++i) { - memcpy( - dst.data() + (rect.height() - 1 - i) * dst_info.wgpu_bytes_per_row, - paint_image_content.data() + i * dst_info.wgpu_bytes_per_row, - dst_info.wgpu_bytes_per_row); - } - } else { - // Copy from required channels pixel by pixel and do flipY if needed. - uint32_t destination_format_pixel_bytes = static_cast<uint32_t>( - DawnTextureFormatBytesPerPixel(destination_format)); - uint32_t paint_image_pixel_bytes = static_cast<uint32_t>( - DawnTextureFormatBytesPerPixel(compatible_dawn_format)); - - for (int i = 0; i < rect.height(); ++i) { - uint32_t dst_height = flipY ? rect.height() - 1 - i : i; - for (int j = 0; j < rect.width(); ++j) { - memcpy(dst.data() + dst_height * dst_info.wgpu_bytes_per_row + - j * destination_format_pixel_bytes, - paint_image_content.data() + - i * pixel_info.wgpu_bytes_per_row + - j * paint_image_pixel_bytes, - destination_format_pixel_bytes); - } - } - } - } - - return true; -} - -uint64_t DawnTextureFormatBytesPerPixel(const WGPUTextureFormat color_type) { - switch (color_type) { - case WGPUTextureFormat_R8Unorm: - return 1; - case WGPUTextureFormat_RG8Unorm: - case WGPUTextureFormat_R16Float: - return 2; - case WGPUTextureFormat_RGBA8Unorm: - case WGPUTextureFormat_RGBA8UnormSrgb: - case WGPUTextureFormat_BGRA8Unorm: - case WGPUTextureFormat_BGRA8UnormSrgb: - case WGPUTextureFormat_RGB10A2Unorm: - case WGPUTextureFormat_RG16Float: - case WGPUTextureFormat_R32Float: - return 4; - case WGPUTextureFormat_RGBA16Float: - case WGPUTextureFormat_RG32Float: - return 8; - case WGPUTextureFormat_RGBA32Float: - return 16; - default: - NOTREACHED(); - return 0; - } -} - -} // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h deleted file mode 100644 index e06ef73..0000000 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h +++ /dev/null
@@ -1,43 +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. - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGPU_IMAGE_BITMAP_HANDLER_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGPU_IMAGE_BITMAP_HANDLER_H_ - -#include <dawn/webgpu.h> - -#include "base/containers/span.h" -#include "third_party/blink/renderer/platform/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/ref_counted.h" - -namespace gfx { -class Rect; -} - -namespace blink { - -struct WebGPUImageUploadSizeInfo { - uint64_t size_in_bytes; - uint32_t wgpu_bytes_per_row; -}; - -class StaticBitmapImage; - -WebGPUImageUploadSizeInfo PLATFORM_EXPORT -ComputeImageBitmapWebGPUUploadSizeInfo( - const gfx::Rect& rect, - const WGPUTextureFormat& destination_format); -bool PLATFORM_EXPORT -CopyBytesFromImageBitmapForWebGPU(scoped_refptr<StaticBitmapImage> image, - base::span<uint8_t> dst, - const gfx::Rect& rect, - const WGPUTextureFormat destination_format, - bool dst_premultiplied_alpha, - bool flipY); - -uint64_t PLATFORM_EXPORT -DawnTextureFormatBytesPerPixel(const WGPUTextureFormat color_type); - -} // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGPU_IMAGE_BITMAP_HANDLER_H_
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc deleted file mode 100644 index 9b729959..0000000 --- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc +++ /dev/null
@@ -1,423 +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 "third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h" - -#include "base/callback_helpers.h" -#include "base/logging.h" -#include "base/memory/scoped_refptr.h" -#include "base/test/null_task_runner.h" -#include "base/test/task_environment.h" -#include "build/build_config.h" -#include "components/viz/common/resources/transferable_resource.h" -#include "components/viz/test/test_context_provider.h" -#include "gpu/command_buffer/client/webgpu_interface_stub.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h" -#include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h" -#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h" -#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h" -#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h" -#include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h" - -using testing::_; -using testing::Return; - -namespace blink { - -namespace { -gpu::SyncToken GenTestSyncToken(GLbyte id) { - gpu::SyncToken token; - token.Set(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(64), id); - return token; -} - -scoped_refptr<StaticBitmapImage> CreateBitmap() { - auto mailbox = gpu::Mailbox::GenerateForSharedImage(); - return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( - mailbox, GenTestSyncToken(100), 0, SkImageInfo::MakeN32Premul(100, 100), - GL_TEXTURE_2D, true, SharedGpuContext::ContextProviderWrapper(), - base::PlatformThread::CurrentRef(), - base::MakeRefCounted<base::NullTaskRunner>(), base::DoNothing()); -} - -bool GPUUploadingPathSupported() { -// In current state, only passthrough command buffer can work on this path. -// and Windows is the platform that is using passthrough command buffer by -// default. -// TODO(shaobo.yan@intel.com): Enable test on more platforms when they're ready. -#if BUILDFLAG(IS_WIN) - return true; -#else - return false; -#endif // BUILDFLAG(IS_WIN) -} - -class MockWebGPUInterface : public gpu::webgpu::WebGPUInterfaceStub { - public: - MockWebGPUInterface() { - // WebGPU functions the tests will call. No-op them since we don't have a - // real WebGPU device. - procs()->deviceReference = [](WGPUDevice) {}; - procs()->deviceRelease = [](WGPUDevice) {}; - procs()->textureRelease = [](WGPUTexture) {}; - } - - MOCK_METHOD(gpu::webgpu::ReservedTexture, - ReserveTexture, - (WGPUDevice device)); - MOCK_METHOD(void, - AssociateMailbox, - (GLuint device_id, - GLuint device_generation, - GLuint id, - GLuint generation, - GLuint usage, - gpu::webgpu::MailboxFlags flags, - const GLbyte* mailbox)); - MOCK_METHOD(void, - DissociateMailbox, - (GLuint texture_id, GLuint texture_generation)); -}; - -// The six reference pixels are: red, green, blue, white, black. -static const uint8_t rgba8[] = { - 0xFF, 0x00, 0x00, 0xFF, // Red - 0x00, 0xFF, 0x00, 0xFF, // Green - 0x00, 0x00, 0xFF, 0xFF, // Blue - 0x00, 0x00, 0x00, 0xFF, // White - 0xFF, 0xFF, 0xFF, 0xFF, // Opaque Black - 0xFF, 0xFF, 0xFF, 0x00, // Transparent Black -}; - -static const uint8_t bgra8[] = { - 0x00, 0x00, 0xFF, 0xFF, // Red - 0x00, 0xFF, 0x00, 0xFF, // Green - 0xFF, 0x00, 0x00, 0xFF, // Blue - 0x00, 0x00, 0x00, 0xFF, // White - 0xFF, 0xFF, 0xFF, 0xFF, // Opaque Black - 0xFF, 0xFF, 0xFF, 0x00, // Transparent Black -}; - -static const uint8_t rgb10a2[] = { - 0xFF, 0x03, 0x00, 0xC0, // Red - 0x00, 0xFC, 0x0F, 0xC0, // Green - 0x00, 0x00, 0xF0, 0xFF, // Blue - 0x00, 0x00, 0x00, 0xC0, // White - 0xFF, 0xFF, 0xFF, 0xFF, // Opaque Black - 0xFF, 0xFF, 0xFF, 0x3F, // Transparent Black -}; - -static const uint16_t f16[] = { - 0x3C00, 0x0000, 0x0000, 0x3C00, // Red - 0x0000, 0x3C00, 0x0000, 0x3C00, // Green - 0x0000, 0x0000, 0x3C00, 0x3C00, // Blue - 0x0000, 0x0000, 0x0000, 0x3C00, // White - 0x3C00, 0x3C00, 0x3C00, 0x3C00, // Opaque Black - 0x3C00, 0x3C00, 0x3C00, 0x0000, // Transparent Black -}; - -static const float f32[] = { - 1.0f, 0.0f, 0.0f, 1.0f, // Red - 0.0f, 1.0f, 0.0f, 1.0f, // Green - 0.0f, 0.0f, 1.0f, 1.0f, // Blue - 0.0f, 0.0f, 0.0f, 1.0f, // White - 1.0f, 1.0f, 1.0f, 1.0f, // Opaque Black - 1.0f, 1.0f, 1.0f, 0.0f, // Transparent Black -}; - -static const uint8_t rg8[] = { - 0xFF, 0x00, // Red - 0x00, 0xFF, // Green - 0x00, 0x00, // No Blue - 0x00, 0x00, // White - 0xFF, 0xFF, // Opaque Black - 0xFF, 0xFF, // Transparent Black -}; - -static const uint16_t rg16f[] = { - 0x3C00, 0x0000, // Red - 0x0000, 0x3C00, // Green - 0x0000, 0x0000, // No Blue - 0x0000, 0x0000, // White - 0x3C00, 0x3C00, // Opaque Black - 0x3C00, 0x3C00, // Transparent Black -}; - -base::span<const uint8_t> GetDstContent(WGPUTextureFormat format) { - switch (format) { - case WGPUTextureFormat_RG8Unorm: - return base::span<const uint8_t>(rg8, sizeof(rg8)); - case WGPUTextureFormat_RGBA8Unorm: - // We need to ensure no color space conversion happens - // during imageBitmap uploading. - case WGPUTextureFormat_RGBA8UnormSrgb: - return base::span<const uint8_t>(rgba8, sizeof(rgba8)); - case WGPUTextureFormat_BGRA8Unorm: - case WGPUTextureFormat_BGRA8UnormSrgb: - return base::span<const uint8_t>(bgra8, sizeof(bgra8)); - case WGPUTextureFormat_RGB10A2Unorm: - return base::span<const uint8_t>(rgb10a2, sizeof(rgb10a2)); - case WGPUTextureFormat_RG16Float: - return base::span<const uint8_t>(reinterpret_cast<const uint8_t*>(rg16f), - sizeof(rg16f)); - case WGPUTextureFormat_RGBA16Float: - return base::span<const uint8_t>(reinterpret_cast<const uint8_t*>(f16), - sizeof(f16)); - case WGPUTextureFormat_RGBA32Float: - return base::span<const uint8_t>(reinterpret_cast<const uint8_t*>(f32), - sizeof(f32)); - default: - NOTREACHED(); - return {}; - } -} - -base::span<const uint8_t> GetSrcPixelContent(SkColorType format) { - switch (format) { - case SkColorType::kRGBA_8888_SkColorType: - return base::span<const uint8_t>(rgba8, sizeof(rgba8)); - case SkColorType::kBGRA_8888_SkColorType: - return base::span<const uint8_t>(bgra8, sizeof(bgra8)); - case SkColorType::kRGBA_F16_SkColorType: - return base::span<const uint8_t>(reinterpret_cast<const uint8_t*>(f16), - sizeof(f16)); - default: - NOTREACHED(); - return {}; - } -} - -} // anonymous namespace - -class WebGPUImageBitmapHandlerTest : public testing::Test { - protected: - void SetUp() override {} - - void VerifyCopyBytesForCanvasColorParams(uint64_t width, - uint64_t height, - SkImageInfo info, - gfx::Rect copy_rect, - WGPUTextureFormat color_type) { - const uint64_t content_length = width * height * info.bytesPerPixel(); - std::vector<uint8_t> contents(content_length, 0); - // Initialize contents. - for (size_t i = 0; i < content_length; ++i) { - contents[i] = i % std::numeric_limits<uint8_t>::max(); - } - - VerifyCopyBytes(width, height, info, copy_rect, color_type, - base::span<uint8_t>(contents.data(), content_length), - base::span<uint8_t>(contents.data(), content_length)); - } - - void VerifyCopyBytes(uint64_t width, - uint64_t height, - SkImageInfo info, - gfx::Rect copy_rect, - WGPUTextureFormat color_type, - base::span<const uint8_t> contents, - base::span<const uint8_t> expected_value) { - uint64_t bytes_per_pixel = DawnTextureFormatBytesPerPixel(color_type); - ASSERT_EQ(contents.size(), width * height * info.bytesPerPixel()); - sk_sp<SkData> image_pixels = - SkData::MakeWithCopy(contents.data(), contents.size()); - scoped_refptr<StaticBitmapImage> image = - StaticBitmapImage::Create(std::move(image_pixels), info); - - WebGPUImageUploadSizeInfo wgpu_info = - ComputeImageBitmapWebGPUUploadSizeInfo(copy_rect, color_type); - - const uint64_t result_length = wgpu_info.size_in_bytes; - std::vector<uint8_t> results(result_length, 0); - bool success = CopyBytesFromImageBitmapForWebGPU( - image, base::span<uint8_t>(results.data(), result_length), copy_rect, - color_type, image->IsPremultiplied(), /* flipY = */ false); - ASSERT_EQ(success, true); - - // Compare content and results - uint32_t bytes_per_row = wgpu_info.wgpu_bytes_per_row; - uint32_t content_row_index = - (copy_rect.y() * width + copy_rect.x()) * bytes_per_pixel; - uint32_t result_row_index = 0; - for (int i = 0; i < copy_rect.height(); ++i) { - EXPECT_EQ(0, memcmp(&expected_value[content_row_index], - &results[result_row_index], - copy_rect.width() * bytes_per_pixel)); - content_row_index += width * bytes_per_pixel; - result_row_index += bytes_per_row; - } - } -}; - -TEST_F(WebGPUImageBitmapHandlerTest, VerifyColorConvert) { - // All supported CanvasPixelFormat mapping to SkColorType - const SkColorType srcSkColorFormat[] = { - SkColorType::kRGBA_8888_SkColorType, - SkColorType::kBGRA_8888_SkColorType, - SkColorType::kRGBA_F16_SkColorType, - }; - - // Joint of SkColorType and WebGPU texture format - const WGPUTextureFormat kDstWebGPUTextureFormat[] = { - WGPUTextureFormat_RG16Float, WGPUTextureFormat_RGBA16Float, - WGPUTextureFormat_RGBA32Float, - - WGPUTextureFormat_RGB10A2Unorm, WGPUTextureFormat_RG8Unorm, - WGPUTextureFormat_RGBA8Unorm, WGPUTextureFormat_BGRA8Unorm, - WGPUTextureFormat_RGBA8UnormSrgb, WGPUTextureFormat_BGRA8UnormSrgb, - }; - - const PredefinedColorSpace kColorSpaces[] = { - PredefinedColorSpace::kSRGB, - PredefinedColorSpace::kRec2020, - PredefinedColorSpace::kP3, - }; - - uint64_t kImageWidth = 3; - uint64_t kImageHeight = 2; - - gfx::Rect image_data_rect(0, 0, kImageWidth, kImageHeight); - - for (SkColorType src_color_type : srcSkColorFormat) { - for (WGPUTextureFormat dst_color_type : kDstWebGPUTextureFormat) { - for (PredefinedColorSpace color_space : kColorSpaces) { - SkImageInfo info = - SkImageInfo::Make(kImageWidth, kImageHeight, src_color_type, - SkAlphaType::kUnpremul_SkAlphaType, - PredefinedColorSpaceToSkColorSpace(color_space)); - VerifyCopyBytes(kImageWidth, kImageHeight, info, image_data_rect, - dst_color_type, GetSrcPixelContent(src_color_type), - GetDstContent(dst_color_type)); - } - } - } -} - -// Test calculate size -TEST_F(WebGPUImageBitmapHandlerTest, VerifyGetWGPUResourceInfo) { - uint64_t kImageWidth = 63; - uint64_t kImageHeight = 1; - - // Prebaked expected values. - uint32_t expected_bytes_per_row = 256; - uint64_t expected_size = 256; - - gfx::Rect test_rect(0, 0, kImageWidth, kImageHeight); - WebGPUImageUploadSizeInfo info = ComputeImageBitmapWebGPUUploadSizeInfo( - test_rect, WGPUTextureFormat_RGBA8Unorm); - ASSERT_EQ(expected_size, info.size_in_bytes); - ASSERT_EQ(expected_bytes_per_row, info.wgpu_bytes_per_row); -} - -// Copy full image bitmap test -TEST_F(WebGPUImageBitmapHandlerTest, VerifyCopyBytesFromImageBitmapForWebGPU) { - uint64_t kImageWidth = 4; - uint64_t kImageHeight = 2; - SkImageInfo info = SkImageInfo::Make( - kImageWidth, kImageHeight, SkColorType::kRGBA_8888_SkColorType, - SkAlphaType::kUnpremul_SkAlphaType, SkColorSpace::MakeSRGB()); - - gfx::Rect image_data_rect(0, 0, kImageWidth, kImageHeight); - VerifyCopyBytesForCanvasColorParams(kImageWidth, kImageHeight, info, - image_data_rect, - WGPUTextureFormat_RGBA8Unorm); -} - -// Copy sub image bitmap test -TEST_F(WebGPUImageBitmapHandlerTest, VerifyCopyBytesFromSubImageBitmap) { - uint64_t kImageWidth = 63; - uint64_t kImageHeight = 4; - SkImageInfo info = SkImageInfo::Make( - kImageWidth, kImageHeight, SkColorType::kRGBA_8888_SkColorType, - SkAlphaType::kUnpremul_SkAlphaType, SkColorSpace::MakeSRGB()); - - gfx::Rect image_data_rect(2, 2, 60, 2); - VerifyCopyBytesForCanvasColorParams(kImageWidth, kImageHeight, info, - image_data_rect, - WGPUTextureFormat_RGBA8Unorm); -} - -// Copy image bitmap with premultiply alpha -TEST_F(WebGPUImageBitmapHandlerTest, VerifyCopyBytesWithPremultiplyAlpha) { - uint64_t kImageWidth = 2; - uint64_t kImageHeight = 1; - SkImageInfo info = SkImageInfo::Make( - kImageWidth, kImageHeight, SkColorType::kRGBA_8888_SkColorType, - SkAlphaType::kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); - - gfx::Rect image_data_rect(0, 0, 2, 1); - VerifyCopyBytesForCanvasColorParams(kImageWidth, kImageHeight, info, - image_data_rect, - WGPUTextureFormat_RGBA8Unorm); -} - -class WebGPUMailboxTextureTest : public testing::Test { - protected: - void SetUp() override { - auto webgpu = std::make_unique<MockWebGPUInterface>(); - webgpu_ = webgpu.get(); - auto provider = std::make_unique<WebGraphicsContext3DProviderForTests>( - std::move(webgpu)); - - dawn_control_client_ = base::MakeRefCounted<DawnControlClientHolder>( - std::move(provider), base::ThreadTaskRunnerHandle::Get()); - - test_context_provider_ = viz::TestContextProvider::Create(); - InitializeSharedGpuContext(test_context_provider_.get()); - } - - void TearDown() override { SharedGpuContext::ResetForTesting(); } - MockWebGPUInterface* webgpu_; - scoped_refptr<DawnControlClientHolder> dawn_control_client_; - scoped_refptr<viz::TestContextProvider> test_context_provider_; - base::test::TaskEnvironment task_environment_; - WGPUDevice fake_device_ = reinterpret_cast<WGPUDevice>(this); -}; - -TEST_F(WebGPUMailboxTextureTest, VerifyAccessTexture) { - if (!GPUUploadingPathSupported()) { - LOG(ERROR) << "Test skipped because GPU uploading path not supported."; - return; - } - auto bitmap = CreateBitmap(); - - viz::TransferableResource resource; - gpu::webgpu::ReservedTexture reservation = { - reinterpret_cast<WGPUTexture>(&resource), 1, 1, /* deviceId */ 2, - /* deviceGeneration */ 3}; - - // Test creating a WebGPUMailboxTexture calls ReserveTexture and - // AssociateMailbox correctly. - gpu::Mailbox mailbox; - EXPECT_CALL(*webgpu_, ReserveTexture(fake_device_)) - .WillOnce(Return(reservation)); - EXPECT_CALL(*webgpu_, - AssociateMailbox(2, 3, reservation.id, reservation.generation, - WGPUTextureUsage_CopySrc, _, _)) - .WillOnce( - testing::Invoke(testing::WithArg<6>([&](const GLbyte* mailbox_bytes) { - mailbox = gpu::Mailbox::FromVolatile( - *reinterpret_cast<const volatile gpu::Mailbox*>(mailbox_bytes)); - }))); - - SkImageInfo image_info = bitmap->PaintImageForCurrentFrame().GetSkImageInfo(); - scoped_refptr<WebGPUMailboxTexture> mailbox_texture = - WebGPUMailboxTexture::FromStaticBitmapImage( - dawn_control_client_, fake_device_, WGPUTextureUsage_CopySrc, bitmap, - PredefinedColorSpace::kSRGB, image_info.colorType()); - - EXPECT_NE(mailbox_texture->GetTexture(), nullptr); - EXPECT_EQ(mailbox_texture->GetTextureIdForTest(), 1u); - EXPECT_EQ(mailbox_texture->GetTextureGenerationForTest(), 1u); - - // Test that ~WebGPUMailboxTexture calls DissociateMailbox - // correctly. - EXPECT_CALL(*webgpu_, DissociateMailbox( - reservation.id, reservation.generation)); - mailbox_texture.reset(); -} -} // namespace blink
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc index ec385870..eb6c57f 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.cc
@@ -434,7 +434,9 @@ webrtc::VideoDecoder::DecoderInfo RTCVideoDecoderAdapter::GetDecoderInfo() const { DecoderInfo info; - info.implementation_name = "ExternalDecoder"; + std::string implementation_name_suffix = + " (" + media::GetDecoderName(video_decoder_->GetDecoderType()) + ")"; + info.implementation_name = "ExternalDecoder" + implementation_name_suffix; info.is_hardware_accelerated = true; return info; }
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc index 3bce0679..e0abc9e 100644 --- a/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc +++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_stream_adapter.cc
@@ -1071,10 +1071,14 @@ decoder_info_.is_hardware_accelerated = decoder->IsPlatformDecoder(); video_decoder_type_ = decoder->GetDecoderType(); - // In order not to break RTC statistics collection, name these in a way that - // third_party/webrtc/video/receive_statistics_proxy2.cc understands. + // In order not to break the RTC statistics collection, name these + // software(libvpx and FFmpeg) decoders in a way that + // third_party/webrtc/video/receive_statistics_proxy2.cc can understand. if (decoder->IsPlatformDecoder()) { - decoder_info_.implementation_name = kExternalDecoderName; + std::string implementation_name_suffix = + " (" + media::GetDecoderName(decoder->GetDecoderType()) + ")"; + decoder_info_.implementation_name = + kExternalDecoderName + implementation_name_suffix; return; }
diff --git a/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h b/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h index 212cd41..bde2710 100644 --- a/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h +++ b/third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h
@@ -50,7 +50,7 @@ // We need to switch to the unsigned type when negating the value since // abs(INT_MIN) == INT_MAX + 1. bool is_negative = base::IsValueNegative(input); - UnsignedIntegerType value = is_negative ? 0u - input : input; + UnsignedIntegerType value = is_negative ? 0u - static_cast<UnsignedIntegerType>(input) : input; do { --begin_;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index f9142b3..c842699 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -391,6 +391,9 @@ crbug.com/730267 virtual/gpu-rasterization/images/yuv-decode-eligible/color-profile-layer-filter.html [ Failure Pass Skip Timeout ] crbug.com/730267 virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-layer.html [ Failure Pass Timeout ] crbug.com/730267 virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-layer-filter.html [ Failure Pass Skip Timeout ] +crbug.com/730267 [ Mac11 ] virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/webp-color-profile-lossy.html [ Failure Pass Timeout ] +crbug.com/730267 [ Mac11 ] virtual/gpu-rasterization/images/yuv-decode-eligible/jpeg-missing-eoi.html [ Failure Pass Timeout ] +crbug.com/730267 [ Mac11 ] virtual/gpu-rasterization/images/yuv-decode-eligible/webp-no-color-profile-lossy.html [ Failure Pass Timeout ] # Flaky virtual/threaded/fast/scrolling tests crbug.com/841567 virtual/threaded-prefer-compositing/fast/scrolling/absolute-position-behind-scrollbar.html [ Failure Pass ] @@ -3336,6 +3339,7 @@ crbug.com/626703 [ Win ] external/wpt/css/css-animations/KeyframeEffect-getKeyframes.tentative.html [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 [ Mac ] external/wpt/css/css-overflow/webkit-line-clamp-036.html [ Failure ] crbug.com/626703 [ Mac ] virtual/prerender/external/wpt/speculation-rules/prerender/media-autoplay.html [ Skip Timeout ] crbug.com/626703 [ Win ] virtual/prerender/external/wpt/speculation-rules/prerender/media-autoplay.html [ Skip Timeout ] crbug.com/626703 [ Mac10.12 ] external/wpt/html/browsers/browsing-the-web/back-forward-cache/eligibility/broadcast-channel.html [ Timeout ] @@ -7583,23 +7587,6 @@ # Disable to skip performance test caused by potential O(n^2) problem in AXObjectCacheImpl::ChildrenChanged crbug.com/1293714 external/wpt/css/selectors/invalidation/has-complexity.html [ Skip ] -# Temporarily disabled to land refactoring in DevTools -crbug.com/1301903 http/tests/devtools/elements/css-variables/defined-css-variables.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/css-variables/resolve-css-variables.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/css-variables/resolve-inherited-css-variables.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/hide-shortcut.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-1/cached-sync-computed-styles.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-1/edit-value-inside-property.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-2/add-import-rule.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-2/import-pseudoclass-crash.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-2/multiple-imports-edit-crash.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-2/property-ui-location.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-3/styles-variables.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-4/disable-last-property-without-semicolon.js [ Skip ] -crbug.com/1301903 http/tests/devtools/elements/styles-4/styles-formatting.js [ Skip ] -crbug.com/1301903 http/tests/devtools/modify-cross-domain-rule.js [ Skip ] - # The test has a flaky baseline crbug.com/1243128 http/tests/devtools/extensions/extensions-useragent.js [ Failure Pass ] @@ -7640,3 +7627,6 @@ # Sheriff 2022-03-01 crbug.com/1302043 [ Linux ] virtual/plz-dedicated-worker/external/wpt/resource-timing/object-not-found-after-cross-origin-redirect.html [ Pass Timeout ] + +# Sheriff 2022-03-03 +crbug.com/1302571 http/tests/devtools/isolated-code-cache/cross-origin-test.js [ Skip ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations index b3c9d00..a419fa8a 100644 --- a/third_party/blink/web_tests/WebGPUExpectations +++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -77,9 +77,6 @@ # Dawn implements validation of the limit at createShaderModule time, while the CTS checks at createRenderPipeline time. crbug.com/dawn/986 wpt_internal/webgpu/cts.https.html?q=webgpu:api,validation,vertex_state:vertex_shader_input_location_limit:* [ Failure ] -# WebGPU allows copy from webgpu context in CopyExternalImageToTexture(). Disable related cts temporarily. -crbug.com/1282838 wpt_internal/webgpu/cts.https.html?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:source_canvas,contexts:* [ Failure ] - # These tests aren't working on CQ, unclear whether the test or harness (or Chrome) is broken. # Mac: mostly works # Linux: Crashes @@ -163,8 +160,8 @@ ### Platform-independent failures ### -# Intentionally hits a CHECK. -crbug.com/1243842 wpt_internal/webgpu/cts.https.html?q=webgpu:api,operation,buffers,map_ArrayBuffer:postMessage:transfer=true;* [ Crash ] +# Test is being updated in https://github.com/gpuweb/cts/pull/1027 +crbug.com/1243842 wpt_internal/webgpu/cts.https.html?q=webgpu:api,operation,buffers,map_ArrayBuffer:postMessage:transfer=true;* [ Failure ] # Our automated build does not support mp4 currently (fails on Linux, Mac, and Win Intel) wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,external_texture,video:importExternalTexture,sample:videoSource="red-green.mp4" [ Failure ] @@ -322,7 +319,6 @@ crbug.com/dawn/685 wpt_internal/webgpu/cts.https.html?q=webgpu:api,validation,createTexture:texture_size,2d_texture,uncompressed_format:size=[1,1,2049];* [ Failure ] crbug.com/1197369 wpt_internal/webgpu/cts.https.html?q=webgpu:api,validation,queue,copyToTexture,CopyExternalImageToTexture:source_image,crossOrigin:* [ Failure ] -crbug.com/1197369 wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="premultiply";orientation="flipY";* [ Skip ] crbug.com/dawn/995 wpt_internal/webgpu/cts.https.html?q=webgpu:api,validation,buffer,create:createBuffer_invalid_and_oom:* [ Failure ] @@ -399,6 +395,16 @@ crbug.com/tint/993 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:shader,execution,robust_access:linear_memory:storageClass="function";* [ Skip ] crbug.com/tint/993 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:shader,execution,robust_access:linear_memory:storageClass="private";access="write";* [ Skip ] +# CopyExernalImageToTexture fails with dest format rgb10a2unorm when input resource is ImageBitmap created with ImageData +crbug.com/1299319 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="none";orientation="flipY";srcDoFlipYDuringCopy=false;dstColorFormat="rgb10a2unorm";* [ Failure ] +crbug.com/1299319 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="none";orientation="flipY";srcDoFlipYDuringCopy=true;dstColorFormat="rgb10a2unorm";* [ Failure ] +crbug.com/1299319 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="none";orientation="none";srcDoFlipYDuringCopy=false;dstColorFormat="rgb10a2unorm";* [ Failure ] +crbug.com/1299319 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="none";orientation="none";srcDoFlipYDuringCopy=true;dstColorFormat="rgb10a2unorm";* [ Failure ] +crbug.com/1299319 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="premultiply";orientation="flipY";srcDoFlipYDuringCopy=false;dstColorFormat="rgb10a2unorm";* [ Failure ] +crbug.com/1299319 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="premultiply";orientation="flipY";srcDoFlipYDuringCopy=true;dstColorFormat="rgb10a2unorm";* [ Failure ] +crbug.com/1299319 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="premultiply";orientation="none";srcDoFlipYDuringCopy=false;dstColorFormat="rgb10a2unorm";* [ Failure ] +crbug.com/1299319 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="premultiply";orientation="none";srcDoFlipYDuringCopy=true;dstColorFormat="rgb10a2unorm";* [ Failure ] + # Only on Mac Intel, baseVertex is always 0 for drawIndirect. crbug.com/dawn/722 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:api,operation,rendering,draw:arguments:indirect=true;base_vertex=9;* [ Failure ] @@ -530,11 +536,6 @@ # Device lost is triggered unexpectedly. crbug.com/dawn/1278 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:api,validation,image_copy,texture_related:format:method="WriteTexture";depthOrArrayLayers=32;dimension="3d";format="r8unorm";mipLevel=2;copyWidthModifier=-1;copyHeightModifier=-1;copyDepthModifier=0;* [ Failure ] -# (Intel-only) Wrong results in copyToTexture. -crbug.com/dawn/1279 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="none";orientation="flipY";srcDoFlipYDuringCopy=false;dstColorFormat="rg32float";width=256;height=255;* [ Failure ] -crbug.com/dawn/1279 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="none";orientation="none";srcDoFlipYDuringCopy=true;dstColorFormat="rg32float";width=256;height=255;* [ Failure ] -crbug.com/dawn/1279 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,ImageBitmap:from_ImageData:alpha="premultiply";orientation="none";srcDoFlipYDuringCopy=true;dstColorFormat="rg32float";width=256;height=255;* [ Failure ] - # (Intel-only) StoreOpClear handling is overclearing resources that should be preserved crbug.com/1237175 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";format="rg32float";uninitializeMethod="StoreOpClear";canaryOnCreation=true;* [ Failure ] crbug.com/1237175 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";format="rgba32float";uninitializeMethod="StoreOpClear";canaryOnCreation=true;* [ Failure ] @@ -548,20 +549,6 @@ # (Intel-only) Unexpected result. Possibly due to using dst-alpha on an attachment with no alpha channel. crbug.com/dawn/1063 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:api,operation,render_pipeline,pipeline_output_targets:color,component_count,blend:* [ Failure ] -# (Intel-HD630/UHD630-only) CopyExternalImageToTexture test failures with CPU uploading path on Windows. -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_2d_context_canvas:canvasType="offscreen";dstColorFormat="rg32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_2d_context_canvas:canvasType="offscreen";dstColorFormat="rgba32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_2d_context_canvas:canvasType="onscreen";dstColorFormat="rg32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_2d_context_canvas:canvasType="onscreen";dstColorFormat="rgba32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:canvasType="offscreen";contextName="webgl";dstColorFormat="rg32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:canvasType="offscreen";contextName="webgl";dstColorFormat="rgba32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:canvasType="offscreen";contextName="webgl2";dstColorFormat="rg32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:canvasType="offscreen";contextName="webgl2";dstColorFormat="rgba32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:canvasType="onscreen";contextName="webgl";dstColorFormat="rg32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:canvasType="onscreen";contextName="webgl";dstColorFormat="rgba32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:canvasType="onscreen";contextName="webgl2";dstColorFormat="rg32float";* [ Failure ] -crbug.com/1269118 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:canvasType="onscreen";contextName="webgl2";dstColorFormat="rgba32float";* [ Failure ] - # KI due to support in Tint being rolled back crbug.com/tint/1322 [ Win ] wpt_internal/webgpu/cts.https.html?q=webgpu:shader,execution,sampling,gradients_in_varying_loop:derivative_in_varying_loop:* [ Failure ]
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version index 0d522326..049af1ac 100644 --- a/third_party/blink/web_tests/external/Version +++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@ -Version: b95980870bfbad4969b88bd8c3a8d488608e86f5 +Version: 73aae07a9513ef44a75d75d02a84630d3d653909
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index a46609c..1d7b08f 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -1857,6 +1857,13 @@ {} ] ], + "negative-section-distribution.html": [ + "b0cedcaf5af86d2b88950deed89d3ff9a05e1ec6", + [ + null, + {} + ] + ], "negative_caption_margin.html": [ "cd3c4f4bf7a83ea59ae4b97aaab94bfe3df2fb7b", [ @@ -90463,7 +90470,7 @@ ] ], "contain-layout-ink-overflow-013.html": [ - "d1431737352ef766f333e160888334b9efa0f66b", + "ca11f420877490d38a7df4b172640e5b4d0e92cb", [ null, [ @@ -90476,12 +90483,12 @@ ] ], "contain-layout-ink-overflow-014.html": [ - "ad1c94e1610584c3f83f43354e830cce137739c9", + "cbb752d625eca13df978aa81908fbf32013686d9", [ null, [ [ - "/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html", + "/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html", "==" ] ], @@ -90515,12 +90522,12 @@ ] ], "contain-layout-ink-overflow-017.html": [ - "ebdcd04fcdbcd1ae78eb065c3dca5d3b76d339b6", + "d6b6f83b3a5f2980b599a0b4ef9a41dd345c52ce", [ null, [ [ - "/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html", + "/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html", "==" ] ], @@ -120290,7 +120297,7 @@ ] ], "masonry-align-tracks-multi-001.html": [ - "2dcdfe4b4bef33806f29a1a70b64037ee167f2c7", + "0e20217da8063dc2e35fae3333b93988210e7eb1", [ null, [ @@ -120407,7 +120414,7 @@ ] ], "masonry-gap-001.html": [ - "17873d1e96c3f996bc6dcaaa08eb41325acbaa7a", + "673bbe40e41f6b35df2403330a8c76af625b2fbd", [ null, [ @@ -120732,7 +120739,7 @@ ] ], "masonry-justify-tracks-multi-001.html": [ - "22a4199642666e76bb716a8894e1e30faf58d716", + "011c487cb721d6185d6a27debf9fec0953af5bfe", [ null, [ @@ -139849,7 +139856,7 @@ ] ], "webkit-line-clamp-036.html": [ - "cc5fb5b13ede54c59a0c69d2a1290a765e575826", + "b8d7b194f05dd8dc1189900b399188e0d17391d1", [ null, [ @@ -157049,7 +157056,33 @@ {} ] ] - } + }, + "section-no-tbody-fixed-distribution.html": [ + "dd403d248c628d6c6b9f4214fff328f66512ff94", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ], + "section-no-tbody-percent-distribution.html": [ + "d1546b1e382db29a82b9489ccd1d7548ef0cedbe", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square-only.html", + "==" + ] + ], + {} + ] + ] }, "toggle-row-display-property-001.html": [ "8755cd068f2feb155cbf8079b0925b9766f53f5e", @@ -235730,7 +235763,7 @@ [] ], "fedcm-mock.js": [ - "6ab4cbfa2fab9fe0b65c86be40bd3c79cd5c8325", + "3d2359a6dfc1552fb64b8903048bbcb0603fe650", [] ], "fedcm.json": [ @@ -246775,6 +246808,10 @@ [] ], "contain-layout-ink-overflow-013-ref.html": [ + "27041414e4f12bad6cbec97740dc670ffc61ea77", + [] + ], + "contain-layout-ink-overflow-014-ref.html": [ "a2b75db3147cec8ff474d126b641df8188859d6e", [] ], @@ -259186,7 +259223,7 @@ [] ], "masonry-align-tracks-multi-001-ref.html": [ - "11ff5081ec1a3c6916e4124788a2e2b36223788c", + "b0bf3578618df14a95e65e5dbcec8a8ef55442df", [] ], "masonry-align-tracks-stretch-001-ref.html": [ @@ -259222,7 +259259,7 @@ [] ], "masonry-gap-001-ref.html": [ - "5e92a681a0d79d80208cc2652a31aa6486477219", + "031629e926bf103fc3700e01a864c341de8bd44d", [] ], "masonry-grid-item-content-baseline-001-ref.html": [ @@ -259322,7 +259359,7 @@ [] ], "masonry-justify-tracks-multi-001-ref.html": [ - "57176e2b1ec61321808499f8285e2ec06b70c5aa", + "319ef217ea759acf81037e414ec0762363bca6c9", [] ], "masonry-justify-tracks-stretch-001-ref.html": [ @@ -263359,7 +263396,7 @@ [] ], "webkit-line-clamp-036-ref.html": [ - "2219e3106d3107bb081b8896d7db898b4dda3c35", + "0de35e98ab353519664996fba8ab8ef6916a18d0", [] ], "webkit-line-clamp-037-ref.html": [ @@ -352044,7 +352081,7 @@ ] ], "child-src-cross-origin-load.sub.html": [ - "1c21a185a62563c9bb6b4617450ec098b16c95d0", + "192f69b8541262cf48f35e1b9eaa0a81a8b9e95b", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-back-forward-same-doc.html b/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-back-forward-same-doc.html index 9b1b777..8cfe2dc 100644 --- a/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-back-forward-same-doc.html +++ b/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-back-forward-same-doc.html
@@ -5,7 +5,7 @@ promise_test(async t => { // Wait for after the load event so that the navigation doesn't get converted // into a replace navigation. - await new Promise(resolve => window.onload = t.step_timeout(resolve, 0)); + await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0)); await appHistory.navigate("#foo").committed; assert_equals(appHistory.entries().length, 2);
diff --git a/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-replace-same-doc.html b/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-replace-same-doc.html index 2967f21d..fa7006b4e 100644 --- a/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-replace-same-doc.html +++ b/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-replace-same-doc.html
@@ -5,7 +5,7 @@ promise_test(async t => { // Wait for after the load event so that the navigation doesn't get converted // into a replace navigation. - await new Promise(resolve => window.onload = t.step_timeout(resolve, 0)); + await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0)); let oncurrentchange_called = false; let original_entry = appHistory.current;
diff --git a/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-same-doc.html b/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-same-doc.html index d112e25..d74048a01 100644 --- a/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-same-doc.html +++ b/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-app-history-navigate-same-doc.html
@@ -5,7 +5,7 @@ promise_test(async t => { // Wait for after the load event so that the navigation doesn't get converted // into a replace navigation. - await new Promise(resolve => window.onload = t.step_timeout(resolve, 0)); + await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0)); let oncurrentchange_called = false; appHistory.oncurrentchange = t.step_func(e => {
diff --git a/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-history-back-same-doc.html b/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-history-back-same-doc.html index 7cfecb1..a90ee1e 100644 --- a/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-history-back-same-doc.html +++ b/third_party/blink/web_tests/external/wpt/app-history/currentchange-event/currentchange-history-back-same-doc.html
@@ -5,7 +5,7 @@ promise_test(async t => { // Wait for after the load event so that the navigation doesn't get converted // into a replace navigation. - await new Promise(resolve => window.onload = t.step_timeout(resolve, 0)); + await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0)); await appHistory.navigate("#foo"); assert_equals(appHistory.entries().length, 2);
diff --git a/third_party/blink/web_tests/external/wpt/app-history/navigate-event/navigate-history-back-after-fragment.html b/third_party/blink/web_tests/external/wpt/app-history/navigate-event/navigate-history-back-after-fragment.html index f0a423a..307fe57 100644 --- a/third_party/blink/web_tests/external/wpt/app-history/navigate-event/navigate-history-back-after-fragment.html +++ b/third_party/blink/web_tests/external/wpt/app-history/navigate-event/navigate-history-back-after-fragment.html
@@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script> async_test(t => { - window.onload = t.step_timeout(() => { + window.onload = () => t.step_timeout(() => { let start_length = history.length; let target_key = appHistory.current.key; let target_id = appHistory.current.id;
diff --git a/third_party/blink/web_tests/external/wpt/app-history/navigate-event/navigate-history-back-after-pushState.html b/third_party/blink/web_tests/external/wpt/app-history/navigate-event/navigate-history-back-after-pushState.html index 40c41ee..74f353d 100644 --- a/third_party/blink/web_tests/external/wpt/app-history/navigate-event/navigate-history-back-after-pushState.html +++ b/third_party/blink/web_tests/external/wpt/app-history/navigate-event/navigate-history-back-after-pushState.html
@@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script> async_test(t => { - window.onload = t.step_timeout(() => { + window.onload = () => t.step_timeout(() => { let start_length = history.length; let target_key = appHistory.current.key; let target_id = appHistory.current.id;
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/parsing/invalid-directive.html b/third_party/blink/web_tests/external/wpt/content-security-policy/parsing/invalid-directive.html new file mode 100644 index 0000000..d96141e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/parsing/invalid-directive.html
@@ -0,0 +1,22 @@ +<meta http-equiv="content-security-policy" content="img-src 'none'; aaa;"> +<title>Parsing: Unknown directive is ignored</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + promise_test(async t => { + img = document.createElement('img'); + img.src = "../support/fail.png"; + return Promise.all([ + new Promise((resolve, reject) => { + img.onerror = resolve; + img.onload = reject; + }), + new Promise(resolve => { + window.addEventListener('securitypolicyviolation', e => { + if (e.blockedURI.endsWith("/support/fail.png")) + resolve(); + }); + }) + ]); + }, "Even if an unknown directive is specified, img-src is honored."); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-013.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-013.html index d143173..ca11f42 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-013.html +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-013.html
@@ -16,7 +16,7 @@ { font-family: monospace; font-size: 100px; - height: 2.8ch; + height: 3em; line-height: 1.5; /* computes to 150px */ width: 4ch;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-014.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-014.html index ad1c94e..cbb752d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-014.html +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-014.html
@@ -7,7 +7,7 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow"> <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout"> - <link rel="match" href="reference/contain-layout-ink-overflow-013-ref.html"> + <link rel="match" href="reference/contain-layout-ink-overflow-014-ref.html"> <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-017.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-017.html index ebdcd04..d6b6f83 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-017.html +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-layout-ink-overflow-017.html
@@ -7,7 +7,7 @@ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> <link rel="help" href="https://www.w3.org/TR/css-overflow-3/#ink-overflow"> <link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-layout"> - <link rel="match" href="reference/contain-layout-ink-overflow-013-ref.html"> + <link rel="match" href="reference/contain-layout-ink-overflow-014-ref.html"> <meta content="This test checks that when the contents of an element with 'contain: layout' overflows, its contents must be treated as ink overflow. In this test, the content overflows the div#inner. If such content was treated as 'overflow: visible', then the div#outer would 'pick up' such content and would make it reachable and accessible via its own generated scrollbar. But the overflowed content must be treated as ink overflow and is therefore treated as a graphical effect that is beyond the scrolling mechanism and outside the scrolling mechanism." name="assert">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html index a2b75db..2704141 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-013-ref.html
@@ -11,7 +11,7 @@ { font-family: monospace; font-size: 100px; - height: 2.8ch; + height: 3em; overflow: scroll; width: 4ch; }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html new file mode 100644 index 0000000..a2b75db --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-layout-ink-overflow-014-ref.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reference Test</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + font-family: monospace; + font-size: 100px; + height: 2.8ch; + overflow: scroll; + width: 4ch; + } + </style> + + <body> + + <p>Test passes if there is no red. + + <div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-align-tracks-multi-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-align-tracks-multi-001-ref.html index 11ff508..b0bf357 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-align-tracks-multi-001-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-align-tracks-multi-001-ref.html
@@ -9,7 +9,7 @@ <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> <style> html,body { - color:black; background-color:white; font:15px/1 monospace; padding:0; margin:0; + color:black; background-color:white; font:15px/1 "Courier New", monospace; padding:0; margin:0; } grid { display: inline-grid;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-align-tracks-multi-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-align-tracks-multi-001.html index 2dcdfe4b..0e20217d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-align-tracks-multi-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-align-tracks-multi-001.html
@@ -11,7 +11,7 @@ <link rel="match" href="masonry-align-tracks-multi-001-ref.html"> <style> html,body { - color:black; background-color:white; font:15px/1 monospace; padding:0; margin:0; + color:black; background-color:white; font:15px/1 "Courier New", monospace; padding:0; margin:0; } grid { display: inline-grid;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-gap-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-gap-001-ref.html index 5e92a68..031629e9 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-gap-001-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-gap-001-ref.html
@@ -9,7 +9,7 @@ <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> <style> html,body { - color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0; + color:black; background-color:white; font:25px/1 "Courier New", monospace; padding:0; margin:0; } grid {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-gap-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-gap-001.html index 17873d1e96..673bbe4 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-gap-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-gap-001.html
@@ -11,7 +11,7 @@ <link rel="match" href="masonry-gap-001-ref.html"> <style> html,body { - color:black; background-color:white; font:25px/1 monospace; padding:0; margin:0; + color:black; background-color:white; font:25px/1 "Courier New", monospace; padding:0; margin:0; } grid {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-justify-tracks-multi-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-justify-tracks-multi-001-ref.html index 57176e2..319ef21 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-justify-tracks-multi-001-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-justify-tracks-multi-001-ref.html
@@ -9,7 +9,7 @@ <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> <style> html,body { - color:black; background-color:white; font:15px/1 monospace; padding:0; margin:0; + color:black; background-color:white; font:15px/1 "Courier New", monospace; padding:0; margin:0; } grid { display: inline-grid;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-justify-tracks-multi-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-justify-tracks-multi-001.html index 22a4199..011c487c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-justify-tracks-multi-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/masonry/tentative/masonry-justify-tracks-multi-001.html
@@ -11,7 +11,7 @@ <link rel="match" href="masonry-justify-tracks-multi-001-ref.html"> <style> html,body { - color:black; background-color:white; font:15px/1 monospace; padding:0; margin:0; + color:black; background-color:white; font:15px/1 "Courier New", monospace; padding:0; margin:0; } grid { display: inline-grid;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/webkit-line-clamp-036-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/webkit-line-clamp-036-ref.html index 2219e31..0de35e9 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/webkit-line-clamp-036-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/webkit-line-clamp-036-ref.html
@@ -4,7 +4,7 @@ .clamp { display: -webkit-box; -webkit-box-orient: vertical; - width: 150px; + width: 10ch; font: 16px / 32px monospace; background-color: yellow; padding: 4px; @@ -13,5 +13,5 @@ </style> <div class="clamp"> supercalifragilisticexpialidocious - supercalifragi… + supercali… </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/webkit-line-clamp-036.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/webkit-line-clamp-036.html index cc5fb5b..b8d7b19 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-overflow/webkit-line-clamp-036.html +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/webkit-line-clamp-036.html
@@ -8,7 +8,7 @@ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; - width: 150px; + width: 10ch; font: 16px / 32px monospace; background-color: yellow; padding: 4px;
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-form-state-restore.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-form-state-restore.tentative.html index 65a6859..1002355 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-form-state-restore.tentative.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-selectmenu-element/selectmenu-form-state-restore.tentative.html
@@ -16,7 +16,7 @@ <script> async_test(t => { - window.onload = t.step_timeout(() => { + window.onload = () => t.step_timeout(() => { let state = document.getElementById('emptyOnFirstVisit'); let selectMenu = document.getElementById("selectmenu0");
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.html deleted file mode 100644 index 32402f5e..0000000 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.html +++ /dev/null
@@ -1,152 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title> - pannernode-basic.html - </title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="../../resources/audit-util.js"></script> - <script src="../../resources/audit.js"></script> - </head> - <body> - <script id="layout-test-code"> - let context; - let panner; - let audit = Audit.createTaskRunner(); - - audit.define('initialize', (task, should) => { - should(() => { - context = new AudioContext(); - panner = context.createPanner(); - }, 'Initialize context and panner').notThrow(); - task.done(); - }); - - audit.define('basic', (task, should) => { - should(panner.numberOfInputs, 'panner.numberOfInputs').beEqualTo(1); - should(panner.numberOfOutputs, 'panner.numberOfOutputs').beEqualTo(1); - should(panner.refDistance, 'panner.refDistance').beEqualTo(1); - panner.refDistance = 270.5; - should(panner.refDistance, 'panner.refDistance = 270.5') - .beEqualTo(270.5); - should(panner.maxDistance, 'panner.maxDistance').beEqualTo(10000); - panner.maxDistance = 100.5; - should(panner.maxDistance, 'panner.maxDistance = 100.5') - .beEqualTo(100.5); - should(panner.rolloffFactor, 'panner.rolloffFactor').beEqualTo(1); - panner.rolloffFactor = 0.75; - should(panner.rolloffFactor, 'panner.rolloffFactor = 0.75') - .beEqualTo(0.75); - should(panner.coneInnerAngle, 'panner.coneInnerAngle').beEqualTo(360); - panner.coneInnerAngle = 240.5; - should(panner.coneInnerAngle, 'panner.coneInnerAngle = 240.5') - .beEqualTo(240.5); - should(panner.coneOuterAngle, 'panner.coneOuterAngle').beEqualTo(360); - panner.coneOuterAngle = 166.5; - should(panner.coneOuterAngle, 'panner.coneOuterAngle = 166.5') - .beEqualTo(166.5); - should(panner.coneOuterGain, 'panner.coneOuterGain').beEqualTo(0); - panner.coneOuterGain = 0.25; - should(panner.coneOuterGain, 'panner.coneOuterGain = 0.25') - .beEqualTo(0.25); - should(panner.panningModel, 'panner.panningModel') - .beEqualTo('equalpower'); - should(panner.distanceModel) - .beEqualTo('inverse', 'panner.distanceModel'); - - should(panner.positionX.value, 'panner.positionX').beEqualTo(0); - should(panner.positionY.value, 'panner.positionY').beEqualTo(0); - should(panner.positionZ.value, 'panner.positionZ').beEqualTo(0); - should(panner.orientationX.value, 'panner.orientationX').beEqualTo(1); - should(panner.orientationY.value, 'panner.orientationY').beEqualTo(0); - should(panner.orientationZ.value, 'panner.orientationZ').beEqualTo(0); - - task.done(); - }); - - audit.define('listener', (task, should) => { - should(context.listener.positionX.value, 'listener.positionX') - .beEqualTo(0); - should(context.listener.positionY.value, 'listener.positionY') - .beEqualTo(0); - should(context.listener.positionZ.value, 'listener.positionZ') - .beEqualTo(0); - should(context.listener.forwardX.value, 'listener.forwardX') - .beEqualTo(0); - should(context.listener.forwardY.value, 'listener.forwardY') - .beEqualTo(0); - should(context.listener.forwardZ.value, 'listener.forwardZ') - .beEqualTo(-1); - should(context.listener.upX.value, 'listener.upX').beEqualTo(0); - should(context.listener.upY.value, 'listener.upY').beEqualTo(1); - should(context.listener.upZ.value, 'listener.upZ').beEqualTo(0); - - task.done(); - }); - - audit.define('panning models', (task, should) => { - // Check that the .panningModel attribute can be set to all legal - // values. - let panningModels = ['equalpower', 'HRTF']; - - for (let i = 0; i < panningModels.length; ++i) { - should(function() { - panner.panningModel = panningModels[i]; - }, 'Set panner.panningModel = "' + panningModels[i] + '"').notThrow(); - - should( - panner.panningModel, - 'panner.panningModel = "' + panningModels[i] + '"') - .beEqualTo(panningModels[i]); - } - - should(function() { - panner.panningModel = 'invalid'; - }, 'panner.panningModel = "invalid"').notThrow(); - - should(panner.panningModel, 'panner.panningModel after invalid setter') - .beEqualTo('HRTF'); - - // Check that numerical values are no longer supported. We shouldn't - // throw and the value shouldn't be changed. - panner.panningModel = 'HRTF'; - should(function() { - panner.panningModel = 1; - }, 'panner.panningModel = 1').notThrow(); - - should(panner.panningModel, 'panner.panningModel').beEqualTo('HRTF'); - - task.done(); - }); - - audit.define('distance models', (task, should) => { - // Check that the .panningModel attribute can be set to all legal - // values. - let distanceModels = ['linear', 'inverse', 'exponential']; - - for (let i = 0; i < distanceModels.length; ++i) { - should(function() { - panner.distanceModel = distanceModels[i]; - }, 'panner.distanceModel = "' + distanceModels[i] + '"').notThrow(); - - should( - panner.distanceModel, - 'panner.distanceModel = "' + distanceModels[i] + '"') - .beEqualTo(distanceModels[i]); - } - - should(function() { - panner.distanceModel = 'invalid'; - }, 'panner.distanceModel = "invalid"').notThrow(); - - should(panner.distanceModel, 'panner.distanceModel') - .beEqualTo('exponential'); - - task.done(); - }); - - audit.run(); - </script> - </body> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.window.js b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.window.js new file mode 100644 index 0000000..298fce0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.window.js
@@ -0,0 +1,71 @@ +test((t) => { + const context = new AudioContext(); + const source = new ConstantSourceNode(context); + const panner = new PannerNode(context); + source.connect(panner).connect(context.destination); + + // Basic parameters + assert_equals(panner.numberOfInputs,1); + assert_equals(panner.numberOfOutputs,1); + assert_equals(panner.refDistance, 1); + panner.refDistance = 270.5; + assert_equals(panner.refDistance, 270.5); + assert_equals(panner.maxDistance, 10000); + panner.maxDistance = 100.5; + assert_equals(panner.maxDistance, 100.5); + assert_equals(panner.rolloffFactor, 1); + panner.rolloffFactor = 0.75; + assert_equals(panner.rolloffFactor, 0.75); + assert_equals(panner.coneInnerAngle, 360); + panner.coneInnerAngle = 240.5; + assert_equals(panner.coneInnerAngle, 240.5); + assert_equals(panner.coneOuterAngle, 360); + panner.coneOuterAngle = 166.5; + assert_equals(panner.coneOuterAngle, 166.5); + assert_equals(panner.coneOuterGain, 0); + panner.coneOuterGain = 0.25; + assert_equals(panner.coneOuterGain, 0.25); + assert_equals(panner.panningModel, 'equalpower'); + assert_equals(panner.distanceModel, 'inverse'); + + // Position/orientation AudioParams + assert_equals(panner.positionX.value, 0); + assert_equals(panner.positionY.value, 0); + assert_equals(panner.positionZ.value, 0); + assert_equals(panner.orientationX.value, 1); + assert_equals(panner.orientationY.value, 0); + assert_equals(panner.orientationZ.value, 0); + + // AudioListener + assert_equals(context.listener.positionX.value, 0); + assert_equals(context.listener.positionY.value, 0); + assert_equals(context.listener.positionZ.value, 0); + assert_equals(context.listener.forwardX.value, 0); + assert_equals(context.listener.forwardY.value, 0); + assert_equals(context.listener.forwardZ.value, -1); + assert_equals(context.listener.upX.value, 0); + assert_equals(context.listener.upY.value, 1); + assert_equals(context.listener.upZ.value, 0); + + panner.panningModel = 'equalpower'; + assert_equals(panner.panningModel, 'equalpower'); + panner.panningModel = 'HRTF'; + assert_equals(panner.panningModel, 'HRTF'); + panner.panningModel = 'invalid'; + assert_equals(panner.panningModel, 'HRTF'); + + // Check that numerical values are no longer supported. We shouldn't + // throw and the value shouldn't be changed. + panner.panningModel = 1; + assert_equals(panner.panningModel, 'HRTF'); + + panner.distanceModel = 'linear'; + assert_equals(panner.distanceModel, 'linear'); + panner.distanceModel = 'inverse'; + assert_equals(panner.distanceModel, 'inverse'); + panner.distanceModel = 'exponential'; + assert_equals(panner.distanceModel, 'exponential'); + + panner.distanceModel = 'invalid'; + assert_equals(panner.distanceModel, 'exponential'); +}, 'Test the PannerNode interface');
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/directive-parsing-02-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/directive-parsing-02-expected.txt deleted file mode 100644 index 71a54ee..0000000 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/directive-parsing-02-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -CONSOLE ERROR: Unrecognized Content-Security-Policy directive 'aaa'. -CONSOLE ERROR: Refused to load the script 'http://127.0.0.1:8000/security/contentSecurityPolicy/resources/script.js' because it violates the following Content Security Policy directive: "script-src 'none'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback. - -This script should not execute even though there are parse errors in the policy. - --------- -Frame: '<!--framePath //<!--frame0-->-->' --------- -PASS
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/directive-parsing-02.html b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/directive-parsing-02.html deleted file mode 100644 index e2b3b66a..0000000 --- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/directive-parsing-02.html +++ /dev/null
@@ -1,17 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script> -if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.dumpChildFrames(); -} -</script> -</head> -<body> - <p> - This script should not execute even though there are parse errors in the policy. - </p> - <iframe src="http://127.0.0.1:8000/security/contentSecurityPolicy/resources/echo-script-src.pl?should_run=no&q=http://127.0.0.1:8000/security/contentSecurityPolicy/resources/script.js&csp=script-src%20'none'%3B%20aaa%20%3B%20"></iframe> -</body> -</html>
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt index 24de3bf..8c01b519 100644 --- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -354,7 +354,6 @@ property port property protocol property referrerPolicy - property registerAttributionSource property rel property relList property rev
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 7a3632a..12a04a7 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -2953,7 +2953,6 @@ getter port getter protocol getter referrerPolicy - getter registerAttributionSource getter rel getter relList getter rev @@ -2986,7 +2985,6 @@ setter port setter protocol setter referrerPolicy - setter registerAttributionSource setter rel setter relList setter rev
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/cts.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/cts.https.html index e2c3b6582..bb6c3b9 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/cts.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/cts.https.html
@@ -64,8 +64,7 @@ <meta name=variant content='?q=webgpu:api,operation,buffers,map:mapAsync,read,typedArrayAccess:*'> <meta name=variant content='?q=webgpu:api,operation,buffers,map:mappedAtCreation:*'> <meta name=variant content='?q=webgpu:api,operation,buffers,map:remapped_for_write:*'> -<meta name=variant content='?q=webgpu:api,operation,buffers,map_ArrayBuffer:postMessage:transfer=false;*'> -<meta name=variant content='?q=webgpu:api,operation,buffers,map_ArrayBuffer:postMessage:transfer=true;*'> +<meta name=variant content='?q=webgpu:api,operation,buffers,map_ArrayBuffer:postMessage:*'> <meta name=variant content='?q=webgpu:api,operation,buffers,map_detach:while_mapped:*'> <meta name=variant content='?q=webgpu:api,operation,buffers,map_oom:mapAsync:*'> <meta name=variant content='?q=webgpu:api,operation,buffers,map_oom:mappedAtCreation,full_getMappedRange:*'>
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py index 001c06b0..1102926 100644 --- a/tools/grit/grit/tool/build.py +++ b/tools/grit/grit/tool/build.py
@@ -479,10 +479,6 @@ ] error = '''Asserted file list does not match. -Expected output files: -%s -Actual output files: -%s Missing output files: %s Extra output files: @@ -490,8 +486,8 @@ Duplicate actual output files: %s ''' - print(error % ('\n'.join(asserted), '\n'.join(actual), '\n'.join(missing), - '\n'.join(extra), '\n'.join(duplicates))) + print(error % + ('\n'.join(missing), '\n'.join(extra), '\n'.join(duplicates))) return False return True
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 913e1d6..169df7d 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -114,13 +114,13 @@ 'android-weblayer-x86-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_disable_proguard_webview_monochrome_reclient', 'android-10-arm64-rel': 'android_release_bot_minimal_symbols_arm64_fastbuild_webview_trichrome_reclient', 'android-11-x86-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_trichrome_reclient', + 'android-12-x64-rel': 'android_release_bot_minimal_symbols_x64_fastbuild_webview_trichrome_reclient', }, 'chromium.android.fyi': { 'Android ASAN (dbg) (reclient)': 'android_clang_asan_debug_bot_reclient', 'Android arm64 Builder (dbg) (reclient)': 'android_webview_google_debug_static_bot_arm64_reclient', 'Android WebView P FYI (rel)': 'android_release_bot_minimal_symbols_arm64_webview_monochrome_reclient', - 'android-12-x64-fyi-rel': 'android_release_bot_minimal_symbols_x64_fastbuild_webview_trichrome_reclient', 'android-annotator-rel': 'android_release_bot_minimal_symbols_arm64_webview_google_reclient', 'android-pie-arm64-wpt-rel-non-cq': 'android_release_bot_minimal_symbols_arm64_webview_monochrome_reclient', 'android-chrome-pie-x86-wpt-fyi-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_monochrome_reclient', @@ -845,8 +845,8 @@ 'android-webview-pie-arm64-fyi-rel': 'android_release_trybot_arm64_webview_monochrome', 'android-10-arm64-rel': 'android_release_trybot_arm64_fastbuild_webview_trichrome', 'android-11-x86-rel': 'android_release_trybot_x86_fastbuild_webview_trichrome', - 'android-12-x64-fyi-rel': 'android_release_trybot_x64_fastbuild_webview_trichrome', 'android-12-x64-dbg': 'android_debug_trybot_x64_webview_trichrome_webview_shell', + 'android-12-x64-rel': 'android_release_trybot_x64_fastbuild_webview_trichrome', 'android-webview-12-x64-dbg': 'android_debug_trybot_x64_webview_trichrome_webview_shell', 'android-webview-marshmallow-arm64-dbg': 'android_release_trybot_arm64_webview_google', 'android-webview-nougat-arm64-dbg': 'android_release_trybot_arm64_webview_monochrome',
diff --git a/tools/mb/mb_config_expectations/chromium.android.fyi.json b/tools/mb/mb_config_expectations/chromium.android.fyi.json index a71467172..51f1c90 100644 --- a/tools/mb/mb_config_expectations/chromium.android.fyi.json +++ b/tools/mb/mb_config_expectations/chromium.android.fyi.json
@@ -44,25 +44,6 @@ "use_remoteexec": true } }, - "android-12-x64-fyi-rel": { - "gn_args": { - "dcheck_always_on": false, - "disable_android_lint": true, - "ffmpeg_branding": "Chrome", - "is_component_build": false, - "is_debug": false, - "proprietary_codecs": true, - "skip_secondary_abi_for_cq": true, - "strip_debug_info": true, - "symbol_level": 1, - "system_webview_package_name": "com.google.android.webview.debug", - "target_cpu": "x64", - "target_os": "android", - "use_errorprone_java_compiler": false, - "use_rbe": true, - "use_remoteexec": true - } - }, "android-annotator-rel": { "gn_args": { "dcheck_always_on": false,
diff --git a/tools/mb/mb_config_expectations/chromium.android.json b/tools/mb/mb_config_expectations/chromium.android.json index 362f0f1..0582901 100644 --- a/tools/mb/mb_config_expectations/chromium.android.json +++ b/tools/mb/mb_config_expectations/chromium.android.json
@@ -141,6 +141,25 @@ "use_remoteexec": true } }, + "android-12-x64-rel": { + "gn_args": { + "dcheck_always_on": false, + "disable_android_lint": true, + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "skip_secondary_abi_for_cq": true, + "strip_debug_info": true, + "symbol_level": 1, + "system_webview_package_name": "com.google.android.webview.debug", + "target_cpu": "x64", + "target_os": "android", + "use_errorprone_java_compiler": false, + "use_rbe": true, + "use_remoteexec": true + } + }, "android-arm64-proguard-rel": { "gn_args": { "dcheck_always_on": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.android.json b/tools/mb/mb_config_expectations/tryserver.chromium.android.json index 7a75e3f..1aadda8 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.android.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.android.json
@@ -49,7 +49,7 @@ "use_goma": true } }, - "android-12-x64-fyi-rel": { + "android-12-x64-rel": { "gn_args": { "blink_enable_generated_code_formatting": false, "dcheck_always_on": true,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 2487f50..27cf13b 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -25999,10 +25999,20 @@ </description> </action> +<action name="Settings.PrivacySandbox.AdPersonalization.SiteRemoved"> + <owner>dullweber@google.com</owner> + <owner>sauski@google.com</owner> + <description> + User removed a site that was previously in their allowed sites list. + </description> +</action> + <action name="Settings.PrivacySandbox.AdPersonalization.TopicRemoved"> <owner>dullweber@google.com</owner> <owner>sauski@google.com</owner> - <description>User removed a topic.</description> + <description> + User removed a topic that was previously in their allowed topics list. + </description> </action> <action name="Settings.PrivacySandbox.ApisDisabled"> @@ -26084,10 +26094,20 @@ </description> </action> +<action name="Settings.PrivacySandbox.RemovedInterests.SiteAdded"> + <owner>dullweber@google.com</owner> + <owner>sauski@google.com</owner> + <description> + User added back a site that was previously in their removed sites list. + </description> +</action> + <action name="Settings.PrivacySandbox.RemovedInterests.TopicAdded"> <owner>dullweber@google.com</owner> <owner>sauski@google.com</owner> - <description>User added back a topic</description> + <description> + User added back a topic that was previously in their removed topics list. + </description> </action> <action name="Settings.PrivacySandbox.SpamFraud.Opened">
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 371aa67..6911b44 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -5760,6 +5760,15 @@ <int value="2" label="Failure"/> </enum> +<enum name="AutofillAssistantCupRpcVerificationEvent"> + <int value="0" label="RPC response verification failure"/> + <int value="1" label="RPC response verification success"/> + <int value="2" label="Failure parsing the response"/> + <int value="3" label="RPC response verification disabled"/> + <int value="4" label="RPC request signing disabled"/> + <int value="5" label="HTTP error"/> +</enum> + <enum name="AutofillAssistantDependenciesInvalidated"> <int value="0" label="Invalidated outside of flow"/> <int value="1" label="Invalidated during startup"/> @@ -11176,6 +11185,9 @@ <int value="5" label="A sync disk process is already in progress"/> <int value="6" label="Failed to get disk information"/> <int value="7" label="Failed to resize the disk"/> + <int value="8" + label="Nonfatal error, size of disk was below the minimum when + shrinking"/> </enum> <enum name="BoringSSLReasonCode"> @@ -55682,6 +55694,7 @@ <int value="841098208" label="ThrottleForegroundTimers:enabled"/> <int value="841276069" label="ChromeHomeDoodle:disabled"/> <int value="841343322" label="disable-new-korean-ime"/> + <int value="841434560" label="DynamicSearchUpdateAnimation:disabled"/> <int value="841779535" label="password-export:enabled"/> <int value="842158411" label="PdfViewerDocumentProperties:enabled"/> <int value="842432903" label="CaptureThumbnailOnNavigatingAway:enabled"/> @@ -56970,6 +56983,7 @@ <int value="1752168018" label="enable-stale-while-revalidate"/> <int value="1753732236" label="SignInProfileCreationEnterprise:enabled"/> <int value="1755024316" label="HostWindowsInAppShimProcess:disabled"/> + <int value="1756736642" label="DynamicSearchUpdateAnimation:enabled"/> <int value="1757894817" label="PrinterStatusDialog:disabled"/> <int value="1758262950" label="OmniboxUIExperimentVerticalMarginLimitToNonTouchOnly:disabled"/> @@ -62374,6 +62388,20 @@ <int value="0" label="Cancelled on Device Name Page"/> <int value="1" label="Candelled on Set Visibility Page"/> <int value="2" label="Onboarding Complete"/> + <int value="3" label="Cancelled on initial page"/> +</enum> + +<enum name="NearbyShareOnboardingFlowEvent"> + <int value="1" label="Onboarding shown"/> + <int value="12" label="Confirm on initial page"/> + <int value="13" label="Cancel on initial page"/> + <int value="14" label="Visibility button on initial page clicked"/> + <int value="141" label="Device visibility page shown"/> + <int value="1412" label="All contacts visibility selected and confirmed"/> + <int value="1413" label="Some contacts visibility selected and confirmed"/> + <int value="1414" label="Hidden visibility selected and confirmed"/> + <int value="1415" label="Manage contacts selected"/> + <int value="1416" label="Cancel selected on visibility page"/> </enum> <enum name="NearbyShareServiceStatusCode"> @@ -85360,7 +85388,7 @@ <int value="15" label="Browser launch count"/> <int value="16" label="Browser crash count"/> <int value="17" label="(Obsolete Dec 2021) Incomplete shutdown count"/> - <int value="22" label="Plugin crash count"/> + <int value="22" label="(Obsolete Mar 2022) Plugin crash count"/> <int value="24" label="Renderer failed launch count"/> <int value="25" label="Extension renderer failed launch count"/> <int value="26" label="Renderer launch count"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml index 2ca70fe..0a3c3a865 100644 --- a/tools/metrics/histograms/metadata/android/histograms.xml +++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -224,6 +224,18 @@ </summary> </histogram> +<histogram name="Android.AutofillAssistant.CupRpcVerificationEvent" + enum="AutofillAssistantCupRpcVerificationEvent" expires_after="2023-02-02"> + <owner>sergiovila@google.com</owner> + <owner>autofill_assistant@google.com</owner> + <summary> + Reports the outcome of the CUP verification process for GetAction RPC calls. + CUP verification is used to check whether the actions delivered to the + client come from a trusted source. The verification event is recorded after + the response is deserialized but before it's actually used in the client. + </summary> +</histogram> + <histogram name="Android.AutofillAssistant.DependenciesInvalidated" enum="AutofillAssistantDependenciesInvalidated" expires_after="2022-10-27"> <owner>fga@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml index 0e94fe03..a59904ed 100644 --- a/tools/metrics/histograms/metadata/arc/histograms.xml +++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -1101,7 +1101,7 @@ </histogram> <histogram name="Arc.Net.ArcNetworkError" enum="ArcNetworkError" - expires_after="2022-04-01"> + expires_after="2022-12-31"> <owner>hugobenichi@google.com</owner> <owner>cros-networking@google.com</owner> <summary> @@ -1110,7 +1110,7 @@ </histogram> <histogram name="Arc.Net.ArcNetworkEvent" enum="ArcNetworkEvent" - expires_after="2022-04-01"> + expires_after="2022-12-31"> <owner>hugobenichi@google.com</owner> <owner>cros-networking@google.com</owner> <summary> @@ -1121,7 +1121,7 @@ </histogram> <histogram name="Arc.Net.DnsQuery.AndroidApi" enum="BooleanSuccess" - expires_after="2022-07-22"> + expires_after="2022-12-31"> <owner>mhasank@google.com</owner> <owner>arc-core@google.com</owner> <summary> @@ -1130,7 +1130,7 @@ </histogram> <histogram name="Arc.Net.DnsQuery.Other" enum="BooleanSuccess" - expires_after="2022-07-22"> + expires_after="2022-12-31"> <owner>mhasank@google.com</owner> <owner>arc-core@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 968e859..1be9f427 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -2804,6 +2804,19 @@ <token key="TabletOrClamshell" variants="DisplayModes"/> </histogram> +<histogram name="Ash.SearchResultUpdateAnimationShortened" enum="Boolean" + expires_after="2022-12-01"> + <owner>yulunwu@google.com</owner> + <owner>tbarzic@google.com</owner> + <owner>tby@google.com</owner> + <summary> + Records whether search result animation times were shorted for recent search + result update animation preemptions. Recorded when productivity launcher + search containers' results change while result containers are still + animating. + </summary> +</histogram> + <histogram name="Ash.Shelf.Menu.NumItemsEnabledUponSelection" units="Count" expires_after="2023-02-01"> <owner>anasalazar@chromium.org</owner> @@ -3035,6 +3048,18 @@ </summary> </histogram> +<histogram name="Ash.Shelf.ShutdownConfirmationBubble.TimeToNextBoot" + units="seconds" expires_after="2022-12-31"> + <owner>sherrilin@google.com</owner> + <owner>cros-lurs@google.com</owner> + <summary> + Emitted at device start-up if a shut-down was previously initiated from the + shelf shutdown button. In other words this metric is only recorded if a + shelf shutdown button was pressed and the device was powered up again soon + after that. + </summary> +</histogram> + <histogram name="Ash.Shelf.TimeBetweenNavigateToTaskSwitches" units="seconds" expires_after="M81"> <owner>tbuckley@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml index 9140690..e152ac9 100644 --- a/tools/metrics/histograms/metadata/autofill/histograms.xml +++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -2256,7 +2256,24 @@ Logs the user's decision for storing a new address profile observed in a form submission, which had it's country complemented based on the predicted country on import. This metric is emitted at the end of an import process - once the user-provided import decision is final. + once the user-provided import decision is final. It is collected in addition + to Autofill.ProfileImport.NewProfileDecision and only if + kAutofillComplementCountryCodeOnImport is enabled. + </summary> +</histogram> + +<histogram + name="Autofill.ProfileImport.NewProfileWithRemovedPhoneNumberDecision" + enum="AutofillProfileImportDecision" expires_after="2022-05-01"> + <owner>fleimgruber@google.com</owner> + <owner>chrome-autofill-team@google.com</owner> + <summary> + Logs the user's decision for storing a new address profile observed in a + form submission. The profile was only considered an import candidate, after + an invalid phone number was removed. This metric is emitted at the end of an + import process once the user-provided import decision is final. It is + collected in addition to Autofill.ProfileImport.NewProfileDecision and only + if kAutofillRemoveInvalidPhoneNumberOnImport is enabled. </summary> </histogram> @@ -2282,6 +2299,21 @@ </summary> </histogram> +<histogram + name="Autofill.ProfileImport.SilentUpdatesWithRemovedPhoneNumberProfileImportType" + enum="AutofillSilentUpdatesProfileImportType" expires_after="2022-05-01"> + <owner>fleimgruber@google.com</owner> + <owner>chrome-autofill-team@google.com</owner> + <summary> + The type of an import of an address that is observed in a form submission + when the form does not satisfy profile import requirements. It was only + considered for a silent update after an invalid phone number was removed. + This metric is emitted once the import decision is final. It is collected in + addition to Autofill.ProfileImport.SilentUpdatesProfileImportType and only + if kAutofillRemoveInvalidPhoneNumberOnImport is enabled. + </summary> +</histogram> + <histogram name="Autofill.ProfileImport.UpdateProfileAffectedType" enum="AutofillSettingsVisibleTypes" expires_after="2022-08-21"> <owner>koerber@google.com</owner> @@ -2449,7 +2481,25 @@ similar profile was observed in a form submission. The new profile had it's country complemented based on the predicted country on import. This metric is emitted at the end of an import process once the user-provided import - decision is final. + decision is final. It is collected in addition to + Autofill.ProfileImport.UpdateProfileDecision and only if + kAutofillComplementCountryCodeOnImport is enabled. + </summary> +</histogram> + +<histogram + name="Autofill.ProfileImport.UpdateProfileWithRemovedPhoneNumberDecision" + enum="AutofillProfileImportDecision" expires_after="2022-05-01"> + <owner>fleimgruber@google.com</owner> + <owner>chrome-autofill-team@google.com</owner> + <summary> + Logs the user's decision for editing an already existing address after a + similar profile was observed in a form submission. The profile was only + considered an import candidate, after an invalid phone number was removed. + This metric is emitted at the end of an import process once the user- + provided import decision is final. It is collected in addition to + Autofill.ProfileImport.UpdateProfileDecision and only if + kAutofillRemoveInvalidPhoneNumberOnImport is enabled. </summary> </histogram>
diff --git a/tools/metrics/histograms/metadata/borealis/histograms.xml b/tools/metrics/histograms/metadata/borealis/histograms.xml index 400f7df..d54c04f 100644 --- a/tools/metrics/histograms/metadata/borealis/histograms.xml +++ b/tools/metrics/histograms/metadata/borealis/histograms.xml
@@ -23,7 +23,7 @@ <histograms> <histogram name="Borealis.AppsInstalledAtLogin" units="apps" - expires_after="2022-12-26"> + expires_after="2023-02-01"> <owner>joelhockey@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -33,7 +33,7 @@ </histogram> <histogram name="Borealis.Disk.Client.AvailableSpaceAtRequest" units="MB" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -44,7 +44,7 @@ </histogram> <histogram name="Borealis.Disk.Client.GetDiskInfoResult" - enum="BorealisGetDiskInfoResult" expires_after="2022-04-08"> + enum="BorealisGetDiskInfoResult" expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -55,7 +55,7 @@ </histogram> <histogram name="Borealis.Disk.Client.NumRequestsPerSesssion" units="requests" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -66,7 +66,7 @@ </histogram> <histogram name="Borealis.Disk.Client.ReleaseSpaceResult" - enum="BorealisResizeDiskResult" expires_after="2022-04-08"> + enum="BorealisResizeDiskResult" expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -77,7 +77,7 @@ </histogram> <histogram name="Borealis.Disk.Client.RequestSpaceResult" - enum="BorealisResizeDiskResult" expires_after="2022-04-08"> + enum="BorealisResizeDiskResult" expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -88,7 +88,7 @@ </histogram> <histogram name="Borealis.Disk.Client.SpaceReleased" units="MB" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -100,7 +100,7 @@ </histogram> <histogram name="Borealis.Disk.Client.SpaceRequested" units="MB" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -112,7 +112,7 @@ </histogram> <histogram name="Borealis.Disk.Startup.Result" - enum="BorealisSyncDiskSizeResult" expires_after="2022-04-08"> + enum="BorealisSyncDiskSizeResult" expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -124,7 +124,7 @@ </histogram> <histogram name="Borealis.Disk.Startup.{TypeOfSpace}Space" units="MB" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -145,7 +145,7 @@ </histogram> <histogram name="Borealis.EngagementTime.{Variant}" units="ms" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>lqu@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -170,7 +170,7 @@ </histogram> <histogram name="Borealis.GameMode.Result" enum="BorealisGameModeResult" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>lqu@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -181,7 +181,7 @@ </histogram> <histogram name="Borealis.Install.NumAttempts" enum="BooleanAttempted" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -194,7 +194,7 @@ </histogram> <histogram name="Borealis.Install.OverallTime" units="ms" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -207,7 +207,7 @@ </histogram> <histogram name="Borealis.Install.Result" enum="BorealisInstallResult" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -218,7 +218,7 @@ </histogram> <histogram name="Borealis.Shutdown.Attempt" enum="BooleanAttempted" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>lqu@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -228,7 +228,7 @@ </histogram> <histogram name="Borealis.Stability" enum="GuestOsFailureClasses" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>cpelling@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -239,14 +239,14 @@ </histogram> <histogram name="Borealis.Startup.NumAttempts" enum="BooleanAttempted" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary>Recording every attempt to start Borealis (via the UI).</summary> </histogram> <histogram name="Borealis.Startup.OverallTime" units="ms" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -256,7 +256,7 @@ </histogram> <histogram name="Borealis.Startup.Result" enum="BorealisStartupResult" - expires_after="2022-04-08"> + expires_after="2023-02-01"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/cookie/histograms.xml b/tools/metrics/histograms/metadata/cookie/histograms.xml index 04357cb..d906d91 100644 --- a/tools/metrics/histograms/metadata/cookie/histograms.xml +++ b/tools/metrics/histograms/metadata/cookie/histograms.xml
@@ -757,7 +757,7 @@ </histogram> <histogram name="Cookie.SamePartySetIncluded.InclusionUnderSameSite" - enum="BooleanIncluded" expires_after="2022-04-10"> + enum="BooleanIncluded" expires_after="2023-04-10"> <owner>cfredric@chromium.org</owner> <owner>bingler@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/file/histograms.xml b/tools/metrics/histograms/metadata/file/histograms.xml index 4fbb522..253c2b426 100644 --- a/tools/metrics/histograms/metadata/file/histograms.xml +++ b/tools/metrics/histograms/metadata/file/histograms.xml
@@ -631,7 +631,7 @@ </histogram> <histogram name="FileBrowser.ViewingFileType.Offline" enum="ViewFileType" - expires_after="2022-04-10"> + expires_after="2023-06-01"> <owner>simmonsjosh@google.com</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary> @@ -642,7 +642,7 @@ </histogram> <histogram name="FileBrowser.ViewingFileType.Online" enum="ViewFileType" - expires_after="2022-04-10"> + expires_after="2023-06-01"> <owner>simmonsjosh@google.com</owner> <owner>src/ui/file_manager/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/nearby/histograms.xml b/tools/metrics/histograms/metadata/nearby/histograms.xml index 74540c1..8681ad1 100644 --- a/tools/metrics/histograms/metadata/nearby/histograms.xml +++ b/tools/metrics/histograms/metadata/nearby/histograms.xml
@@ -890,6 +890,16 @@ </summary> </histogram> +<histogram name="Nearby.Share.Onboarding.FlowEvent" + enum="NearbyShareOnboardingFlowEvent" expires_after="2023-02-01"> + <owner>pushi@google.com</owner> + <owner>nearby-share-chromeos-eng@google.com</owner> + <summary> + Records how users interacte with the onboarding flow. Emitted when users + embark the Nearby Share onboarding flow, click buttons during the process. + </summary> +</histogram> + <histogram name="Nearby.Share.Onboarding.Result" enum="NearbyShareOnboardingFinalState" expires_after="2023-02-01"> <owner>cvandermerwe@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index 611bdbf..26a573d 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -926,7 +926,7 @@ </histogram> <histogram name="Network.Patchpanel.ArcService" - enum="NetworkPatchpanelArcEvent" expires_after="2022-04-01"> + enum="NetworkPatchpanelArcEvent" expires_after="2022-12-31"> <owner>hugobenichi@google.com</owner> <owner>cros-connectivity@google.com</owner> <owner>cros-network-metrics@google.com</owner> @@ -941,7 +941,7 @@ </histogram> <histogram name="Network.Patchpanel.Dbus" enum="NetworkPatchpanelDbusEvent" - expires_after="2022-04-01"> + expires_after="2022-12-31"> <owner>hugobenichi@google.com</owner> <owner>cros-connectivity@google.com</owner> <owner>cros-network-metrics@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml index f0944bb..58fd01a1 100644 --- a/tools/metrics/histograms/metadata/page/histograms.xml +++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -2245,11 +2245,9 @@ <histogram name="PageLoad.PaintTiming.NavigationToFirstPaint.AfterBackForwardCacheRestore" - units="ms" expires_after="never"> -<!-- expires-never: used in server pipeline to derive additional metrics --> - + units="ms" expires_after="2022-06-19"> <owner>altimin@chromium.org</owner> - <owner>hajimehoshi@chromium.org</owner> + <owner>djw@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> <owner>speed-metrics-dev@chromium.org</owner> <summary> @@ -2258,23 +2256,31 @@ only when the page is restored from back-forward cache. Do not modify this metric in any way without contacting - speed-metrics-dev@chromium.org AND chrome-analysis-team@google.com. + speed-metrics-dev@chromium.org. Bucketing for this histogram should be kept in sync with bucketing for - PageLoad.PaintTiming.NavigationToFirstContentfulPaint. These two histograms - will be aggregated on the server to form the authoritative metric. + PageLoad.PaintTiming.NavigationToFirstContentfulPaint. </summary> </histogram> <histogram name="PageLoad.PaintTiming.NavigationToFirstPaint.BFCachePolyfill{Count}" - units="ms" expires_after="2021-11-01"> + units="ms" expires_after="never"> +<!-- expires-never: used in server pipeline to derive additional metrics --> + <owner>altimin@chromium.org</owner> - <owner>bmcquade@chromium.org</owner> - <owner>hajimehoshi@chromium.org</owner> + <owner>bfcache-dev@chromium.org</owner> + <owner>speed-metrics-dev@chromium.org</owner> <summary> Meastures the time duration between the page restore from BFcache and the {Count} requestAnimationFrame time. + + Do not modify this metric in any way without contacting + speed-metrics-dev@chromium.org AND chrome-analysis-team@google.com. + + Bucketing for this histogram should be kept in sync with bucketing for + PageLoad.PaintTiming.NavigationToFirstContentfulPaint. These two histograms + will be aggregated on the server to form the authoritative metric. </summary> <token key="Count"> <variant name="First"/>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index 30a3c54..9bfa5d7 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -199,7 +199,7 @@ </histogram> <histogram name="Sync.CommitResponse{SyncModelType}" enum="SyncerErrorValues" - expires_after="2022-04-10"> + expires_after="2023-04-10"> <owner>rushans@google.com</owner> <owner>treib@chromium.org</owner> <component>Services>Sync</component>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml index e6bd688..4f4c6dc 100644 --- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml +++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -3940,7 +3940,7 @@ </histogram> <histogram name="WebRTC.webkitApiCount" enum="RTCAPIName" - expires_after="2022-04-24"> + expires_after="2023-04-24"> <owner>toprice@chromium.org</owner> <owner>hbos@chromium.org</owner> <owner>mcasas@chromium.org</owner> @@ -3950,7 +3950,7 @@ </histogram> <histogram name="WebRTC.webkitApiCountPerSession" enum="RTCAPIName" - expires_after="2022-03-07"> + expires_after="2023-03-07"> <owner>toprice@chromium.org</owner> <owner>hbos@chromium.org</owner> <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 9edb2ef..7810ebc 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@ "remote_path": "perfetto_binaries/trace_processor_shell/linux_arm64/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell" }, "win": { - "hash": "23340d9d01e807352193ef2caa6f8705b2948475", - "remote_path": "perfetto_binaries/trace_processor_shell/win/a930f3799c34bedb97a76b2292ac02b3bc053ccb/trace_processor_shell.exe" + "hash": "d72bd5a879fefaf5836c78b9f2224fd74eeb8ef9", + "remote_path": "perfetto_binaries/trace_processor_shell/win/11de3dcf8b4e4c727906a0fb055b5493e9d2de82/trace_processor_shell.exe" }, "linux_arm": { "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893", @@ -21,8 +21,8 @@ "remote_path": "perfetto_binaries/trace_processor_shell/mac_arm64/cefb3e0ec3a0580c996f801e854fe02963c03d5c/trace_processor_shell" }, "linux": { - "hash": "6c115ffc4a7ad1bf5341e01e307599d3e673c4c7", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/dfc6cffca9b6a34068386915d50040c6bc142717/trace_processor_shell" + "hash": "5557a39925471dc411ec48c5f6a0b8e715772d36", + "remote_path": "perfetto_binaries/trace_processor_shell/linux/11de3dcf8b4e4c727906a0fb055b5493e9d2de82/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index d54a6de..fd4be59 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -98,8 +98,6 @@ crbug.com/1236631 [ linux ] desktop_ui/side_search:* [ Skip ] # Benchmark: blink_perf.webcodecs -crbug.com/1300680 [ android ] blink_perf.webcodecs/software-video-encoding.html [ Skip ] -crbug.com/1301260 [ linux ] blink_perf.webcodecs/hardware-video-encoding.html [ Skip ] # Benchmark: dromaeo crbug.com/1050065 [ android-pixel-2 ] dromaeo/http://dromaeo.com?dom-modify [ Skip ]
diff --git a/tools/rust/build_rust.py b/tools/rust/build_rust.py index 2ecdd2c..5116640 100755 --- a/tools/rust/build_rust.py +++ b/tools/rust/build_rust.py
@@ -64,6 +64,8 @@ THIRD_PARTY_DIR = os.path.join(CHROMIUM_DIR, 'third_party') RUST_SRC_DIR = os.path.join(THIRD_PARTY_DIR, 'rust-src') +# Download crates.io dependencies to rust-src subdir (rather than $HOME/.cargo) +CARGO_HOME_DIR = os.path.join(RUST_SRC_DIR, 'cargo-home') RUST_SRC_VERSION_FILE_PATH = os.path.join(RUST_SRC_DIR, 'src', 'version') RUST_TOOLCHAIN_OUT_DIR = os.path.join(THIRD_PARTY_DIR, 'rust-toolchain') RUST_TOOLCHAIN_LIB_DIR = os.path.join(RUST_TOOLCHAIN_OUT_DIR, 'lib') @@ -148,6 +150,8 @@ ''' Run x.py, Rust's build script''' clang_path = os.path.join(LLVM_BUILD_DIR, 'bin', 'clang') RUSTENV = collections.defaultdict(str, os.environ) + # Cargo normally stores files in $HOME. Override this. + RUSTENV['CARGO_HOME'] = CARGO_HOME_DIR RUSTENV['AR'] = os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-ar') RUSTENV['CC'] = clang_path RUSTENV['CXX'] = os.path.join(LLVM_BUILD_DIR, 'bin', 'clang++') @@ -243,31 +247,33 @@ Configure(llvm_libs_root) if not args.skip_clean: + print('Cleaning build artifacts...') RunXPy('clean', [], args.gcc_toolchain, args.verbose) + if not args.skip_test: + print('Running stage 2 tests...') + # Run a subset of tests. Tell x.py to keep the rustc we already built. + RunXPy('test', + ['--stage', '2', 'library/std', 'src/test/codegen', 'src/test/ui'], + args.gcc_toolchain, args.verbose) + targets = [ 'library/proc_macro', 'library/std', 'src/tools/cargo', 'src/tools/clippy', 'src/tools/rustfmt' ] - # Build stage 1 compiler and tools. - RunXPy('build', ['--stage', '1'] + targets, args.gcc_toolchain, args.verbose) - - if not args.skip_test: - # Run a subset of tests. Tell x.py to keep the rustc we already built. - RunXPy('test', [ - '--stage', '1', '--keep-stage', '1', 'library/std', 'src/test/codegen', - 'src/test/ui' - ], args.gcc_toolchain, args.verbose) + # Build stage 2 compiler, tools, and libraries. This should reuse earlier + # stages from the test command (if run). + print('Building stage 2 artifacts...') + RunXPy('build', ['--stage', '2'] + targets, args.gcc_toolchain, args.verbose) if not args.skip_install: + print(f'Installing to {RUST_TOOLCHAIN_OUT_DIR} ...') # Clean output directory. if os.path.exists(RUST_TOOLCHAIN_OUT_DIR): shutil.rmtree(RUST_TOOLCHAIN_OUT_DIR) - RunXPy('install', - ['--stage', '1', '--keep-stage', '1'] + DISTRIBUTION_ARTIFACTS, - args.gcc_toolchain, args.verbose) + RunXPy('install', DISTRIBUTION_ARTIFACTS, args.gcc_toolchain, args.verbose) # Write expected `rustc --version` string to our toolchain directory. with open(RUST_SRC_VERSION_FILE_PATH) as version_file:
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index 0d7d47d..b702c9e2 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -44,6 +44,8 @@ "resource/resource_handle.h", "resource/resource_scale_factor.cc", "resource/resource_scale_factor.h", + "resource/scoped_file_writer.cc", + "resource/scoped_file_writer.h", ] deps = [
diff --git a/ui/base/resource/data_pack.cc b/ui/base/resource/data_pack.cc index fcbe2e4c..02f5367 100644 --- a/ui/base/resource/data_pack.cc +++ b/ui/base/resource/data_pack.cc
@@ -24,6 +24,7 @@ #include "build/build_config.h" #include "net/filter/gzip_header.h" #include "third_party/zlib/google/compression_utils.h" +#include "ui/base/resource/scoped_file_writer.h" // For details of the file layout, see // http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalizedstrings @@ -93,78 +94,6 @@ } } -// Convenience class to write data to a file. Usage is the following: -// 1) Create a new instance, passing a base::FilePath. -// 2) Call Write() repeatedly to write all desired data to the file. -// 3) Call valid() whenever you want to know if something failed. -// 4) The file is closed automatically on destruction. Though it is possible -// to call the Close() method before that. -// -// If an I/O error happens, a PLOG(ERROR) message will be generated, and -// a flag will be set in the writer, telling it to ignore future Write() -// requests. This allows the caller to ignore error handling until the -// very end, as in: -// -// { -// base::ScopedFileWriter writer(<some-path>); -// writer.Write(&foo, sizeof(foo)); -// writer.Write(&bar, sizeof(bar)); -// .... -// writer.Write(&zoo, sizeof(zoo)); -// if (!writer.valid()) { -// // An error happened. -// } -// } // closes the file. -// -class ScopedFileWriter { - public: - // Constructor takes a |path| parameter and tries to open the file. - // Call valid() to check if the operation was successful. - explicit ScopedFileWriter(const base::FilePath& path) - : valid_(true), file_(base::OpenFile(path, "wb")) { - if (!file_) { - PLOG(ERROR) << "Could not open pak file for writing"; - valid_ = false; - } - } - - ScopedFileWriter(const ScopedFileWriter&) = delete; - ScopedFileWriter& operator=(const ScopedFileWriter&) = delete; - - // Destructor. - ~ScopedFileWriter() { Close(); } - - // Return true if the last i/o operation was successful. - bool valid() const { return valid_; } - - // Try to write |data_size| bytes from |data| into the file, if a previous - // operation didn't already failed. - void Write(const void* data, size_t data_size) { - if (valid_ && fwrite(data, data_size, 1, file_) != 1) { - PLOG(ERROR) << "Could not write to pak file"; - valid_ = false; - } - } - - // Close the file explicitly. Return true if all previous operations - // succeeded, including the close, or false otherwise. - bool Close() { - if (file_) { - valid_ = (fclose(file_) == 0); - file_ = nullptr; - if (!valid_) { - PLOG(ERROR) << "Could not close pak file"; - } - } - return valid_; - } - - private: - bool valid_ = false; - raw_ptr<FILE> file_ = - nullptr; // base::ScopedFILE doesn't check errors on close. -}; - bool MmapHasGzipHeader(const base::MemoryMappedFile* mmap) { net::GZipHeader header; const char* header_end = nullptr;
diff --git a/ui/base/resource/data_pack.h b/ui/base/resource/data_pack.h index e4ff3b11..5e35e63d 100644 --- a/ui/base/resource/data_pack.h +++ b/ui/base/resource/data_pack.h
@@ -76,12 +76,11 @@ uint16_t resource_id) const override; TextEncodingType GetTextEncodingType() const override; ResourceScaleFactor GetResourceScaleFactor() const override; - #if DCHECK_IS_ON() // Checks to see if any resource in this DataPack already exists in the list // of resources. void CheckForDuplicateResources( - const std::vector<std::unique_ptr<ResourceHandle>>& packs); + const std::vector<std::unique_ptr<ResourceHandle>>& packs) override; #endif // Return the size of the resource and alias tables. Should only be used for
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc index 66733441..2888b12 100644 --- a/ui/base/resource/resource_bundle.cc +++ b/ui/base/resource/resource_bundle.cc
@@ -57,7 +57,7 @@ #include "ui/base/resource/resource_bundle_android.h" #endif -#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(IS_CHROMEOS) #include "ui/gfx/platform_font_skia.h" #endif @@ -387,7 +387,7 @@ ResourceScaleFactor scale_factor) { std::unique_ptr<DataPack> data_pack(new DataPack(scale_factor)); if (data_pack->LoadFromBuffer(buffer)) { - AddDataPack(std::move(data_pack)); + AddResourceHandle(std::move(data_pack)); } else { LOG(ERROR) << "Failed to load data pack from buffer"; } @@ -399,7 +399,7 @@ ResourceScaleFactor scale_factor) { auto data_pack = std::make_unique<DataPack>(scale_factor); if (data_pack->LoadFromFileRegion(std::move(file), region)) { - AddDataPack(std::move(data_pack)); + AddResourceHandle(std::move(data_pack)); } else { LOG(ERROR) << "Failed to load data pack from file." << "\nSome features may not be available."; @@ -481,7 +481,7 @@ ui::GetSupportedResourceScaleFactors()[0]); auto data_pack = std::make_unique<DataPack>(scale_factor); CHECK(data_pack->LoadFromPath(path)); - AddDataPack(std::move(data_pack)); + AddResourceHandle(std::move(data_pack)); } auto data_pack = std::make_unique<DataPack>(ui::kScaleFactorNone); @@ -676,10 +676,10 @@ } if (scale_factor != ui::k100Percent) { - for (size_t i = 0; i < data_packs_.size(); i++) { - if (data_packs_[i]->GetResourceScaleFactor() == scale_factor && - data_packs_[i]->GetStringPiece(static_cast<uint16_t>(resource_id), - &data)) { + for (const auto& resource_handle : resource_handles_) { + if (resource_handle->GetResourceScaleFactor() == scale_factor && + resource_handle->GetStringPiece(static_cast<uint16_t>(resource_id), + &data)) { if (loaded_scale_factor) *loaded_scale_factor = scale_factor; return data; @@ -687,15 +687,15 @@ } } - for (size_t i = 0; i < data_packs_.size(); i++) { - if ((data_packs_[i]->GetResourceScaleFactor() == ui::k100Percent || - data_packs_[i]->GetResourceScaleFactor() == ui::k200Percent || - data_packs_[i]->GetResourceScaleFactor() == ui::k300Percent || - data_packs_[i]->GetResourceScaleFactor() == ui::kScaleFactorNone) && - data_packs_[i]->GetStringPiece(static_cast<uint16_t>(resource_id), - &data)) { + for (const auto& resource_handle : resource_handles_) { + if ((resource_handle->GetResourceScaleFactor() == ui::k100Percent || + resource_handle->GetResourceScaleFactor() == ui::k200Percent || + resource_handle->GetResourceScaleFactor() == ui::k300Percent || + resource_handle->GetResourceScaleFactor() == ui::kScaleFactorNone) && + resource_handle->GetStringPiece(static_cast<uint16_t>(resource_id), + &data)) { if (loaded_scale_factor) - *loaded_scale_factor = data_packs_[i]->GetResourceScaleFactor(); + *loaded_scale_factor = resource_handle->GetResourceScaleFactor(); return data; } } @@ -982,27 +982,29 @@ auto data_pack = std::make_unique<DataPack>(scale_factor); if (data_pack->LoadFromPath(pack_path)) { - AddDataPack(std::move(data_pack)); + AddResourceHandle(std::move(data_pack)); } else if (!optional) { LOG(ERROR) << "Failed to load " << pack_path.value() << "\nSome features may not be available."; } } -void ResourceBundle::AddDataPack(std::unique_ptr<DataPack> data_pack) { +void ResourceBundle::AddResourceHandle( + std::unique_ptr<ResourceHandle> resource_handle) { #if DCHECK_IS_ON() - data_pack->CheckForDuplicateResources(data_packs_); + resource_handle->CheckForDuplicateResources(resource_handles_); #endif - if (GetScaleForResourceScaleFactor(data_pack->GetResourceScaleFactor()) > + if (GetScaleForResourceScaleFactor( + resource_handle->GetResourceScaleFactor()) > GetScaleForResourceScaleFactor(max_scale_factor_)) - max_scale_factor_ = data_pack->GetResourceScaleFactor(); + max_scale_factor_ = resource_handle->GetResourceScaleFactor(); - data_packs_.push_back(std::move(data_pack)); + resource_handles_.push_back(std::move(resource_handle)); } void ResourceBundle::InitDefaultFontList() { -#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(IS_CHROMEOS) // InitDefaultFontList() is called earlier than overriding the locale strings. // So we call the |GetLocalizedStringImpl()| which doesn't set the flag // |can_override_locale_string_resources_| to false. This is okay, because the @@ -1022,7 +1024,7 @@ } gfx::ImageSkia ResourceBundle::CreateImageSkia(int resource_id) { - DCHECK(!data_packs_.empty()) << "Missing call to SetResourcesDataDLL?"; + DCHECK(!resource_handles_.empty()) << "Missing call to SetResourcesDataDLL?"; #if BUILDFLAG(IS_CHROMEOS_ASH) std::string lottie_bytes_string; if (LoadLottieBytesString(resource_id, &lottie_bytes_string)) @@ -1078,7 +1080,7 @@ SkBitmap* bitmap, bool* fell_back_to_1x) const { DCHECK(fell_back_to_1x); - for (const auto& pack : data_packs_) { + for (const auto& pack : resource_handles_) { if (pack->GetResourceScaleFactor() == ui::kScaleFactorNone && LoadBitmap(*pack, resource_id, bitmap, fell_back_to_1x)) { DCHECK(!*fell_back_to_1x); @@ -1095,7 +1097,7 @@ // Unit tests may only have 1x data pack. Allow them to fallback to 1x // resources. if (is_test_resources_ && *scale_factor != ui::k100Percent) { - for (const auto& pack : data_packs_) { + for (const auto& pack : resource_handles_) { if (pack->GetResourceScaleFactor() == ui::k100Percent && LoadBitmap(*pack, resource_id, bitmap, fell_back_to_1x)) { *fell_back_to_1x = true;
diff --git a/ui/base/resource/resource_bundle.h b/ui/base/resource/resource_bundle.h index f2728d3d..7cfaa60b 100644 --- a/ui/base/resource/resource_bundle.h +++ b/ui/base/resource/resource_bundle.h
@@ -439,9 +439,9 @@ ResourceScaleFactor scale_factor, bool optional); - // Inserts |data_pack| to |data_pack_| and updates |max_scale_factor_| - // accordingly. - void AddDataPack(std::unique_ptr<DataPack> data_pack); + // Inserts |resource_handle| to |resource_handle_| and updates + // |max_scale_factor_| accordingly. + void AddResourceHandle(std::unique_ptr<ResourceHandle> resource_handle); // Try to load the locale specific strings from an external data module. // Returns the locale that is loaded or an empty string if no resources were @@ -534,7 +534,7 @@ // Handles for data sources. std::unique_ptr<ResourceHandle> locale_resources_data_; std::unique_ptr<ResourceHandle> secondary_locale_resources_data_; - std::vector<std::unique_ptr<ResourceHandle>> data_packs_; + std::vector<std::unique_ptr<ResourceHandle>> resource_handles_; // The maximum scale factor currently loaded. ResourceScaleFactor max_scale_factor_;
diff --git a/ui/base/resource/resource_bundle_mac.mm b/ui/base/resource/resource_bundle_mac.mm index 96a0879..5bf89a0 100644 --- a/ui/base/resource/resource_bundle_mac.mm +++ b/ui/base/resource/resource_bundle_mac.mm
@@ -99,9 +99,9 @@ if (image.IsEmpty()) { base::scoped_nsobject<NSImage> ns_image; - for (const auto& data_pack : data_packs_) { + for (const auto& resource_handle : resource_handles_) { scoped_refptr<base::RefCountedStaticMemory> data( - data_pack->GetStaticMemory(resource_id)); + resource_handle->GetStaticMemory(resource_id)); if (!data.get()) continue;
diff --git a/ui/base/resource/resource_bundle_unittest.cc b/ui/base/resource/resource_bundle_unittest.cc index 57e238c2..2c0143e9 100644 --- a/ui/base/resource/resource_bundle_unittest.cc +++ b/ui/base/resource/resource_bundle_unittest.cc
@@ -414,7 +414,7 @@ // Returns the number of DataPacks managed by |resource_bundle|. size_t NumDataPacksInResourceBundle(ResourceBundle* resource_bundle) { DCHECK(resource_bundle); - return resource_bundle->data_packs_.size(); + return resource_bundle->resource_handles_.size(); } private:
diff --git a/ui/base/resource/resource_bundle_win.cc b/ui/base/resource/resource_bundle_win.cc index 1db7224d..1adc8a75 100644 --- a/ui/base/resource/resource_bundle_win.cc +++ b/ui/base/resource/resource_bundle_win.cc
@@ -32,7 +32,7 @@ void ResourceBundle::LoadCommonResources() { // As a convenience, add the current resource module as a data packs. - data_packs_.push_back( + resource_handles_.push_back( std::make_unique<ResourceDataDLL>(GetCurrentResourceDLL())); LoadChromeResources();
diff --git a/ui/base/resource/resource_data_dll_win.h b/ui/base/resource/resource_data_dll_win.h index e90b65a..68d320cce 100644 --- a/ui/base/resource/resource_data_dll_win.h +++ b/ui/base/resource/resource_data_dll_win.h
@@ -29,6 +29,10 @@ uint16_t resource_id) const override; TextEncodingType GetTextEncodingType() const override; ResourceScaleFactor GetResourceScaleFactor() const override; +#if DCHECK_IS_ON() + void CheckForDuplicateResources( + const std::vector<std::unique_ptr<ResourceHandle>>& packs) override {} +#endif private: const HINSTANCE module_;
diff --git a/ui/base/resource/resource_handle.h b/ui/base/resource/resource_handle.h index d85ab14..1d06d6d 100644 --- a/ui/base/resource/resource_handle.h +++ b/ui/base/resource/resource_handle.h
@@ -48,6 +48,13 @@ // The scale of images in this resource pack relative to images in the 1x // resource pak. virtual ResourceScaleFactor GetResourceScaleFactor() const = 0; + +#if DCHECK_IS_ON() + // Checks to see if any resource in this DataPack already exists in the list + // of resources. + virtual void CheckForDuplicateResources( + const std::vector<std::unique_ptr<ResourceHandle>>& packs) = 0; +#endif }; } // namespace ui
diff --git a/ui/base/resource/scoped_file_writer.cc b/ui/base/resource/scoped_file_writer.cc new file mode 100644 index 0000000..fe8c59c91 --- /dev/null +++ b/ui/base/resource/scoped_file_writer.cc
@@ -0,0 +1,46 @@ +// 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 "ui/base/resource/scoped_file_writer.h" + +#include "base/files/file_util.h" +#include "base/logging.h" + +namespace ui { + +// ScopedFileWriter implementation. +ScopedFileWriter::ScopedFileWriter(const base::FilePath& path) + : valid_(true), file_(base::OpenFile(path, "wb")) { + if (!file_) { + PLOG(ERROR) << "Could not open pak file for writing"; + valid_ = false; + } +} + +ScopedFileWriter::~ScopedFileWriter() { + Close(); +} + +void ScopedFileWriter::Write(const void* data, size_t data_size) { + if (!data_size) + return; + + if (valid_ && fwrite(data, data_size, 1, file_) != 1) { + PLOG(ERROR) << "Could not write to pak file"; + valid_ = false; + } +} + +bool ScopedFileWriter::Close() { + if (file_) { + valid_ = (fclose(file_) == 0); + file_ = nullptr; + if (!valid_) { + PLOG(ERROR) << "Could not close pak file"; + } + } + return valid_; +} + +} // namespace ui
diff --git a/ui/base/resource/scoped_file_writer.h b/ui/base/resource/scoped_file_writer.h new file mode 100644 index 0000000..b2a0386 --- /dev/null +++ b/ui/base/resource/scoped_file_writer.h
@@ -0,0 +1,70 @@ +// 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 UI_BASE_RESOURCE_SCOPED_FILE_WRITER_H_ +#define UI_BASE_RESOURCE_SCOPED_FILE_WRITER_H_ + +#include <stdio.h> + +#include "base/files/file_path.h" +#include "base/memory/raw_ptr.h" + +namespace ui { + +// Convenience class to write data to a file. Usage is the following: +// 1) Create a new instance, passing a base::FilePath. +// 2) Call Write() repeatedly to write all desired data to the file. +// 3) Call valid() whenever you want to know if something failed. +// 4) The file is closed automatically on destruction. Though it is possible +// to call the Close() method before that. +// +// If an I/O error happens, a PLOG(ERROR) message will be generated, and +// a flag will be set in the writer, telling it to ignore future Write() +// requests. This allows the caller to ignore error handling until the +// very end, as in: +// +// { +// base::ScopedFileWriter writer(<some-path>); +// writer.Write(&foo, sizeof(foo)); +// writer.Write(&bar, sizeof(bar)); +// .... +// writer.Write(&zoo, sizeof(zoo)); +// if (!writer.valid()) { +// // An error happened. +// } +// } // closes the file. +// + +class ScopedFileWriter { + public: + // Constructor takes a |path| parameter and tries to open the file. + // Call valid() to check if the operation was successful. + explicit ScopedFileWriter(const base::FilePath& path); + + ScopedFileWriter(const ScopedFileWriter&) = delete; + ScopedFileWriter& operator=(const ScopedFileWriter&) = delete; + + // Destructor. + ~ScopedFileWriter(); + + // Return true if the last i/o operation was successful. + bool valid() const { return valid_; } + + // Try to write |data_size| bytes from |data| into the file, if a previous + // operation didn't already failed. + void Write(const void* data, size_t data_size); + + // Close the file explicitly. Return true if all previous operations + // succeeded, including the close, or false otherwise. + bool Close(); + + private: + bool valid_ = false; + raw_ptr<FILE> file_ = + nullptr; // base::ScopedFILE doesn't check errors on close. +}; + +} // namespace ui + +#endif // UI_BASE_RESOURCE_SCOPED_FILE_WRITER_H_
diff --git a/ui/chromeos/strings/network_element_localized_strings_provider.cc b/ui/chromeos/strings/network_element_localized_strings_provider.cc index 894bb74..4fbf889 100644 --- a/ui/chromeos/strings/network_element_localized_strings_provider.cc +++ b/ui/chromeos/strings/network_element_localized_strings_provider.cc
@@ -250,6 +250,7 @@ {"OncVPN-OpenVPN-Username", IDS_ONC_VPN_USERNAME}, {"OncVPN-ProviderName", IDS_ONC_VPN_THIRD_PARTY_VPN_PROVIDER_NAME}, {"OncVPN-Type", IDS_ONC_VPN_TYPE}, + {"OncVPN-Type_IKEv2", IDS_ONC_VPN_TYPE_IKEV2}, {"OncVPN-Type_L2TP_IPsec", IDS_ONC_VPN_TYPE_L2TP_IPSEC}, {"OncVPN-Type_OpenVPN", IDS_ONC_VPN_TYPE_OPENVPN}, {"OncVPN-Type_WireGuard", IDS_ONC_VPN_TYPE_WIREGUARD},
diff --git a/ui/file_manager/base/gn/PRESUBMIT.py b/ui/file_manager/base/gn/PRESUBMIT.py index c9b1c50..7b8be55 100644 --- a/ui/file_manager/base/gn/PRESUBMIT.py +++ b/ui/file_manager/base/gn/PRESUBMIT.py
@@ -49,7 +49,7 @@ validation_results.append( output_api.PresubmitError(f'{file_path}: must be a json array.')) else: - required_str_fields = ['name', 'type', 'subtype'] + required_str_fields = ['translationKey', 'type', 'subtype'] for item in json_data: for field in required_str_fields: if not isinstance(item.get(field), str):
diff --git a/ui/file_manager/base/gn/file_types.json5 b/ui/file_manager/base/gn/file_types.json5 index 708ad3b..a4c63c1 100644 --- a/ui/file_manager/base/gn/file_types.json5 +++ b/ui/file_manager/base/gn/file_types.json5
@@ -5,8 +5,8 @@ /** * Known file extension and mime type mapping. * - * 1. Fields "type/name/subtype/extensions" are mandatory, "mime/icon" are - * optional, if "mime" is missing, we won't generate a mapping for that type + * 1. Fields "type/translationKey/subtype/extensions" are mandatory, "mime/icon" + * are optional, if "mime" is missing, we won't generate a mapping for that type * in backend. * 2. The extensions must be an array where each extension starts with a dot. * 3. One extension can be mapped to multiple mime types, this is mainly used @@ -25,77 +25,77 @@ // Images { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "JPEG", "extensions": [".jpeg", ".jpg", ".jfif", ".pjpeg", ".pjp"], "mime": "image/jpeg" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "BMP", "extensions": [".bmp"], "mime": "image/bmp" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "GIF", "extensions": [".gif"], "mime": "image/gif" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "ICO", "extensions": [".ico"], "mime": "image/x-icon" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "PNG", "extensions": [".png"], "mime": "image/png" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "WebP", "extensions": [".webp"], "mime": "image/webp" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "TIFF", "extensions": [".tif", ".tiff"], "mime": "image/tiff" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "SVG", "extensions": [".svg", ".svgz"], "mime": "image/svg+xml" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "AVIF", "extensions": [".avif"], "mime": "image/avif" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "JXL", "extensions": [".jxl"], "mime": "image/jxl" }, { "type": "image", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "XBM", "extensions": [".xbm"], "mime": "image/x-xbitmap" @@ -104,7 +104,7 @@ // Raw { "type": "raw", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "ARW", "extensions": [".arw"], "icon": "image", @@ -112,7 +112,7 @@ }, { "type": "raw", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "CR2", "extensions": [".cr2"], "icon": "image", @@ -120,7 +120,7 @@ }, { "type": "raw", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "DNG", "extensions": [".dng"], "icon": "image", @@ -128,7 +128,7 @@ }, { "type": "raw", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "NEF", "extensions": [".nef"], "icon": "image", @@ -136,7 +136,7 @@ }, { "type": "raw", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "NRW", "extensions": [".nrw"], "icon": "image", @@ -144,7 +144,7 @@ }, { "type": "raw", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "ORF", "extensions": [".orf"], "icon": "image", @@ -152,7 +152,7 @@ }, { "type": "raw", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "RAF", "extensions": [".raf"], "icon": "image", @@ -160,7 +160,7 @@ }, { "type": "raw", - "name": "IMAGE_FILE_TYPE", + "translationKey": "IMAGE_FILE_TYPE", "subtype": "RW2", "extensions": [".rw2"], "icon": "image", @@ -170,63 +170,63 @@ // Video { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "3GP", "extensions": [".3gp", ".3gpp"], "mime": "video/3gpp" }, { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "AVI", "extensions": [".avi"], "mime": "video/x-msvideo" }, { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "QuickTime", "extensions": [".mov"], "mime": "video/quicktime" }, { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "MKV", "extensions": [".mkv"], "mime": "video/x-matroska" }, { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "MPEG", "extensions": [".mp4", ".m4v", ".mpg4", ".mpeg4"], "mime": "video/mp4" }, { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "MPEG", "extensions": [".mpg", ".mpeg"], "mime": "video/mpeg" }, { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "OGG", "extensions": [".ogm", ".ogv", ".ogx"], "mime": "video/ogg" }, { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "OGG", "extensions": [".ogm", ".ogv", ".ogx"], "mime": "application/ogg" }, { "type": "video", - "name": "VIDEO_FILE_TYPE", + "translationKey": "VIDEO_FILE_TYPE", "subtype": "WebM", "extensions": [".webm"], "mime": "video/webm" @@ -235,49 +235,49 @@ // Audio { "type": "audio", - "name": "AUDIO_FILE_TYPE", + "translationKey": "AUDIO_FILE_TYPE", "subtype": "AMR", "extensions": [".amr"], "mime": "audio/amr" }, { "type": "audio", - "name": "AUDIO_FILE_TYPE", + "translationKey": "AUDIO_FILE_TYPE", "subtype": "FLAC", "extensions": [".flac"], "mime": "audio/flac" }, { "type": "audio", - "name": "AUDIO_FILE_TYPE", + "translationKey": "AUDIO_FILE_TYPE", "subtype": "MP3", "extensions": [".mp3"], "mime": "audio/mpeg" }, { "type": "audio", - "name": "AUDIO_FILE_TYPE", + "translationKey": "AUDIO_FILE_TYPE", "subtype": "MPEG", "extensions": [".m4a"], "mime": "audio/mp4a-latm" }, { "type": "audio", - "name": "AUDIO_FILE_TYPE", + "translationKey": "AUDIO_FILE_TYPE", "subtype": "OGG", "extensions": [".oga", ".ogg", ".opus"], "mime": "audio/ogg" }, { "type": "audio", - "name": "AUDIO_FILE_TYPE", + "translationKey": "AUDIO_FILE_TYPE", "subtype": "WAV", "extensions": [".wav"], "mime": "audio/x-wav" }, { "type": "audio", - "name": "AUDIO_FILE_TYPE", + "translationKey": "AUDIO_FILE_TYPE", "subtype": "WEBA", "extensions": [".weba"], "mime": "audio/webm" @@ -286,7 +286,7 @@ // Text { "type": "text", - "name": "PLAIN_TEXT_FILE_TYPE", + "translationKey": "PLAIN_TEXT_FILE_TYPE", "subtype": "TXT", "extensions": [".txt"], "mime": "text/plain" @@ -295,77 +295,77 @@ // Archive { "type": "archive", - "name": "ZIP_ARCHIVE_FILE_TYPE", + "translationKey": "ZIP_ARCHIVE_FILE_TYPE", "subtype": "ZIP", "extensions": [".zip"], "mime": "application/zip" }, { "type": "archive", - "name": "RAR_ARCHIVE_FILE_TYPE", + "translationKey": "RAR_ARCHIVE_FILE_TYPE", "subtype": "RAR", "extensions": [".rar"], "mime": "application/x-rar-compressed" }, { "type": "archive", - "name": "TAR_ARCHIVE_FILE_TYPE", + "translationKey": "TAR_ARCHIVE_FILE_TYPE", "subtype": "TAR", "extensions": [".tar"], "mime": "application/x-tar" }, { "type": "archive", - "name": "TAR_BZIP2_ARCHIVE_FILE_TYPE", + "translationKey": "TAR_BZIP2_ARCHIVE_FILE_TYPE", "subtype": "TBZ2", "extensions": [".tar.bz2", ".tbz", ".tbz2"], "mime": "application/x-bzip2" }, { "type": "archive", - "name": "BZIP2_ARCHIVE_FILE_TYPE", + "translationKey": "BZIP2_ARCHIVE_FILE_TYPE", "subtype": "BZ2", "extensions": [".bz2"], "mime": "application/x-bzip2" }, { "type": "archive", - "name": "TAR_GZIP_ARCHIVE_FILE_TYPE", + "translationKey": "TAR_GZIP_ARCHIVE_FILE_TYPE", "subtype": "TGZ", "extensions": [".tar.gz", ".tgz"], "mime": "application/x-gzip" }, { "type": "archive", - "name": "GZIP_ARCHIVE_FILE_TYPE", + "translationKey": "GZIP_ARCHIVE_FILE_TYPE", "subtype": "GZ", "extensions": [".gz"], "mime": "application/x-gzip" }, { "type": "archive", - "name": "TAR_LZMA_ARCHIVE_FILE_TYPE", + "translationKey": "TAR_LZMA_ARCHIVE_FILE_TYPE", "subtype": "TLZMA", "extensions": [".tar.lzma", ".tlzma"], "mime": "application/x-lzma" }, { "type": "archive", - "name": "LZMA_ARCHIVE_FILE_TYPE", + "translationKey": "LZMA_ARCHIVE_FILE_TYPE", "subtype": "LZMA", "extensions": [".lzma"], "mime": "application/x-lzma" }, { "type": "archive", - "name": "TAR_XZ_ARCHIVE_FILE_TYPE", + "translationKey": "TAR_XZ_ARCHIVE_FILE_TYPE", "subtype": "TXZ", "extensions": [".tar.xz", ".txz"], "mime": "application/x-xz" }, { "type": "archive", - "name": "XZ_ARCHIVE_FILE_TYPE", + "translationKey": "XZ_ARCHIVE_FILE_TYPE", "subtype": "XZ", "extensions": [".xz"], "mime": "application/x-xz" @@ -375,7 +375,7 @@ { "type": "hosted", "icon": "gdoc", - "name": "GDOC_DOCUMENT_FILE_TYPE", + "translationKey": "GDOC_DOCUMENT_FILE_TYPE", "subtype": "doc", "extensions": [".gdoc"], // "mime": "application/vnd.google-apps.document" @@ -383,7 +383,7 @@ { "type": "hosted", "icon": "gsheet", - "name": "GSHEET_DOCUMENT_FILE_TYPE", + "translationKey": "GSHEET_DOCUMENT_FILE_TYPE", "subtype": "sheet", "extensions": [".gsheet"], // "mime": "application/vnd.google-apps.spreadsheet" @@ -391,7 +391,7 @@ { "type": "hosted", "icon": "gslides", - "name": "GSLIDES_DOCUMENT_FILE_TYPE", + "translationKey": "GSLIDES_DOCUMENT_FILE_TYPE", "subtype": "slides", "extensions": [".gslides"], // "mime": "application/vnd.google-apps.presentation" @@ -399,7 +399,7 @@ { "type": "hosted", "icon": "gdraw", - "name": "GDRAW_DOCUMENT_FILE_TYPE", + "translationKey": "GDRAW_DOCUMENT_FILE_TYPE", "subtype": "draw", "extensions": [".gdraw"], // "mime": "application/vnd.google-apps.drawing" @@ -407,7 +407,7 @@ { "type": "hosted", "icon": "gtable", - "name": "GTABLE_DOCUMENT_FILE_TYPE", + "translationKey": "GTABLE_DOCUMENT_FILE_TYPE", "subtype": "table", "extensions": [".gtable"], // "mime": "application/vnd.google-apps.fusiontable" @@ -415,7 +415,7 @@ { "type": "hosted", "icon": "glink", - "name": "GLINK_DOCUMENT_FILE_TYPE", + "translationKey": "GLINK_DOCUMENT_FILE_TYPE", "subtype": "glink", "extensions": [".glink"], // "mime": "application/vnd.google-apps.shortcut" @@ -423,7 +423,7 @@ { "type": "hosted", "icon": "gform", - "name": "GFORM_DOCUMENT_FILE_TYPE", + "translationKey": "GFORM_DOCUMENT_FILE_TYPE", "subtype": "form", "extensions": [".gform"], // "mime": "application/vnd.google-apps.form" @@ -431,7 +431,7 @@ { "type": "hosted", "icon": "gmap", - "name": "GMAP_DOCUMENT_FILE_TYPE", + "translationKey": "GMAP_DOCUMENT_FILE_TYPE", "subtype": "map", "extensions": [".gmap"], // "mime": "application/vnd.google-apps.map" @@ -439,7 +439,7 @@ { "type": "hosted", "icon": "gsite", - "name": "GSITE_DOCUMENT_FILE_TYPE", + "translationKey": "GSITE_DOCUMENT_FILE_TYPE", "subtype": "site", "extensions": [".gsite"], // "mime": "application/vnd.google-apps.site" @@ -449,14 +449,14 @@ { "type": "document", "icon": "pdf", - "name": "PDF_DOCUMENT_FILE_TYPE", + "translationKey": "PDF_DOCUMENT_FILE_TYPE", "subtype": "PDF", "extensions": [".pdf"], "mime": "application/pdf" }, { "type": "document", - "name": "HTML_DOCUMENT_FILE_TYPE", + "translationKey": "HTML_DOCUMENT_FILE_TYPE", "subtype": "HTML", "extensions": [".htm", ".html", ".mht", ".mhtml", ".shtml", ".xht", ".xhtml"], "mime": "text/html" @@ -464,7 +464,7 @@ { "type": "document", "icon": "word", - "name": "WORD_DOCUMENT_FILE_TYPE", + "translationKey": "WORD_DOCUMENT_FILE_TYPE", "subtype": "Word", "extensions": [".doc"], "mime": "application/msword" @@ -472,7 +472,7 @@ { "type": "document", "icon": "word", - "name": "WORD_DOCUMENT_FILE_TYPE", + "translationKey": "WORD_DOCUMENT_FILE_TYPE", "subtype": "Word", "extensions": [".docx"], "mime": "application/vnd.openxmlformats-officedocument.wordprocessingml.document" @@ -480,7 +480,7 @@ { "type": "document", "icon": "ppt", - "name": "POWERPOINT_PRESENTATION_FILE_TYPE", + "translationKey": "POWERPOINT_PRESENTATION_FILE_TYPE", "subtype": "PPT", "extensions": [".ppt"], "mime": "application/vnd.ms-powerpoint" @@ -488,7 +488,7 @@ { "type": "document", "icon": "ppt", - "name": "POWERPOINT_PRESENTATION_FILE_TYPE", + "translationKey": "POWERPOINT_PRESENTATION_FILE_TYPE", "subtype": "PPT", "extensions": [".pptx"], "mime": "application/vnd.openxmlformats-officedocument.presentationml.presentation" @@ -496,7 +496,7 @@ { "type": "document", "icon": "excel", - "name": "EXCEL_FILE_TYPE", + "translationKey": "EXCEL_FILE_TYPE", "subtype": "Excel", "extensions": [".xls"], "mime": "application/vnd.ms-excel" @@ -504,7 +504,7 @@ { "type": "document", "icon": "excel", - "name": "EXCEL_FILE_TYPE", + "translationKey": "EXCEL_FILE_TYPE", "subtype": "Excel", "extensions": [".xlsx"], "mime": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" @@ -512,7 +512,7 @@ { "type": "archive", "icon": "tini", - "name": "TINI_FILE_TYPE", + "translationKey": "TINI_FILE_TYPE", "subtype": "TGZ", "extensions": [".tini"] }
diff --git a/ui/file_manager/base/gn/file_types_data.js.jinja b/ui/file_manager/base/gn/file_types_data.js.jinja index f3f6d81..0e62984a 100644 --- a/ui/file_manager/base/gn/file_types_data.js.jinja +++ b/ui/file_manager/base/gn/file_types_data.js.jinja
@@ -11,7 +11,7 @@ {%- raw %} /** * @typedef {{ - * name: !string, + * translationKey: !string, * type: !string, * icon: (string|undefined), * subtype: !string,
diff --git a/ui/file_manager/file_manager/common/js/file_type.js b/ui/file_manager/file_manager/common/js/file_type.js index 59882e2..dcb771762 100644 --- a/ui/file_manager/file_manager/common/js/file_type.js +++ b/ui/file_manager/file_manager/common/js/file_type.js
@@ -23,7 +23,7 @@ * @const */ FileType.DIRECTORY = { - name: 'FOLDER', + translationKey: 'FOLDER', type: '.folder', icon: 'folder', subtype: '' @@ -35,7 +35,7 @@ * @const */ FileType.PLACEHOLDER = { - name: 'NO_EXTENSION_FILE_TYPE', + translationKey: 'NO_EXTENSION_FILE_TYPE', type: 'UNKNOWN', icon: '', subtype: '' @@ -109,7 +109,7 @@ // subtype is the extension excluding the first dot. return { - name: 'GENERIC_FILE_TYPE', + translationKey: 'GENERIC_FILE_TYPE', type: 'UNKNOWN', subtype: extension.substr(1).toUpperCase(), icon: '' @@ -130,10 +130,10 @@ if (/** @type {VolumeEntry}*/ (entry).volumeInfo && /** @type {VolumeEntry}*/ (entry).volumeInfo.diskFileSystemType) { return { - name: '', + translationKey: '', type: 'partition', - subtype: - assert(/** @type {VolumeEntry}*/ (entry).volumeInfo.diskFileSystemType), + subtype: assert( + /** @type {VolumeEntry}*/ (entry).volumeInfo.diskFileSystemType), icon: '', }; }
diff --git a/ui/file_manager/file_manager/foreground/js/file_list_model.js b/ui/file_manager/file_manager/foreground/js/file_list_model.js index 3d88190..f82ee677 100644 --- a/ui/file_manager/file_manager/foreground/js/file_list_model.js +++ b/ui/file_manager/file_manager/foreground/js/file_list_model.js
@@ -92,9 +92,9 @@ return fileType.subtype; } if (fileType.subtype) { - return strf(fileType.name, fileType.subtype); + return strf(fileType.translationKey, fileType.subtype); } else { - return str(fileType.name); + return str(fileType.translationKey); } }
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js index 45957533..eb62496 100644 --- a/ui/file_manager/file_manager/foreground/js/task_controller.js +++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -340,6 +340,9 @@ * @private */ onSelectionChanged_() { + if (window.IN_TEST) { + this.ui_.taskMenuButton.removeAttribute('get-tasks-completed'); + } const selection = this.selectionHandler_.selection; // Caller of update context menu task items. // FileSelectionHandler.EventType.CHANGE @@ -369,6 +372,10 @@ .then(tasks => { tasks.display(this.ui_.taskMenuButton); this.updateContextMenuTaskItems_(tasks.getOpenTaskItems()); + if (window.IN_TEST) { + this.ui_.taskMenuButton.toggleAttribute( + 'get-tasks-completed', true); + } }) .catch(error => { if (error) { @@ -377,6 +384,9 @@ }); } else { this.ui_.taskMenuButton.hidden = true; + if (window.IN_TEST) { + this.ui_.taskMenuButton.toggleAttribute('get-tasks-completed', true); + } } }
diff --git a/ui/file_manager/integration_tests/file_manager/guest_os.js b/ui/file_manager/integration_tests/file_manager/guest_os.js index 4ca972aa..1fc09761 100644 --- a/ui/file_manager/integration_tests/file_manager/guest_os.js +++ b/ui/file_manager/integration_tests/file_manager/guest_os.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {ENTRIES, RootPath} from '../test_util.js'; +import {ENTRIES, RootPath, sendTestMessage} from '../test_util.js'; import {testcase} from '../testcase.js'; import {IGNORE_APP_ERRORS, remoteCall, setupAndWaitUntilReady} from './background.js'; @@ -12,6 +12,12 @@ * files app integration is disabled. */ testcase.notListedWithoutFlag = async () => { + // Prepopulate the list with a bunch of guests. + const names = ['Electra', 'Etcetera', 'Jemima']; + for (const name of names) { + await sendTestMessage({name: 'registerMountableGuest', displayName: name}); + } + // Open the files app. const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.hello], []); @@ -25,14 +31,19 @@ * Tests that Guest OS entries show up in the sidebar at files app launch. */ testcase.fakesListed = async () => { + // Prepopulate the list with a bunch of guests. + const names = ['Electra', 'Etcetera', 'Jemima']; + for (const name of names) { + await sendTestMessage({name: 'registerMountableGuest', displayName: name}); + } + // Open the files app. const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.hello], []); - // Browsertest base registers two mock Guest OSs, check that they're both - // listed. + // Check that our guests are listed. const query = '#directory-tree [root-type-icon=guest_os]'; - await remoteCall.waitForElementsCount(appId, [query], 2); + await remoteCall.waitForElementsCount(appId, [query], names.length); }; /** @@ -42,21 +53,23 @@ * Need to fix that, then update this test to check for the expected error. */ testcase.mountGuestError = async () => { + const guestName = 'Jellylorum'; + // Start off with one guest. + const id = await sendTestMessage( + {name: 'registerMountableGuest', displayName: guestName}); // Open the files app. const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.hello], []); - // Browsertest base registers some mock Guest OSs, wait for one to appear and - // click it. + // Wait for our guest to appear and click it. const query = '#directory-tree [root-type-icon=guest_os]'; await remoteCall.waitAndClickElement(appId, query); - // Check that the Guest is selected. Guests are listed alphabetically so - // Electra should be first. + // Check that the Guest is selected. // TODO(crbug/1293229): It looks like scan errors are no longer surfaced in // the UI, I remember they used to be? Need to figure out surfacing errors and // then we check that instead. - await remoteCall.waitForElement(appId, '#breadcrumbs[path=Electra]'); + await remoteCall.waitForElement(appId, `#breadcrumbs[path=${guestName}]`); // We expect there to be an error, from the mount failure. return IGNORE_APP_ERRORS;
diff --git a/ui/file_manager/integration_tests/file_manager/office.js b/ui/file_manager/integration_tests/file_manager/office.js index 11de483..31e6409c 100644 --- a/ui/file_manager/integration_tests/file_manager/office.js +++ b/ui/file_manager/integration_tests/file_manager/office.js
@@ -9,31 +9,46 @@ import {FILE_MANAGER_EXTENSIONS_ID, FILE_MANAGER_SWA_APP_ID, FILE_SWA_BASE_URL} from './test_data.js'; /** - * Waits until a task has been executed, and returns the executed task's - * descriptor. + * Returns Web Drive Office's task descriptor. * - * @param {string} appId Window ID. * @return {!chrome.fileManagerPrivate.FileTaskDescriptor} */ -async function getExecutedTask(appId) { +function webDriveOfficeDescriptor() { + const filesAppId = remoteCall.isSwaMode() ? FILE_MANAGER_SWA_APP_ID : + FILE_MANAGER_EXTENSIONS_ID; + const filesTaskType = remoteCall.isSwaMode() ? 'web' : 'app'; + const actionIdPrefix = remoteCall.isSwaMode() ? FILE_SWA_BASE_URL + '?' : ''; + const actionId = `${actionIdPrefix}open-web-drive-office`; + + return {appId: filesAppId, taskType: filesTaskType, actionId: actionId}; +} + +/** + * Waits for the expected number of tasks executions, and returns the descriptor + * of the last executed task. + * + * @param {string} appId Window ID. + * @param {number} expectedCount + * @return {!chrome.fileManagerPrivate.FileTaskDescriptor} + */ +async function getExecutedTask(appId, expectedCount = 1) { const caller = getCaller(); // Wait until a task has been executed. await repeatUntil(async () => { const executeTaskCount = await remoteCall.callRemoteTestUtil( 'staticFakeCounter', appId, ['chrome.fileManagerPrivate.executeTask']); - if (executeTaskCount == 1) { + if (executeTaskCount == expectedCount) { return true; } - // Expect no executedTasks calls. - chrome.test.assertFalse(!!executeTaskCount); + chrome.test.assertTrue(executeTaskCount < expectedCount); return pending(caller, 'Waiting for a task to execute'); }); - // Arguments for the only execution of executeTask(). + // Arguments provided for the last call to executeTask(). const executeTaskArgs = (await remoteCall.callRemoteTestUtil( 'staticFakeCalledArgs', appId, - ['chrome.fileManagerPrivate.executeTask']))[0]; + ['chrome.fileManagerPrivate.executeTask']))[expectedCount - 1]; // The task descriptor is the first argument. return executeTaskArgs[0]; @@ -42,21 +57,21 @@ testcase.openOfficeFile = async () => { await sendTestMessage({ name: 'expectFileTask', - fileNames: [ENTRIES.smallDocx.targetPath], + fileNames: [ENTRIES.smallDocxHosted.targetPath], openType: 'launch' }); - const appId = - await setupAndWaitUntilReady(RootPath.DRIVE, [], [ENTRIES.smallDocx]); + const appId = await setupAndWaitUntilReady( + RootPath.DRIVE, [], [ENTRIES.smallDocxHosted]); // Open file. - chrome.test.assertTrue( - await remoteCall.callRemoteTestUtil('openFile', appId, ['text.docx'])); + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'openFile', appId, [ENTRIES.smallDocxHosted.nameText])); // Check that the Office file's alternate URL has been opened in a browser // window. await remoteCall.waitForActiveBrowserTabUrl( - 'https://file_alternate_link/text.docx'); + ENTRIES.smallDocxHosted.alternateUrl); }; testcase.openOfficeFromMyFiles = async () => { @@ -71,16 +86,14 @@ await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]); // Open file. - chrome.test.assertTrue( - await remoteCall.callRemoteTestUtil('openFile', appId, ['text.docx'])); + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'openFile', appId, [ENTRIES.smallDocx.nameText])); // The Web Drive Office task should not be available: another // task should have been executed instead (QuickOffice or generic task). const taskDescriptor = await getExecutedTask(appId); - const webDriveOfficeActionId = - (remoteCall.isSwaMode() ? FILE_SWA_BASE_URL + '?' : '') + - 'open-web-drive-office'; - chrome.test.assertFalse(taskDescriptor.actionId == webDriveOfficeActionId); + chrome.test.assertFalse( + taskDescriptor.actionId == webDriveOfficeDescriptor().actionId); // Remove fakes. const removedCount = await remoteCall.callRemoteTestUtil( @@ -89,6 +102,109 @@ }; testcase.openOfficeFromDrive = async () => { + const appId = await setupAndWaitUntilReady( + RootPath.DRIVE, [], [ENTRIES.smallDocxHosted]); + + // Fake chrome.fileManagerPrivate.executeTask to return + // chrome.fileManagerPrivate.TaskResult.OPENED. + const fakeData = { + 'chrome.fileManagerPrivate.executeTask': ['static_fake', ['opened']], + }; + await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]); + + // Open file. + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'openFile', appId, [ENTRIES.smallDocxHosted.nameText])); + + // The Web Drive Office task should be available and executed. + const taskDescriptor = await getExecutedTask(appId); + chrome.test.assertEq(webDriveOfficeDescriptor(), taskDescriptor); + + // Remove fakes. + const removedCount = await remoteCall.callRemoteTestUtil( + 'removeAllForegroundFakes', appId, []); + chrome.test.assertEq(1, removedCount); +}; + +testcase.openMultipleOfficeFromDrive = async () => { + const appId = await setupAndWaitUntilReady(RootPath.DRIVE, [], [ + ENTRIES.smallDocx, ENTRIES.smallDocxHosted, ENTRIES.smallXlsxPinned, + ENTRIES.smallPptxPinned + ]); + + const enterKey = ['#file-list', 'Enter', false, false, false]; + + // Fake chrome.fileManagerPrivate.executeTask to return + // chrome.fileManagerPrivate.TaskResult.OPENED. + const fakeData = { + 'chrome.fileManagerPrivate.executeTask': ['static_fake', ['opened']], + }; + await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]); + + // Select all the files. + const ctrlA = ['#file-list', 'a', true, false, false]; + await remoteCall.fakeKeyDown(appId, ...ctrlA); + + // Check: the file-list should show 4 selected files. + const caller = getCaller(); + await repeatUntil(async () => { + const element = await remoteCall.waitForElement( + appId, '.check-select #files-selected-label'); + if (element.text !== '4 files selected') { + return pending( + caller, `Waiting for files to be selected, got: ${element.text}`); + } + }); + + let taskDescriptor; + let expectedExecuteTaskCount = 0; + + // Wait for the tasks calculation to complete, updating the "Open" button. + await remoteCall.waitForElement(appId, '#tasks[get-tasks-completed]'); + + // Check whether the open button is available. + const openButton = await remoteCall.waitForElement(appId, '#tasks'); + + // Check that the Web Drive Office task is not available: one of the + // selected entries doesn't have a "docs.google.com" alternate URL. The "Open" + // button will be hidden if there is no other task to execute the selected + // office files, this happens to non-branded bots because QuickOffice is only + // available for branded builds. + if (!openButton.hidden) { + // Press Enter to execute it. + remoteCall.fakeKeyDown(appId, ...enterKey); + + // check that it's not the Web Drive Office task. + expectedExecuteTaskCount++; + taskDescriptor = await getExecutedTask(appId, expectedExecuteTaskCount); + chrome.test.assertFalse( + taskDescriptor.actionId == webDriveOfficeDescriptor().actionId); + } + + // Unselect the file that doesn't have an alternate URL. + await remoteCall.waitAndClickElement( + appId, `#file-list [file-name="${ENTRIES.smallDocx.nameText}"]`, + {ctrl: true}); + + // Wait for the file to be unselected. + await remoteCall.waitForElement( + appId, `[file-name="${ENTRIES.smallDocx.nameText}"]:not([selected])`); + + // Press Enter. + remoteCall.fakeKeyDown(appId, ...enterKey); + + // The Web Drive Office task should be available and executed. + expectedExecuteTaskCount++; + taskDescriptor = await getExecutedTask(appId, expectedExecuteTaskCount); + chrome.test.assertEq(webDriveOfficeDescriptor(), taskDescriptor); + + // Remove fakes. + const removedCount = await remoteCall.callRemoteTestUtil( + 'removeAllForegroundFakes', appId, []); + chrome.test.assertEq(1, removedCount); +}; + +testcase.openOfficeFromDriveNotSynced = async () => { const appId = await setupAndWaitUntilReady(RootPath.DRIVE, [], [ENTRIES.smallDocx]); @@ -100,23 +216,16 @@ await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]); // Open file. - chrome.test.assertTrue( - await remoteCall.callRemoteTestUtil('openFile', appId, ['text.docx'])); + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'openFile', appId, [ENTRIES.smallDocx.nameText])); - const filesAppId = remoteCall.isSwaMode() ? FILE_MANAGER_SWA_APP_ID : - FILE_MANAGER_EXTENSIONS_ID; - const filesTaskType = remoteCall.isSwaMode() ? 'web' : 'app'; - const actionId = (remoteCall.isSwaMode() ? FILE_SWA_BASE_URL + '?' : '') + - 'open-web-drive-office'; - - // The Web Drive Office task should be available and executed. - const expectedDescriptor = { - appId: filesAppId, - taskType: filesTaskType, - actionId: actionId - }; + // When the office file doesn't have an expected alternate URL + // (docs.google.com host), the Web Drive Office task should not be available: + // another task should have been executed instead (QuickOffice or generic + // task). const taskDescriptor = await getExecutedTask(appId); - chrome.test.assertEq(expectedDescriptor, taskDescriptor); + chrome.test.assertFalse( + taskDescriptor.actionId == webDriveOfficeDescriptor().actionId); // Remove fakes. const removedCount = await remoteCall.callRemoteTestUtil( @@ -136,16 +245,14 @@ await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]); // Open file. - chrome.test.assertTrue( - await remoteCall.callRemoteTestUtil('openFile', appId, ['pinned.docx'])); + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'openFile', appId, [ENTRIES.smallDocxPinned.nameText])); // When offline, the Web Drive Office task should not be available: another // task should have been executed instead (QuickOffice or generic task). const taskDescriptor = await getExecutedTask(appId); - const webDriveOfficeActionId = - (remoteCall.isSwaMode() ? FILE_SWA_BASE_URL + '?' : '') + - 'open-web-drive-office'; - chrome.test.assertFalse(taskDescriptor.actionId == webDriveOfficeActionId); + chrome.test.assertFalse( + taskDescriptor.actionId == webDriveOfficeDescriptor().actionId); // Remove fakes. const removedCount = await remoteCall.callRemoteTestUtil(
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js index bbab5e0..36a6fb5 100644 --- a/ui/file_manager/integration_tests/test_util.js +++ b/ui/file_manager/integration_tests/test_util.js
@@ -382,6 +382,10 @@ * folderFeature: Folder features of this file. Defaults to all features * disabled. * + * pinned: Drive pinned status of this file. Defaults to false. + * + * alternateUrl: File's Drive alternate URL. Defaults to an empty string. + * * @typedef {{ * type: EntryType, * sourceFileName: (string|undefined), @@ -396,6 +400,8 @@ * typeText: (string|undefined), * capabilities: (TestEntryCapabilities|undefined), * folderFeature: (TestEntryFolderFeature|undefined), + * pinned: (boolean|undefined), + * alternateUrl: (string|undefined), * }} */ export let TestEntryInfoOptions; @@ -427,6 +433,7 @@ this.capabilities = options.capabilities; this.folderFeature = options.folderFeature; this.pinned = !!options.pinned; + this.alternateUrl = options.alternateUrl || ''; Object.freeze(this); } @@ -821,6 +828,20 @@ typeText: 'Office document', }), + smallDocxHosted: new TestEntryInfo({ + type: EntryType.FILE, + sourceFileName: 'text.docx', + targetPath: 'synced.docx', + mimeType: `application/vnd.openxmlformats-officedocument.wordprocessingml\ +.document`, + lastModifiedTime: 'Jan 4, 2019, 10:57 AM', + nameText: 'synced.docx', + sizeText: '8.7 KB', + typeText: 'Office document', + alternateUrl: 'https://docs.google.com/document/d/smalldocxid?rtpof=true&\ +usp=drive_fs', + }), + smallDocxPinned: new TestEntryInfo({ type: EntryType.FILE, sourceFileName: 'text.docx', @@ -832,6 +853,38 @@ sizeText: '8.7 KB', typeText: 'Office document', pinned: true, + alternateUrl: 'https://docs.google.com/document/d/pinneddocxid?rtpof=true&\ +usp=drive_fs', + }), + + smallXlsxPinned: new TestEntryInfo({ + type: EntryType.FILE, + sourceFileName: 'sheet.xlsx', + targetPath: 'pinned.xlsx', + mimeType: `application/vnd.openxmlformats-officedocument.spreadsheetml\ +.sheet`, + lastModifiedTime: 'Jan 10, 2020, 11:58 PM', + nameText: 'pinned.xlsx', + sizeText: '5.7 KB', + typeText: 'Office spreadsheet', + pinned: true, + alternateUrl: 'https://docs.google.com/document/d/pinnedxlsxid?rtpof=true&\ +usp=drive_fs', + }), + + smallPptxPinned: new TestEntryInfo({ + type: EntryType.FILE, + sourceFileName: 'presentation.pptx', + targetPath: 'pinned.pptx', + mimeType: `application/vnd.openxmlformats-officedocument.presentationml\ +.presentation`, + lastModifiedTime: 'Jan 14, 2020, 10:15 AM', + nameText: 'pinned.pptx', + sizeText: '35.2 KB', + typeText: 'Office document', + pinned: true, + alternateUrl: 'https://docs.google.com/document/d/pinnedpptxid?rtpof=true&\ +usp=drive_fs', }), pinned: new TestEntryInfo({
diff --git a/ui/gfx/interpolated_transform.cc b/ui/gfx/interpolated_transform.cc index 6277fa4..e92f587 100644 --- a/ui/gfx/interpolated_transform.cc +++ b/ui/gfx/interpolated_transform.cc
@@ -30,7 +30,6 @@ return false; gfx::Transform transform; - skia::Matrix44& m = transform.matrix(); float degrees_by_ninety = degrees / 90.0f; int n = base::ClampRound(degrees_by_ninety); @@ -40,19 +39,21 @@ n += 4; // n should now be in the range [0, 3] + // clang-format off if (n == 1) { - m.set3x3( 0, 1, 0, - -1, 0, 0, - 0, 0, 1); + transform.matrix().set3x3( 0, 1, 0, + -1, 0, 0, + 0, 0, 1); } else if (n == 2) { - m.set3x3(-1, 0, 0, - 0, -1, 0, - 0, 0, 1); + transform.matrix().set3x3(-1, 0, 0, + 0, -1, 0, + 0, 0, 1); } else if (n == 3) { - m.set3x3( 0, -1, 0, - 1, 0, 0, - 0, 0, 1); + transform.matrix().set3x3( 0, -1, 0, + 1, 0, 0, + 0, 0, 1); } + // clang-format on *rotation = transform; return true;
diff --git a/ui/gfx/interpolated_transform_unittest.cc b/ui/gfx/interpolated_transform_unittest.cc index 347b624..89e74e9 100644 --- a/ui/gfx/interpolated_transform_unittest.cc +++ b/ui/gfx/interpolated_transform_unittest.cc
@@ -176,11 +176,10 @@ std::unique_ptr<ui::InterpolatedTransform> screen_rotation( GetScreenRotation(degrees, reversed)); gfx::Transform interpolated = screen_rotation->Interpolate(1.0f); - skia::Matrix44& m = interpolated.matrix(); // Upper-left 3x3 matrix should all be 0, 1 or -1. for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - float entry = m.rc(row, col); + float entry = interpolated.matrix().rc(row, col); EXPECT_TRUE(entry == 0 || entry == 1 || entry == -1); } } @@ -226,11 +225,10 @@ TEST(InterpolatedTransformTest, MaximizeEndsCleanly) { std::unique_ptr<ui::InterpolatedTransform> maximize(GetMaximize()); gfx::Transform interpolated = maximize->Interpolate(1.0f); - skia::Matrix44& m = interpolated.matrix(); // Upper-left 3x3 matrix should all be 0, 1 or -1. for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { - float entry = m.rc(row, col); + float entry = interpolated.matrix().rc(row, col); EXPECT_TRUE(entry == 0 || entry == 1 || entry == -1); } }
diff --git a/ui/ozone/platform/drm/common/drm_util_unittest.cc b/ui/ozone/platform/drm/common/drm_util_unittest.cc index 7a40ed64..0edb8f69 100644 --- a/ui/ozone/platform/drm/common/drm_util_unittest.cc +++ b/ui/ozone/platform/drm/common/drm_util_unittest.cc
@@ -9,7 +9,6 @@ #include <map> -#include "skia/ext/skia_matrix_44.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "ui/display/types/display_snapshot.h"
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index 22c8759..a9d3bc9 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -674,6 +674,9 @@ <message name="IDS_APP_F1_KEY" desc="F1 key"> F1 </message> + <message name="IDS_APP_F5_KEY" desc="F5 key"> + F5 + </message> <message name="IDS_APP_F6_KEY" is_accessibility_with_no_ui="true" desc="F6 key"> F6 </message> @@ -723,6 +726,9 @@ </message> </if> <if expr="chromeos"> + <message name="IDS_APP_META_KEY" desc="External Meta key (Search key on ChromeOS keyboards, Windows key on Windows keyboards, and Command key on Mac keyboards)"> + Meta + </message> <message name="IDS_APP_FULLSCREEN_KEY" desc="This refers to the 'Fullscreen' media key on certain keyboards."> Fullscreen </message>
diff --git a/ui/strings/ui_strings_grd/IDS_APP_F5_KEY.png.sha1 b/ui/strings/ui_strings_grd/IDS_APP_F5_KEY.png.sha1 new file mode 100644 index 0000000..87a5b281 --- /dev/null +++ b/ui/strings/ui_strings_grd/IDS_APP_F5_KEY.png.sha1
@@ -0,0 +1 @@ +acfa0af623fc7b62fcc699df8f2c7bcc58b38206 \ No newline at end of file
diff --git a/ui/strings/ui_strings_grd/IDS_APP_META_KEY.png.sha1 b/ui/strings/ui_strings_grd/IDS_APP_META_KEY.png.sha1 new file mode 100644 index 0000000..87a5b281 --- /dev/null +++ b/ui/strings/ui_strings_grd/IDS_APP_META_KEY.png.sha1
@@ -0,0 +1 @@ +acfa0af623fc7b62fcc699df8f2c7bcc58b38206 \ No newline at end of file
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.cc b/ui/views/accessibility/ax_view_obj_wrapper.cc index b56b7dd..72efa37 100644 --- a/ui/views/accessibility/ax_view_obj_wrapper.cc +++ b/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -69,13 +69,15 @@ if (view_accessibility.GetNextFocus()) { out_node_data->AddIntAttribute( ax::mojom::IntAttribute::kNextFocusId, - aura_obj_cache_->GetID(view_accessibility.GetNextFocus())); + aura_obj_cache_->GetOrCreate(view_accessibility.GetNextFocus()) + ->GetUniqueId()); } if (view_accessibility.GetPreviousFocus()) { out_node_data->AddIntAttribute( ax::mojom::IntAttribute::kPreviousFocusId, - aura_obj_cache_->GetID(view_accessibility.GetPreviousFocus())); + aura_obj_cache_->GetOrCreate(view_accessibility.GetPreviousFocus()) + ->GetUniqueId()); } }
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc index e921c7b..73a968a3 100644 --- a/ui/views/accessibility/view_accessibility.cc +++ b/ui/views/accessibility/view_accessibility.cc
@@ -442,19 +442,25 @@ } void ViewAccessibility::OverrideNextFocus(Widget* widget) { - next_focus_ = widget; + if (widget) + next_focus_ = widget->GetWeakPtr(); + else + next_focus_ = nullptr; } void ViewAccessibility::OverridePreviousFocus(Widget* widget) { - previous_focus_ = widget; + if (widget) + previous_focus_ = widget->GetWeakPtr(); + else + previous_focus_ = nullptr; } Widget* ViewAccessibility::GetNextFocus() const { - return next_focus_; + return next_focus_.get(); } Widget* ViewAccessibility::GetPreviousFocus() const { - return previous_focus_; + return previous_focus_.get(); } void ViewAccessibility::OverrideChildTreeID(ui::AXTreeID tree_id) {
diff --git a/ui/views/accessibility/view_accessibility.h b/ui/views/accessibility/view_accessibility.h index ca120a0..4028a007 100644 --- a/ui/views/accessibility/view_accessibility.h +++ b/ui/views/accessibility/view_accessibility.h
@@ -276,8 +276,8 @@ // Used by the Views system to help some assistive technologies, such as // screen readers, transition focus from one widget to another. - raw_ptr<Widget> next_focus_ = nullptr; - raw_ptr<Widget> previous_focus_ = nullptr; + base::WeakPtr<Widget> next_focus_ = nullptr; + base::WeakPtr<Widget> previous_focus_ = nullptr; // This view's child tree id. absl::optional<ui::AXTreeID> child_tree_id_;
diff --git a/ui/webui/resources/cr_components/app_management/BUILD.gn b/ui/webui/resources/cr_components/app_management/BUILD.gn index a1fd6d8fc..47f82302 100644 --- a/ui/webui/resources/cr_components/app_management/BUILD.gn +++ b/ui/webui/resources/cr_components/app_management/BUILD.gn
@@ -44,6 +44,7 @@ public_deps = [ "//components/services/app_service/public/mojom", "//mojo/public/mojom/base", + "//url/mojom:url_mojom_gurl", ] }
diff --git a/ui/webui/resources/cr_components/app_management/app_management.mojom b/ui/webui/resources/cr_components/app_management/app_management.mojom index bf4e9c2..905d960 100644 --- a/ui/webui/resources/cr_components/app_management/app_management.mojom +++ b/ui/webui/resources/cr_components/app_management/app_management.mojom
@@ -5,6 +5,7 @@ module app_management.mojom; import "components/services/app_service/public/mojom/types.mojom"; +import "url/mojom/url.mojom"; struct App { string id; @@ -22,6 +23,7 @@ string? size; map<apps.mojom.PermissionType, apps.mojom.Permission> permissions; apps.mojom.InstallReason install_reason; + apps.mojom.InstallSource install_source; bool hide_more_settings; bool hide_pin_to_shelf; bool is_preferred_app; @@ -85,5 +87,11 @@ struct FileHandlingState { bool enabled; bool is_managed; + // A list of all file type associations, such as "MD, TXT, CSV". string user_visible_types; + // A label that displays a possibly truncated list of file type associations + // and may be linkified to display overflow. + string user_visible_types_label; + // The URL for the learn more link. If empty, the link defaults to "#". + url.mojom.Url learn_more_url; };
diff --git a/ui/webui/resources/cr_components/app_management/constants.ts b/ui/webui/resources/cr_components/app_management/constants.ts index ffa97dd9..ae16d108 100644 --- a/ui/webui/resources/cr_components/app_management/constants.ts +++ b/ui/webui/resources/cr_components/app_management/constants.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -export {AppType, InstallReason, OptionalBool, RunOnOsLogin, RunOnOsLoginMode, WindowMode} from './types.mojom-webui.js'; +export {AppType, InstallReason, InstallSource, OptionalBool, RunOnOsLogin, RunOnOsLoginMode, WindowMode} from './types.mojom-webui.js'; /** * The number of apps displayed in app list in the main view before expanding.
diff --git a/ui/webui/resources/cr_components/app_management/file_handling_item.html b/ui/webui/resources/cr_components/app_management/file_handling_item.html index 9cd2a6d..a4dac01 100644 --- a/ui/webui/resources/cr_components/app_management/file_handling_item.html +++ b/ui/webui/resources/cr_components/app_management/file_handling_item.html
@@ -1,6 +1,29 @@ -<app-management-toggle-row - id="toggle-row" - label="[[fileHandlingHeader]]" - managed="[[isManaged_(app)]]" - value="[[getValue_(app)]]"> -</app-management-toggle-row> +<style include="app-management-shared-css"> + :host(:not([available_])) { + display: none; + } + + #file-handling-item { + margin: var(--row-item-vertical-padding) 0; + width: 100%; + } + + #toggle-row:not([disabled_]) { + cursor: pointer; + } +</style> + +<div id="file-handling-item"> + <app-management-toggle-row + id="toggle-row" + label="[[fileHandlingHeader]]" + managed="[[isManaged_(app)]]" + value="[[getValue_(app)]]"> + </app-management-toggle-row> + <p> + <localized-link localized-string="[[userVisibleTypesLabel_(app)]]"> + </localized-link> + </p> + <localized-link localized-string="[[fileHandlingSetDefaults]]" link-url="[[getLearnMoreLinkUrl_(app)]]"> + </localized-link> +</div>
diff --git a/ui/webui/resources/cr_components/app_management/file_handling_item.ts b/ui/webui/resources/cr_components/app_management/file_handling_item.ts index 44546f2..1b004a5 100644 --- a/ui/webui/resources/cr_components/app_management/file_handling_item.ts +++ b/ui/webui/resources/cr_components/app_management/file_handling_item.ts
@@ -26,6 +26,7 @@ static get properties() { return { fileHandlingHeader: String, + fileHandlingSetDefaults: String, app: Object, @@ -42,10 +43,10 @@ app: App; fileHandlingHeader: String; + fileHandlingSetDefaults: String; ready() { super.ready(); - this.addEventListener('click', this.onClick_); this.addEventListener('change', this.onChanged_); } @@ -63,6 +64,20 @@ return false; } + private userVisibleTypesLabel_(app: App): string { + if (app && app.fileHandlingState) { + return app.fileHandlingState.userVisibleTypesLabel; + } + return ''; + } + + private getLearnMoreLinkUrl_(app: App): string { + if (app && app.fileHandlingState) { + return app.fileHandlingState.learnMoreUrl.url; + } + return ''; + } + private getValue_(app: App): boolean { if (app && app.fileHandlingState) { return app.fileHandlingState.enabled; @@ -70,11 +85,6 @@ return false; } - private onClick_() { - this.shadowRoot! - .querySelector<AppManagementToggleRowElement>('#toggle-row')!.click(); - } - private onChanged_() { assert(this.app); const enabled = this.shadowRoot!
diff --git a/ui/webui/resources/cr_components/app_management/shared_vars.html b/ui/webui/resources/cr_components/app_management/shared_vars.html index e6d17350..f34fa3a 100644 --- a/ui/webui/resources/cr_components/app_management/shared_vars.html +++ b/ui/webui/resources/cr_components/app_management/shared_vars.html
@@ -14,6 +14,7 @@ --permission-list-item-with-description-height: 64px; --primary-text-color: var(--cr-primary-text-color); --row-item-icon-padding: 12px; + --row-item-vertical-padding: 16px; --secondary-font-weight: 400; --secondary-text-color: var(--cr-secondary-text-color); --text-permission-list-row-height: 40px;
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.html b/ui/webui/resources/cr_components/chromeos/network/network_config.html index 65b00819..32d42da 100644 --- a/ui/webui/resources/cr_components/chromeos/network/network_config.html +++ b/ui/webui/resources/cr_components/chromeos/network/network_config.html
@@ -96,25 +96,28 @@ property="[[managedProperties_.typeProperties.vpn.host]]"> </network-config-input> </template> - <template is="dom-if" if="[[showVpn_.L2TPIPsec]]" restamp> + <template is="dom-if" if="[[showVpn_.IPsec]]" restamp> <network-config-select label="[[i18n('OncVPN-IPsec-AuthType')]]" - id="vpn-ipsec-auth-type" value="{{ipsecAuthType_}}" + id="ipsec-auth-type" value="{{ipsecAuthType_}}" items="[[ipsecAuthTypeItems_]]" onc-prefix="VPN.IPsec.AuthType" disabled="[[hasGuid_(guid)]]"> </network-config-select> - <network-config-input label="[[i18n('OncVPN-L2TP-Username')]]" - value="{{configProperties_.typeConfig.vpn.l2tp.username}}" - property="[[managedProperties_.typeProperties.vpn.l2tp.username]]"> - </network-config-input> - <network-password-input label="[[i18n('OncVPN-L2TP-Password')]]" - value="{{configProperties_.typeConfig.vpn.l2tp.password}}" - property="[[managedProperties_.typeProperties.vpn.l2tp.password]]"> - </network-password-input> - <network-config-input label="[[i18n('OncVPN-IPsec-Group')]]" - value="{{configProperties_.typeConfig.vpn.ipSec.group}}" - property="[[managedProperties_.typeProperties.vpn.ipSec.group]]"> - </network-config-input> - <template is="dom-if" if="[[!showVpn_.Cert]]" restamp> + <template is="dom-if" if="[[!showVpn_.IKEv2]]" restamp> + <network-config-input label="[[i18n('OncVPN-L2TP-Username')]]" + id="l2tp-username-input" + value="{{configProperties_.typeConfig.vpn.l2tp.username}}" + property="[[managedProperties_.typeProperties.vpn.l2tp.username]]"> + </network-config-input> + <network-password-input label="[[i18n('OncVPN-L2TP-Password')]]" + value="{{configProperties_.typeConfig.vpn.l2tp.password}}" + property="[[managedProperties_.typeProperties.vpn.l2tp.password]]"> + </network-password-input> + <network-config-input label="[[i18n('OncVPN-IPsec-Group')]]" + value="{{configProperties_.typeConfig.vpn.ipSec.group}}" + property="[[managedProperties_.typeProperties.vpn.ipSec.group]]"> + </network-config-input> + </template> + <template is="dom-if" if="[[showVpn_.IPsecPSK]]" restamp> <network-password-input label="[[i18n('OncVPN-IPsec-PSK')]]" id="ipsec-psk-input" value="{{configProperties_.typeConfig.vpn.ipSec.psk}}" @@ -122,8 +125,9 @@ </network-password-input> </template> </template> - <template is="dom-if" if="[[showVpn_.OpenVPN]]"> + <template is="dom-if" if="[[showVpn_.OpenVPN]]" restamp> <network-config-input label="[[i18n('OncVPN-OpenVPN-Username')]]" + id="openvpn-username-input" value="{{configProperties_.typeConfig.vpn.openVpn.username}}" property="[[managedProperties_.typeProperties.vpn.openVpn.username]]"> </network-config-input> @@ -136,13 +140,15 @@ property="[[managedProperties_.typeProperties.vpn.openVpn.otp]]"> </network-config-input> </template> - <template is="dom-if" if="[[showVpn_.Cert]]" restamp> + <template is="dom-if" if="[[showVpn_.ServerCA]]" restamp> <network-config-select id="vpnServerCa" label="[[i18n('OncEAP-ServerCA')]]" value="{{selectedServerCaHash_}}" items="[[serverCaCerts_]]" cert-list property="[[getManagedVpnServerCaRefs_(managedProperties_)]]"> </network-config-select> + </template> + <template is="dom-if" if="[[showVpn_.UserCert]]" restamp> <network-config-select id="vpnUserCert" label="[[i18n('OncEAP-UserCert')]]" value="{{selectedUserCertHash_}}" items="[[userCerts_]]"
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js index c008d06..775713e7 100644 --- a/ui/webui/resources/cr_components/chromeos/network/network_config.js +++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -13,6 +13,7 @@ * @enum {string} */ const VPNConfigType = { + IKEV2: 'IKEv2', L2TP_IPSEC: 'L2TP_IPsec', OPEN_VPN: 'OpenVPN', WIREGUARD: 'WireGuard', @@ -284,10 +285,13 @@ * Dictionary of boolean values determining which VPN properties to show, * or null to hide all VPN settings. * @private {?{ - * L2TPIPsec: (boolean|undefined), + * IPsec: (boolean|undefined), + * IPsecPSK: (boolean|undefined), + * IKEv2: (boolean|undefined), * OpenVPN: (boolean|undefined), * WireGuard: (boolean|undefined), - * Cert: (boolean|undefined), + * ServerCA: (boolean|undefined), + * UserCert: (boolean|undefined), * }} */ showVpn_: { @@ -627,6 +631,14 @@ * @return {boolean} * @private */ + isIkev2Supported_() { + return this.vpnTypeItems_.includes(VPNConfigType.IKEV2); + }, + + /** + * @return {boolean} + * @private + */ isWireGuardSupported_() { return this.vpnTypeItems_.includes(VPNConfigType.WIREGUARD); }, @@ -640,6 +652,9 @@ VPNConfigType.L2TP_IPSEC, VPNConfigType.OPEN_VPN, ]; + if (responseTypes.includes('ikev2')) { + this.vpnTypeItems_.unshift(VPNConfigType.IKEV2); + } if (responseTypes.includes('wireguard')) { this.vpnTypeItems_.push(VPNConfigType.WIREGUARD); } @@ -703,6 +718,18 @@ }, /** + * @param {?mojom.ManagedInt32|undefined} property + * @return {number} + * @private + */ + getActiveInt32_(property) { + if (!property) { + return 0; + } + return property.activeValue; + }, + + /** * @param {?mojom.ManagedStringList|undefined} property * @return {!Array<string>|undefined} * @private @@ -735,6 +762,8 @@ const vpn = managedProperties.typeProperties.vpn; if (vpn.type === mojom.VpnType.kOpenVPN) { saveCredentials = this.getActiveBoolean_(vpn.openVpn.saveCredentials); + } else if (vpn.type === mojom.VpnType.kIKEv2) { + saveCredentials = this.getActiveBoolean_(vpn.ipSec.saveCredentials); } else if (vpn.type === mojom.VpnType.kL2TPIPsec) { saveCredentials = this.getActiveBoolean_(vpn.ipSec.saveCredentials) || this.getActiveBoolean_(vpn.l2tp.saveCredentials); @@ -841,7 +870,7 @@ clientCertPkcs11Id: OncMojo.getActiveString(ipSec.clientCertPkcs11Id), clientCertType: OncMojo.getActiveString(ipSec.clientCertType), group: OncMojo.getActiveString(ipSec.group), - ikeVersion: 1, + ikeVersion: this.getActiveInt32_(ipSec.ikeVersion), psk: OncMojo.getActiveString(ipSec.psk), saveCredentials: this.getActiveBoolean_(ipSec.saveCredentials), serverCaPems: this.getActiveStringList_(ipSec.serverCaPems), @@ -959,7 +988,13 @@ const configVpn = configProperties.typeConfig.vpn; configVpn.host = OncMojo.getActiveString(vpn.host); configVpn.type = {value: vpnType}; - if (vpnType === mojom.VpnType.kL2TPIPsec) { + if (vpnType === mojom.VpnType.kIKEv2) { + if (!this.isIkev2Supported_()) { + break; + } + assert(vpn.ipSec); + configVpn.ipSec = this.getIPSecConfigProperties_(vpn.ipSec); + } else if (vpnType === mojom.VpnType.kL2TPIPsec) { assert(vpn.ipSec); configVpn.ipSec = this.getIPSecConfigProperties_(vpn.ipSec); assert(vpn.l2tp); @@ -1173,7 +1208,9 @@ getVpnTypeFromProperties_(properties) { const vpn = properties.typeConfig.vpn; assert(vpn); - if (!!vpn.type && vpn.type.value === mojom.VpnType.kL2TPIPsec) { + if (!!vpn.type && vpn.type.value === mojom.VpnType.kIKEv2) { + return VPNConfigType.IKEV2; + } else if (!!vpn.type && vpn.type.value === mojom.VpnType.kL2TPIPsec) { return VPNConfigType.L2TP_IPSEC; } else if (!!vpn.type && vpn.type.value === mojom.VpnType.kWireGuard) { return VPNConfigType.WIREGUARD; @@ -1189,8 +1226,10 @@ getIpsecAuthTypeFromProperties_(properties) { const vpn = properties.typeConfig.vpn; assert(vpn); - if (!vpn.type || vpn.type.value !== mojom.VpnType.kL2TPIPsec) { - // This field will not be used by services other than L2TP/IPsec VPN. + if (!vpn.type || + !(vpn.type.value === mojom.VpnType.kL2TPIPsec || + vpn.type.value === mojom.VpnType.kIKEv2)) { + // This field will not be used by services other than IPsec-based VPN. // Initiate it to "PSK" for simplicity. return IpsecAuthType.PSK; } @@ -1212,7 +1251,8 @@ } const isOpenVpn = this.vpnType_ === VPNConfigType.OPEN_VPN; - const isIpsec = this.vpnType_ === VPNConfigType.L2TP_IPSEC; + const isIpsec = this.vpnType_ === VPNConfigType.L2TP_IPSEC || + this.vpnType_ === VPNConfigType.IKEV2; let caCerts = this.cachedServerCaCerts_.slice(); if (!isOpenVpn && !isIpsec) { // 'Default' is the same as 'Do not check' except that 'Default' sets @@ -1272,48 +1312,53 @@ return; } switch (this.vpnType_) { + case VPNConfigType.IKEV2: + vpn.type = {value: mojom.VpnType.kIKEv2}; + if (!vpn.ipSec) { + vpn.ipSec = { + authenticationType: this.ipsecAuthType_, + ikeVersion: 2, + saveCredentials: false, + }; + } + break; case VPNConfigType.L2TP_IPSEC: vpn.type = {value: mojom.VpnType.kL2TPIPsec}; if (!vpn.ipSec) { vpn.ipSec = { - authenticationType: 'PSK', + authenticationType: this.ipsecAuthType_, ikeVersion: 1, saveCredentials: false, }; } - switch (this.ipsecAuthType_) { - case IpsecAuthType.PSK: - this.showVpn_ = { - Cert: false, - L2TPIPsec: true, - OpenVPN: false, - WireGuard: false - }; - break; - case IpsecAuthType.CERT: - vpn.ipSec.authenticationType = 'Cert'; - this.showVpn_ = - {Cert: true, L2TPIPsec: true, OpenVPN: false, WireGuard: false}; - break; - default: - assertNotReached(); - } break; case VPNConfigType.OPEN_VPN: vpn.type = {value: mojom.VpnType.kOpenVPN}; vpn.openVpn = vpn.openVpn || {saveCredentials: false}; - this.showVpn_ = - {Cert: true, L2TPIPsec: false, OpenVPN: true, WireGuard: false}; break; case VPNConfigType.WIREGUARD: vpn.type = {value: mojom.VpnType.kWireGuard}; vpn.wireguard = vpn.wireguard || {peers: [{}]}; - this.showVpn_ = - {Cert: false, L2TPIPsec: false, OpenVPN: false, WireGuard: true}; break; default: assertNotReached(); } + + const isIpsec = this.vpnType_ === VPNConfigType.L2TP_IPSEC || + this.vpnType_ === VPNConfigType.IKEV2; + const ipsecAuthIsPsk = this.ipsecAuthType_ === IpsecAuthType.PSK; + const ipsecAuthIsCert = this.ipsecAuthType_ === IpsecAuthType.CERT; + const isOpenvpn = this.vpnType_ === VPNConfigType.OPEN_VPN; + this.showVpn_ = { + IPsec: isIpsec, + IPsecPSK: isIpsec && ipsecAuthIsPsk, + IKEv2: this.vpnType_ === VPNConfigType.IKEV2, + OpenVPN: isOpenvpn, + WireGuard: this.vpnType_ === VPNConfigType.WIREGUARD, + ServerCA: (isIpsec && !ipsecAuthIsPsk) || isOpenvpn, + UserCert: (isIpsec && ipsecAuthIsCert) || isOpenvpn, + }; + if (vpn.type.value === mojom.VpnType.kL2TPIPsec && !vpn.l2tp) { vpn.l2tp = { lcpEchoDisabled: false, @@ -1322,9 +1367,12 @@ username: '', }; } + if (vpn.type.value !== mojom.VpnType.kL2TPIPsec && + vpn.type.value !== mojom.VpnType.kIKEv2) { + delete vpn.ipSec; + } if (vpn.type.value !== mojom.VpnType.kL2TPIPsec) { delete vpn.l2tp; - delete vpn.ipSec; } if (vpn.type.value !== mojom.VpnType.kOpenVPN) { delete vpn.openVpn; @@ -1337,8 +1385,11 @@ /** @private */ updateVpnIPsecCerts_() { - if (this.vpnType_ !== VPNConfigType.L2TP_IPSEC || - this.ipsecAuthType_ !== IpsecAuthType.CERT) { + if (this.vpnType_ !== VPNConfigType.L2TP_IPSEC && + this.vpnType_ !== VPNConfigType.IKEV2) { + return; + } + if (this.ipsecAuthType_ !== IpsecAuthType.CERT) { return; } const ipSec = this.configProperties_.typeConfig.vpn.ipSec; @@ -1526,6 +1577,9 @@ const typeConfig = this.configProperties_.typeConfig; if (typeConfig.vpn) { + if (this.vpnType_ === VPNConfigType.IKEV2 && !this.isIkev2Supported_()) { + return false; + } return this.vpnIsConfigured_(); } @@ -1718,6 +1772,26 @@ * @return {boolean} * @private */ + ikev2IsConfigured_() { + const vpn = this.configProperties_.typeConfig.vpn; + switch (this.ipsecAuthType_) { + case IpsecAuthType.PSK: + return !!vpn.ipSec.psk; + case IpsecAuthType.CERT: + // TODO(b/206722135): Show proper error message in the UI if server CA + // is invalid. + return this.selectedServerCaHashIsValid_() && + this.selectedUserCertHashIsValid_(); + default: + assertNotReached(); + } + }, + + + /** + * @return {boolean} + * @private + */ l2tpIpsecIsConfigured_() { const vpn = this.configProperties_.typeConfig.vpn; switch (this.ipsecAuthType_) { @@ -1796,6 +1870,8 @@ } switch (this.vpnType_) { + case VPNConfigType.IKEV2: + return this.ikev2IsConfigured_(); case VPNConfigType.L2TP_IPSEC: return this.l2tpIpsecIsConfigured_(); case VPNConfigType.OPEN_VPN: @@ -1838,8 +1914,10 @@ } else { delete propertiesToSet.typeConfig.vpn.openVpn; } - if (vpnType === mojom.VpnType.kL2TPIPsec) { - this.setVpnIPsecProperties_(propertiesToSet); + if (vpnType === mojom.VpnType.kIKEv2) { + this.setVpnIkev2Properties_(propertiesToSet); + } else if (vpnType === mojom.VpnType.kL2TPIPsec) { + this.setVpnL2tpIpsecProperties_(propertiesToSet); } else { delete propertiesToSet.typeConfig.vpn.ipSec; delete propertiesToSet.typeConfig.vpn.l2tp; @@ -1898,6 +1976,33 @@ * @param {!mojom.ConfigProperties} propertiesToSet * @private */ + setVpnIkev2Properties_(propertiesToSet) { + const ipsec = propertiesToSet.typeConfig.vpn.ipSec; + assert(!!ipsec); + + ipsec.authenticationType = this.ipsecAuthType_; + if (ipsec.authenticationType !== IpsecAuthType.PSK) { + // Set psk to empty string to make sure the value is cleared. + ipsec.psk = ''; + // For non-PSK auth method, server CA is mandatory. + ipsec.serverCaPems = this.getServerCaPems_(); + } + + if (ipsec.authenticationType === IpsecAuthType.CERT) { + ipsec.clientCertType = 'PKCS11Id'; + ipsec.clientCertPkcs11Id = this.getUserCertPkcs11Id_(); + } else { + delete ipsec.clientCertType; + } + + ipsec.ikeVersion = 2; + ipsec.saveCredentials = this.vpnSaveCredentials_; + }, + + /** + * @param {!mojom.ConfigProperties} propertiesToSet + * @private + */ setOpenVPNProperties_(propertiesToSet) { const openVpn = propertiesToSet.typeConfig.vpn.openVpn; assert(!!openVpn); @@ -1960,12 +2065,12 @@ * @param {!mojom.ConfigProperties} propertiesToSet * @private */ - setVpnIPsecProperties_(propertiesToSet) { + setVpnL2tpIpsecProperties_(propertiesToSet) { const vpn = propertiesToSet.typeConfig.vpn; assert(vpn.ipSec); assert(vpn.l2tp); - if (vpn.ipSec.authenticationType === 'Cert') { + if (vpn.ipSec.authenticationType === IpsecAuthType.CERT) { vpn.ipSec.clientCertType = 'PKCS11Id'; vpn.ipSec.clientCertPkcs11Id = this.getUserCertPkcs11Id_(); vpn.ipSec.serverCaPems = this.getServerCaPems_(); @@ -2124,6 +2229,8 @@ getManagedVpnSaveCredentials_(managedProperties) { const vpn = managedProperties.typeProperties.vpn; switch (vpn.type) { + case mojom.VpnType.kIKEv2: + return vpn.ipSec.saveCredentials || OncMojo.createManagedBool(false); case mojom.VpnType.kOpenVPN: return vpn.openVpn.saveCredentials || OncMojo.createManagedBool(false); case mojom.VpnType.kL2TPIPsec: @@ -2146,6 +2253,7 @@ switch (vpn.type) { case mojom.VpnType.kOpenVPN: return vpn.openVpn.serverCaRefs; + case mojom.VpnType.kIKEv2: case mojom.VpnType.kL2TPIPsec: return vpn.ipSec.serverCaRefs; } @@ -2163,6 +2271,7 @@ switch (vpn.type) { case mojom.VpnType.kOpenVPN: return vpn.openVpn.clientCertType || OncMojo.createManagedString(''); + case mojom.VpnType.kIKEv2: case mojom.VpnType.kL2TPIPsec: return vpn.ipSec.clientCertType || OncMojo.createManagedString(''); }