diff --git a/BUILD.gn b/BUILD.gn index ea356bd..e8b687f 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -115,7 +115,7 @@ deps += [ "//third_party/abseil-cpp:absl_tests" ] } - if (enable_js_type_check) { + if (is_chromeos_ash && enable_js_type_check) { deps += [ ":webui_closure_compile" ] }
diff --git a/DEPS b/DEPS index f98f90b4..0055a08 100644 --- a/DEPS +++ b/DEPS
@@ -304,15 +304,15 @@ # 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': '8c2e58a736090658f5e51104f0e21e6336fac47a', + 'skia_revision': '90fda2e72314afaa03a54ca7648cd25347a775b7', # 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': '3a6551d622111e5cc6ce3c6328c0226bc99ab6e5', + 'v8_revision': 'e3b3263ced8d6e08fbc804dfe8228ee21b12dfa9', # 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': '8d2f5e0ed46244ead609a14bc4a7798ea67dfb72', + 'angle_revision': '13e0847bace1d3355dc1879f1113dca9d28e7e91', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -375,7 +375,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': 'c4e9d16032d8217ec6de404a66f4f0cc1d8e366a', + 'catapult_revision': 'c95933a0d5f6eb2fff47c29f55b6d4b70d996ce3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -383,7 +383,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'd1aa06917bd906ec743e27fe47c5c7ec4bd9732b', + 'devtools_frontend_revision': 'f38525585e6f527d8bf3fdeb90e501f71a3400de', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -419,7 +419,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': 'ad98166fe71e1c5dcbc6981e2c7082960000b112', + 'dawn_revision': 'c252c642f4a243c119fe9992f103530894309ff0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -443,7 +443,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': '43ec97b13bdaf7cb90941a87b0457948d4a0410d', + 'nearby_revision': '7f34968b7850b2bd575601bcab8f745220cab8ff', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -455,7 +455,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. - 'cros_components_revision': '45ca37d4c4b5ca1e751df3c2761b5b9a1f00e49c', + 'cros_components_revision': '64d107c35744760124f2b6353d9309cee2c71767', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -483,7 +483,7 @@ # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. - 'libcxx_revision': 'cf803236eb29c7b6192ad129ad23ad80a3d99239', + 'libcxx_revision': '885d5d1cd59a7c88cee3c83fc71be5812c8e6bbd', # GN CIPD package version. 'gn_version': 'git_revision:5e19d2fb166fbd4f6f32147fbb2f497091a54ad8', @@ -739,7 +739,7 @@ }, 'src/chrome/test/data/autofill/captured_sites': { - 'url': 'https://chrome-internal.googlesource.com/chrome/test/captured_sites/autofill.git' + '@' + 'b5c90453694ba7a4a412ce45152d4593c4d657ee', + 'url': 'https://chrome-internal.googlesource.com/chrome/test/captured_sites/autofill.git' + '@' + '58a7920c173397b57d8d7be95cb93c2b43d02e26', 'condition': 'checkout_chromium_autofill_test_dependencies', }, @@ -770,12 +770,12 @@ 'src/clank': { 'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' + - '934e146d0f42ad72b9a19bf5f7923c83b4de4a86', + '8742812c2fd4f96f76a68685ddbd705f1b0b4c98', 'condition': 'checkout_android and checkout_src_internal', }, 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + 'a9579b1779e134a085eaa006e87ad41ef74c5da3', + 'url': Var('chromium_git') + '/website.git' + '@' + 'bf44f1a6a4b0a2e50c4a9487d2ff532da239d9de', }, 'src/ios/third_party/earl_grey2/src': { @@ -869,7 +869,7 @@ 'packages': [ { 'package': 'chromium/rts/model/linux-amd64', - 'version': 'FaATxNFJ5nwCC9yNFWKbtK5Q33vliOg0GmtMPlENofIC', + 'version': 'l_jC80R_Le8zKH9ueI5HF0VhjvAQgtIY7pOytB9VA34C', }, ], 'dep_type': 'cipd', @@ -880,7 +880,7 @@ 'packages': [ { 'package': 'chromium/rts/model/mac-amd64', - 'version': 'EKYxNJShDcIpOiYXBPHP4UfGIAEORcLDTdBtJ50n3boC', + 'version': 'M2ZvaCbz4Ws3Qsv6jRj0Uf1a3yCeHymPetKfObWUsgMC', }, ], 'dep_type': 'cipd', @@ -891,7 +891,7 @@ 'packages': [ { 'package': 'chromium/rts/model/windows-amd64', - 'version': 'YobeTwr7Ojy8z5eEFcCQZnFtpNXSDc89zGRL73RG6EIC', + 'version': 'l1qKaWv2pfsr2Ma1Ip_sAstI_hk0ZQjWuSNxt8yY5G4C', }, ], 'dep_type': 'cipd', @@ -959,7 +959,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'amhjv4Hj48NMXw5Ntbp8u4o8TrRCD7nJxJsdEt10Cb0C', + 'version': 'jv57gOQkV2sCpOYMfl61a1uigXjtNTanhXQbA-NIVj4C', }, ], 'condition': 'checkout_android', @@ -1176,7 +1176,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0def61ff6777c884af5ea1ee7d508244290a77ac', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '2391a174d3221285c59d723742cd6d2825554fb5', 'condition': 'checkout_chromeos', }, @@ -1194,7 +1194,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': { - 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '74799e2b19b31b823f8fc1573eb24bb1deadddef', + 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'e0bfd3d75917adfa22e401805f9f9793cec82559', 'condition': 'checkout_linux', }, @@ -1204,13 +1204,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e8523914418f7c71281df174be4778f36a357b12', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '26b6c9b4cf9617cfa196a0415baadd764a069e57', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'e016065f54348d1ca6848cb82e68bc743c8e076d', + 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '23d644e00507a4d10306ebb51ceea87d8fac860b', 'condition': 'checkout_src_internal', }, @@ -1441,7 +1441,7 @@ Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'e8712e415627f22d0b00ebee8db99547077f39bd', 'src/third_party/libaom/source/libaom': - Var('aomedia_git') + '/aom.git' + '@' + '5115747345e7de18fdbafc333e078604f39ba932', + Var('aomedia_git') + '/aom.git' + '@' + '9c915757e556d5df75400a6b847c37f06a71a426', 'src/third_party/libavif/src': Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'), @@ -1502,7 +1502,7 @@ }, 'src/third_party/libvpx/source/libvpx': - Var('chromium_git') + '/webm/libvpx.git' + '@' + '605350bd5b68ac47f595d60cc8ef346588e773c0', + Var('chromium_git') + '/webm/libvpx.git' + '@' + 'b7c22b3a9584d7d9c0a7b9b37a52bc595113b398', 'src/third_party/libwebm/source': Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4fbea0c9751ae8aa86629b197a28d8276a2b0da', @@ -1655,7 +1655,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '61f6f28a07752c9a38fa2309d20557d5d8647eaf', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f1c4ce9b46ee662faed75adf6bfbff99ab2ca3e2', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1689,7 +1689,7 @@ }, 'src/third_party/re2/src': - Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '954656f47fe8fb505d4818da1e128417a79ea500', + Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'ba541565b4fbe1684d4b98695ec0b6d6c13ba98b', 'src/third_party/r8': { 'packages': [ @@ -1787,7 +1787,7 @@ Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f', 'src/third_party/tflite/src': - Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'e6ad9bf9bcd3f33783f4363984f4b24adfd8a469', + Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + 'ef70dc999eee784e3f505e89c798f8b9cc894e52', 'src/third_party/turbine': { 'packages': [ @@ -1800,7 +1800,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@fbcb93d162f3756c2f4cdeb384fb02c37ab5a5e1', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@445542dc8f2af640d67cf739ee8d918e64bb9c76', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', @@ -1837,10 +1837,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '9fbed0099e425cb735e6745bd2ce30a880e5075c', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '3f9b09b36b8cefc84c30adad2ecd2824caded6e7', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '9f9671fe7fa63738d564adbf94e8863597b6ac0b', + Var('webrtc_git') + '/src.git' + '@' + '2810c14ade3ffa06b06d9ea96a2354645eb86beb', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -1910,7 +1910,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2ab4c3e237edb91a9daa62f6b065ac8825ce880f', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@dc0a3e4d71a343994ae4e58544e359272728fab8', 'condition': 'checkout_src_internal', }, @@ -1929,7 +1929,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/eche_app/app', - 'version': 'OIhYH2KUvD3c7QEwNBfBcCSWzukSn2w3hChSu3xL1CAC', + 'version': '08CYaHzgiih7alMtbwWqfwd-4GXzrP4Pkz-xXo8sHPoC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1951,7 +1951,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'L-fIlmTvVKZ6HE65IxkPFoFIe4bsOgMSxHrxFljsQ-0C', + 'version': 'JuWJBdkLW-fu18WobGg5o0klzkqSBgw2h1Ne5BHoIEUC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1962,7 +1962,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/projector_app/app', - 'version': 'm581vq4D8SsE0_bMxv_mFM3-o6wz1lnPYk030fF2LN0C', + 'version': '9_YPq-7rVC3g0cuAG5BJLkP3A-_Fa5DLqssVwS-74rAC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3432,6 +3432,17 @@ 'dep_type': 'cipd', }, + 'src/third_party/android_deps/libs/org_conscrypt_conscrypt_openjdk_uber': { + 'packages': [ + { + 'package': 'chromium/third_party/android_deps/libs/org_conscrypt_conscrypt_openjdk_uber', + 'version': 'version:2@2.5.2.cr1', + }, + ], + 'condition': 'checkout_android', + 'dep_type': 'cipd', + }, + 'src/third_party/android_deps/libs/org_eclipse_jgit_org_eclipse_jgit': { 'packages': [ {
diff --git a/WATCHLISTS b/WATCHLISTS index 74f2335..5d6eef9e 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -697,7 +697,6 @@ }, 'chrome_cleaner': { 'filepath': 'chrome/browser/component_updater/sw_reporter_'\ - '|chrome/browser/resources/settings/chrome_cleanup_page/'\ '|chrome/browser/safe_browsing/chrome_cleaner/'\ '|chrome/browser/ui/views/chrome_cleaner_'\ '|chrome/browser/ui/webui/settings/chrome_cleanup_'\
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 19d8805..06a0f09 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -506,6 +506,7 @@ "java/src/org/chromium/android_webview/AwFeatureList.java", "java/src/org/chromium/android_webview/AwFormDatabase.java", "java/src/org/chromium/android_webview/AwHttpAuthHandler.java", + "java/src/org/chromium/android_webview/AwOriginVerificationSchedulerBridge.java", "java/src/org/chromium/android_webview/AwPacProcessor.java", "java/src/org/chromium/android_webview/AwPdfExporter.java", "java/src/org/chromium/android_webview/AwProxyController.java", @@ -568,6 +569,7 @@ "java/src/org/chromium/android_webview/AwLayoutSizer.java", "java/src/org/chromium/android_webview/AwNetworkChangeNotifierRegistrationPolicy.java", "java/src/org/chromium/android_webview/AwOriginVerificationScheduler.java", + "java/src/org/chromium/android_webview/AwOriginVerificationSchedulerBridge.java", "java/src/org/chromium/android_webview/AwOriginVerifier.java", "java/src/org/chromium/android_webview/AwPacProcessor.java", "java/src/org/chromium/android_webview/AwPdfExporter.java",
diff --git a/android_webview/browser/BUILD.gn b/android_webview/browser/BUILD.gn index 2a1ed4ab..030be9b 100644 --- a/android_webview/browser/BUILD.gn +++ b/android_webview/browser/BUILD.gn
@@ -81,6 +81,8 @@ "aw_media_url_interceptor.h", "aw_metrics_service_client_delegate.cc", "aw_metrics_service_client_delegate.h", + "aw_origin_verification_scheduler_bridge.cc", + "aw_origin_verification_scheduler_bridge.h", "aw_pac_processor.cc", "aw_pac_processor.h", "aw_pdf_exporter.cc", @@ -238,6 +240,7 @@ "//components/crash/android:crashpad_main", "//components/crash/content/browser", "//components/crash/core/app", + "//components/digital_asset_links", "//components/embedder_support/android:web_contents_delegate", "//components/embedder_support/android/metrics", "//components/google/core/common",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS index 30d9865a..d46a038 100644 --- a/android_webview/browser/DEPS +++ b/android_webview/browser/DEPS
@@ -17,6 +17,7 @@ "+components/component_updater/installer_policies", "+components/crash/content/browser", "+components/crash/core", + "+components/digital_asset_links", "+components/download/public/common", "+components/embedder_support", "+components/favicon_base",
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index 26569df9..e606727 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -18,6 +18,7 @@ #include "android_webview/browser/aw_devtools_manager_delegate.h" #include "android_webview/browser/aw_feature_list_creator.h" #include "android_webview/browser/aw_http_auth_handler.h" +#include "android_webview/browser/aw_origin_verification_scheduler_bridge.h" #include "android_webview/browser/aw_resource_context.h" #include "android_webview/browser/aw_settings.h" #include "android_webview/browser/aw_speech_recognition_manager_delegate.h" @@ -587,6 +588,15 @@ std::vector<std::unique_ptr<blink::URLLoaderThrottle>> result; + if (request.is_outermost_main_frame && + base::FeatureList::IsEnabled( + features::kWebViewRestrictThirdPartyContent)) { + auto* origin_verification_bridge = + AwOriginVerificationSchedulerBridge::GetInstance(); + result.push_back(digital_asset_links::BrowserURLLoaderThrottle::Create( + origin_verification_bridge)); + } + result.push_back(safe_browsing::BrowserURLLoaderThrottle::Create( base::BindOnce( [](AwContentBrowserClient* client) {
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc index 7e0829a..40a85486 100644 --- a/android_webview/browser/aw_contents_io_thread_client.cc +++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -388,24 +388,6 @@ return web_resource_intercept_response; } -bool RunShouldBlockRequest(AwWebResourceRequest request, - JavaObjectWeakGlobalRef ref) { - if (!request.is_outermost_main_frame) { - return false; - } - - JNIEnv* env = AttachCurrentThread(); - base::android::ScopedJavaLocalRef<jobject> obj = ref.get(env); - if (!obj) { - return true; - } - AwWebResourceRequest::AwJavaWebResourceRequest java_web_resource_request; - AwWebResourceRequest::ConvertToJava(env, request, &java_web_resource_request); - - return Java_AwContentsBackgroundThreadClient_shouldBlockRequestFromNative( - env, obj, java_web_resource_request.jurl); -} - } // namespace void AwContentsIoThreadClient::ShouldInterceptRequestAsync( @@ -429,23 +411,6 @@ FROM_HERE, std::move(get_response), std::move(callback)); } -bool AwContentsIoThreadClient::ShouldBlockRequest( - AwWebResourceRequest request) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - JNIEnv* env = AttachCurrentThread(); - if (!bg_thread_client_object_) { - bg_thread_client_object_.Reset( - Java_AwContentsIoThreadClient_getBackgroundThreadClient(env, - java_object_)); - } - if (bg_thread_client_object_) { - return RunShouldBlockRequest( - request, JavaObjectWeakGlobalRef(env, bg_thread_client_object_.obj())); - } - // Block request if validation did not run. - return true; -} - bool AwContentsIoThreadClient::ShouldBlockContentUrls() const { DCHECK_CURRENTLY_ON(BrowserThread::IO);
diff --git a/android_webview/browser/aw_origin_verification_scheduler_bridge.cc b/android_webview/browser/aw_origin_verification_scheduler_bridge.cc new file mode 100644 index 0000000..d7f9c86 --- /dev/null +++ b/android_webview/browser/aw_origin_verification_scheduler_bridge.cc
@@ -0,0 +1,44 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/browser/aw_origin_verification_scheduler_bridge.h" + +#include <string> +#include "android_webview/browser_jni_headers/AwOriginVerificationSchedulerBridge_jni.h" +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/no_destructor.h" + +namespace android_webview { + +// static +AwOriginVerificationSchedulerBridge* +AwOriginVerificationSchedulerBridge::GetInstance() { + static base::NoDestructor<AwOriginVerificationSchedulerBridge> instance; + return instance.get(); +} + +void AwOriginVerificationSchedulerBridge::Verify( + std::string url, + OriginVerifierCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + JNIEnv* env = base::android::AttachCurrentThread(); + intptr_t callback_id = reinterpret_cast<intptr_t>( + new OriginVerifierCallback(std::move(callback))); + + auto j_url = base::android::ConvertUTF8ToJavaString(env, url); + Java_AwOriginVerificationSchedulerBridge_verify(env, j_url, callback_id); +} + +static void JNI_AwOriginVerificationSchedulerBridge_OnVerificationResult( + JNIEnv* env, + jlong callback_id, + jboolean verified) { + std::unique_ptr<OriginVerifierCallback> cb( + reinterpret_cast<OriginVerifierCallback*>(callback_id)); + std::move(*cb).Run(verified); +} + +} // namespace android_webview
diff --git a/android_webview/browser/aw_origin_verification_scheduler_bridge.h b/android_webview/browser/aw_origin_verification_scheduler_bridge.h new file mode 100644 index 0000000..26a2d5d --- /dev/null +++ b/android_webview/browser/aw_origin_verification_scheduler_bridge.h
@@ -0,0 +1,38 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_BROWSER_AW_ORIGIN_VERIFICATION_SCHEDULER_BRIDGE_H_ +#define ANDROID_WEBVIEW_BROWSER_AW_ORIGIN_VERIFICATION_SCHEDULER_BRIDGE_H_ + +#include "base/functional/callback.h" +#include "base/no_destructor.h" + +#include "components/digital_asset_links/browser_url_loader_throttle.h" + +namespace android_webview { +using OriginVerifierCallback = base::OnceCallback<void(bool /*verified*/)>; + +class AwOriginVerificationSchedulerBridge + : public digital_asset_links::BrowserURLLoaderThrottle:: + OriginVerificationSchedulerBridge { + public: + static AwOriginVerificationSchedulerBridge* GetInstance(); + + AwOriginVerificationSchedulerBridge( + const AwOriginVerificationSchedulerBridge&) = delete; + AwOriginVerificationSchedulerBridge& operator=( + const AwOriginVerificationSchedulerBridge&) = delete; + + void Verify(std::string url, OriginVerifierCallback callback) override; + + private: + AwOriginVerificationSchedulerBridge() = default; + ~AwOriginVerificationSchedulerBridge() override = default; + + friend class base::NoDestructor<AwOriginVerificationSchedulerBridge>; +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_BROWSER_AW_ORIGIN_VERIFICATION_SCHEDULER_BRIDGE_H_
diff --git a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc index 8c546bf9..f8561a42 100644 --- a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc +++ b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
@@ -405,13 +405,6 @@ request_.referrer.spec()); } - if (io_thread_client->ShouldBlockRequest(AwWebResourceRequest(request_))) { - // TODO(swestphal): Show alternative UI to inform the user about blocked - // third party web content. - SendErrorAndCompleteImmediately(net::ERR_ACCESS_DENIED); - return; - } - base::RepeatingClosure arg_ready_closure; // Pointer lifetime is tied to |arg_ready_closure|. InterceptResponseReceivedArgs* intercept_response_received_args;
diff --git a/android_webview/browser/tracing/aw_tracing_delegate.cc b/android_webview/browser/tracing/aw_tracing_delegate.cc index 213a59a..51e6287 100644 --- a/android_webview/browser/tracing/aw_tracing_delegate.cc +++ b/android_webview/browser/tracing/aw_tracing_delegate.cc
@@ -65,8 +65,13 @@ return false; } - // TODO(crbug.com/1290887): check the trace limit per week (to be implemented - // later) + // Check the trace limit both when starting and ending a scenario + // because there is no point starting a trace that can't be uploaded. + if (state.DidRecentlyUploadForScenario(config)) { + tracing::RecordDisallowedMetric( + tracing::TracingFinalizationDisallowedReason::kTraceUploadedRecently); + return false; + } state.NotifyTracingStarted(); return true; @@ -85,8 +90,13 @@ tracing::BackgroundTracingStateManager::GetInstance(); state.NotifyFinalizationStarted(); - // TODO(crbug.com/1290887): check the trace limit per week (to be implemented - // later) + // Check the trace limit both when starting and ending a scenario + // because there is no point starting a trace that can't be uploaded. + if (state.DidRecentlyUploadForScenario(config)) { + tracing::RecordDisallowedMetric( + tracing::TracingFinalizationDisallowedReason::kTraceUploadedRecently); + return false; + } state.OnScenarioUploaded(config.scenario_name()); return true;
diff --git a/android_webview/browser/tracing/aw_tracing_delegate_unittest.cc b/android_webview/browser/tracing/aw_tracing_delegate_unittest.cc index d267e82..b0fb7696 100644 --- a/android_webview/browser/tracing/aw_tracing_delegate_unittest.cc +++ b/android_webview/browser/tracing/aw_tracing_delegate_unittest.cc
@@ -89,4 +89,25 @@ *config, /*requires_anonymized_data=*/false)); } +TEST_F(AwTracingDelegateTest, IsAllowedToBeginRecentlyUploaded) { + tracing::BackgroundTracingStateManager::GetInstance().Initialize(nullptr); + tracing::BackgroundTracingStateManager::GetInstance().OnScenarioUploaded( + "TestScenario"); + + auto config = CreateValidConfig(); + EXPECT_FALSE(delegate_.IsAllowedToBeginBackgroundScenario( + *config, /*requires_anonymized_data=*/false)); +} + +TEST_F(AwTracingDelegateTest, IsAllowedToEndRecentlyUploaded) { + tracing::BackgroundTracingStateManager::GetInstance().Initialize(nullptr); + tracing::BackgroundTracingStateManager::GetInstance().OnScenarioUploaded( + "TestScenario"); + + auto config = CreateValidConfig(); + EXPECT_FALSE(delegate_.IsAllowedToEndBackgroundScenario( + *config, /*requires_anonymized_data=*/false, + /*is_crash_scenario*/ false)); +} + } // namespace android_webview \ No newline at end of file
diff --git a/android_webview/docs/test-instructions.md b/android_webview/docs/test-instructions.md index 2e3d9a41..f20e0cf6 100644 --- a/android_webview/docs/test-instructions.md +++ b/android_webview/docs/test-instructions.md
@@ -155,6 +155,20 @@ -f=AwContentsTest#testClearCacheInQuickSuccession ``` +A bash for loop can be used instead if the flake seems to happen during +specific conditions that need to be configured before each test run: + +```sh +$ for (( c=1; c<100; c++ )) +$ do +$ echo "\n\n\nTest $c/100 \n\n\n" +$ <Any setup command you need to do - eg: adb reboot> +$ out/Default/bin/run_webview_instrumentation_test_apk \ # Any test runner + --num_retries=0 \ # Tests normally retry-on-failure; disable for easier repo + -f= +$ done +``` + #### Enable a Feature for a local run ```sh
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 40e27a8..8fb0e66 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -137,9 +137,6 @@ import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -672,38 +669,6 @@ } return webResourceResponseInfo; } - - @Override - public boolean shouldBlockRequest(String url) { - if (!AwFeatureList.isEnabled(AwFeatures.WEBVIEW_RESTRICT_THIRD_PARTY_CONTENT)) { - return false; - } - // TODO(1376958): Implement a URLLoaderThrottle to not block the IO thread before - // enabling the feature. - - CountDownLatch countDownLatch = new CountDownLatch(1); - AtomicBoolean verified = new AtomicBoolean(false); - - // Verifications are scheduled when WebView is initialized, so when this is called, the - // verification is likely finished here. - if (AwOriginVerificationScheduler.getInstance().getOriginVerifier().checkForSavedResult( - url)) { - return false; - } - - AwThreadUtils.postToUiThreadLooper(() -> { - AwOriginVerificationScheduler.getInstance().verify(url, (result) -> { - verified.set(result); - countDownLatch.countDown(); - }); - }); - try { - countDownLatch.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - // Returning the default value as no successful verification was performed. - } - return !verified.get(); - } } //--------------------------------------------------------------------------------------------
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsBackgroundThreadClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsBackgroundThreadClient.java index 8c43f94..121556e 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsBackgroundThreadClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsBackgroundThreadClient.java
@@ -22,8 +22,6 @@ public abstract WebResourceResponseInfo shouldInterceptRequest( AwContentsClient.AwWebResourceRequest request); - public abstract boolean shouldBlockRequest(String url); - // Protected methods --------------------------------------------------------------------------- @NonNull @@ -49,9 +47,4 @@ return new AwWebResourceInterceptResponse(null, /*raisedException=*/true); } } - - @CalledByNative - private boolean shouldBlockRequestFromNative(String url) { - return shouldBlockRequest(url); - } }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwOriginVerificationSchedulerBridge.java b/android_webview/java/src/org/chromium/android_webview/AwOriginVerificationSchedulerBridge.java new file mode 100644 index 0000000..26e5f4d2 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/AwOriginVerificationSchedulerBridge.java
@@ -0,0 +1,25 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.android_webview; + +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; + +@JNINamespace("android_webview") +class AwOriginVerificationSchedulerBridge { + @CalledByNative + static void verify(String url, long nativeCallbackPtr) { + AwOriginVerificationScheduler.getInstance().verify(url, (verified) -> { + AwOriginVerificationSchedulerBridgeJni.get().onVerificationResult( + nativeCallbackPtr, verified); + }); + } + + @NativeMethods + interface Natives { + void onVerificationResult(long callbackPtr, boolean verified); + } +}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwServiceWorkerController.java b/android_webview/java/src/org/chromium/android_webview/AwServiceWorkerController.java index fd929621..f6c4cd5 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwServiceWorkerController.java +++ b/android_webview/java/src/org/chromium/android_webview/AwServiceWorkerController.java
@@ -10,15 +10,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.chromium.android_webview.common.AwFeatures; import org.chromium.android_webview.safe_browsing.AwSafeBrowsingConfigHelper; import org.chromium.build.annotations.DoNotInline; import org.chromium.components.embedder_support.util.WebResourceResponseInfo; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - /** * Manages clients and settings for Service Workers. */ @@ -123,34 +118,5 @@ : null; } } - @Override - public boolean shouldBlockRequest(String url) { - if (!AwFeatureList.isEnabled(AwFeatures.WEBVIEW_RESTRICT_THIRD_PARTY_CONTENT)) { - return false; - } - - CountDownLatch countDownLatch = new CountDownLatch(1); - AtomicBoolean verified = new AtomicBoolean(false); - - // Verifications are scheduled when WebView is initialized, so when this is called, the - // verification is likely finished here. - AwOriginVerificationScheduler scheduler = AwOriginVerificationScheduler.getInstance(); - if (scheduler != null && scheduler.getOriginVerifier().checkForSavedResult(url)) { - return false; - } - - AwThreadUtils.postToUiThreadLooper(() -> { - AwOriginVerificationScheduler.getInstance().verify(url, (result) -> { - verified.set(result); - countDownLatch.countDown(); - }); - }); - try { - countDownLatch.await(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - return true; - } - return !verified.get(); - } } }
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index eecdb0d..b7c29b5 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -356,6 +356,7 @@ "If enabled, the frequency to upload UMA is increased."), Flag.baseFeature(ContentFeatures.AVOID_UNNECESSARY_NAVIGATION_CANCELLATIONS, "If enabled, avoids unnecessary navigation cancellations."), + Flag.baseFeature("CanvasColorCache"), // Add new commandline switches and features above. The final entry should have a // trailing comma for cleaner diffs. };
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java index 81664677..9a06916 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java
@@ -6,7 +6,6 @@ import static org.chromium.android_webview.test.AwActivityTestRule.SCALED_WAIT_TIMEOUT_MS; -import android.content.Context; import android.support.test.InstrumentationRegistry; import android.util.Pair; import android.webkit.JavascriptInterface; @@ -23,19 +22,15 @@ import org.junit.runner.RunWith; import org.chromium.android_webview.AwContents; -import org.chromium.android_webview.AwOriginVerificationScheduler; import org.chromium.android_webview.InterceptionType; import org.chromium.android_webview.test.TestAwContentsClient.OnReceivedErrorHelper; import org.chromium.android_webview.test.util.AwTestTouchUtils; import org.chromium.android_webview.test.util.CommonResources; import org.chromium.android_webview.test.util.JSUtils; -import org.chromium.base.PackageUtils; import org.chromium.base.metrics.RecordHistogram; 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.TestFileUtil; -import org.chromium.components.embedder_support.util.Origin; import org.chromium.components.embedder_support.util.WebResourceResponseInfo; import org.chromium.net.test.util.TestWebServer; import org.chromium.net.test.util.WebServer; @@ -47,7 +42,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -75,11 +69,6 @@ CommonResources.ABOUT_HTML); } - private String addAssetListToTestServer(TestWebServer webServer, String fingerprint) { - return addPageToTestServer(webServer, CommonResources.ASSET_LINKS_PATH, - CommonResources.makeAssetFile(fingerprint)); - } - private WebResourceResponseInfo stringWithHeadersToWebResourceResponseInfo( String input, Map<String, String> responseHeaders) throws Throwable { final String mimeType = "text/html"; @@ -1462,114 +1451,4 @@ Assert.assertEquals(preflightTriggeringMethod, fetchRequestToPass.getMethod()); Assert.assertEquals(customScheme, fetchRequestToPass.headerValue("Origin")); } - - @Test - @SmallTest - @Feature({"AndroidWebView"}) - @CommandLineFlags.Add({"disable-features=WebViewRestrictThirdPartyContent"}) - public void testDoCallInterceptRequestIfThridPartyRestrictionIsDisabled() throws Throwable { - final String aboutPageUrl = addAboutPageToTestServer(mWebServer); - final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - mActivityTestRule.runOnUiThread( - () - -> AwOriginVerificationScheduler.init(context.getPackageName(), - mActivityTestRule.getAwBrowserContext(), context)); - - Assert.assertEquals(1, - AwOriginVerificationScheduler.getInstance().getPendingOriginsForTesting().size()); - - int callCount = mShouldInterceptRequestHelper.getCallCount(); - mActivityTestRule.loadUrlAsync(mAwContents, aboutPageUrl); - mShouldInterceptRequestHelper.waitForCallback(callCount, 1); - - Assert.assertEquals(1, - AwOriginVerificationScheduler.getInstance().getPendingOriginsForTesting().size()); - } - - @Test - @SmallTest - @Feature({"AndroidWebView"}) - @CommandLineFlags.Add({"enable-features=WebViewRestrictThirdPartyContent"}) - public void testDoesNotCallInterceptRequestIfThridPartyRestrictionIsEnabledAndNotVerified() - throws Throwable { - final String aboutPageUrl = addAboutPageToTestServer(mWebServer); - final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - mActivityTestRule.runOnUiThread( - () - -> AwOriginVerificationScheduler.init(context.getPackageName(), - mActivityTestRule.getAwBrowserContext(), context)); - - Set<Origin> pendingOrigins = - AwOriginVerificationScheduler.getInstance().getPendingOriginsForTesting(); - - Assert.assertEquals(1, pendingOrigins.size()); - Assert.assertTrue(pendingOrigins.contains(Origin.create("https://example.com"))); - - mActivityTestRule.loadUrlSync( - mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl); - - Assert.assertEquals(0, mShouldInterceptRequestHelper.getCallCount()); - } - - @Test - @SmallTest - @Feature({"AndroidWebView"}) - @CommandLineFlags.Add({"enable-features=WebViewRestrictThirdPartyContent"}) - public void testDoesCallInterceptRequestIfThridPartyRestrictionIsEnabledAndVerified() - throws Throwable { - final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - final String aboutPageUrl = addAboutPageToTestServer(mWebServer); - - List<String> mSignatureFingerprints = - PackageUtils.getCertificateSHA256FingerprintForPackage(context.getPackageName()); - - final String assetLinksUrl = - addAssetListToTestServer(mWebServer, mSignatureFingerprints.get(0)); - mActivityTestRule.runOnUiThread( - () - -> AwOriginVerificationScheduler.init(context.getPackageName(), - mActivityTestRule.getAwBrowserContext(), context)); - - // Inject current base url of the test server for verifying the url. - AwOriginVerificationScheduler.getInstance().addPendingOriginForTesting( - Origin.create(aboutPageUrl)); - - Assert.assertEquals(2, - AwOriginVerificationScheduler.getInstance().getPendingOriginsForTesting().size()); - - Assert.assertFalse(AwOriginVerificationScheduler.getInstance() - .getOriginVerifier() - .wasPreviouslyVerified(Origin.create(aboutPageUrl))); - mActivityTestRule.loadUrlSync( - mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl); - - Assert.assertEquals(1, - AwOriginVerificationScheduler.getInstance().getPendingOriginsForTesting().size()); - Assert.assertTrue(AwOriginVerificationScheduler.getInstance() - .getOriginVerifier() - .wasPreviouslyVerified(Origin.create(aboutPageUrl))); - Assert.assertEquals(1, mShouldInterceptRequestHelper.getCallCount()); - } - - @Test - @SmallTest - @Feature({"AndroidWebView"}) - @CommandLineFlags.Add({"enable-features=WebViewRestrictThirdPartyContent"}) - public void testfThridPartyRestrictionInitAndScheduleAll() throws Throwable { - final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - - CountDownLatch countVerifiedLatch = new CountDownLatch(1); - mActivityTestRule.runOnUiThread( - () - -> AwOriginVerificationScheduler.initAndScheduleAll( - context.getPackageName(), context, - mActivityTestRule.getAwBrowserContext(), - (res) -> { countVerifiedLatch.countDown(); })); - countVerifiedLatch.await(); - - AwOriginVerificationScheduler scheduler = AwOriginVerificationScheduler.getInstance(); - - Set<Origin> pendingOrigins = scheduler.getPendingOriginsForTesting(); - Assert.assertEquals(0, pendingOrigins.size()); - } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwRestrictThirdPartyContentTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwRestrictThirdPartyContentTest.java new file mode 100644 index 0000000..fb9ab0e2 --- /dev/null +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwRestrictThirdPartyContentTest.java
@@ -0,0 +1,209 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.android_webview.test; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.util.Pair; + +import androidx.test.filters.SmallTest; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.android_webview.AwContents; +import org.chromium.android_webview.AwOriginVerificationScheduler; +import org.chromium.android_webview.test.util.CommonResources; +import org.chromium.base.PackageUtils; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Feature; +import org.chromium.components.embedder_support.util.Origin; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.net.test.util.TestWebServer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeoutException; + +/** + * Tests for the restricting third party access. + */ +@RunWith(AwJUnit4ClassRunner.class) +public class AwRestrictThirdPartyContentTest { + @Rule + public AwActivityTestRule mActivityTestRule = new AwActivityTestRule(); + + private static class OnProgressChangedClient extends TestAwContentsClient { + List<Integer> mProgresses = new ArrayList<Integer>(); + + @Override + public void onProgressChanged(int progress) { + super.onProgressChanged(progress); + mProgresses.add(Integer.valueOf(progress)); + if (progress == 100 && mCallbackHelper.getCallCount() == 0) { + mCallbackHelper.notifyCalled(); + } + } + + public void waitForFullLoad() throws TimeoutException { + mCallbackHelper.waitForFirst(); + } + private CallbackHelper mCallbackHelper = new CallbackHelper(); + } + + private TestWebServer mWebServer; + private OnProgressChangedClient mContentsClient; + private AwTestContainerView mTestContainerView; + private AwContents mAwContents; + + @Before + public void setUp() throws Exception { + mContentsClient = new OnProgressChangedClient(); + mTestContainerView = mActivityTestRule.createAwTestContainerViewOnMainSync(mContentsClient); + mAwContents = mTestContainerView.getAwContents(); + + mWebServer = TestWebServer.start(); + } + + @After + public void tearDown() { + mWebServer.shutdown(); + } + + private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) { + List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>(); + headers.add(Pair.create("Content-Type", "text/html")); + headers.add(Pair.create("Cache-Control", "no-store")); + return webServer.setResponse(httpPath, html, headers); + } + + private String addAboutPageToTestServer(TestWebServer webServer) { + return addPageToTestServer( + webServer, "/" + CommonResources.ABOUT_FILENAME, CommonResources.ABOUT_HTML); + } + + private String addAssetListToTestServer(TestWebServer webServer, String fingerprint) { + return addPageToTestServer(webServer, CommonResources.ASSET_LINKS_PATH, + CommonResources.makeAssetFile(fingerprint)); + } + + @Test + @SmallTest + @Feature({"AndroidWebView"}) + @CommandLineFlags.Add({"disable-features=WebViewRestrictThirdPartyContent"}) + public void disablingFeatureDoesValidatePendingOrigins() throws Throwable { + final String aboutPageUrl = addAboutPageToTestServer(mWebServer); + final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + TestThreadUtils.runOnUiThreadBlocking( + () + -> AwOriginVerificationScheduler.init(context.getPackageName(), + mActivityTestRule.getAwBrowserContext(), context)); + + AwOriginVerificationScheduler scheduler = AwOriginVerificationScheduler.getInstance(); + + scheduler.addPendingOriginForTesting(Origin.create(aboutPageUrl)); + Assert.assertEquals(2, scheduler.getPendingOriginsForTesting().size()); + + InstrumentationRegistry.getInstrumentation().runOnMainSync( + () -> mTestContainerView.getAwContents().loadUrl(aboutPageUrl, null)); + mContentsClient.waitForFullLoad(); + + Assert.assertEquals(2, scheduler.getPendingOriginsForTesting().size()); + Assert.assertTrue( + scheduler.getPendingOriginsForTesting().contains(Origin.create(aboutPageUrl))); + } + + @Test + @SmallTest + @Feature({"AndroidWebView"}) + @CommandLineFlags.Add({"enable-features=WebViewRestrictThirdPartyContent"}) + public void testfThridPartyRestrictionInitAndScheduleAll() throws Throwable { + final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + CountDownLatch countVerifiedLatch = new CountDownLatch(1); + mActivityTestRule.runOnUiThread( + () + -> AwOriginVerificationScheduler.initAndScheduleAll( + context.getPackageName(), context, + mActivityTestRule.getAwBrowserContext(), + (res) -> { countVerifiedLatch.countDown(); })); + countVerifiedLatch.await(); + + AwOriginVerificationScheduler scheduler = AwOriginVerificationScheduler.getInstance(); + + Set<Origin> pendingOrigins = scheduler.getPendingOriginsForTesting(); + Assert.assertEquals(0, pendingOrigins.size()); + } + + @Test + @SmallTest + @Feature({"AndroidWebView"}) + @CommandLineFlags.Add({"enable-features=WebViewRestrictThirdPartyContent"}) + public void testDoesNotBlockVerifiedContent() throws Throwable { + final String aboutPageUrl = addAboutPageToTestServer(mWebServer); + final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + List<String> mSignatureFingerprints = + PackageUtils.getCertificateSHA256FingerprintForPackage(context.getPackageName()); + final String assetLinksUrl = + addAssetListToTestServer(mWebServer, mSignatureFingerprints.get(0)); + + mActivityTestRule.runOnUiThread( + () + -> AwOriginVerificationScheduler.init(context.getPackageName(), + mActivityTestRule.getAwBrowserContext(), context)); + + AwOriginVerificationScheduler scheduler = AwOriginVerificationScheduler.getInstance(); + + AwOriginVerificationScheduler.getInstance().addPendingOriginForTesting( + Origin.create(aboutPageUrl)); + Set<Origin> pendingOrigins = scheduler.getPendingOriginsForTesting(); + Assert.assertEquals(2, pendingOrigins.size()); + Assert.assertTrue(pendingOrigins.contains(Origin.create(aboutPageUrl))); + + InstrumentationRegistry.getInstrumentation().runOnMainSync( + () -> mTestContainerView.getAwContents().loadUrl(aboutPageUrl, null)); + mContentsClient.waitForFullLoad(); + + Set<Origin> pendingOriginsAfterRequest = scheduler.getPendingOriginsForTesting(); + Assert.assertEquals(1, pendingOriginsAfterRequest.size()); + Assert.assertFalse(pendingOriginsAfterRequest.contains(Origin.create(aboutPageUrl))); + + Assert.assertEquals(CommonResources.ABOUT_TITLE, mAwContents.getTitle()); + } + + @Test + @SmallTest + @Feature({"AndroidWebView"}) + @CommandLineFlags.Add({"enable-features=WebViewRestrictThirdPartyContent"}) + public void doesBlockAccessForFailedValidation() throws Throwable { + final String webpageNotAvailable = "Webpage not available"; + + final String aboutPageUrl = addAboutPageToTestServer(mWebServer); + final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + mActivityTestRule.runOnUiThread( + () + -> AwOriginVerificationScheduler.init(context.getPackageName(), + mActivityTestRule.getAwBrowserContext(), context)); + + Set<Origin> pendingOrigins = + AwOriginVerificationScheduler.getInstance().getPendingOriginsForTesting(); + Assert.assertFalse(pendingOrigins.contains(Origin.create(aboutPageUrl))); + + InstrumentationRegistry.getInstrumentation().runOnMainSync( + () -> mTestContainerView.getAwContents().loadUrl(aboutPageUrl, null)); + mContentsClient.waitForFullLoad(); + + Assert.assertEquals(webpageNotAvailable, mAwContents.getTitle()); + } +}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java index f485f558..e25a02f 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
@@ -21,7 +21,6 @@ import org.chromium.android_webview.test.TestAwContentsClient.OnReceivedErrorHelper; import org.chromium.android_webview.test.util.CommonResources; import org.chromium.android_webview.test.util.JSUtils; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer; import org.chromium.content_public.common.ContentUrlConstants; @@ -72,7 +71,6 @@ @Test @MediumTest @Feature({"AndroidWebView"}) - @DisabledTest(message = "crbug.com/652577") public void testCalledAfterError() throws Throwable { class LocalTestClient extends TestAwContentsClient { private boolean mIsOnReceivedErrorCalled;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/devui/FlagsFragmentTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/devui/FlagsFragmentTest.java index 63c182f..821908d 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/devui/FlagsFragmentTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/devui/FlagsFragmentTest.java
@@ -10,6 +10,7 @@ import static androidx.test.espresso.action.ViewActions.replaceText; import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.RootMatchers.isDialog; import static androidx.test.espresso.matcher.ViewMatchers.hasSibling; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withId; @@ -21,7 +22,6 @@ import static org.hamcrest.Matchers.anything; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.lessThan; import static org.hamcrest.Matchers.not; @@ -512,12 +512,17 @@ */ private DataInteraction toggleFlag(DataInteraction flagInteraction, Boolean state) { String stateText = state == null ? "Default" : state ? "Enabled" : "Disabled"; + // We first select the spinner on the list of flags. + // That will make a dialog appear witch the option we wish to select. flagInteraction.onChildView(withId(R.id.flag_toggle)).perform(click()); - // In rare conditions, the onData check can be performed before the dialog - // has been displayed. The wait for view waits for the default text that - // is only present in the dialog to be visible (see crbug.com/1400515 for more details). - ViewUtils.waitForView(withText(containsString("Default"))); - onData(allOf(is(instanceOf(String.class)), is(stateText))).perform(click()); + // We then select the state we want from the dialog. + // We cannot use onData because in rare conditions, + // the onData check can be performed before the dialog has been displayed. + // Adding the inRoot check below ensures that we don't match with the spinner that also + // have the state we are waiting for (see crbug.com/1400515 for more details). + onView(withText(stateText)).inRoot(isDialog()).perform(click()); + // Finally we confirm that the original spinner was updated after the dialog option has + // been selected. flagInteraction.onChildView(withId(R.id.flag_toggle)) .check(matches(withSpinnerText(containsString(stateText))));
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index bfaa9a58..57339a3 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -359,6 +359,7 @@ "../javatests/src/org/chromium/android_webview/test/AwPersistentOriginTrialTest.java", "../javatests/src/org/chromium/android_webview/test/AwProxyControllerTest.java", "../javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java", + "../javatests/src/org/chromium/android_webview/test/AwRestrictThirdPartyContentTest.java", "../javatests/src/org/chromium/android_webview/test/AwSecondBrowserProcessTest.java", "../javatests/src/org/chromium/android_webview/test/AwServiceWorkerClientTest.java", "../javatests/src/org/chromium/android_webview/test/AwServiceWorkerSettingsTest.java",
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 00bb7a1..6c07340 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2195,6 +2195,8 @@ "wm/lock_window_state.h", "wm/mru_window_tracker.cc", "wm/mru_window_tracker.h", + "wm/multi_display/multi_display_metrics_controller.cc", + "wm/multi_display/multi_display_metrics_controller.h", "wm/multitask_menu_nudge_controller.cc", "wm/multitask_menu_nudge_controller.h", "wm/native_cursor_manager_ash.cc", @@ -3280,6 +3282,7 @@ "wm/lock_layout_manager_unittest.cc", "wm/lock_state_controller_unittest.cc", "wm/mru_window_tracker_unittest.cc", + "wm/multi_display/multi_display_metrics_controller_unittest.cc", "wm/multitask_menu_nudge_controller_unittest.cc", "wm/native_cursor_manager_ash_unittest.cc", "wm/overlay_event_filter_unittest.cc",
diff --git a/ash/ambient/ui/ambient_animation_view.cc b/ash/ambient/ui/ambient_animation_view.cc index 217b6c0..68c15bc7 100644 --- a/ash/ambient/ui/ambient_animation_view.cc +++ b/ash/ambient/ui/ambient_animation_view.cc
@@ -30,6 +30,7 @@ #include "ash/public/cpp/metrics_util.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" +#include "ash/style/ash_color_id.h" #include "base/check.h" #include "base/functional/bind.h" #include "base/location.h" @@ -290,8 +291,7 @@ views::BoxLayout::CrossAxisAlignment::kStart); glanceable_info_container_->SetBorder(CreateGlanceableInfoBorder()); glanceable_info_container_->AddChildView(std::make_unique<GlanceableInfoView>( - view_delegate_.get(), kTimeFontSizeDip, - /*time_temperature_font_color=*/gfx::kGoogleGrey900)); + view_delegate_.get(), this, kTimeFontSizeDip)); // Media string should appear in the top-right corner of the // AmbientAnimationView's bounds. @@ -305,12 +305,7 @@ views::BoxLayout::CrossAxisAlignment::kEnd); media_string_container_->SetBorder(CreateMediaStringBorder()); MediaStringView* media_string_view = media_string_container_->AddChildView( - std::make_unique<MediaStringView>(MediaStringView::Settings( - {/*icon_light_mode_color=*/gfx::kGoogleGrey600, - /*icon_dark_mode_color=*/gfx::kGoogleGrey500, - /*text_light_mode_color=*/gfx::kGoogleGrey600, - /*text_dark_mode_color=*/gfx::kGoogleGrey500, - kMediaStringTextElevation}))); + std::make_unique<MediaStringView>(this)); media_string_view->SetVisible(false); } @@ -391,6 +386,19 @@ window_to_throttle, animated_image_view_->animated_image()); } +SkColor AmbientAnimationView::GetTimeTemperatureFontColor() { + return gfx::kGoogleGrey900; +} + +MediaStringView::Settings AmbientAnimationView::GetSettings() { + return MediaStringView::Settings( + {/*icon_light_mode_color=*/gfx::kGoogleGrey600, + /*icon_dark_mode_color=*/gfx::kGoogleGrey500, + /*text_light_mode_color=*/gfx::kGoogleGrey600, + /*text_dark_mode_color=*/gfx::kGoogleGrey500, + kMediaStringTextElevation}); +} + void AmbientAnimationView::StartPlayingAnimation() { // There should only be one active AmbientAnimationPlayer at any given time, // otherwise multiple active players can lead to confusing simultaneous state
diff --git a/ash/ambient/ui/ambient_animation_view.h b/ash/ambient/ui/ambient_animation_view.h index a2ff998b..d469268 100644 --- a/ash/ambient/ui/ambient_animation_view.h +++ b/ash/ambient/ui/ambient_animation_view.h
@@ -8,7 +8,9 @@ #include <memory> #include "ash/ambient/model/ambient_animation_photo_provider.h" +#include "ash/ambient/ui/glanceable_info_view.h" #include "ash/ambient/ui/jitter_calculator.h" +#include "ash/ambient/ui/media_string_view.h" #include "ash/ash_export.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" @@ -39,7 +41,9 @@ class ASH_EXPORT AmbientAnimationView : public views::View, public lottie::AnimationObserver, - public views::ViewObserver { + public views::ViewObserver, + public GlanceableInfoView::Delegate, + public MediaStringView::Delegate { public: METADATA_HEADER(AmbientAnimationView); @@ -63,6 +67,12 @@ void OnViewBoundsChanged(View* observed_view) override; void OnViewAddedToWidget(View* observed_view) override; + // GlanceableInfoView::Delegate: + SkColor GetTimeTemperatureFontColor() override; + + // MediaStringView::Delegate: + MediaStringView::Settings GetSettings() override; + void StartPlayingAnimation(); void StartThroughputTracking(); void RestartThroughputTracking();
diff --git a/ash/ambient/ui/ambient_background_image_view.cc b/ash/ambient/ui/ambient_background_image_view.cc index a0371f7..53c69c1 100644 --- a/ash/ambient/ui/ambient_background_image_view.cc +++ b/ash/ambient/ui/ambient_background_image_view.cc
@@ -14,6 +14,7 @@ #include "ash/ambient/ui/media_string_view.h" #include "ash/ambient/util/ambient_util.h" #include "ash/shell.h" +#include "ash/style/ash_color_id.h" #include "base/no_destructor.h" #include "base/rand_util.h" #include "ui/base/metadata/metadata_impl_macros.h" @@ -155,6 +156,24 @@ SetResizedImage(related_image_view_, related_image_unscaled_); } +MediaStringView::Settings AmbientBackgroundImageView::GetSettings() { + return MediaStringView::Settings( + {/*icon_light_mode_color=*/ambient::util::GetColor( + GetColorProvider(), kColorAshIconColorPrimary, + /*dark_mode_enabled=*/false), + /*icon_dark_mode_color=*/ + ambient::util::GetColor(GetColorProvider(), kColorAshIconColorPrimary, + /*dark_mode_enabled=*/true), + /*text_light_mode_color=*/ + ambient::util::GetColor(GetColorProvider(), kColorAshTextColorPrimary, + /*dark_mode_enabled=*/false), + /*text_dark_mode_color=*/ + ambient::util::GetColor(GetColorProvider(), kColorAshTextColorPrimary, + /*dark_mode_enabled=*/true), + /*text_shadow_elevation=*/ + ambient::util::kDefaultTextShadowElevation}); +} + void AmbientBackgroundImageView::UpdateImage( const gfx::ImageSkia& image, const gfx::ImageSkia& related_image, @@ -264,24 +283,7 @@ gfx::Insets::TLBR(kMediaStringMarginDip + shadow_insets.top(), 0, 0, kMediaStringMarginDip + shadow_insets.right())); media_string_view_ = media_string_view_container_->AddChildView( - std::make_unique<MediaStringView>(MediaStringView::Settings( - {/*icon_light_mode_color=*/ambient::util::GetContentLayerColor( - AshColorProvider::ContentLayerType::kIconColorPrimary, - /*dark_mode_enable=*/false), - /*icon_dark_mode_color=*/ - ambient::util::GetContentLayerColor( - AshColorProvider::ContentLayerType::kIconColorPrimary, - /*dark_mode_enable=*/true), - /*text_light_mode_color=*/ - ambient::util::GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary, - /*dark_mode_enable=*/false), - /*text_dark_mode_color=*/ - ambient::util::GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary, - /*dark_mode_enable=*/true), - /*text_shadow_elevation=*/ - ambient::util::kDefaultTextShadowElevation}))); + std::make_unique<MediaStringView>(this)); media_string_view_->SetVisible(false); }
diff --git a/ash/ambient/ui/ambient_background_image_view.h b/ash/ambient/ui/ambient_background_image_view.h index 324d8c6..3252b6c 100644 --- a/ash/ambient/ui/ambient_background_image_view.h +++ b/ash/ambient/ui/ambient_background_image_view.h
@@ -8,6 +8,7 @@ #include <string> #include "ash/ambient/ui/ambient_view_delegate.h" +#include "ash/ambient/ui/media_string_view.h" #include "ash/ash_export.h" #include "ash/public/cpp/ambient/ambient_backend_controller.h" #include "base/memory/raw_ptr.h" @@ -29,7 +30,8 @@ // It also handles specific mouse/gesture events to dismiss ambient when user // interacts with the background photos. class ASH_EXPORT AmbientBackgroundImageView : public views::View, - public views::ViewObserver { + public views::ViewObserver, + public MediaStringView::Delegate { public: METADATA_HEADER(AmbientBackgroundImageView); @@ -47,6 +49,9 @@ // views::ViewObserver: void OnViewBoundsChanged(views::View* observed_view) override; + // MediaStringView::Delegate: + MediaStringView::Settings GetSettings() override; + // Updates the display images. void UpdateImage(const gfx::ImageSkia& image, const gfx::ImageSkia& related_image,
diff --git a/ash/ambient/ui/ambient_info_view.cc b/ash/ambient/ui/ambient_info_view.cc index 6967e9c..33fec11 100644 --- a/ash/ambient/ui/ambient_info_view.cc +++ b/ash/ambient/ui/ambient_info_view.cc
@@ -10,6 +10,7 @@ #include "ash/ambient/ui/ambient_view_ids.h" #include "ash/ambient/ui/glanceable_info_view.h" #include "ash/ambient/util/ambient_util.h" +#include "ash/style/ash_color_id.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/compositor/layer.h" #include "ui/gfx/geometry/insets.h" @@ -33,8 +34,6 @@ views::Label* AddLabel(views::View* parent) { auto* label = parent->AddChildView(std::make_unique<views::Label>()); label->SetAutoColorReadabilityEnabled(false); - label->SetEnabledColor(ambient::util::GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorSecondary)); label->SetFontList(ambient::util::GetDefaultFontlist().DeriveWithSizeDelta( kDetailsFontSizeDip - kDefaultFontSizeDip)); label->SetPaintToLayer(); @@ -58,8 +57,16 @@ const auto* color_provider = GetColorProvider(); details_label_->SetShadows( ambient::util::GetTextShadowValues(color_provider)); + details_label_->SetEnabledColor( + ambient::util::GetColor(color_provider, kColorAshTextColorSecondary)); related_details_label_->SetShadows( ambient::util::GetTextShadowValues(color_provider)); + related_details_label_->SetEnabledColor( + ambient::util::GetColor(color_provider, kColorAshTextColorSecondary)); +} + +SkColor AmbientInfoView::GetTimeTemperatureFontColor() { + return ambient::util::GetColor(GetColorProvider(), kColorAshTextColorPrimary); } void AmbientInfoView::UpdateImageDetails( @@ -96,10 +103,8 @@ layout->set_between_child_spacing(kSpacingDip + shadow_insets.top() + shadow_insets.bottom()); - glanceable_info_view_ = AddChildView(std::make_unique<GlanceableInfoView>( - delegate_, kTimeFontSizeDip, /*time_temperature_font_color=*/ - ambient::util::GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary))); + glanceable_info_view_ = AddChildView( + std::make_unique<GlanceableInfoView>(delegate_, this, kTimeFontSizeDip)); glanceable_info_view_->SetPaintToLayer(); details_label_ = AddLabel(this);
diff --git a/ash/ambient/ui/ambient_info_view.h b/ash/ambient/ui/ambient_info_view.h index 7ffe3d0..b8a2e334 100644 --- a/ash/ambient/ui/ambient_info_view.h +++ b/ash/ambient/ui/ambient_info_view.h
@@ -6,6 +6,7 @@ #define ASH_AMBIENT_UI_AMBIENT_INFO_VIEW_H_ #include "ash/ambient/ui/ambient_view_delegate.h" +#include "ash/ambient/ui/glanceable_info_view.h" #include "ash/ash_export.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/view.h" @@ -22,7 +23,8 @@ class GlanceableInfoView; -class ASH_EXPORT AmbientInfoView : public views::View { +class ASH_EXPORT AmbientInfoView : public views::View, + public GlanceableInfoView::Delegate { public: METADATA_HEADER(AmbientInfoView); @@ -31,9 +33,12 @@ AmbientInfoView& operator=(AmbientInfoView&) = delete; ~AmbientInfoView() override; - // views::View + // views::View: void OnThemeChanged() override; + // GlanceableInfoView::Delegate: + SkColor GetTimeTemperatureFontColor() override; + void UpdateImageDetails(const std::u16string& details, const std::u16string& related_details);
diff --git a/ash/ambient/ui/glanceable_info_view.cc b/ash/ambient/ui/glanceable_info_view.cc index 07e27b23..3fdc8af 100644 --- a/ash/ambient/ui/glanceable_info_view.cc +++ b/ash/ambient/ui/glanceable_info_view.cc
@@ -22,6 +22,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/color/color_id.h" #include "ui/compositor/layer.h" #include "ui/gfx/font_list.h" #include "ui/gfx/geometry/insets.h" @@ -75,12 +76,13 @@ } // namespace -GlanceableInfoView::GlanceableInfoView(AmbientViewDelegate* delegate, - int time_font_size_dip, - SkColor time_temperature_font_color) +GlanceableInfoView::GlanceableInfoView( + AmbientViewDelegate* delegate, + GlanceableInfoView::Delegate* glanceable_info_view_delegate, + int time_font_size_dip) : delegate_(delegate), - time_font_size_dip_(time_font_size_dip), - time_temperature_font_color_(time_temperature_font_color) { + glanceable_info_view_delegate_(glanceable_info_view_delegate), + time_font_size_dip_(time_font_size_dip) { DCHECK(delegate); DCHECK_GT(time_font_size_dip_, 0); SetID(AmbientViewID::kAmbientGlanceableInfoView); @@ -106,7 +108,12 @@ gfx::ShadowValues text_shadow_values = ambient::util::GetTextShadowValues(GetColorProvider()); time_view_->SetTextShadowValues(text_shadow_values); + time_view_->SetTextColor( + glanceable_info_view_delegate_->GetTimeTemperatureFontColor(), + /*auto_color_readability_enabled=*/false); temperature_->SetShadows(text_shadow_values); + temperature_->SetEnabledColor( + glanceable_info_view_delegate_->GetTimeTemperatureFontColor()); } void GlanceableInfoView::Show() { @@ -158,8 +165,6 @@ 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(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(gfx::Insets::TLBR( -kUnifiedTrayTextTopPadding, -kUnifiedTrayTimeLeftPadding, 0, @@ -180,7 +185,6 @@ // Inits the temp view. temperature_ = AddChildView(std::make_unique<views::Label>()); temperature_->SetAutoColorReadabilityEnabled(false); - temperature_->SetEnabledColor(time_temperature_font_color_); temperature_->SetFontList(GetWeatherTemperatureFontList()); temperature_->SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR( 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 e664326..b377c04 100644 --- a/ash/ambient/ui/glanceable_info_view.h +++ b/ash/ambient/ui/glanceable_info_view.h
@@ -9,6 +9,7 @@ #include "ash/ambient/model/ambient_weather_model_observer.h" #include "base/scoped_observation.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/color/color_id.h" #include "ui/views/view.h" namespace views { @@ -25,11 +26,20 @@ class GlanceableInfoView : public views::View, public AmbientWeatherModelObserver { public: + class Delegate { + public: + virtual ~Delegate() = default; + + // Returns the color for time and temperature text in |GlanceableInfoView|. + virtual SkColor GetTimeTemperatureFontColor() = 0; + }; + METADATA_HEADER(GlanceableInfoView); - GlanceableInfoView(AmbientViewDelegate* delegate, - int time_font_size_dip, - SkColor time_temperature_font_color); + GlanceableInfoView( + AmbientViewDelegate* delegate, + GlanceableInfoView::Delegate* glanceable_info_view_delegate, + int time_font_size_dip); GlanceableInfoView(const GlanceableInfoView&) = delete; GlanceableInfoView& operator=(const GlanceableInfoView&) = delete; ~GlanceableInfoView() override; @@ -57,8 +67,11 @@ // Owned by |AmbientController|. AmbientViewDelegate* const delegate_ = nullptr; + // Unowned. Must out live |GlancealeInfoView|. + base::raw_ptr<GlanceableInfoView::Delegate> const + glanceable_info_view_delegate_ = nullptr; + const int time_font_size_dip_; - const SkColor time_temperature_font_color_; base::ScopedObservation<AmbientWeatherModel, AmbientWeatherModelObserver> scoped_weather_model_observer_{this};
diff --git a/ash/ambient/ui/media_string_view.cc b/ash/ambient/ui/media_string_view.cc index d46e31d..5bc9d93 100644 --- a/ash/ambient/ui/media_string_view.cc +++ b/ash/ambient/ui/media_string_view.cc
@@ -64,8 +64,8 @@ } // namespace -MediaStringView::MediaStringView(Settings settings) - : settings_(std::move(settings)) { +MediaStringView::MediaStringView(MediaStringView::Delegate* delegate) + : delegate_(delegate) { SetID(AmbientViewID::kAmbientMediaStringView); InitLayout(); } @@ -75,19 +75,25 @@ void MediaStringView::OnThemeChanged() { views::View::OnThemeChanged(); media_text_->SetShadows(ambient::util::GetTextShadowValues( - GetColorProvider(), settings_.text_shadow_elevation)); + GetColorProvider(), delegate_->GetSettings().text_shadow_elevation)); const bool dark_mode_enabled = DarkLightModeControllerImpl::Get()->IsDarkModeEnabled(); DCHECK(icon_); - icon_->SetImage(gfx::CreateVectorIcon(kMusicNoteIcon, kMusicNoteIconSizeDip, - dark_mode_enabled - ? settings_.icon_dark_mode_color - : settings_.icon_light_mode_color)); + icon_->SetImage(gfx::CreateVectorIcon( + kMusicNoteIcon, kMusicNoteIconSizeDip, + dark_mode_enabled ? delegate_->GetSettings().icon_dark_mode_color + : delegate_->GetSettings().icon_light_mode_color)); DCHECK(media_text_); - media_text_->SetEnabledColor(dark_mode_enabled - ? settings_.text_dark_mode_color - : settings_.text_light_mode_color); + media_text_->SetEnabledColor( + dark_mode_enabled ? delegate_->GetSettings().text_dark_mode_color + : delegate_->GetSettings().text_light_mode_color); + gfx::Insets shadow_insets = + gfx::ShadowValue::GetMargin(ambient::util::GetTextShadowValues( + nullptr, delegate_->GetSettings().text_shadow_elevation)); + // Compensate the shadow insets to put the text middle align with the icon. + media_text_->SetBorder(views::CreateEmptyBorder( + gfx::Insets::TLBR(-shadow_insets.bottom(), 0, -shadow_insets.top(), 0))); } void MediaStringView::OnViewBoundsChanged(views::View* observed_view) { @@ -200,12 +206,6 @@ .DeriveWithSizeDelta(kMediaStringFontSizeDip - kDefaultFontSizeDip) .DeriveWithWeight(gfx::Font::Weight::MEDIUM)); media_text_->SetElideBehavior(gfx::ElideBehavior::NO_ELIDE); - gfx::Insets shadow_insets = - gfx::ShadowValue::GetMargin(ambient::util::GetTextShadowValues( - nullptr, settings_.text_shadow_elevation)); - // Compensate the shadow insets to put the text middle align with the icon. - media_text_->SetBorder(views::CreateEmptyBorder( - gfx::Insets::TLBR(-shadow_insets.bottom(), 0, -shadow_insets.top(), 0))); BindMediaControllerObserver(); } @@ -286,10 +286,11 @@ { // Desired speed is 10 seconds for kMediaStringMaxWidthDip. const int text_width = media_text_->GetPreferredSize().width(); - const int shadow_width = gfx::ShadowValue::GetMargin( - ambient::util::GetTextShadowValues( - nullptr, settings_.text_shadow_elevation)) - .width(); + const int shadow_width = + gfx::ShadowValue::GetMargin( + ambient::util::GetTextShadowValues( + nullptr, delegate_->GetSettings().text_shadow_elevation)) + .width(); const int start_x = text_layer->GetTargetTransform().To2dTranslation().x(); const int end_x = -(text_width + shadow_width) / 2; const int transform_distance = start_x - end_x;
diff --git a/ash/ambient/ui/media_string_view.h b/ash/ambient/ui/media_string_view.h index 636c7f1..8168ece 100644 --- a/ash/ambient/ui/media_string_view.h +++ b/ash/ambient/ui/media_string_view.h
@@ -39,9 +39,17 @@ int text_shadow_elevation; }; + class Delegate { + public: + virtual ~Delegate() = default; + + // Returns the settings for |MediaStringView|. + virtual Settings GetSettings() = 0; + }; + METADATA_HEADER(MediaStringView); - explicit MediaStringView(Settings settings); + explicit MediaStringView(MediaStringView::Delegate* delegate); MediaStringView(const MediaStringView&) = delete; MediaStringView& operator=(const MediaStringView&) = delete; ~MediaStringView() override; @@ -90,7 +98,8 @@ views::Label* media_text_label_for_testing() { return media_text_; } - const Settings settings_; + // Unowned. Must out live |MediaStringView|. + base::raw_ptr<MediaStringView::Delegate> delegate_ = nullptr; // Music eighth note. views::ImageView* icon_ = nullptr;
diff --git a/ash/ambient/util/ambient_util.cc b/ash/ambient/util/ambient_util.cc index 888c63fe..bb06a41 100644 --- a/ash/ambient/util/ambient_util.cc +++ b/ash/ambient/util/ambient_util.cc
@@ -9,6 +9,7 @@ #include "ash/public/cpp/ambient/ambient_backend_controller.h" #include "ash/public/cpp/ambient/ambient_client.h" #include "ash/public/cpp/ambient/proto/photo_cache_entry.pb.h" +#include "ash/style/ash_color_id.h" #include "ash/style/dark_light_mode_controller_impl.h" #include "ash/utility/lottie_util.h" #include "base/no_destructor.h" @@ -28,26 +29,22 @@ return LockScreen::HasInstance() && LockScreen::Get()->screen_type() == type; } -SkColor GetContentLayerColor( - AshColorProvider::ContentLayerType content_layer_type) { - return GetContentLayerColor( - content_layer_type, - DarkLightModeControllerImpl::Get()->IsDarkModeEnabled()); +SkColor GetColor(const ui::ColorProvider* color_provider, + ui::ColorId color_id) { + return GetColor(color_provider, color_id, + DarkLightModeControllerImpl::Get()->IsDarkModeEnabled()); } -SkColor GetContentLayerColor( - AshColorProvider::ContentLayerType content_layer_type, - bool dark_mode_enable) { - auto* ash_color_provider = AshColorProvider::Get(); - - switch (content_layer_type) { - case AshColorProvider::ContentLayerType::kTextColorPrimary: - case AshColorProvider::ContentLayerType::kTextColorSecondary: - case AshColorProvider::ContentLayerType::kIconColorPrimary: - case AshColorProvider::ContentLayerType::kIconColorSecondary: - return dark_mode_enable - ? ash_color_provider->GetContentLayerColor(content_layer_type) - : SK_ColorWHITE; +SkColor GetColor(const ui::ColorProvider* color_provider, + ui::ColorId color_id, + bool dark_mode_enabled) { + switch (color_id) { + case kColorAshTextColorPrimary: + case kColorAshTextColorSecondary: + case kColorAshIconColorPrimary: + case kColorAshIconColorSecondary: + return dark_mode_enabled ? color_provider->GetColor(color_id) + : SK_ColorWHITE; default: NOTREACHED() << "Unsupported content layer type"; // Return a very bright color so it's obvious there is a mistake.
diff --git a/ash/ambient/util/ambient_util.h b/ash/ambient/util/ambient_util.h index 9292674..69779c7 100644 --- a/ash/ambient/util/ambient_util.h +++ b/ash/ambient/util/ambient_util.h
@@ -31,16 +31,15 @@ ASH_EXPORT bool IsShowing(LockScreen::ScreenType type); // Ambient mode uses non-standard colors for some text and the media icon, so -// provides a wrapper for |AshColorProvider::GetContentLayerColor|. This is -// currently only supported for primary and secondary text and icons. -// TODO(b/262012604) rework to use ui::ColorProvider. -ASH_EXPORT SkColor -GetContentLayerColor(AshColorProvider::ContentLayerType content_layer_type, - bool dark_mode_enable); +// provides a wrapper for |ColorProvider::GetColor|. This is currently only +// supported for primary and secondary text and icons. +ASH_EXPORT SkColor GetColor(const ui::ColorProvider* color_provider, + ui::ColorId color_id, + bool dark_mode_enabled); + // Version of the above that uses AshColorProvider::IsDarkModeEnabled(). -// TODO(b/262012604) rework to use ui::ColorProvider. -ASH_EXPORT SkColor -GetContentLayerColor(AshColorProvider::ContentLayerType content_layer_type); +ASH_EXPORT SkColor GetColor(const ui::ColorProvider* color_provider, + ui::ColorId color_id); // Returns the default fontlist for Ambient Mode. ASH_EXPORT const gfx::FontList& GetDefaultFontlist();
diff --git a/ash/app_list/views/app_list_page.cc b/ash/app_list/views/app_list_page.cc index c1a9b93..0552f4be 100644 --- a/ash/app_list/views/app_list_page.cc +++ b/ash/app_list/views/app_list_page.cc
@@ -5,7 +5,6 @@ #include "ash/app_list/views/app_list_page.h" #include "ash/app_list/views/contents_view.h" -#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/views/focus/focus_manager.h" namespace ash { @@ -47,18 +46,6 @@ this, GetWidget(), true /* reverse */, false /* dont_loop */); } -void AppListPage::AnimateOpacity(AppListViewState current_view_state, - AppListViewState target_view_state, - const OpacityAnimator& animator) { - animator.Run(this, target_view_state != AppListViewState::kClosed); -} - -void AppListPage::AnimateYPosition(AppListViewState target_view_state, - const TransformAnimator& animator, - float default_offset) { - animator.Run(default_offset, layer()); -} - gfx::Rect AppListPage::GetDefaultContentsBounds() const { DCHECK(contents_view_); return contents_view_->GetContentsBounds();
diff --git a/ash/app_list/views/app_list_page.h b/ash/app_list/views/app_list_page.h index 4b1ae881..285bbaf 100644 --- a/ash/app_list/views/app_list_page.h +++ b/ash/app_list/views/app_list_page.h
@@ -5,8 +5,8 @@ #ifndef ASH_APP_LIST_VIEWS_APP_LIST_PAGE_H_ #define ASH_APP_LIST_VIEWS_APP_LIST_PAGE_H_ -#include "ash/app_list/model/app_list_model.h" #include "ash/ash_export.h" +#include "ash/public/cpp/app_list/app_list_types.h" #include "ui/views/view.h" namespace ash { @@ -90,27 +90,6 @@ // Returns the last focusable view in this page. views::View* GetLastFocusableView(); - // Called when the app list view state changes to |target_view_state| to - // animate the app list page opacity. - // |animator| - callback that when run starts the opacity animation. - using OpacityAnimator = - base::RepeatingCallback<void(views::View* view, bool target_visibility)>; - virtual void AnimateOpacity(AppListViewState current_view_state, - AppListViewState target_view_state, - const OpacityAnimator& animator); - - // Called when the app list view state changes to |target_view_state| to - // animate the app list page vertical offset from the app list view top. - // |animator| - The callback that runs the transform animation to update the - // page's vertical position. - // |default_offset| - the default transform offset that can be passed to - // |animator| to follow the search box position animation. - using TransformAnimator = - base::RepeatingCallback<void(float offset, ui::Layer* layer)>; - virtual void AnimateYPosition(AppListViewState target_view_state, - const TransformAnimator& animator, - float default_offset); - // Returns the default bounds of pages inside the contents view, in the // contents view's coordinate space. This is the area of the contents view // below the search box.
diff --git a/ash/app_list/views/apps_container_view.cc b/ash/app_list/views/apps_container_view.cc index 2de42fc3..a6873c8 100644 --- a/ash/app_list/views/apps_container_view.cc +++ b/ash/app_list/views/apps_container_view.cc
@@ -36,7 +36,6 @@ #include "base/time/time.h" #include "ui/color/color_id.h" #include "ui/compositor/layer.h" -#include "ui/compositor/layer_animation_element.h" #include "ui/compositor/layer_animator.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/display/display.h" @@ -818,34 +817,6 @@ app_list_state == AppListViewState::kFullscreenSearch); } -void AppsContainerView::AnimateOpacity(AppListViewState current_view_state, - AppListViewState target_view_state, - const OpacityAnimator& animator) { - if (!apps_grid_view_->layer()->GetAnimator()->IsAnimatingProperty( - ui::LayerAnimationElement::OPACITY)) { - apps_grid_view_->layer()->SetOpacity( - current_view_state != AppListViewState::kClosed ? 1.0f : 0.0f); - } - - const bool target_grid_visibility = - target_view_state == AppListViewState::kFullscreenAllApps || - target_view_state == AppListViewState::kFullscreenSearch; - animator.Run(apps_grid_view_, target_grid_visibility); - animator.Run(page_switcher_, target_grid_visibility); -} - -void AppsContainerView::AnimateYPosition(AppListViewState target_view_state, - const TransformAnimator& animator, - float default_offset) { - const int target_app_list_y = GetAppListY(target_view_state); - - scrollable_container_->SetY(target_app_list_y + - scrollable_container_y_distance_); - animator.Run(default_offset, scrollable_container_->layer()); - page_switcher_->SetY(target_app_list_y + scrollable_container_y_distance_); - animator.Run(default_offset, page_switcher_->layer()); -} - void AppsContainerView::Layout() { gfx::Rect rect(GetContentsBounds()); if (rect.IsEmpty())
diff --git a/ash/app_list/views/apps_container_view.h b/ash/app_list/views/apps_container_view.h index 83ea9ca7..247c1424 100644 --- a/ash/app_list/views/apps_container_view.h +++ b/ash/app_list/views/apps_container_view.h
@@ -137,12 +137,6 @@ AppListState state, const gfx::Rect& contents_bounds, const gfx::Rect& search_box_bounds) const override; - void AnimateOpacity(AppListViewState current_view_state, - AppListViewState target_view_state, - const OpacityAnimator& animator) override; - void AnimateYPosition(AppListViewState target_view_state, - const TransformAnimator& animator, - float default_offset) override; // AppListModelProvider::Observer: void OnActiveAppListModelsChanged(AppListModel* model,
diff --git a/ash/app_list/views/assistant/assistant_page_view.cc b/ash/app_list/views/assistant/assistant_page_view.cc index d36c6730..e49a10b 100644 --- a/ash/app_list/views/assistant/assistant_page_view.cc +++ b/ash/app_list/views/assistant/assistant_page_view.cc
@@ -8,7 +8,6 @@ #include <utility> #include "ash/app_list/app_list_view_delegate.h" -#include "ash/app_list/views/app_list_main_view.h" #include "ash/app_list/views/app_list_view.h" #include "ash/app_list/views/assistant/assistant_main_view.h" #include "ash/app_list/views/contents_view.h" @@ -16,11 +15,7 @@ #include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/ui/assistant_ui_constants.h" #include "ash/assistant/ui/assistant_view_delegate.h" -#include "ash/assistant/ui/colors/assistant_colors.h" -#include "ash/assistant/ui/colors/assistant_colors_util.h" #include "ash/assistant/util/assistant_util.h" -#include "ash/constants/ash_features.h" -#include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/assistant/assistant_state.h" #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h" #include "ash/public/cpp/style/color_provider.h" @@ -31,7 +26,6 @@ #include "ash/style/ash_color_id.h" #include "base/functional/bind.h" #include "base/metrics/histogram_functions.h" -#include "base/strings/utf_string_conversions.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkTypes.h" #include "ui/accessibility/ax_node_data.h" @@ -42,7 +36,6 @@ #include "ui/compositor/layer_type.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/compositor_extra/shadow.h" -#include "ui/views/background.h" #include "ui/views/layout/layout_manager_base.h" namespace ash { @@ -315,24 +308,6 @@ return gfx::Size(kPreferredWidthDip, kSearchBoxHeightDip); } -void AssistantPageView::AnimateYPosition(AppListViewState target_view_state, - const TransformAnimator& animator, - float default_offset) { - // Assistant page view may host native views for its content. The native view - // hosts use view to widget coordinate conversion to calculate the native view - // bounds, and thus depend on the view transform values. - // Make sure the view is laid out before starting the transform animation so - // native views are not placed according to interim, animated page transform - // value. - layer()->GetAnimator()->StopAnimatingProperty( - ui::LayerAnimationElement::TRANSFORM); - if (needs_layout()) - Layout(); - - animator.Run(default_offset, layer()); - animator.Run(default_offset, view_shadow_->shadow()->shadow_layer()); -} - void AssistantPageView::UpdatePageOpacityForState(AppListState state, float search_box_opacity) { layer()->SetOpacity(search_box_opacity);
diff --git a/ash/app_list/views/assistant/assistant_page_view.h b/ash/app_list/views/assistant/assistant_page_view.h index 25e0dc6..5b2758bd 100644 --- a/ash/app_list/views/assistant/assistant_page_view.h +++ b/ash/app_list/views/assistant/assistant_page_view.h
@@ -54,9 +54,6 @@ AppListState state, const gfx::Rect& contents_bounds, const gfx::Rect& search_box_bounds) const override; - void AnimateYPosition(AppListViewState target_view_state, - const TransformAnimator& animator, - float default_offset) override; // ui::EventHandler: void OnMouseEvent(ui::MouseEvent* event) override;
diff --git a/ash/app_list/views/search_result_page_view.cc b/ash/app_list/views/search_result_page_view.cc index 047f8d5..987be16 100644 --- a/ash/app_list/views/search_result_page_view.cc +++ b/ash/app_list/views/search_result_page_view.cc
@@ -9,23 +9,17 @@ #include <algorithm> #include <utility> -#include "ash/app_list/app_list_util.h" #include "ash/app_list/views/app_list_search_view.h" #include "ash/app_list/views/contents_view.h" #include "ash/app_list/views/search_box_view.h" -#include "ash/app_list/views/search_result_page_anchored_dialog.h" #include "ash/public/cpp/style/color_provider.h" #include "ash/search_box/search_box_constants.h" -#include "ash/style/ash_color_id.h" #include "ash/style/system_shadow.h" #include "base/functional/bind.h" #include "base/time/time.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" -#include "ui/color/color_id.h" -#include "ui/color/color_provider.h" #include "ui/compositor/layer.h" -#include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/insets.h" #include "ui/views/animation/animation_builder.h" #include "ui/views/background.h" @@ -391,32 +385,6 @@ ShouldShowSearchResultView()); } -void SearchResultPageView::AnimateYPosition(AppListViewState target_view_state, - const TransformAnimator& animator, - float default_offset) { - // Search result page view may host a native view to show answer card results. - // The native view hosts use view to widget coordinate conversion to calculate - // the native view bounds, and thus depend on the view transform values. - // Make sure the view is laid out before starting the transform animation so - // native views are not placed according to interim, animated page transform - // value. - layer()->GetAnimator()->StopAnimatingProperty( - ui::LayerAnimationElement::TRANSFORM); - if (needs_layout()) - Layout(); - - animator.Run(default_offset, layer()); - if (shadow_) - animator.Run(default_offset, shadow_->GetNinePatchLayer()); - SearchResultPageAnchoredDialog* search_page_dialog = - dialog_controller_->dialog(); - if (search_page_dialog) { - const float offset = - search_page_dialog->AdjustVerticalTransformOffset(default_offset); - animator.Run(offset, search_page_dialog->widget()->GetLayer()); - } -} - void SearchResultPageView::UpdatePageOpacityForState(AppListState state, float search_box_opacity) { layer()->SetOpacity(search_box_opacity);
diff --git a/ash/app_list/views/search_result_page_view.h b/ash/app_list/views/search_result_page_view.h index 9558ded..559d13dee 100644 --- a/ash/app_list/views/search_result_page_view.h +++ b/ash/app_list/views/search_result_page_view.h
@@ -41,9 +41,6 @@ // AppListPage overrides: void OnHidden() override; void OnShown() override; - void AnimateYPosition(AppListViewState target_view_state, - const TransformAnimator& animator, - float default_offset) override; void UpdatePageOpacityForState(AppListState state, float search_box_opacity) override; void UpdatePageBoundsForState(AppListState state,
diff --git a/ash/capture_mode/capture_mode_controller.h b/ash/capture_mode/capture_mode_controller.h index 8ba4edf9..3a98b0f 100644 --- a/ash/capture_mode/capture_mode_controller.h +++ b/ash/capture_mode/capture_mode_controller.h
@@ -236,13 +236,13 @@ // Returns the current parent window for the on-capture-surface widgets such // as `CaptureModeCameraController::camera_preview_widget_` and - // `CaptureModeDemoToolsController::demo_tools_widget_`. + // `CaptureModeDemoToolsController::key_combo_widget_`. aura::Window* GetOnCaptureSurfaceWidgetParentWindow() const; // Returns the bounds, within which the on-capture-surface widgets (such as - // the camera preview and the demo tools widget) will be confined. The bounds - // is in screen coordinate when capture source is `kFullscreen` or 'kRegion', - // but in window's coordinate when it is 'kWindow' type. + // the camera preview widget and the key combo widget) will be confined. The + // bounds is in screen coordinate when capture source is `kFullscreen` or + // 'kRegion', but in window's coordinate when it is 'kWindow' type. gfx::Rect GetCaptureSurfaceConfineBounds() const; // recording::mojom::RecordingServiceClient:
diff --git a/ash/capture_mode/capture_mode_demo_tools_controller.cc b/ash/capture_mode/capture_mode_demo_tools_controller.cc index 8e992c1..a080e8a 100644 --- a/ash/capture_mode/capture_mode_demo_tools_controller.cc +++ b/ash/capture_mode/capture_mode_demo_tools_controller.cc
@@ -164,7 +164,7 @@ } void CaptureModeDemoToolsController::RefreshBounds() { - demo_tools_widget_->SetBounds(CalculateKeyComboWidgetBounds()); + key_combo_widget_->SetBounds(CalculateKeyComboWidgetBounds()); } void CaptureModeDemoToolsController::OnTouchEvent( @@ -220,8 +220,9 @@ } const auto& target_delay = - ShouldResetWidget() ? capture_mode::kRefreshKeyComboWidgetLongDelay - : capture_mode::kRefreshKeyComboWidgetShortDelay; + ShouldResetKeyComboWidget() + ? capture_mode::kRefreshKeyComboWidgetLongDelay + : capture_mode::kRefreshKeyComboWidgetShortDelay; key_up_refresh_timer_.Start( FROM_HERE, target_delay, this, @@ -255,22 +256,22 @@ } void CaptureModeDemoToolsController::RefreshKeyComboViewer() { - if (ShouldResetWidget()) { - AnimateToResetTheWidget(); + if (ShouldResetKeyComboWidget()) { + AnimateToResetKeyComboWidget(); return; } - if (!demo_tools_widget_) { - demo_tools_widget_ = std::make_unique<views::Widget>(); - demo_tools_widget_->Init(CreateWidgetParams(video_recording_watcher_)); + if (!key_combo_widget_) { + key_combo_widget_ = std::make_unique<views::Widget>(); + key_combo_widget_->Init(CreateWidgetParams(video_recording_watcher_)); key_combo_view_ = - demo_tools_widget_->SetContentsView(std::make_unique<KeyComboView>()); - demo_tools_widget_->SetVisibilityAnimationTransition( + key_combo_widget_->SetContentsView(std::make_unique<KeyComboView>()); + key_combo_widget_->SetVisibilityAnimationTransition( views::Widget::ANIMATE_NONE); - ui::Layer* layer = demo_tools_widget_->GetLayer(); + ui::Layer* layer = key_combo_widget_->GetLayer(); layer->SetFillsBoundsOpaquely(false); layer->SetMasksToBounds(true); - demo_tools_widget_->Show(); + key_combo_widget_->Show(); } key_combo_view_->RefreshView(modifiers_, last_non_modifier_key_); @@ -293,14 +294,14 @@ return gfx::Rect(gfx::Point(key_combo_x, key_combo_y), preferred_size); } -bool CaptureModeDemoToolsController::ShouldResetWidget() const { +bool CaptureModeDemoToolsController::ShouldResetKeyComboWidget() const { return (modifiers_ == 0) && !ShouldConsiderKey(last_non_modifier_key_); } -void CaptureModeDemoToolsController::AnimateToResetTheWidget() { +void CaptureModeDemoToolsController::AnimateToResetKeyComboWidget() { // TODO(http://b/258349669): apply animation to the hide process when the // specs are ready. - demo_tools_widget_.reset(); + key_combo_widget_.reset(); key_combo_view_ = nullptr; }
diff --git a/ash/capture_mode/capture_mode_demo_tools_controller.h b/ash/capture_mode/capture_mode_demo_tools_controller.h index 29f4ecd8..2d2a7ff4a 100644 --- a/ash/capture_mode/capture_mode_demo_tools_controller.h +++ b/ash/capture_mode/capture_mode_demo_tools_controller.h
@@ -80,10 +80,10 @@ // Returns true if there is no modifier keys pressed and the non-modifier key // can not be displayed independently. - bool ShouldResetWidget() const; + bool ShouldResetKeyComboWidget() const; - // Resets the `demo_tools_widget_` when the `hide_timer_` expires. - void AnimateToResetTheWidget(); + // Resets the `key_combo_widget_` when the `hide_timer_` expires. + void AnimateToResetKeyComboWidget(); void UpdateTextInputType(const ui::TextInputClient* client); @@ -109,7 +109,7 @@ const gfx::PointF& event_location_in_window); VideoRecordingWatcher* const video_recording_watcher_; - views::UniqueWidgetPtr demo_tools_widget_; + views::UniqueWidgetPtr key_combo_widget_; KeyComboView* key_combo_view_ = nullptr; // The state of the modifier keys i.e. Shift/Ctrl/Alt/Launcher keys.
diff --git a/ash/capture_mode/capture_mode_demo_tools_test_api.cc b/ash/capture_mode/capture_mode_demo_tools_test_api.cc index d9faa5f0..8b78376 100644 --- a/ash/capture_mode/capture_mode_demo_tools_test_api.cc +++ b/ash/capture_mode/capture_mode_demo_tools_test_api.cc
@@ -18,7 +18,7 @@ views::Widget* CaptureModeDemoToolsTestApi::GetKeyComboWidget() { DCHECK(demo_tools_controller_); - return demo_tools_controller_->demo_tools_widget_.get(); + return demo_tools_controller_->key_combo_widget_.get(); } KeyComboView* CaptureModeDemoToolsTestApi::GetKeyComboView() {
diff --git a/ash/capture_mode/capture_mode_demo_tools_unittests.cc b/ash/capture_mode/capture_mode_demo_tools_unittests.cc index c1bf8224b..605f740 100644 --- a/ash/capture_mode/capture_mode_demo_tools_unittests.cc +++ b/ash/capture_mode/capture_mode_demo_tools_unittests.cc
@@ -16,7 +16,6 @@ #include "ash/capture_mode/capture_mode_session.h" #include "ash/capture_mode/capture_mode_session_test_api.h" #include "ash/capture_mode/capture_mode_settings_test_api.h" -#include "ash/capture_mode/capture_mode_settings_view.h" #include "ash/capture_mode/capture_mode_test_util.h" #include "ash/capture_mode/capture_mode_types.h" #include "ash/capture_mode/capture_mode_util.h" @@ -29,6 +28,7 @@ #include "ash/shell.h" #include "ash/style/icon_button.h" #include "ash/test/ash_test_base.h" +#include "ash/wm/splitview/split_view_controller.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/timer/timer.h" @@ -94,6 +94,35 @@ aura::Window* window() const { return window_.get(); } + gfx::Rect GetConfinedBoundsInScreenCoordinates() { + auto* recording_watcher = + CaptureModeController::Get()->video_recording_watcher_for_testing(); + gfx::Rect confined_bounds_in_screen = + recording_watcher->GetCaptureSurfaceConfineBounds(); + wm::ConvertRectToScreen(recording_watcher->window_being_recorded(), + &confined_bounds_in_screen); + return confined_bounds_in_screen; + } + + // Verifies that the `key_combo_widget` is positioned in the middle + // horizontally within the confined bounds and that the distance between the + // bottom of the widget and the bottom of the confined bounds is always equal + // to `capture_mode::kKeyWidgetDistanceFromBottom`. + void VerifyKeyComboWidgetPosition() { + CaptureModeDemoToolsTestApi demo_tools_test_api( + GetCaptureModeDemoToolsController()); + auto* key_combo_widget = demo_tools_test_api.GetKeyComboWidget(); + ASSERT_TRUE(key_combo_widget); + auto confined_bounds_in_screen = GetConfinedBoundsInScreenCoordinates(); + const gfx::Rect key_combo_widget_bounds = + key_combo_widget->GetWindowBoundsInScreen(); + EXPECT_NEAR(confined_bounds_in_screen.CenterPoint().x(), + key_combo_widget_bounds.CenterPoint().x(), /*abs_error=*/1); + EXPECT_EQ( + confined_bounds_in_screen.bottom() - key_combo_widget_bounds.bottom(), + capture_mode::kKeyWidgetDistanceFromBottom); + } + IconButton* GetSettingsButton() const { return GetCaptureModeBarView()->settings_button(); } @@ -201,7 +230,7 @@ std::unique_ptr<ui::FakeTextInputClient> fake_text_input_client_; }; -// Tests that the key event is considered to generate the `demo_tools_widget_` +// Tests that the key event is considered to generate the `key_combo_widget_` // or ignored otherwise in a correct way. TEST_F(CaptureModeDemoToolsTest, ConsiderKeyEvent) { CaptureModeController* controller = StartCaptureSession( @@ -671,6 +700,7 @@ DCHECK(demo_tools_controller); CaptureModeDemoToolsTestApi demo_tools_test_api(demo_tools_controller); KeyComboView* key_combo_view = demo_tools_test_api.GetKeyComboView(); + EXPECT_TRUE(key_combo_view); const auto confine_bounds = controller->GetCaptureSurfaceConfineBounds(); EXPECT_LT(confine_bounds.width(), key_combo_view->GetBoundsInScreen().width()); @@ -678,6 +708,39 @@ key_combo_view->GetBoundsInScreen().right()); } +// Tests that the key combo widget will be re-posisioned correctly on capture +// window bounds change. +TEST_F(CaptureModeDemoToolsTest, CaptureBoundsChangeTest) { + UpdateDisplay("800x700"); + const auto window = CreateTestWindow(gfx::Rect(100, 150, 300, 500)); + auto* split_view_controller = + SplitViewController::Get(Shell::GetPrimaryRootWindow()); + EXPECT_EQ(split_view_controller->state(), + SplitViewController::State::kNoSnap); + + auto* capture_mode_controller = + StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo); + auto* event_generator = GetEventGenerator(); + event_generator->MoveMouseToCenterOf(window.get()); + + capture_mode_controller->EnableDemoTools(true); + StartVideoRecordingImmediately(); + EXPECT_TRUE(capture_mode_controller->is_recording_in_progress()); + auto* demo_tools_controller = GetCaptureModeDemoToolsController(); + DCHECK(demo_tools_controller); + + event_generator->PressKey(ui::VKEY_CONTROL, ui::EF_NONE); + event_generator->PressKey(ui::VKEY_C, ui::EF_NONE); + VerifyKeyComboWidgetPosition(); + + // Snap the `window` which will result in window bounds change and the key + // combo widget will still be centered horizontally. + split_view_controller->SnapWindow( + window.get(), SplitViewController::SnapPosition::kPrimary); + EXPECT_EQ(split_view_controller->primary_window(), window.get()); + VerifyKeyComboWidgetPosition(); +} + // Tests that the metrics that record if a recording starts with demo tools // feature enabled are recorded correctly in a capture session both in clamshell // and tablet mode. @@ -746,36 +809,6 @@ EXPECT_TRUE(controller->is_recording_in_progress()); return controller; } - - gfx::Rect GetDemoToolsConfinedBoundsInScreenCoordinates() { - auto* recording_watcher = - CaptureModeController::Get()->video_recording_watcher_for_testing(); - gfx::Rect confined_bounds_in_screen = - recording_watcher->GetCaptureSurfaceConfineBounds(); - wm::ConvertRectToScreen(recording_watcher->window_being_recorded(), - &confined_bounds_in_screen); - return confined_bounds_in_screen; - } - - // Verifies that the `demo_tools_widget` is positioned in the middle - // horizontally within the confined bounds and that the distance between the - // bottom of the widget and the bottom of the confined bounds is always equal - // to `capture_mode::kKeyWidgetDistanceFromBottom`. - void VerifyKeyComboWidgetPosition() { - CaptureModeDemoToolsTestApi demo_tools_test_api( - GetCaptureModeDemoToolsController()); - auto* demo_tools_widget = demo_tools_test_api.GetKeyComboWidget(); - ASSERT_TRUE(demo_tools_widget); - auto confined_bounds_in_screen = - GetDemoToolsConfinedBoundsInScreenCoordinates(); - const gfx::Rect demo_tools_widget_bounds = - demo_tools_widget->GetWindowBoundsInScreen(); - EXPECT_NEAR(confined_bounds_in_screen.CenterPoint().x(), - demo_tools_widget_bounds.CenterPoint().x(), /*abs_error=*/1); - EXPECT_EQ( - confined_bounds_in_screen.bottom() - demo_tools_widget_bounds.bottom(), - capture_mode::kKeyWidgetDistanceFromBottom); - } }; // Tests that the key combo viewer widget should be centered within its confined @@ -808,8 +841,7 @@ EXPECT_TRUE(demo_tools_controller); CaptureModeDemoToolsTestApi demo_tools_test_api(demo_tools_controller); - gfx::Rect confined_bounds_in_screen = - GetDemoToolsConfinedBoundsInScreenCoordinates(); + gfx::Rect confined_bounds_in_screen = GetConfinedBoundsInScreenCoordinates(); auto* event_generator = GetEventGenerator(); event_generator->MoveMouseTo(confined_bounds_in_screen.CenterPoint()); event_generator->PressLeftButton(); @@ -839,7 +871,7 @@ CaptureModeDemoToolsTestApi demo_tools_test_api = CaptureModeDemoToolsTestApi(demo_tools_controller); - gfx::Rect inner_rect = GetDemoToolsConfinedBoundsInScreenCoordinates(); + gfx::Rect inner_rect = GetConfinedBoundsInScreenCoordinates(); inner_rect.Inset(5); const auto& layers_vector = demo_tools_test_api.GetMouseHighlightLayers(); @@ -893,7 +925,7 @@ CaptureModeDemoToolsTestApi demo_tools_test_api(demo_tools_controller); const gfx::Rect confined_bounds_in_screen = - GetDemoToolsConfinedBoundsInScreenCoordinates(); + GetConfinedBoundsInScreenCoordinates(); auto* event_generator = GetEventGenerator(); const auto& touch_highlight_map = @@ -931,7 +963,7 @@ demo_tools_test_api.GetTouchIdToHighlightLayerMap(); EXPECT_TRUE(touch_highlight_map.empty()); - gfx::Rect inner_rect = GetDemoToolsConfinedBoundsInScreenCoordinates(); + gfx::Rect inner_rect = GetConfinedBoundsInScreenCoordinates(); inner_rect.Inset(20); struct {
diff --git a/ash/capture_mode/capture_mode_feature_pod_controller.cc b/ash/capture_mode/capture_mode_feature_pod_controller.cc index 2766063..04ada78 100644 --- a/ash/capture_mode/capture_mode_feature_pod_controller.cc +++ b/ash/capture_mode/capture_mode_feature_pod_controller.cc
@@ -7,6 +7,7 @@ #include "ash/capture_mode/capture_mode_controller.h" #include "ash/capture_mode/capture_mode_metrics.h" #include "ash/constants/quick_settings_catalogs.h" +#include "ash/public/cpp/ash_view_ids.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" @@ -26,6 +27,11 @@ CaptureModeFeaturePodController::~CaptureModeFeaturePodController() = default; +// static +bool CaptureModeFeaturePodController::CalculateButtonVisibility() { + return !Shell::Get()->session_controller()->IsUserSessionBlocked(); +} + FeaturePodButton* CaptureModeFeaturePodController::CreateButton() { DCHECK(!button_); DCHECK(!features::IsQsRevampEnabled()); @@ -36,36 +42,42 @@ button_->SetLabel(label_text); button_->icon_button()->SetTooltipText(label_text); button_->SetLabelTooltip(label_text); - const bool visible = - !Shell::Get()->session_controller()->IsUserSessionBlocked(); - button_->SetVisible(visible); + const bool target_visibility = CalculateButtonVisibility(); + button_->SetVisible(target_visibility); - if (visible) + if (target_visibility) { TrackVisibilityUMA(); + } button_->DisableLabelButtonFocus(); return button_; } -std::unique_ptr<FeatureTile> CaptureModeFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> CaptureModeFeaturePodController::CreateTile( + bool compact) { DCHECK(features::IsQsRevampEnabled()); - // TODO(b/263423627): Tile should be compact if applicable. auto feature_tile = std::make_unique<FeatureTile>( base::BindRepeating(&FeaturePodControllerBase::OnIconPressed, weak_ptr_factory_.GetWeakPtr()), - /*is_togglable=*/false, FeatureTile::TileType::kPrimary); + /*is_togglable=*/false, + compact ? FeatureTile::TileType::kCompact + : FeatureTile::TileType::kPrimary); + feature_tile->SetID(VIEW_ID_SCREEN_CAPTURE_FEATURE_TILE); + + const bool target_visibility = CalculateButtonVisibility(); + feature_tile->SetVisible(target_visibility); + if (target_visibility) { + TrackVisibilityUMA(); + } + feature_tile->SetVectorIcon(kCaptureModeIcon); const auto label_text = l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAPTURE_MODE_BUTTON_LABEL); feature_tile->SetLabel(label_text); - feature_tile->SetSubLabelVisibility(false); - feature_tile->SetTooltipText(label_text); - const bool visible = - !Shell::Get()->session_controller()->IsUserSessionBlocked(); - feature_tile->SetVisible(visible); - if (visible) { - TrackVisibilityUMA(); + if (!compact) { + feature_tile->SetSubLabelVisibility(false); } + feature_tile->SetTooltipText(label_text); return feature_tile; }
diff --git a/ash/capture_mode/capture_mode_feature_pod_controller.h b/ash/capture_mode/capture_mode_feature_pod_controller.h index 5766b4ba..e7def59a 100644 --- a/ash/capture_mode/capture_mode_feature_pod_controller.h +++ b/ash/capture_mode/capture_mode_feature_pod_controller.h
@@ -29,9 +29,13 @@ const CaptureModeFeaturePodController&) = delete; ~CaptureModeFeaturePodController() override; + // Referenced by `UnifiedSystemTrayController` to know whether to construct a + // Primary or Compact tile. + static bool CalculateButtonVisibility(); + // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override;
diff --git a/ash/capture_mode/capture_mode_session.h b/ash/capture_mode/capture_mode_session.h index 1e46802..c422d4f0 100644 --- a/ash/capture_mode/capture_mode_session.h +++ b/ash/capture_mode/capture_mode_session.h
@@ -166,12 +166,12 @@ // Returns the current parent window for the on-capture-surface widgets such // as `CaptureModeCameraController::camera_preview_widget_` and - // `CaptureModeDemoToolsController::demo_tools_widget_` when capture mode + // `CaptureModeDemoToolsController::key_combo_widget_` when capture mode // session is active. aura::Window* GetOnCaptureSurfaceWidgetParentWindow() const; // Returns the confine bounds for the on-capture-surface widgets (such as the - // camera preview and demo tools widgets) when capture session is active. + // camera preview widget and key combo widget) when capture session is active. gfx::Rect GetCaptureSurfaceConfineBounds() const; // Returns the in-session target value that should be used for the visibility
diff --git a/ash/capture_mode/key_item_view.cc b/ash/capture_mode/key_item_view.cc index 7c5980a..ca82ca436 100644 --- a/ash/capture_mode/key_item_view.cc +++ b/ash/capture_mode/key_item_view.cc
@@ -24,14 +24,14 @@ namespace { -constexpr int kKeyItemMinWidth = 64; -constexpr int kKeyItemHeight = 64; +constexpr int kKeyItemMinWidth = 56; +constexpr int kKeyItemHeight = 56; constexpr int kKeyItemVerticalPadding = 16; -constexpr int kKeyItemHorizontalPadding = 24; -constexpr gfx::Size kIconSize{24, 24}; +constexpr int kKeyItemHorizontalPadding = 20; +constexpr gfx::Size kIconSize{20, 20}; constexpr char kGoogleSansFont[] = "Google Sans"; -constexpr int kKeyItemViewFontSize = 24; -constexpr int kKeyItemViewLineHeight = 32; +constexpr int kKeyItemViewFontSize = 18; +constexpr int kKeyItemViewLineHeight = 24; } // namespace
diff --git a/ash/capture_mode/video_recording_watcher.cc b/ash/capture_mode/video_recording_watcher.cc index 952ead5..c8228041 100644 --- a/ash/capture_mode/video_recording_watcher.cc +++ b/ash/capture_mode/video_recording_watcher.cc
@@ -346,11 +346,13 @@ const gfx::Rect& old_bounds, const gfx::Rect& new_bounds, ui::PropertyChangeReason reason) { - if (is_in_projector_mode_) + if (is_in_projector_mode_) { recording_overlay_controller_->SetBounds(GetOverlayWidgetBounds()); + } - if (recording_source_ != CaptureModeSource::kWindow) + if (recording_source_ != CaptureModeSource::kWindow) { return; + } // We care only about size changes, since the location of the window won't // affect the recorded video frames of it, however, the size of the window @@ -362,9 +364,13 @@ FROM_HERE, kWindowSizeChangeThrottleDelay, this, &VideoRecordingWatcher::OnWindowSizeChangeThrottleTimerFiring); - // The bounds of the camera preview should be updated if the bounds of the - // window being recorded is changed. + // The bounds of the camera preview widget and key combo widget should be + // updated if the bounds of the window being recorded is changed. controller_->camera_controller()->MaybeUpdatePreviewWidget(); + + if (demo_tools_controller_) { + demo_tools_controller_->RefreshBounds(); + } } void VideoRecordingWatcher::OnWindowOpacitySet(
diff --git a/ash/capture_mode/video_recording_watcher.h b/ash/capture_mode/video_recording_watcher.h index 660885c..ff69e47 100644 --- a/ash/capture_mode/video_recording_watcher.h +++ b/ash/capture_mode/video_recording_watcher.h
@@ -81,13 +81,13 @@ // Returns the current parent window for the on-capture-surface widgets such // as `CaptureModeCameraController::camera_preview_widget_` and - // `CaptureModeDemoToolsController::demo_tools_widget_` when recording is in + // `CaptureModeDemoToolsController::key_combo_widget_` when recording is in // progress. aura::Window* GetOnCaptureSurfaceWidgetParentWindow() const; - // Returns the bounds within which the on-capture-surface widgets such as - // capture mode preview and capture mode demo tools will be confined when - // recording is in progress. + // Returns the bounds within which the on-capture-surface widgets (such as + // capture mode camera preview widget and key combo widget) will be confined + // when recording is in progress. gfx::Rect GetCaptureSurfaceConfineBounds() const; // aura::WindowObserver:
diff --git a/ash/components/arc/mojom/BUILD.gn b/ash/components/arc/mojom/BUILD.gn index d1b0be7..37dfd71 100644 --- a/ash/components/arc/mojom/BUILD.gn +++ b/ash/components/arc/mojom/BUILD.gn
@@ -22,7 +22,6 @@ "bluetooth.mojom", "boot_phase_monitor.mojom", "camera.mojom", - "cert_store.mojom", "clipboard.mojom", "compatibility_mode.mojom", "crash_collector.mojom",
diff --git a/ash/components/arc/mojom/arc_bridge.mojom b/ash/components/arc/mojom/arc_bridge.mojom index cf122023..25eae9d 100644 --- a/ash/components/arc/mojom/arc_bridge.mojom +++ b/ash/components/arc/mojom/arc_bridge.mojom
@@ -15,7 +15,6 @@ import "ash/components/arc/mojom/bluetooth.mojom"; import "ash/components/arc/mojom/boot_phase_monitor.mojom"; import "ash/components/arc/mojom/camera.mojom"; -import "ash/components/arc/mojom/cert_store.mojom"; import "ash/components/arc/mojom/clipboard.mojom"; import "ash/components/arc/mojom/compatibility_mode.mojom"; import "ash/components/arc/mojom/crash_collector.mojom"; @@ -64,7 +63,7 @@ import "ash/components/arc/mojom/webapk.mojom"; // Next MinVersion: 63 -// Deprecated method IDs: 101, 105, 121, 132, 154, 160 +// Deprecated method IDs: 101, 105, 121, 132, 136, 153, 154, 160 // Next method ID: 168 interface ArcBridgeHost { // Keep the entries alphabetical. In order to do so without breaking @@ -114,10 +113,6 @@ [MinVersion=46] OnCameraInstanceReady@151( pending_remote<CameraInstance> instance_remote); - // Notifies Chrome that the CertStoreInstance interface is ready. - [MinVersion=31] OnCertStoreInstanceReady@136( - pending_remote<CertStoreInstance> instance_remote); - // Notifies Chrome that the ClipboardInstance interface is ready. [MinVersion=2] OnClipboardInstanceReady@109( pending_remote<ClipboardInstance> instance_remote); @@ -256,10 +251,6 @@ [MinVersion=52] OnSharesheetInstanceReady@157( pending_remote<SharesheetInstance> instance_remote); - // Notifies Chrome that the SmartCardManagerInstance interface is ready. - [MinVersion=48] OnSmartCardManagerInstanceReady@153( - pending_remote<SmartCardManagerInstance> instance_remote); - // Notifies Chrome that the StorageManagerInstance interface is ready. [MinVersion=12] OnStorageManagerInstanceReady@118( pending_remote<StorageManagerInstance> instance_remote);
diff --git a/ash/components/arc/mojom/cert_store.mojom b/ash/components/arc/mojom/cert_store.mojom deleted file mode 100644 index 795ceb8..0000000 --- a/ash/components/arc/mojom/cert_store.mojom +++ /dev/null
@@ -1,136 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Next MinVersion: 2 - -// -// CertStoreHost is modeled after Android keymaster interface -// hardware/libhardware/include/hardware/keymaster2.h -// -// and must follow the concept if extended in the future. -// Please keep names in sync as far as it is possible. -// -// Enums/structures are modeled after structures from -// hardware/libhardware/include/hardware/keymaster_defs.h -// - -module arc.mojom; - -// Describes a keymaster operation result. -[Extensible] -enum KeymasterError { - ERROR_OK = 0, - ERROR_INVALID_OPERATION_HANDLE = -28, - ERROR_INVALID_KEY_BLOB = -33, - ERROR_UNIMPLEMENTED = -100, - ERROR_UNKNOWN_ERROR = -1000, -}; - -// Enumerates the crypto algorithms supported by Host. -[Extensible] -enum Algorithm { - ALGORITHM_RSA = 1, - ALGORITHM_EC = 3, -}; - -// Enumerates the digests supported by Host. -[Extensible] -enum Digest { - DIGEST_NONE = 0, - DIGEST_SHA1 = 2, - DIGEST_SHA_2_224 = 3, - DIGEST_SHA_2_256 = 4, - DIGEST_SHA_2_384 = 5, - DIGEST_SHA_2_512 = 6, -}; - -// Enumerates the paddings supported by Host. -[Extensible] -enum Padding { - PAD_NONE = 1, - PAD_RSA_PKCS1_1_5_SIGN = 5, -}; - -// Describes a parameter of client certificate provided by Host. -union KeyParam { - Algorithm algorithm; - Digest digest; - Padding padding; -}; - -// Describes a client certificate provided by Host. -// Does not correspond to keymaster type. -struct Certificate { - // Nickname/alias of the certificate. - string alias; - - // PEM-encoded client certificate. - string cert; -}; - -// Next method ID: 6 -// The interface is modeled after keymaster interface and must follow the format -// if extended in the future. -interface CertStoreHost { - // The helper method, which does not correspond to keymaster interface. - // It returns a list of Chrome OS corporate usage client certificates if - // any Android app is allowlisted to use them, otherwise returns an - // empty list. - ListCertificates@0() => (array<Certificate> certs); - - // Retrieves key characteristics for the specified key with alias. - // params is null if any error occurred during retrieval. - GetKeyCharacteristics@1(string alias) - => (KeymasterError error, array<KeyParam>? params); - - // Begins the operation using the specified key with alias and operation - // parameters (such as algorithm, digest, padding). - // If all is well, returns ERROR_OK and creates an operation handle which - // must be passed to subsequent calls to Update(), Finish() or Abort(). - // Currently only signature operations are supported. - Begin@2(string alias, array<KeyParam> params) - => (KeymasterError error, uint64 operation_handle); - - // Provides data to an ongoing cryptographic operation begun with Begin(). - // Returns an amount of data consumed by Update(). - Update@3(uint64 operation_handle, array<uint8> data) - => (KeymasterError error, uint32 input_consumed); - - // Finalizes a cryptographic operation begun with Begin() and invalidates - // operation handle. Retrieves the result (signature). In case of any error, - // signed_data is null. - Finish@4(uint64 operation_handle) - => (KeymasterError error, array<uint8>? signed_data); - - // Aborts a cryptographic operation begun with Begin(), freeing all internal - // resources and invalidating operation handle. - Abort@5(uint64 operation_handle) => (KeymasterError error); -}; - -// Deprecated method IDs: 0 -// Next method ID: 4 -interface CertStoreInstance { - // Establishes full-duplex communication with the host. - [MinVersion=1] Init@3(pending_remote<CertStoreHost> host_remote) => (); - - // Informs the key permissions are changed: only listed packages are allowed - // to use exposed certificates. - OnKeyPermissionsChanged@1(array<string> permissions); - - // Informs the certificates are changed (added, removed or updated): - // CertStoreInstance must call ListCertficates to update its database. - OnCertificatesChanged@2(); -}; - -// Next method ID: 1 -interface SmartCardManagerHost { - // Refreshes smart card certificates available to Android apps. - Refresh@0() => (bool result); -}; - -// Next method ID: 1 -interface SmartCardManagerInstance { - // Establishes full-duplex communication with the host. - Init@0(pending_remote<SmartCardManagerHost> host_remote) => (); -};
diff --git a/ash/components/arc/session/arc_bridge_host_impl.cc b/ash/components/arc/session/arc_bridge_host_impl.cc index 15b5b0d..54eb9f482 100644 --- a/ash/components/arc/session/arc_bridge_host_impl.cc +++ b/ash/components/arc/session/arc_bridge_host_impl.cc
@@ -17,7 +17,6 @@ #include "ash/components/arc/mojom/bluetooth.mojom.h" #include "ash/components/arc/mojom/boot_phase_monitor.mojom.h" #include "ash/components/arc/mojom/camera.mojom.h" -#include "ash/components/arc/mojom/cert_store.mojom.h" #include "ash/components/arc/mojom/clipboard.mojom.h" #include "ash/components/arc/mojom/compatibility_mode.mojom.h" #include "ash/components/arc/mojom/crash_collector.mojom.h" @@ -152,12 +151,6 @@ OnInstanceReady(arc_bridge_service_->camera(), std::move(camera_remote)); } -void ArcBridgeHostImpl::OnCertStoreInstanceReady( - mojo::PendingRemote<mojom::CertStoreInstance> instance_remote) { - OnInstanceReady(arc_bridge_service_->cert_store(), - std::move(instance_remote)); -} - void ArcBridgeHostImpl::OnClipboardInstanceReady( mojo::PendingRemote<mojom::ClipboardInstance> clipboard_remote) { OnInstanceReady(arc_bridge_service_->clipboard(), @@ -371,13 +364,6 @@ std::move(sharesheet_remote)); } -void ArcBridgeHostImpl::OnSmartCardManagerInstanceReady( - mojo::PendingRemote<mojom::SmartCardManagerInstance> - smart_card_manager_remote) { - OnInstanceReady(arc_bridge_service_->smart_card_manager(), - std::move(smart_card_manager_remote)); -} - void ArcBridgeHostImpl::OnStorageManagerInstanceReady( mojo::PendingRemote<mojom::StorageManagerInstance> storage_manager_remote) { OnInstanceReady(arc_bridge_service_->storage_manager(),
diff --git a/ash/components/arc/session/arc_bridge_host_impl.h b/ash/components/arc/session/arc_bridge_host_impl.h index 3b794710..3fe2f94a 100644 --- a/ash/components/arc/session/arc_bridge_host_impl.h +++ b/ash/components/arc/session/arc_bridge_host_impl.h
@@ -69,8 +69,6 @@ boot_phase_monitor_remote) override; void OnCameraInstanceReady( mojo::PendingRemote<mojom::CameraInstance> camera_remote) override; - void OnCertStoreInstanceReady( - mojo::PendingRemote<mojom::CertStoreInstance> instance_remote) override; void OnClipboardInstanceReady( mojo::PendingRemote<mojom::ClipboardInstance> clipboard_remote) override; void OnCompatibilityModeInstanceReady( @@ -155,9 +153,6 @@ override; void OnSharesheetInstanceReady(mojo::PendingRemote<mojom::SharesheetInstance> sharesheet_remote) override; - void OnSmartCardManagerInstanceReady( - mojo::PendingRemote<mojom::SmartCardManagerInstance> - smart_card_manager_remote) override; void OnStorageManagerInstanceReady( mojo::PendingRemote<mojom::StorageManagerInstance> storage_manager_remote) override;
diff --git a/ash/components/arc/session/arc_bridge_host_impl_unittest.cc b/ash/components/arc/session/arc_bridge_host_impl_unittest.cc index 5052f0b..c3aef4f7 100644 --- a/ash/components/arc/session/arc_bridge_host_impl_unittest.cc +++ b/ash/components/arc/session/arc_bridge_host_impl_unittest.cc
@@ -118,7 +118,6 @@ MAKE_INSTANCE_READY(Bluetooth); MAKE_INSTANCE_READY(BootPhaseMonitor); MAKE_INSTANCE_READY(Camera); - MAKE_INSTANCE_READY(CertStore); MAKE_INSTANCE_READY(Clipboard); MAKE_INSTANCE_READY(CompatibilityMode); MAKE_INSTANCE_READY(CrashCollector); @@ -153,7 +152,6 @@ MAKE_INSTANCE_READY(RotationLock); MAKE_INSTANCE_READY(ScreenCapture); MAKE_INSTANCE_READY(Sharesheet); - MAKE_INSTANCE_READY(SmartCardManager); MAKE_INSTANCE_READY(StorageManager); MAKE_INSTANCE_READY(Timer); MAKE_INSTANCE_READY(Tracing);
diff --git a/ash/components/arc/session/arc_bridge_service.cc b/ash/components/arc/session/arc_bridge_service.cc index ee58c6c..587bbc60 100644 --- a/ash/components/arc/session/arc_bridge_service.cc +++ b/ash/components/arc/session/arc_bridge_service.cc
@@ -17,7 +17,6 @@ #include "ash/components/arc/mojom/bluetooth.mojom.h" #include "ash/components/arc/mojom/boot_phase_monitor.mojom.h" #include "ash/components/arc/mojom/camera.mojom.h" -#include "ash/components/arc/mojom/cert_store.mojom.h" #include "ash/components/arc/mojom/clipboard.mojom.h" #include "ash/components/arc/mojom/crash_collector.mojom.h" #include "ash/components/arc/mojom/digital_goods.mojom.h"
diff --git a/ash/components/arc/session/arc_bridge_service.h b/ash/components/arc/session/arc_bridge_service.h index 2c9fba5a..8661e2a 100644 --- a/ash/components/arc/session/arc_bridge_service.h +++ b/ash/components/arc/session/arc_bridge_service.h
@@ -35,8 +35,6 @@ class CameraHost; class CameraInstance; class CastReceiverInstance; -class CertStoreHost; -class CertStoreInstance; class ClipboardHost; class ClipboardInstance; class CompatibilityModeInstance; @@ -96,8 +94,6 @@ class ScreenCaptureInstance; class SharesheetHost; class SharesheetInstance; -class SmartCardManagerHost; -class SmartCardManagerInstance; class StorageManagerInstance; class SystemUiInstance; class TimerHost; @@ -190,10 +186,6 @@ ConnectionHolder<mojom::CastReceiverInstance>* cast_receiver() { return &cast_receiver_; } - ConnectionHolder<mojom::CertStoreInstance, mojom::CertStoreHost>* - cert_store() { - return &cert_store_; - } ConnectionHolder<mojom::ClipboardInstance, mojom::ClipboardHost>* clipboard() { return &clipboard_; @@ -304,11 +296,6 @@ sharesheet() { return &sharesheet_; } - ConnectionHolder<mojom::SmartCardManagerInstance, - mojom::SmartCardManagerHost>* - smart_card_manager() { - return &smart_card_manager_; - } ConnectionHolder<mojom::StorageManagerInstance>* storage_manager() { return &storage_manager_; @@ -357,7 +344,6 @@ boot_phase_monitor_; ConnectionHolder<mojom::CameraInstance, mojom::CameraHost> camera_; ConnectionHolder<mojom::CastReceiverInstance> cast_receiver_; - ConnectionHolder<mojom::CertStoreInstance, mojom::CertStoreHost> cert_store_; ConnectionHolder<mojom::ClipboardInstance, mojom::ClipboardHost> clipboard_; ConnectionHolder<mojom::CompatibilityModeInstance> compatibility_mode_; ConnectionHolder<mojom::CrashCollectorInstance, mojom::CrashCollectorHost> @@ -406,8 +392,6 @@ screen_capture_; ConnectionHolder<mojom::SharesheetInstance, mojom::SharesheetHost> sharesheet_; - ConnectionHolder<mojom::SmartCardManagerInstance, mojom::SmartCardManagerHost> - smart_card_manager_; ConnectionHolder<mojom::StorageManagerInstance> storage_manager_; ConnectionHolder<mojom::SystemUiInstance> system_ui_; ConnectionHolder<mojom::TimerInstance, mojom::TimerHost> timer_;
diff --git a/ash/components/arc/test/fake_arc_bridge_host.cc b/ash/components/arc/test/fake_arc_bridge_host.cc index bdfe59e..883b8e2 100644 --- a/ash/components/arc/test/fake_arc_bridge_host.cc +++ b/ash/components/arc/test/fake_arc_bridge_host.cc
@@ -16,7 +16,6 @@ #include "ash/components/arc/mojom/bluetooth.mojom.h" #include "ash/components/arc/mojom/boot_phase_monitor.mojom.h" #include "ash/components/arc/mojom/camera.mojom.h" -#include "ash/components/arc/mojom/cert_store.mojom.h" #include "ash/components/arc/mojom/clipboard.mojom.h" #include "ash/components/arc/mojom/compatibility_mode.mojom.h" #include "ash/components/arc/mojom/crash_collector.mojom.h" @@ -103,9 +102,6 @@ void FakeArcBridgeHost::OnCameraInstanceReady( mojo::PendingRemote<mojom::CameraInstance> camera_remote) {} -void FakeArcBridgeHost::OnCertStoreInstanceReady( - mojo::PendingRemote<mojom::CertStoreInstance> instance_remote) {} - void FakeArcBridgeHost::OnClipboardInstanceReady( mojo::PendingRemote<mojom::ClipboardInstance> clipboard_remote) {} @@ -216,10 +212,6 @@ void FakeArcBridgeHost::OnSharesheetInstanceReady( mojo::PendingRemote<mojom::SharesheetInstance> sharesheet_remote) {} -void FakeArcBridgeHost::OnSmartCardManagerInstanceReady( - mojo::PendingRemote<mojom::SmartCardManagerInstance> - smart_cardManager_remote) {} - void FakeArcBridgeHost::OnStorageManagerInstanceReady( mojo::PendingRemote<mojom::StorageManagerInstance> storage_manager_remote) { }
diff --git a/ash/components/arc/test/fake_arc_bridge_host.h b/ash/components/arc/test/fake_arc_bridge_host.h index fb92ad2f..e238bb87 100644 --- a/ash/components/arc/test/fake_arc_bridge_host.h +++ b/ash/components/arc/test/fake_arc_bridge_host.h
@@ -47,8 +47,6 @@ boot_phase_monitor_remote) override; void OnCameraInstanceReady( mojo::PendingRemote<mojom::CameraInstance> camera_remote) override; - void OnCertStoreInstanceReady( - mojo::PendingRemote<mojom::CertStoreInstance> instance_remote) override; void OnClipboardInstanceReady( mojo::PendingRemote<mojom::ClipboardInstance> clipboard_remote) override; void OnCompatibilityModeInstanceReady( @@ -133,9 +131,6 @@ override; void OnSharesheetInstanceReady(mojo::PendingRemote<mojom::SharesheetInstance> sharesheet_remote) override; - void OnSmartCardManagerInstanceReady( - mojo::PendingRemote<mojom::SmartCardManagerInstance> - smart_card_manager_remote) override; void OnStorageManagerInstanceReady( mojo::PendingRemote<mojom::StorageManagerInstance> storage_manager_remote) override;
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 5c4399e..585db2e 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -705,13 +705,6 @@ "EnableBackgroundBlur", base::FEATURE_ENABLED_BY_DEFAULT); -// Enables the DNS proxy service providing support split and secure DNS -// for ChromeOS. -// TODO(b/265091596): Remove. -BASE_FEATURE(kEnableDnsProxy, - "EnableDnsProxy", - base::FEATURE_ENABLED_BY_DEFAULT); - // Enables external keyboard testers in the diagnostics app. BASE_FEATURE(kEnableExternalKeyboardsInDiagnostics, "EnableExternalKeyboardsInDiagnosticsApp", @@ -1421,6 +1414,11 @@ "EcheLauncherIconsInMoreAppsButton", base::FEATURE_DISABLED_BY_DEFAULT); +// Enables multi-zone rgb keyboard customization. +BASE_FEATURE(kMultiZoneRgbKeyboard, + "MultiZoneRgbKeyboard", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables support for multilingual assistive typing on ChromeOS. BASE_FEATURE(kMultilingualTyping, "MultilingualTyping", @@ -1666,6 +1664,12 @@ "ProjectorExcludeTranscript", base::FEATURE_ENABLED_BY_DEFAULT); +// Controls whether to fold short gap between transcript into the previous +// transcript. +BASE_FEATURE(kProjectorFoldShortGapIntoPreviousTranscript, + "ProjectorFoldShortGapIntoPreviousTranscript", + base::FEATURE_ENABLED_BY_DEFAULT); + // Controls whether Projector's tutorial videos are displayed. BASE_FEATURE(kProjectorTutorialVideoView, "ProjectorTutorialVideoView", @@ -2810,6 +2814,10 @@ return base::FeatureList::IsEnabled(kMinimumChromeVersion); } +bool IsMultiZoneRgbKeyboardEnabled() { + return base::FeatureList::IsEnabled(kMultiZoneRgbKeyboard); +} + bool IsEcheLauncherEnabled() { return base::FeatureList::IsEnabled(kEcheLauncher) && base::FeatureList::IsEnabled(kEcheSWA); @@ -3042,6 +3050,11 @@ return base::FeatureList::IsEnabled(kProjectorAccountSwitchNotification); } +bool IsProjectorFoldShortGapIntoPreviousTranscriptEnabled() { + return base::FeatureList::IsEnabled( + kProjectorFoldShortGapIntoPreviousTranscript); +} + bool IsQuickDimEnabled() { return base::FeatureList::IsEnabled(kQuickDim) && switches::HasHps(); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 9553fa2..d268f71 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -211,7 +211,6 @@ BASE_DECLARE_FEATURE(kEcheSWACheckAndroidNetworkInfo); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kAudioSettingsPage); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEnableBackgroundBlur); -COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEnableDnsProxy); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEnableExternalKeyboardsInDiagnostics); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kEnableFilesAppCopyImage); @@ -407,6 +406,7 @@ BASE_DECLARE_FEATURE(kDisableMessagesCrossDeviceIntegration); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMinimumChromeVersion); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMojoDBusRelay); +COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMultiZoneRgbKeyboard); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMultilingualTyping); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kNearbyKeepAliveFix); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMoreVideoCaptureBuffers); @@ -491,6 +491,8 @@ BASE_DECLARE_FEATURE(kProjectorViewerUseSecondaryAccount); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kProjectorAccountSwitchNotification); +COMPONENT_EXPORT(ASH_CONSTANTS) +BASE_DECLARE_FEATURE(kProjectorFoldShortGapIntoPreviousTranscript); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kPromiseIcons); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQsRevamp); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kQuickDim); @@ -765,6 +767,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsManagedTermsOfServiceEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsMicMuteNotificationsEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsMinimumChromeVersionEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsMultiZoneRgbKeyboardEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsNearbyKeepAliveFixEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsEducationEnrollmentOobeFlowEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsNewLockScreenReauthLayoutEnabled(); @@ -833,6 +836,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorWebReportCrashEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorUseApiKeyForTranslationEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) +bool IsProjectorFoldShortGapIntoPreviousTranscriptEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsQsRevampEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsQuickDimEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/glanceables/glanceables_unittests.cc b/ash/glanceables/glanceables_unittests.cc index 967457f..d1985b2 100644 --- a/ash/glanceables/glanceables_unittests.cc +++ b/ash/glanceables/glanceables_unittests.cc
@@ -21,6 +21,7 @@ #include "ash/glanceables/signout_screenshot_handler.h" #include "ash/glanceables/test_glanceables_delegate.h" #include "ash/public/cpp/ambient/fake_ambient_backend_controller_impl.h" +#include "ash/public/cpp/test/in_process_image_decoder.h" #include "ash/public/cpp/test/test_system_tray_client.h" #include "ash/shell.h" #include "ash/style/pill_button.h" @@ -45,7 +46,6 @@ #include "chromeos/ash/components/settings/scoped_timezone_settings.h" #include "google_apis/calendar/calendar_api_response_types.h" #include "google_apis/common/api_error_codes.h" -#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/accelerators/accelerator.h" #include "ui/compositor/layer.h" @@ -367,7 +367,7 @@ } TEST_F(GlanceablesTest, RestoreViewRendersScreenshot) { - data_decoder::test::InProcessDataDecoder data_decoder; + InProcessImageDecoder data_decoder; const SkColor expected_color = SK_ColorYELLOW; // Override home directory.
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 2e03a8ed..c535bdd 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -467,6 +467,7 @@ "holding_space/holding_space_progress_unittest.cc", "holding_space/holding_space_section_unittest.cc", "holding_space/holding_space_util_unittest.cc", + "image_util_unittest.cc", "metrics_util_unittest.cc", "pagination/pagination_model_unittest.cc", "power_utils_unittest.cc", @@ -486,6 +487,8 @@ "//base/test:test_support", "//chromeos/ui/vector_icons", "//mojo/public/cpp/bindings", + "//services/data_decoder/public/mojom", + "//skia", "//testing/gtest", "//ui/aura:test_support", "//ui/chromeos/styles:cros_styles_views", @@ -504,6 +507,8 @@ source_set("test_support") { testonly = true sources = [ + "test/in_process_image_decoder.cc", + "test/in_process_image_decoder.h", "test/mock_in_session_auth_token_provider.cc", "test/mock_in_session_auth_token_provider.h", "test/mock_projector_client.cc", @@ -530,13 +535,19 @@ ":cpp", "//base", "//components/access_code_cast/common", + "//mojo/public/cpp/bindings", + "//services/data_decoder/public/cpp:service_provider", + "//services/data_decoder/public/mojom", "//services/device/public/cpp:test_support", "//services/network/public/cpp:cpp", + "//skia", "//testing/gmock", + "//testing/gtest", "//ui/aura", "//ui/aura:test_support", "//ui/gfx", "//ui/gfx:test_support", + "//ui/gfx/codec", "//ui/views", ] }
diff --git a/ash/public/cpp/ash_view_ids.h b/ash/public/cpp/ash_view_ids.h index 1e41174..3047a2f 100644 --- a/ash/public/cpp/ash_view_ids.h +++ b/ash/public/cpp/ash_view_ids.h
@@ -17,6 +17,12 @@ VIEW_ID_ACCESSIBILITY_VIRTUAL_KEYBOARD, // Icon that indicates the virtual keyboard is enabled. VIEW_ID_ACCESSIBILITY_VIRTUAL_KEYBOARD_ENABLED, + + // Feature tile ids. + VIEW_ID_SCREEN_CAPTURE_FEATURE_TILE, + VIEW_ID_DND_FEATURE_TILE, + VIEW_ID_AUTOROTATE_FEATURE_TILE, + // Accessibility feature pod button in main view. VIEW_ID_ACCESSIBILITY_TRAY_ITEM, // System tray AddUserButton in UserChooserView.
diff --git a/ash/public/cpp/image_util.h b/ash/public/cpp/image_util.h index 0b08636..9eab48c 100644 --- a/ash/public/cpp/image_util.h +++ b/ash/public/cpp/image_util.h
@@ -28,6 +28,9 @@ using DecodeImageCallback = base::OnceCallback<void(const gfx::ImageSkia&)>; +// TESTING NOTE: See ash::InProcessImageDecoder for unit testing code that +// calls any of the DecodeImage*() functions below. + // Reads contents at |file_path| and calls |callback| with a decoded image. // Calls |callback| with an empty image on failure to read the file or decode // the image.
diff --git a/ash/public/cpp/image_util_unittest.cc b/ash/public/cpp/image_util_unittest.cc new file mode 100644 index 0000000..74168d8 --- /dev/null +++ b/ash/public/cpp/image_util_unittest.cc
@@ -0,0 +1,220 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/public/cpp/image_util.h" + +#include <string> + +#include "ash/public/cpp/image_util.h" +#include "ash/public/cpp/test/in_process_image_decoder.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/location.h" +#include "base/run_loop.h" +#include "base/strings/string_piece.h" +#include "base/test/bind.h" +#include "base/test/scoped_run_loop_timeout.h" +#include "base/test/task_environment.h" +#include "base/time/time.h" +#include "services/data_decoder/public/mojom/image_decoder.mojom-shared.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/codec/jpeg_codec.h" +#include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_unittest_util.h" + +namespace ash { +namespace { + +// How long to wait for a DecodeImageCallback to be run before a test times +// out and fails. Prevents the unit tests from hanging indefinitely (or for a +// very long time) if there's a bug in the code where the callback is not being +// run. +constexpr base::TimeDelta kDecodeImageTimeout = base::Seconds(3); + +gfx::ImageSkia CreateTestImage(int width, int height, SkColor color) { + SkBitmap bitmap; + bitmap.allocN32Pixels(width, height); + bitmap.eraseColor(color); + return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); +} + +using EncodingFunction = + base::RepeatingCallback<bool(const SkBitmap&, std::vector<unsigned char>*)>; + +void EncodeImage(const gfx::ImageSkia& image, + std::string* output, + EncodingFunction encoding_fn) { + std::vector<unsigned char> encoded_data; + ASSERT_TRUE(encoding_fn.Run(*image.bitmap(), &encoded_data)); + output->assign(reinterpret_cast<const char*>(encoded_data.data()), + encoded_data.size()); +} + +std::string EncodeToString(const gfx::ImageSkia& image, + EncodingFunction encoding_fn) { + std::string output; + EncodeImage(image, &output, encoding_fn); + return output; +} + +std::string EncodeAsJpeg(const gfx::ImageSkia& image) { + return EncodeToString( + image, base::BindRepeating([](const SkBitmap& bitmap, + std::vector<unsigned char>* encoded_data) { + return gfx::JPEGCodec::Encode(bitmap, /*quality=*/90, encoded_data); + })); +} + +std::string EncodeAsPng(const gfx::ImageSkia& image) { + return EncodeToString( + image, base::BindRepeating([](const SkBitmap& bitmap, + std::vector<unsigned char>* encoded_data) { + return gfx::PNGCodec::EncodeBGRASkBitmap( + bitmap, /*discard_transparency=*/false, encoded_data); + })); +} + +} // namespace + +class ImageUtilTest : public ::testing::Test { + protected: + void SetUp() override { ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); } + + base::FilePath CreateFilePath(base::FilePath::StringPieceType file_name) { + return scoped_temp_dir_.GetPath().Append(file_name); + } + + image_util::DecodeImageCallback CreateDecodeImageCallback( + base::RunLoop& run_loop, + gfx::ImageSkia& image_out) { + return base::BindLambdaForTesting( + [&image_out, &run_loop](const gfx::ImageSkia& result) { + image_out = result; + run_loop.Quit(); + }); + } + + gfx::ImageSkia DecodeImageFile(base::FilePath::StringPieceType file_name, + data_decoder::mojom::ImageCodec codec) { + base::test::ScopedRunLoopTimeout timeout(FROM_HERE, kDecodeImageTimeout); + base::RunLoop run_loop; + gfx::ImageSkia image_out; + image_util::DecodeImageFile(CreateDecodeImageCallback(run_loop, image_out), + CreateFilePath(file_name), codec); + run_loop.Run(); + return image_out; + } + + gfx::ImageSkia DecodeImageData(data_decoder::mojom::ImageCodec codec, + const std::string& data) { + base::test::ScopedRunLoopTimeout timeout(FROM_HERE, kDecodeImageTimeout); + base::RunLoop run_loop; + gfx::ImageSkia image_out; + image_util::DecodeImageData(CreateDecodeImageCallback(run_loop, image_out), + codec, data); + run_loop.Run(); + return image_out; + } + + base::test::TaskEnvironment task_environment_; + InProcessImageDecoder decoder_; + base::ScopedTempDir scoped_temp_dir_; +}; + +TEST_F(ImageUtilTest, DecodeImageDataDefaultCodec) { + gfx::ImageSkia original_image = CreateTestImage(200, 100, SK_ColorYELLOW); + gfx::ImageSkia decoded_image = DecodeImageData( + data_decoder::mojom::ImageCodec::kDefault, EncodeAsJpeg(original_image)); + EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(decoded_image), + gfx::Image(original_image))); +} + +TEST_F(ImageUtilTest, DecodeImageDataPng) { + gfx::ImageSkia original_image = CreateTestImage(200, 100, SK_ColorYELLOW); + gfx::ImageSkia decoded_image = DecodeImageData( + data_decoder::mojom::ImageCodec::kPng, EncodeAsPng(original_image)); + EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(decoded_image), + gfx::Image(original_image))); +} + +TEST_F(ImageUtilTest, DecodeImageDataFailsForInvalidData) { + gfx::ImageSkia decoded_image = + DecodeImageData(data_decoder::mojom::ImageCodec::kDefault, "gibberish"); + EXPECT_TRUE(decoded_image.isNull()); +} + +TEST_F(ImageUtilTest, DecodeImageFileDefaultCodec) { + gfx::ImageSkia original_image = CreateTestImage(200, 100, SK_ColorYELLOW); + ASSERT_TRUE(base::WriteFile(CreateFilePath("test_image.jpg"), + EncodeAsJpeg(original_image))); + gfx::ImageSkia decoded_image = DecodeImageFile( + "test_image.jpg", data_decoder::mojom::ImageCodec::kDefault); + EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(decoded_image), + gfx::Image(original_image))); +} + +TEST_F(ImageUtilTest, DecodeImageFilePng) { + gfx::ImageSkia original_image = CreateTestImage(200, 100, SK_ColorYELLOW); + ASSERT_TRUE(base::WriteFile(CreateFilePath("test_image.png"), + EncodeAsPng(original_image))); + gfx::ImageSkia decoded_image = + DecodeImageFile("test_image.png", data_decoder::mojom::ImageCodec::kPng); + EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(decoded_image), + gfx::Image(original_image))); +} + +TEST_F(ImageUtilTest, DecodeImageFileFailsForInvalidData) { + ASSERT_TRUE(base::WriteFile(CreateFilePath("test_image.jpg"), "gibberish")); + gfx::ImageSkia decoded_image = DecodeImageFile( + "test_image.jpg", data_decoder::mojom::ImageCodec::kDefault); +} + +TEST_F(ImageUtilTest, DecodeImageFileFailsForMissingFile) { + gfx::ImageSkia decoded_image = DecodeImageFile( + "test_image.jpg", data_decoder::mojom::ImageCodec::kDefault); + EXPECT_TRUE(decoded_image.isNull()); +} + +TEST_F(ImageUtilTest, DecodeImageFileMultipleFiles) { + gfx::ImageSkia original_image_1 = CreateTestImage(200, 100, SK_ColorYELLOW); + gfx::ImageSkia original_image_2 = CreateTestImage(100, 200, SK_ColorCYAN); + ASSERT_TRUE(base::WriteFile(CreateFilePath("test_image_1.jpg"), + EncodeAsJpeg(original_image_1))); + ASSERT_TRUE(base::WriteFile(CreateFilePath("test_image_2.jpg"), + EncodeAsJpeg(original_image_2))); + gfx::ImageSkia decoded_image_1 = DecodeImageFile( + "test_image_1.jpg", data_decoder::mojom::ImageCodec::kDefault); + gfx::ImageSkia decoded_image_2 = DecodeImageFile( + "test_image_2.jpg", data_decoder::mojom::ImageCodec::kDefault); + EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(decoded_image_1), + gfx::Image(original_image_1))); + EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(decoded_image_2), + gfx::Image(original_image_2))); +} + +TEST_F(ImageUtilTest, DecodeImageFileSameFileMultipleTimes) { + gfx::ImageSkia original_image = CreateTestImage(200, 100, SK_ColorYELLOW); + ASSERT_TRUE(base::WriteFile(CreateFilePath("test_image.jpg"), + EncodeAsJpeg(original_image))); + gfx::ImageSkia decoded_image = DecodeImageFile( + "test_image.jpg", data_decoder::mojom::ImageCodec::kDefault); + EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(decoded_image), + gfx::Image(original_image))); + + original_image = CreateTestImage(100, 200, SK_ColorCYAN); + ASSERT_TRUE(base::WriteFile(CreateFilePath("test_image.jpg"), + EncodeAsJpeg(original_image))); + decoded_image = DecodeImageFile("test_image.jpg", + data_decoder::mojom::ImageCodec::kDefault); + EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(decoded_image), + gfx::Image(original_image))); +} + +} // namespace ash
diff --git a/ash/public/cpp/test/in_process_image_decoder.cc b/ash/public/cpp/test/in_process_image_decoder.cc new file mode 100644 index 0000000..aab6c8d1 --- /dev/null +++ b/ash/public/cpp/test/in_process_image_decoder.cc
@@ -0,0 +1,140 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/public/cpp/test/in_process_image_decoder.h" + +#include "base/timer/elapsed_timer.h" +#include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "services/data_decoder/public/mojom/data_decoder_service.mojom.h" +#include "services/data_decoder/public/mojom/image_decoder.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/codec/jpeg_codec.h" +#include "ui/gfx/codec/png_codec.h" + +namespace ash { +namespace { + +class ImageDecoderImpl : public data_decoder::mojom::ImageDecoder { + public: + ImageDecoderImpl() = default; + ImageDecoderImpl(const ImageDecoderImpl&) = delete; + ImageDecoderImpl& operator=(const ImageDecoderImpl&) = delete; + ~ImageDecoderImpl() override = default; + + // data_decoder::mojom::ImageDecoder: + // + // |shrink_to_fit|, |max_size_in_bytes|, and |desired_image_frame_size| are + // left unimplemented for now because there are currently no testing use + // cases for these. They may be implemented later if required. + void DecodeImage(mojo_base::BigBuffer encoded_data, + data_decoder::mojom::ImageCodec codec, + bool shrink_to_fit, + int64_t max_size_in_bytes, + const gfx::Size& desired_image_frame_size, + DecodeImageCallback callback) override { + ASSERT_TRUE(callback); + base::ElapsedTimer timer; + SkBitmap output; + if (encoded_data.size() == 0) { + std::move(callback).Run(timer.Elapsed(), output); + return; + } + + switch (codec) { + case data_decoder::mojom::ImageCodec::kDefault: { + // Only "default" codec currently used in ash/ is jpeg. Others may be + // added here in the future if necessary. + std::unique_ptr<SkBitmap> decoded_jpeg = + gfx::JPEGCodec::Decode(encoded_data.data(), encoded_data.size()); + if (decoded_jpeg) { + output = std::move(*decoded_jpeg); + } + break; + } + case data_decoder::mojom::ImageCodec::kPng: + gfx::PNGCodec::Decode(encoded_data.data(), encoded_data.size(), + &output); + break; + } + std::move(callback).Run(timer.Elapsed(), output); + } + + void DecodeAnimation(mojo_base::BigBuffer encoded_data, + bool shrink_to_fit, + int64_t max_size_in_bytes, + DecodeAnimationCallback callback) override { + FAIL(); + } +}; + +} // namespace + +// Everything not related to image decoding is left unimplemented because +// this was specifically written to address the image decoding drawbacks within +// data_decoder::test::InProcessDataDecoder. For all other data decoding, +// using data_decoder::test::InProcessDataDecoder directly should be sufficient. +class InProcessImageDecoder::DataDecoderServiceImpl + : public data_decoder::mojom::DataDecoderService { + public: + DataDecoderServiceImpl() = default; + DataDecoderServiceImpl(const DataDecoderServiceImpl&) = delete; + DataDecoderServiceImpl& operator=(const DataDecoderServiceImpl&) = delete; + ~DataDecoderServiceImpl() override = default; + + // data_decoder::mojom::DataDecoderService implementation: + void BindImageDecoder(mojo::PendingReceiver<data_decoder::mojom::ImageDecoder> + receiver) override { + mojo::MakeSelfOwnedReceiver(std::make_unique<ImageDecoderImpl>(), + std::move(receiver)); + } + void BindJsonParser(mojo::PendingReceiver<data_decoder::mojom::JsonParser> + receiver) override { + FAIL(); + } + void BindStructuredHeadersParser( + mojo::PendingReceiver<data_decoder::mojom::StructuredHeadersParser> + receiver) override { + FAIL(); + } + void BindXmlParser( + mojo::PendingReceiver<data_decoder::mojom::XmlParser> receiver) override { + FAIL(); + } + void BindWebBundleParserFactory( + mojo::PendingReceiver<web_package::mojom::WebBundleParserFactory> + receiver) override { + FAIL(); + } + void BindWebBundler(mojo::PendingReceiver<data_decoder::mojom::WebBundler> + receiver) override { + FAIL(); + } + void BindGzipper( + mojo::PendingReceiver<data_decoder::mojom::Gzipper> receiver) override { + FAIL(); + } + void BindBleScanParser( + mojo::PendingReceiver<data_decoder::mojom::BleScanParser> receiver) + override { + FAIL(); + } +}; + +InProcessImageDecoder::InProcessImageDecoder() + : service_(std::make_unique<DataDecoderServiceImpl>()) { + ServiceProvider::Set(this); +} + +InProcessImageDecoder::~InProcessImageDecoder() { + ServiceProvider::Set(nullptr); +} + +void InProcessImageDecoder::BindDataDecoderService( + mojo::PendingReceiver<data_decoder::mojom::DataDecoderService> receiver) { + receivers_.Add(service_.get(), std::move(receiver)); +} + +} // namespace ash
diff --git a/ash/public/cpp/test/in_process_image_decoder.h b/ash/public/cpp/test/in_process_image_decoder.h new file mode 100644 index 0000000..baa14164 --- /dev/null +++ b/ash/public/cpp/test/in_process_image_decoder.h
@@ -0,0 +1,51 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_PUBLIC_CPP_TEST_IN_PROCESS_IMAGE_DECODER_H_ +#define ASH_PUBLIC_CPP_TEST_IN_PROCESS_IMAGE_DECODER_H_ + +#include <memory> + +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "services/data_decoder/public/cpp/service_provider.h" +#include "services/data_decoder/public/mojom/data_decoder_service.mojom.h" + +namespace ash { + +// Serves as the underlying decoder implementation in tests for any code that +// uses the decoding functions in image_util.h. To use, simply instantiate an +// InProcessImageDecoder somewhere in the test harness before a call to +// ash::DecodeImage*() is made, and all of the rest is taken care of. +// +// This is exactly the same as data_decoder::test::InProcessDataDecoder in that +// it is an in-process implementation of the data decoding mojo service, which +// avoids the complexity of a multi-process environment in tests. The difference +// is that: +// 1) It only supports image decoding; it was specifically written to address +// the drawback mentioned in 2). +// 2) The image decoding implementation does not depend on blink like +// data_decoder::test::InProcessDataDecoder does. This is problematic within +// ash/ specifically because blink is an undesirable dependency. +class InProcessImageDecoder : public data_decoder::ServiceProvider { + public: + InProcessImageDecoder(); + InProcessImageDecoder(const InProcessImageDecoder&) = delete; + InProcessImageDecoder& operator=(const InProcessImageDecoder&) = delete; + ~InProcessImageDecoder() override; + + private: + class DataDecoderServiceImpl; + + // ServiceProvider implementation: + void BindDataDecoderService( + mojo::PendingReceiver<data_decoder::mojom::DataDecoderService> receiver) + override; + + const std::unique_ptr<DataDecoderServiceImpl> service_; + mojo::ReceiverSet<data_decoder::mojom::DataDecoderService> receivers_; +}; + +} // namespace ash + +#endif // ASH_PUBLIC_CPP_TEST_IN_PROCESS_IMAGE_DECODER_H_
diff --git a/ash/session/session_controller_impl.cc b/ash/session/session_controller_impl.cc index 5a9209b..d1ffc9a1 100644 --- a/ash/session/session_controller_impl.cc +++ b/ash/session/session_controller_impl.cc
@@ -118,10 +118,7 @@ } bool SessionControllerImpl::ShouldShowNotificationTray() const { - if (!IsActiveUserSessionStarted() || IsInSecondaryLoginScreen()) - return false; - - return true; + return IsActiveUserSessionStarted() && !IsInSecondaryLoginScreen(); } const SessionControllerImpl::UserSessions&
diff --git a/ash/shelf/drag_window_from_shelf_controller.cc b/ash/shelf/drag_window_from_shelf_controller.cc index dfe5a1e..cc682c1 100644 --- a/ash/shelf/drag_window_from_shelf_controller.cc +++ b/ash/shelf/drag_window_from_shelf_controller.cc
@@ -20,6 +20,7 @@ #include "ash/wallpaper/wallpaper_constants.h" #include "ash/wallpaper/wallpaper_view.h" #include "ash/wallpaper/wallpaper_widget_controller.h" +#include "ash/wm/float/float_controller.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/overview/overview_constants.h" #include "ash/wm/overview/overview_controller.h" @@ -81,13 +82,14 @@ class DragWindowFromShelfController::WindowsHider : public aura::WindowObserver { public: - explicit WindowsHider(aura::Window* dragged_window) + WindowsHider(aura::Window* dragged_window, aura::Window* other_window) : dragged_window_(dragged_window) { std::vector<aura::Window*> windows = Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk); for (auto* window : windows) { - if (window == dragged_window_) + if (window == dragged_window_ || window == other_window) { continue; + } if (wm::HasTransientAncestor(window, dragged_window_)) continue; if (!window->IsVisible()) @@ -161,6 +163,42 @@ const gfx::PointF& location_in_screen) : window_(window) { window_->AddObserver(this); + + // Find the other window that is visible while `window_` is being dragged. + // There will only be another window if there is a float window (splitview has + // two visible windows but is handled separately). + if (auto* float_controller = Shell::Get()->float_controller()) { + if (auto* floated_window = float_controller->FindFloatedWindowOfDesk( + DesksController::Get()->GetTargetActiveDesk())) { + // If the floated window is the dragged window, then the other window is + // the top most non floated window, if it exists. Otherwise the floated + // window is the active window. + if (floated_window == window_) { + aura::Window* candidate_other_window = + window_util::GetTopNonFloatedWindow(); + if (candidate_other_window && + !WindowState::Get(candidate_other_window)->IsMinimized()) { + other_window_ = candidate_other_window; + } + } else { + other_window_ = floated_window; + } + + // Create a copy of the other window. This will be stacked on top and + // faded out as we drag. The original window will be placed immediately + // into overview mode on a successful drag, or return to its original + // position on a canceled drag. + if (other_window_) { + other_window_->AddObserver(this); + other_window_copy_ = wm::RecreateLayers(other_window_); + other_window_copy_->root()->SetVisible(true); + other_window_copy_->root()->SetOpacity(1.f); + other_window_->layer()->parent()->StackAbove(other_window_copy_->root(), + other_window_->layer()); + } + } + } + OnDragStarted(location_in_screen); presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder( @@ -172,6 +210,7 @@ CancelDrag(); if (window_) window_->RemoveObserver(this); + ResetOtherWindow(); } void DragWindowFromShelfController::Drag(const gfx::PointF& location_in_screen, @@ -343,6 +382,11 @@ } void DragWindowFromShelfController::OnWindowDestroying(aura::Window* window) { + if (window == other_window_) { + ResetOtherWindow(); + return; + } + DCHECK_EQ(window_, window); CancelDrag(); @@ -364,7 +408,7 @@ WindowBackdrop::Get(window_)->DisableBackdrop(); // Hide all visible windows behind the dragged window during dragging. - windows_hider_ = std::make_unique<WindowsHider>(window_); + windows_hider_ = std::make_unique<WindowsHider>(window_, other_window_); // Hide the home launcher until it's eligible to show it. Shell::Get()->app_list_controller()->OnWindowDragStarted(); @@ -462,12 +506,14 @@ } window_drag_result_.reset(); started_in_overview_ = false; + + ResetOtherWindow(); } void DragWindowFromShelfController::UpdateDraggedWindow( const gfx::PointF& location_in_screen) { gfx::Rect bounds = window_->bounds(); - ::wm::ConvertRectToScreen(window_->parent(), &bounds); + wm::ConvertRectToScreen(window_->parent(), &bounds); // Calculate the window's transform based on the location. // For scale, at |initial_location_in_screen_| or bounds.bottom(), the scale @@ -508,7 +554,7 @@ TransformAboutPivot(gfx::PointF(window_->bounds().origin()), transform); gfx::RectF transformed_bounds = new_tranform.MapRect(gfx::RectF(window_->bounds())); - ::wm::TranslateRectToScreen(window_->parent(), &transformed_bounds); + wm::TranslateRectToScreen(window_->parent(), &transformed_bounds); if (transformed_bounds.y() < display_bounds.y()) { transform.Translate(0, (display_bounds.y() - transformed_bounds.y()) / scale); @@ -519,6 +565,17 @@ } SetTransform(window_, transform); + + if (other_window_copy_) { + // TODO(b/252504142): Figure out the opacity once motion specs are ready. + // For now, the opacity will become zero once we have dragged more than one + // eighth of the display. + float opacity = (initial_location_in_screen_.y() - location_in_screen.y()) / + (display_bounds.height() / 8.f); + + opacity = base::clamp(opacity, 0.f, 1.f); + other_window_copy_->root()->SetOpacity(1.f - opacity); + } } SplitViewController::SnapPosition @@ -745,4 +802,12 @@ HideOverviewDuringDrag(); } +void DragWindowFromShelfController::ResetOtherWindow() { + if (other_window_) { + other_window_->RemoveObserver(this); + other_window_ = nullptr; + } + other_window_copy_.reset(); +} + } // namespace ash
diff --git a/ash/shelf/drag_window_from_shelf_controller.h b/ash/shelf/drag_window_from_shelf_controller.h index dee260e..4eabfe4 100644 --- a/ash/shelf/drag_window_from_shelf_controller.h +++ b/ash/shelf/drag_window_from_shelf_controller.h
@@ -172,7 +172,15 @@ // function is supposed to be called with an active overview session. void OnWindowDragStartedInOverview(); + // Cleans up `other_window_` and `other_window_copy`. + void ResetOtherWindow(); + aura::Window* window_ = nullptr; + // The `other_window_` refers to the window other than `window_` that is + // visible while `window_` is being dragged. This happens when there is a + // floated window. + aura::Window* other_window_ = nullptr; + std::unique_ptr<ui::LayerTreeOwner> other_window_copy_; gfx::PointF initial_location_in_screen_; gfx::PointF previous_location_in_screen_; bool drag_started_ = false;
diff --git a/ash/shelf/drag_window_from_shelf_controller_test_api.cc b/ash/shelf/drag_window_from_shelf_controller_test_api.cc index 69dc4e45..c36d092 100644 --- a/ash/shelf/drag_window_from_shelf_controller_test_api.cc +++ b/ash/shelf/drag_window_from_shelf_controller_test_api.cc
@@ -32,4 +32,11 @@ run_loop.Run(); } +ui::Layer* DragWindowFromShelfControllerTestApi::GetOtherWindowCopyLayer( + DragWindowFromShelfController* window_drag_controller) { + ui::LayerTreeOwner* layer_tree_owner = + window_drag_controller->other_window_copy_.get(); + return layer_tree_owner ? layer_tree_owner->root() : nullptr; +} + } // namespace ash
diff --git a/ash/shelf/drag_window_from_shelf_controller_test_api.h b/ash/shelf/drag_window_from_shelf_controller_test_api.h index 2c090b7d..968e5887 100644 --- a/ash/shelf/drag_window_from_shelf_controller_test_api.h +++ b/ash/shelf/drag_window_from_shelf_controller_test_api.h
@@ -7,6 +7,10 @@ #include "ash/ash_export.h" +namespace ui { +class Layer; +} + namespace ash { class DragWindowFromShelfController; @@ -22,6 +26,12 @@ void WaitUntilOverviewIsShown( DragWindowFromShelfController* window_drag_controller); + + // Retrieves the copy layer of the "other" window during a drag from shelf + // with a floated window. See `DragWindowFromShelfController::other_window_` + // for more details. + ui::Layer* GetOtherWindowCopyLayer( + DragWindowFromShelfController* window_drag_controller); }; } // namespace ash
diff --git a/ash/shelf/drag_window_from_shelf_controller_unittest.cc b/ash/shelf/drag_window_from_shelf_controller_unittest.cc index f53e8b9..52cedb1 100644 --- a/ash/shelf/drag_window_from_shelf_controller_unittest.cc +++ b/ash/shelf/drag_window_from_shelf_controller_unittest.cc
@@ -19,6 +19,7 @@ #include "ash/shelf/window_scale_animation.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" +#include "ash/test/ash_test_util.h" #include "ash/wallpaper/wallpaper_constants.h" #include "ash/wallpaper/wallpaper_view.h" #include "ash/wallpaper/wallpaper_widget_controller.h" @@ -35,6 +36,8 @@ #include "ash/wm/window_util.h" #include "base/ranges/algorithm.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" +#include "chromeos/ui/wm/features.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/window_parenting_client.h" #include "ui/compositor/layer.h" @@ -51,14 +54,8 @@ namespace { -// Helper function to get the index of |child|, given its parent window -// |parent|. -int IndexOf(aura::Window* child, aura::Window* parent) { - aura::Window::Windows children = parent->children(); - auto it = base::ranges::find(children, child); - DCHECK(it != children.end()); - - return static_cast<int>(std::distance(children.begin(), it)); +gfx::Rect GetShelfBounds() { + return Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); } } // namespace @@ -159,8 +156,7 @@ TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDraggingWithFlag) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window3 = CreateTestWindow(); auto window2 = CreateTestWindow(); @@ -194,8 +190,7 @@ TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDraggingInSplitView) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window3 = CreateTestWindow(); auto window2 = CreateTestWindow(); @@ -254,8 +249,7 @@ // Test home launcher is hidden during dragging. TEST_F(DragWindowFromShelfControllerTest, HideHomeLauncherDuringDraggingTest) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window = CreateTestWindow(); StartDrag(window.get(), shelf_bounds.CenterPoint()); Drag(gfx::Point(0, 200), 0.f, 1.f); @@ -273,8 +267,7 @@ // depending on different scenarios. TEST_F(DragWindowFromShelfControllerTest, MayOrMayNotReShowHiddenWindows) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window2 = CreateTestWindow(); auto window1 = CreateTestWindow(); EXPECT_FALSE(window1->GetProperty(kHideDuringWindowDragging)); @@ -342,13 +335,11 @@ // show correctly in overview. TEST_F(DragWindowFromShelfControllerTest, MinimizedWindowsShowInOverview) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window3 = CreateTestWindow(); auto window2 = CreateTestWindow(); auto window1 = CreateTestWindow(); - StartDrag(window1.get(), shelf_bounds.CenterPoint()); + StartDrag(window1.get(), GetShelfBounds().CenterPoint()); // Drag it far enough so overview should be open behind the dragged window. Drag(gfx::Point(200, 200), 0.f, 1.f); DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( @@ -376,11 +367,9 @@ // delta (velocity) decrease to kOpenOverviewThreshold or less. TEST_F(DragWindowFromShelfControllerTest, OpenOverviewWhenHold) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - StartDrag(window.get(), shelf_bounds.CenterPoint()); + StartDrag(window.get(), GetShelfBounds().CenterPoint()); Drag(gfx::Point(200, 200), 0.f, DragWindowFromShelfController::kOpenOverviewThreshold + 1); OverviewController* overview_controller = Shell::Get()->overview_controller(); @@ -396,8 +385,7 @@ // back to its original position. TEST_F(DragWindowFromShelfControllerTest, RestoreWindowToOriginalBounds) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window = CreateTestWindow(); const gfx::Rect display_bounds = display::Screen::GetScreen() ->GetDisplayNearestWindow(window.get()) @@ -452,8 +440,7 @@ // or may not head to the home screen. TEST_F(DragWindowFromShelfControllerTest, FlingInOverview) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window = CreateTestWindow(); // If downward fling velocity is equal or larger than @@ -501,15 +488,13 @@ ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); base::HistogramTester histogram_tester; // Ensure that fling velocity is sufficient to show homelauncher without // triggering overview mode. - StartDrag(window.get(), shelf_bounds.CenterPoint()); + StartDrag(window.get(), GetShelfBounds().CenterPoint()); Drag(gfx::Point(200, 200), 0.f, DragWindowFromShelfController::kOpenOverviewThreshold + 1); EndDrag(gfx::Point(0, 350), @@ -526,8 +511,7 @@ // overview. TEST_F(DragWindowFromShelfControllerTest, DragOrFlingInSplitView) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window1 = CreateTestWindow(); auto window2 = CreateTestWindow(); @@ -598,8 +582,7 @@ // not open during dragging. TEST_F(DragWindowFromShelfControllerTest, WallpaperBlurDuringDragging) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window = CreateTestWindow(); StartDrag(window.get(), shelf_bounds.CenterPoint()); @@ -613,8 +596,7 @@ ->wallpaper_view(); EXPECT_EQ(wallpaper_view->blur_sigma(), wallpaper_constants::kOverviewBlur); - EndDrag(shelf_bounds.CenterPoint(), - /*velocity_y=*/absl::nullopt); + EndDrag(shelf_bounds.CenterPoint(), /*velocity_y=*/absl::nullopt); EXPECT_EQ(wallpaper_view->blur_sigma(), wallpaper_constants::kClear); } @@ -622,12 +604,10 @@ // stops. TEST_F(DragWindowFromShelfControllerTest, HideOverviewDuringDragging) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window2 = CreateTestWindow(); auto window1 = CreateTestWindow(); - StartDrag(window1.get(), shelf_bounds.CenterPoint()); + StartDrag(window1.get(), GetShelfBounds().CenterPoint()); Drag(gfx::Point(200, 200), 0.5f, 0.5f); DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( window_drag_controller()); @@ -664,8 +644,7 @@ TEST_F(DragWindowFromShelfControllerTest, SplitViewDragIndicatorsWindowDraggingStates) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window = CreateTestWindow(); StartDrag(window.get(), shelf_bounds.CenterPoint()); @@ -695,8 +674,7 @@ EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kFromShelf, drag_indicators->current_window_dragging_state()); - EndDrag(shelf_bounds.CenterPoint(), - /*velocity_y=*/absl::nullopt); + EndDrag(shelf_bounds.CenterPoint(), /*velocity_y=*/absl::nullopt); } // Test there is no black backdrop behind the dragged window if we're doing the @@ -705,14 +683,12 @@ ui::ScopedAnimationDurationScaleMode test_duration_mode( ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); EXPECT_TRUE(window->layer()->GetTargetTransform().IsIdentity()); WindowBackdrop* window_backdrop = WindowBackdrop::Get(window.get()); EXPECT_NE(window_backdrop->mode(), WindowBackdrop::BackdropMode::kDisabled); - StartDrag(window.get(), shelf_bounds.left_center()); + StartDrag(window.get(), GetShelfBounds().left_center()); Drag(gfx::Point(0, 200), 0.f, 10.f); EndDrag(gfx::Point(0, 200), absl::make_optional( @@ -725,8 +701,6 @@ // Test that if drag is cancelled, overview should be dismissed and other // hidden windows should restore to its previous visibility state. TEST_F(DragWindowFromShelfControllerTest, CancelDragDismissOverview) { - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window3 = CreateTestWindow(); auto window2 = CreateTestWindow(); auto window1 = CreateTestWindow(); @@ -734,7 +708,7 @@ EXPECT_TRUE(window2->IsVisible()); EXPECT_TRUE(window3->IsVisible()); - StartDrag(window1.get(), shelf_bounds.CenterPoint()); + StartDrag(window1.get(), GetShelfBounds().CenterPoint()); Drag(gfx::Point(200, 200), 0.5f, 0.5f); DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( window_drag_controller()); @@ -752,10 +726,8 @@ } TEST_F(DragWindowFromShelfControllerTest, CancelDragIfWindowDestroyed) { - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - StartDrag(window.get(), shelf_bounds.CenterPoint()); + StartDrag(window.get(), GetShelfBounds().CenterPoint()); Drag(gfx::Point(200, 200), 0.5f, 0.5f); DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( window_drag_controller()); @@ -782,10 +754,8 @@ kHandleDragWindowFromShelfHistogramName, ShelfWindowDragResult::kRestoreToOriginalBounds, 0); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - gfx::Point start = shelf_bounds.CenterPoint(); + gfx::Point start = GetShelfBounds().CenterPoint(); StartDrag(window.get(), start); // Only drag for a small distance and then fling. Drag(gfx::Point(start.x(), start.y() - 10), 0.5f, 0.5f); @@ -817,8 +787,7 @@ TEST_F(DragWindowFromShelfControllerTest, DragToSnapMinDistance) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window1 = CreateTestWindow(); auto window2 = CreateTestWindow(); @@ -944,8 +913,7 @@ TEST_F(DragWindowFromShelfControllerTest, TestOverviewInvisible) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window = CreateTestWindow(); StartDrag(window.get(), shelf_bounds.left_center()); @@ -990,10 +958,7 @@ TestOverviewInvisibleWithMinSnapDistance) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); - const gfx::Rect display_bounds = display::Screen::GetScreen() ->GetDisplayNearestWindow(window.get()) .bounds(); @@ -1003,7 +968,7 @@ // Start the drag outside snap region. gfx::Point start = gfx::Point(display_bounds.x() + snap_edge_inset + 70, - shelf_bounds.CenterPoint().y()); + GetShelfBounds().CenterPoint().y()); StartDrag(window.get(), start); // Drag into the snap region and release without a fling. // At this moment overview should be invisible, so the window should be taken @@ -1022,8 +987,7 @@ // ends, no matter where the window ends. TEST_F(DragWindowFromShelfControllerTest, RestoreBackdropAfterDragEnds) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window = CreateTestWindow(); WindowBackdrop* window_backdrop = WindowBackdrop::Get(window.get()); EXPECT_EQ(window_backdrop->mode(), WindowBackdrop::BackdropMode::kAuto); @@ -1096,13 +1060,11 @@ TEST_F(DragWindowFromShelfControllerTest, DoNotChangeActiveWindowDuringDragging) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); wm::ActivateWindow(window.get()); EXPECT_EQ(window.get(), window_util::GetActiveWindow()); - StartDrag(window.get(), shelf_bounds.CenterPoint()); + StartDrag(window.get(), GetShelfBounds().CenterPoint()); Drag(gfx::Point(200, 200), 0.f, 1.f); DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( window_drag_controller()); @@ -1132,13 +1094,11 @@ base::Milliseconds(100)); UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); wm::ActivateWindow(window.get()); EXPECT_EQ(window.get(), window_util::GetActiveWindow()); - StartDrag(window.get(), shelf_bounds.CenterPoint()); + StartDrag(window.get(), GetShelfBounds().CenterPoint()); Drag(gfx::Point(200, 200), 0.f, 1.f); DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( window_drag_controller()); @@ -1179,9 +1139,7 @@ EXPECT_EQ(window1.get(), split_view_controller()->primary_window()); EXPECT_EQ(window2.get(), split_view_controller()->secondary_window()); ToggleOverview(); - StartDrag(window1.get(), Shelf::ForWindow(Shell::GetPrimaryRootWindow()) - ->GetIdealBounds() - .left_center()); + StartDrag(window1.get(), GetShelfBounds().left_center()); Drag(gfx::Point(200, 200), 1.f, 1.f); DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( window_drag_controller()); @@ -1204,22 +1162,16 @@ aura::Window* parent = window1->parent(); ASSERT_EQ(parent, window2->parent()); ASSERT_EQ(parent, window3->parent()); - EXPECT_GT(IndexOf(GetOverviewItemForWindow(window2.get()) - ->item_widget() - ->GetNativeWindow(), - parent), - IndexOf(GetOverviewItemForWindow(window1.get()) - ->item_widget() - ->GetNativeWindow(), - parent)); - EXPECT_GT(IndexOf(GetOverviewItemForWindow(window1.get()) - ->item_widget() - ->GetNativeWindow(), - parent), - IndexOf(GetOverviewItemForWindow(window3.get()) - ->item_widget() - ->GetNativeWindow(), - parent)); + EXPECT_TRUE(IsStackedBelow( + GetOverviewItemForWindow(window1.get())->item_widget()->GetNativeWindow(), + GetOverviewItemForWindow(window2.get()) + ->item_widget() + ->GetNativeWindow())); + EXPECT_TRUE(IsStackedBelow( + GetOverviewItemForWindow(window3.get())->item_widget()->GetNativeWindow(), + GetOverviewItemForWindow(window1.get()) + ->item_widget() + ->GetNativeWindow())); } // Test that when the dragged window is returned to maximized state, the @@ -1230,10 +1182,7 @@ std::unique_ptr<aura::Window> window2 = CreateTestWindow(); // Drag |window1| so that overview is shown. - const gfx::Point shelf_centerpoint = - Shelf::ForWindow(Shell::GetPrimaryRootWindow()) - ->GetIdealBounds() - .CenterPoint(); + const gfx::Point shelf_centerpoint = GetShelfBounds().CenterPoint(); StartDrag(window1.get(), shelf_centerpoint); Drag(gfx::Point(200, 200), 1.f, 1.f); DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( @@ -1266,8 +1215,7 @@ TEST_F(DragWindowFromShelfControllerTest, KeepSplitWindowSnappedAfterRestoreToOriginalBounds) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); auto window1 = CreateTestWindow(); auto window2 = CreateTestWindow(); @@ -1328,8 +1276,6 @@ ui::ScopedAnimationDurationScaleMode animation_scale( ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); UpdateDisplay("1366x768"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); auto window = CreateTestWindow(); auto window_transient = CreateTransientModalChildWindow( @@ -1337,7 +1283,7 @@ wm::TransientWindowManager::GetOrCreate(window_transient.get()) ->set_parent_controls_visibility(true); - StartDrag(window_transient.get(), shelf_bounds.right_center()); + StartDrag(window_transient.get(), GetShelfBounds().right_center()); Drag(gfx::Point(745, 616), 47, -47); EndDrag(gfx::Point(1366, 0), -1815.28); WaitForHomeLauncherAnimationToFinish(); @@ -1382,9 +1328,6 @@ // https://crbug.com/1263183 TEST_F(DragWindowFromShelfControllerTest, DragWindowWithMultipleTransientChildWindows) { - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); - // Specify using `ZERO_DURATION` here to make sure the drag will still work // even all the animations are no-ops. ui::ScopedAnimationDurationScaleMode animation_scale( @@ -1400,7 +1343,7 @@ wm::TransientWindowManager::GetOrCreate(transient_child_win2.get()) ->set_parent_controls_visibility(true); - StartDrag(window.get(), shelf_bounds.right_center()); + StartDrag(window.get(), GetShelfBounds().right_center()); Drag(gfx::Point(745, 616), 47, -47); EndDrag(gfx::Point(1366, 0), -1815.28); WaitForHomeLauncherAnimationToFinish(); @@ -1418,8 +1361,7 @@ // Tests that destroying a trasient child that is being dragged from the shelf // does not result in a crash. Regression test for https://crbug.com/1200596. TEST_F(DragWindowFromShelfControllerTest, DestroyTransientWhileAnimating) { - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); // The crash occurred while destroying an animating window. ui::ScopedAnimationDurationScaleMode animation_scale( @@ -1448,8 +1390,7 @@ TEST_F(DragWindowFromShelfControllerTest, DestroyWindowDuringDraggingInSplitView) { UpdateDisplay("500x400"); - const gfx::Rect shelf_bounds = - Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); + const gfx::Rect shelf_bounds = GetShelfBounds(); // Create a window and snapped to the left in split screen. auto window = CreateTestWindow(); @@ -1466,4 +1407,115 @@ EndDrag(shelf_bounds.CenterPoint(), /*velocity_y=*/absl::nullopt); } +class FloatDragWindowFromShelfControllerTest + : public DragWindowFromShelfControllerTest { + public: + FloatDragWindowFromShelfControllerTest() + : scoped_feature_list_(chromeos::wm::features::kFloatWindow) {} + FloatDragWindowFromShelfControllerTest( + const FloatDragWindowFromShelfControllerTest&) = delete; + FloatDragWindowFromShelfControllerTest& operator=( + const FloatDragWindowFromShelfControllerTest&) = delete; + ~FloatDragWindowFromShelfControllerTest() override = default; + + ui::Layer* GetOtherWindowCopyLayer() { + return DragWindowFromShelfControllerTestApi().GetOtherWindowCopyLayer( + window_drag_controller()); + } + + // Creates a floated application window. + std::unique_ptr<aura::Window> CreateFloatedWindow() { + std::unique_ptr<aura::Window> floated_window = CreateAppWindow(); + PressAndReleaseKey(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN); + DCHECK(WindowState::Get(floated_window.get())->IsFloated()); + return floated_window; + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +TEST_F(FloatDragWindowFromShelfControllerTest, DragFloatedWindow) { + const gfx::Rect shelf_bounds = GetShelfBounds(); + + // Create one maximized and one floated window. + auto maximized_window = CreateTestWindow(); + auto floated_window = CreateFloatedWindow(); + wm::ActivateWindow(floated_window.get()); + + const gfx::Point start_drag_point( + floated_window->GetBoundsInScreen().CenterPoint().x(), + shelf_bounds.CenterPoint().y()); + // Try to drag the window from shelf. + StartDrag(floated_window.get(), start_drag_point); + ui::Layer* other_window_copy_layer = GetOtherWindowCopyLayer(); + ASSERT_TRUE(other_window_copy_layer); + + // To check if the copy is of the maximized window, we check the parent and + // bounds. + EXPECT_EQ(maximized_window->layer()->parent(), + other_window_copy_layer->parent()); + EXPECT_EQ(maximized_window->layer()->bounds(), + other_window_copy_layer->bounds()); + + Drag(gfx::Point(0, 200), 1.f, 1.f); + EndDrag(shelf_bounds.CenterPoint(), /*velocity_y=*/absl::nullopt); + EXPECT_FALSE(GetOtherWindowCopyLayer()); +} + +TEST_F(FloatDragWindowFromShelfControllerTest, DragMaximizedWindow) { + const gfx::Rect shelf_bounds = GetShelfBounds(); + + // Create one maximized and one floated window. + auto maximized_window = CreateTestWindow(); + auto floated_window = CreateFloatedWindow(); + wm::ActivateWindow(maximized_window.get()); + + const gfx::Point start_drag_point( + maximized_window->GetBoundsInScreen().CenterPoint().x(), + shelf_bounds.CenterPoint().y()); + // Try to drag the window from shelf. + StartDrag(maximized_window.get(), start_drag_point); + ui::Layer* other_window_copy_layer = GetOtherWindowCopyLayer(); + ASSERT_TRUE(other_window_copy_layer); + + // To check if the copy is of the floated window, we check the parent and + // bounds. + EXPECT_EQ(floated_window->layer()->parent(), + other_window_copy_layer->parent()); + EXPECT_EQ(floated_window->layer()->bounds(), + other_window_copy_layer->bounds()); + + Drag(gfx::Point(0, 200), 1.f, 1.f); + EndDrag(shelf_bounds.CenterPoint(), /*velocity_y=*/absl::nullopt); + EXPECT_FALSE(GetOtherWindowCopyLayer()); +} + +// Tests that when dragging from shelf with a floated window into overview, the +// window state does not change on overview exit. +TEST_F(FloatDragWindowFromShelfControllerTest, WindowStatePreserved) { + // Create one maximized and one floated window. + auto maximized_window = CreateTestWindow(); + auto floated_window = CreateFloatedWindow(); + wm::ActivateWindow(maximized_window.get()); + + // Perform a drag such that we end up in overview. + const gfx::Point start_drag_point( + floated_window->GetBoundsInScreen().CenterPoint().x(), + GetShelfBounds().CenterPoint().y()); + StartDrag(floated_window.get(), start_drag_point); + Drag(gfx::Point(200, 200), 1.f, 1.f); + DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown( + window_drag_controller()); + EndDrag(gfx::Point(200, 200), /*velocity_y=*/absl::nullopt); + + // Verify that on exiting overview, the original window state is preserved + // (neither window is minimized). + OverviewController* overview_controller = Shell::Get()->overview_controller(); + ASSERT_TRUE(overview_controller->InOverviewSession()); + ExitOverview(); + EXPECT_TRUE(WindowState::Get(maximized_window.get())->IsMaximized()); + EXPECT_TRUE(WindowState::Get(floated_window.get())->IsFloated()); +} + } // namespace ash
diff --git a/ash/shelf/shelf_party_feature_pod_controller.cc b/ash/shelf/shelf_party_feature_pod_controller.cc index 8b516e3..b39586d17 100644 --- a/ash/shelf/shelf_party_feature_pod_controller.cc +++ b/ash/shelf/shelf_party_feature_pod_controller.cc
@@ -56,7 +56,8 @@ return button_; } -std::unique_ptr<FeatureTile> ShelfPartyFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> ShelfPartyFeaturePodController::CreateTile( + bool compact) { DCHECK(!tile_); DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<FeatureTile>(
diff --git a/ash/shelf/shelf_party_feature_pod_controller.h b/ash/shelf/shelf_party_feature_pod_controller.h index 00303f8..70b6a0d 100644 --- a/ash/shelf/shelf_party_feature_pod_controller.h +++ b/ash/shelf/shelf_party_feature_pod_controller.h
@@ -32,7 +32,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override;
diff --git a/ash/shell.cc b/ash/shell.cc index 195dbbfa..258d2e9f 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -181,6 +181,7 @@ #include "ash/wm/immersive_context_ash.h" #include "ash/wm/lock_state_controller.h" #include "ash/wm/mru_window_tracker.h" +#include "ash/wm/multi_display/multi_display_metrics_controller.h" #include "ash/wm/multitask_menu_nudge_controller.h" #include "ash/wm/native_cursor_manager_ash.h" #include "ash/wm/overlay_event_filter.h" @@ -859,6 +860,9 @@ system_tray_model_.reset(); system_sounds_delegate_.reset(); + // MultiDisplayMetricsController has a dependency on `mru_window_tracker_`. + multi_display_metrics_controller_.reset(); + // MruWindowTracker must be destroyed after all windows have been deleted to // avoid a possible crash when Shell is destroyed from a non-normal shutdown // path. (crbug.com/485438). @@ -1403,6 +1407,10 @@ mru_window_tracker_ = std::make_unique<MruWindowTracker>(); assistant_controller_ = std::make_unique<AssistantControllerImpl>(); + // MultiDisplayMetricsController has a dependency on `mru_window_tracker_`. + multi_display_metrics_controller_ = + std::make_unique<MultiDisplayMetricsController>(); + // |assistant_controller_| is put before |ambient_controller_| as it will be // used by the latter. if (features::IsAmbientModeEnabled()) {
diff --git a/ash/shell.h b/ash/shell.h index bcd36da..aafc581 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -169,6 +169,7 @@ class MouseCursorEventFilter; class MruWindowTracker; class MultiDeviceNotificationPresenter; +class MultiDisplayMetricsController; class MultitaskMenuNudgeController; class NearbyShareControllerImpl; class NearbyShareDelegate; @@ -565,6 +566,9 @@ return mouse_cursor_filter_.get(); } MruWindowTracker* mru_window_tracker() { return mru_window_tracker_.get(); } + MultiDisplayMetricsController* multi_display_metrics_controller() { + return multi_display_metrics_controller_.get(); + } MultitaskMenuNudgeController* multitask_menu_nudge_controller() { return multitask_menu_nudge_controller_.get(); } @@ -927,6 +931,8 @@ std::unique_ptr<MicrophonePrivacySwitchController> microphone_privacy_switch_controller_; std::unique_ptr<MruWindowTracker> mru_window_tracker_; + std::unique_ptr<MultiDisplayMetricsController> + multi_display_metrics_controller_; std::unique_ptr<MultiDeviceNotificationPresenter> multidevice_notification_presenter_; std::unique_ptr<MultitaskMenuNudgeController>
diff --git a/ash/style/close_button.cc b/ash/style/close_button.cc index fd0c53f..c882568 100644 --- a/ash/style/close_button.cc +++ b/ash/style/close_button.cc
@@ -127,6 +127,8 @@ // added separately so its easier to monitor performance. StyleUtil::ConfigureInkDropAttributes( this, StyleUtil::kBaseColor | StyleUtil::kInkDropOpacity); + + SchedulePaint(); } gfx::Size CloseButton::CalculatePreferredSize() const {
diff --git a/ash/system/accessibility/accessibility_feature_pod_controller.cc b/ash/system/accessibility/accessibility_feature_pod_controller.cc index 699cadd18..e7c5484 100644 --- a/ash/system/accessibility/accessibility_feature_pod_controller.cc +++ b/ash/system/accessibility/accessibility_feature_pod_controller.cc
@@ -49,7 +49,8 @@ return button; } -std::unique_ptr<FeatureTile> AccessibilityFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> AccessibilityFeaturePodController::CreateTile( + bool compact) { DCHECK(features::IsQsRevampEnabled()); auto feature_tile = std::make_unique<FeatureTile>( base::BindRepeating(&FeaturePodControllerBase::OnIconPressed,
diff --git a/ash/system/accessibility/accessibility_feature_pod_controller.h b/ash/system/accessibility/accessibility_feature_pod_controller.h index 020d074..99b5982 100644 --- a/ash/system/accessibility/accessibility_feature_pod_controller.h +++ b/ash/system/accessibility/accessibility_feature_pod_controller.h
@@ -33,7 +33,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override;
diff --git a/ash/system/bluetooth/bluetooth_feature_pod_controller.cc b/ash/system/bluetooth/bluetooth_feature_pod_controller.cc index 2f402eb..aa080961d 100644 --- a/ash/system/bluetooth/bluetooth_feature_pod_controller.cc +++ b/ash/system/bluetooth/bluetooth_feature_pod_controller.cc
@@ -68,7 +68,8 @@ return button_; } -std::unique_ptr<FeatureTile> BluetoothFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> BluetoothFeaturePodController::CreateTile( + bool compact) { DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<FeatureTile>( base::BindRepeating(&BluetoothFeaturePodController::OnIconPressed,
diff --git a/ash/system/bluetooth/bluetooth_feature_pod_controller.h b/ash/system/bluetooth/bluetooth_feature_pod_controller.h index 32ad29c..60d4cf0 100644 --- a/ash/system/bluetooth/bluetooth_feature_pod_controller.h +++ b/ash/system/bluetooth/bluetooth_feature_pod_controller.h
@@ -37,7 +37,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override; void OnLabelPressed() override;
diff --git a/ash/system/camera/autozoom_feature_pod_controller.cc b/ash/system/camera/autozoom_feature_pod_controller.cc index 1e92fd5c..47b2d15 100644 --- a/ash/system/camera/autozoom_feature_pod_controller.cc +++ b/ash/system/camera/autozoom_feature_pod_controller.cc
@@ -56,7 +56,8 @@ return button_; } -std::unique_ptr<FeatureTile> AutozoomFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> AutozoomFeaturePodController::CreateTile( + bool compact) { DCHECK(!tile_); DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<FeatureTile>(
diff --git a/ash/system/camera/autozoom_feature_pod_controller.h b/ash/system/camera/autozoom_feature_pod_controller.h index fad48c1..ee043719 100644 --- a/ash/system/camera/autozoom_feature_pod_controller.h +++ b/ash/system/camera/autozoom_feature_pod_controller.h
@@ -30,7 +30,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override;
diff --git a/ash/system/cast/cast_feature_pod_controller.cc b/ash/system/cast/cast_feature_pod_controller.cc index 65a9d25..5d8cee7 100644 --- a/ash/system/cast/cast_feature_pod_controller.cc +++ b/ash/system/cast/cast_feature_pod_controller.cc
@@ -34,6 +34,20 @@ CastConfigController::Get()->RemoveObserver(this); } +// static +bool CastFeaturePodController::CalculateButtonVisibility() { + // The button is visible if there is a primary profile (e.g. after login) and + // that profile has a media router (e.g. it is not disabled by policy). + // QsRevamp shows the button even if there are no media sinks. + auto* cast_config = CastConfigController::Get(); + return features::IsQsRevampEnabled() + ? cast_config && cast_config->HasMediaRouterForPrimaryProfile() + : cast_config && + (cast_config->HasSinksAndRoutes() || + cast_config->AccessCodeCastingEnabled()) && + !cast_config->HasActiveRoute(); +} + FeaturePodButton* CastFeaturePodController::CreateButton() { DCHECK(!features::IsQsRevampEnabled()); button_ = new FeaturePodButton(this); @@ -56,39 +70,50 @@ return button_; } -std::unique_ptr<FeatureTile> CastFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> CastFeaturePodController::CreateTile( + bool compact) { DCHECK(features::IsQsRevampEnabled()); - auto tile = std::make_unique<FeatureTile>(base::BindRepeating( - &CastFeaturePodController::OnIconPressed, weak_factory_.GetWeakPtr())); + auto tile = std::make_unique<FeatureTile>( + base::BindRepeating(&CastFeaturePodController::OnIconPressed, + weak_factory_.GetWeakPtr()), + /*is_togglable=*/true, + compact ? FeatureTile::TileType::kCompact + : FeatureTile::TileType::kPrimary); tile_ = tile.get(); + tile->SetID(VIEW_ID_CAST_MAIN_VIEW); + + bool target_visibility = CalculateButtonVisibility(); + if (target_visibility) { + TrackVisibilityUMA(); + } + tile->SetVisible(target_visibility); + tile->SetVectorIcon(kUnifiedMenuCastIcon); tile->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST)); - tile->SetSubLabel( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_DEVICES_AVAILABLE)); const std::u16string tooltip = l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_TOOLTIP); tile->SetTooltipText(tooltip); - tile->CreateDrillInButton( - base::BindRepeating(&CastFeaturePodController::OnLabelPressed, - weak_factory_.GetWeakPtr()), - tooltip); - tile->SetID(VIEW_ID_CAST_MAIN_VIEW); - // The tile is visible if there is a primary profile (e.g. after login) and - // that profile has a media router (e.g. it is not disabled by policy). - // QsRevamp shows the tile even if there are no media sinks. auto* cast_config = CastConfigController::Get(); - bool visible = cast_config && cast_config->HasMediaRouterForPrimaryProfile(); - if (visible) - TrackVisibilityUMA(); - tile->SetVisible(visible); - - // Refresh cast devices to update the "Devices available" sublabel visibility. if (cast_config) { cast_config->AddObserver(this); cast_config->RequestDeviceRefresh(); } + + // Compact tile doesn't have a sub-label or drill-in button. + if (compact) { + return tile; + } + + tile->SetSubLabel( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_DEVICES_AVAILABLE)); + tile->CreateDrillInButton( + base::BindRepeating(&CastFeaturePodController::OnLabelPressed, + weak_factory_.GetWeakPtr()), + tooltip); + UpdateSublabelVisibility(); + return tile; } @@ -123,22 +148,23 @@ void CastFeaturePodController::OnDevicesUpdated( const std::vector<SinkAndRoute>& devices) { - if (features::IsQsRevampEnabled()) + if (features::IsQsRevampEnabled()) { + if (tile_->tile_type() == FeatureTile::TileType::kCompact) { + return; + } UpdateSublabelVisibility(); - else + } else { Update(); + } } void CastFeaturePodController::Update() { DCHECK(!features::IsQsRevampEnabled()); - auto* cast_config = CastConfigController::Get(); - const bool visible = cast_config && - (cast_config->HasSinksAndRoutes() || - cast_config->AccessCodeCastingEnabled()) && - !cast_config->HasActiveRoute(); - if (!button_->GetVisible() && visible) + const bool target_visibility = CalculateButtonVisibility(); + if (!button_->GetVisible() && target_visibility) { TrackVisibilityUMA(); - button_->SetVisible(visible); + } + button_->SetVisible(target_visibility); } void CastFeaturePodController::UpdateSublabelVisibility() {
diff --git a/ash/system/cast/cast_feature_pod_controller.h b/ash/system/cast/cast_feature_pod_controller.h index 5ddf2cc4..c4dd8c9 100644 --- a/ash/system/cast/cast_feature_pod_controller.h +++ b/ash/system/cast/cast_feature_pod_controller.h
@@ -28,9 +28,13 @@ ~CastFeaturePodController() override; + // Referenced by `UnifiedSystemTrayController` to know whether to construct a + // Primary or Compact tile. + static bool CalculateButtonVisibility(); + // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override; void OnLabelPressed() override;
diff --git a/ash/system/ime/ime_feature_pod_controller.cc b/ash/system/ime/ime_feature_pod_controller.cc index 63f7813..5c6ad7b 100644 --- a/ash/system/ime/ime_feature_pod_controller.cc +++ b/ash/system/ime/ime_feature_pod_controller.cc
@@ -85,7 +85,7 @@ return button_; } -std::unique_ptr<FeatureTile> IMEFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> IMEFeaturePodController::CreateTile(bool compact) { DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<FeatureTile>( base::BindRepeating(&IMEFeaturePodController::OnIconPressed,
diff --git a/ash/system/ime/ime_feature_pod_controller.h b/ash/system/ime/ime_feature_pod_controller.h index 52a7083..9b8a4903 100644 --- a/ash/system/ime/ime_feature_pod_controller.h +++ b/ash/system/ime/ime_feature_pod_controller.h
@@ -31,7 +31,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override;
diff --git a/ash/system/locale/locale_feature_pod_controller.cc b/ash/system/locale/locale_feature_pod_controller.cc index d3d0899..2f02e548 100644 --- a/ash/system/locale/locale_feature_pod_controller.cc +++ b/ash/system/locale/locale_feature_pod_controller.cc
@@ -59,7 +59,8 @@ return button; } -std::unique_ptr<FeatureTile> LocaleFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> LocaleFeaturePodController::CreateTile( + bool compact) { DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<FeatureTile>( base::BindRepeating(&LocaleFeaturePodController::OnIconPressed,
diff --git a/ash/system/locale/locale_feature_pod_controller.h b/ash/system/locale/locale_feature_pod_controller.h index a2a1a5f..bc38001 100644 --- a/ash/system/locale/locale_feature_pod_controller.h +++ b/ash/system/locale/locale_feature_pod_controller.h
@@ -30,7 +30,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override;
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc index fbce780..b28525e 100644 --- a/ash/system/message_center/ash_notification_view.cc +++ b/ash/system/message_center/ash_notification_view.cc
@@ -53,6 +53,7 @@ #include "ui/gfx/text_constants.h" #include "ui/gfx/text_elider.h" #include "ui/message_center/message_center.h" +#include "ui/message_center/notification_list.h" #include "ui/message_center/notification_view_controller.h" #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/public/cpp/notification.h" @@ -259,13 +260,15 @@ // animation triggers an additional resize animation when it is finished. This // needs to be aborted explicitly to prevent a crash. We do not need to this // observation for grouped notification views. - if (!is_grouped_child_view_) + if (!is_grouped_child_view_) { widget_observation_.Observe(GetWidget()); + } } void AshNotificationView::Layout() { - if (is_animating_) + if (is_animating_) { return; + } message_center::NotificationViewBase::Layout(); } @@ -675,8 +678,9 @@ AshNotificationExpandButton* expand_button, NotificationGroupingController* grouping_controller, const std::string& notification_id, std::string parent_id) { - if (!parent) + if (!parent) { return; + } auto* parent_notification = message_center::MessageCenter::Get()->FindNotificationById( @@ -686,8 +690,9 @@ notification_id); // The child and parent notifications are not guaranteed to exist. If // they were deleted avoid the animation cleanup. - if (!parent_notification || !child_notification) + if (!parent_notification || !child_notification) { return; + } grouping_controller->ConvertFromSingleToGroupNotificationAfterAnimation( notification_id, parent_id, parent_notification); @@ -739,7 +744,11 @@ } void AshNotificationView::ToggleExpand() { - SetManuallyExpandedOrCollapsed(true); + const bool target_expanded_state = !IsExpanded(); + + SetManuallyExpandedOrCollapsed( + target_expanded_state ? message_center::ExpandState::USER_EXPANDED + : message_center::ExpandState::USER_COLLAPSED); if (inline_reply() && inline_reply()->GetVisible()) { message_center_utils::FadeOutView( @@ -757,7 +766,7 @@ "Ash.NotificationView.InlineReply.FadeOut.AnimationSmoothness"); } - SetExpanded(!IsExpanded()); + SetExpanded(target_expanded_state); PerformExpandCollapseAnimation(); @@ -786,8 +795,9 @@ // This is called after the parent gets notified of // `ChildPreferredSizeChanged()`, so the current expanded state is the target // state. - if (!notification.image().IsEmpty()) + if (!notification.image().IsEmpty()) { return base::Milliseconds(kLargeImageExpandAndCollapseAnimationDuration); + } if (HasInlineReply(notification) || is_grouped_parent_view_) { if (IsExpanded()) { @@ -803,8 +813,9 @@ kInlineSettingsExpandAndCollapseAnimationDuration); } - if (IsExpanded()) + if (IsExpanded()) { return base::Milliseconds(kGeneralExpandAnimationDuration); + } return base::Milliseconds(kGeneralCollapseAnimationDuration); } @@ -812,8 +823,9 @@ const message_center::Notification& notification) { DCHECK(is_grouped_parent_view_); // Do not add a grouped notification if a view for it already exists. - if (FindGroupNotificationView(notification.id())) + if (FindGroupNotificationView(notification.id())) { return; + } auto notification_view = std::make_unique<AshNotificationView>(notification, @@ -848,8 +860,9 @@ std::make_unique<AshNotificationView>(*notification, /*shown_in_popup=*/false); - if (!total_grouped_notifications_) + if (!total_grouped_notifications_) { header_row()->SetTimestamp(notification->timestamp()); + } notification_view->SetVisible( total_grouped_notifications_ < @@ -872,8 +885,9 @@ void AshNotificationView::RemoveGroupNotification( const std::string& notification_id) { auto* child_view = FindGroupNotificationView(notification_id); - if (!child_view) + if (!child_view) { return; + } base::WeakPtr<AshNotificationView> to_be_removed = static_cast<AshNotificationView*>(child_view)->weak_factory_.GetWeakPtr(); @@ -885,19 +899,22 @@ to_be_removed->layer()->GetAnimator()->AbortAllAnimations(); } - if (!to_be_removed) + if (!to_be_removed) { return; + } auto on_notification_slid_out = base::BindRepeating( [](base::WeakPtr<AshNotificationView> self, const std::string& notification_id) { - if (!self) + if (!self) { return; + } views::View* to_be_removed = self->FindGroupNotificationView(notification_id); - if (!to_be_removed) + if (!to_be_removed) { return; + } self->total_grouped_notifications_--; self->expand_button_->UpdateGroupedNotificationsCount( @@ -910,13 +927,15 @@ auto on_animation_aborted = base::BindRepeating( [](base::WeakPtr<AshNotificationView> self, const std::string& notification_id) { - if (!self) + if (!self) { return; + } views::View* to_be_removed = self->FindGroupNotificationView(notification_id); - if (!to_be_removed) + if (!to_be_removed) { return; + } self->total_grouped_notifications_--; self->expand_button_->UpdateGroupedNotificationsCount( @@ -1029,12 +1048,14 @@ is_grouped_child_view_ = notification.group_child(); is_grouped_parent_view_ = notification.group_parent(); - if (grouped_notifications_scroll_view_) + if (grouped_notifications_scroll_view_) { grouped_notifications_scroll_view_->SetVisible(is_grouped_parent_view_); + } grouped_notifications_container_->SetVisible(is_grouped_parent_view_); - if (is_grouped_child_view_ && !is_nested()) + if (is_grouped_child_view_ && !is_nested()) { SetIsNested(); + } header_row()->SetIsInGroupChildNotification(is_grouped_child_view_); UpdateMessageLabelInExpandedState(notification); @@ -1045,8 +1066,9 @@ // Configure views style. UpdateIconAndButtonsColor(¬ification); - if (message_label()) + if (message_label()) { ConfigureLabelStyle(message_label(), kMessageLabelSize, false); + } if (inline_reply()) { SkColor text_color = ash::AshColorProvider::Get()->GetContentLayerColor( ash::AshColorProvider::ContentLayerType::kTextColorSecondary); @@ -1168,8 +1190,9 @@ control_buttons_view()->ShowSnoozeButton(false); // Hide settings button for grouped child notifications. - if (is_grouped_child_view_) + if (is_grouped_child_view_) { control_buttons_view()->ShowSettingsButton(false); + } } bool AshNotificationView::IsIconViewShown() const { @@ -1182,8 +1205,9 @@ bool AshNotificationView::IsExpandable() const { // Inline settings can not be expanded. - if (GetMode() == Mode::SETTING) + if (GetMode() == Mode::SETTING) { return false; + } // Notification should always be expandable since we hide `header_row()` in // collapsed state. @@ -1207,8 +1231,9 @@ AshColorProvider::ContentLayerType::kTextColorSecondary); header_row()->SetColor(secondary_text_color); - if (message_label()) + if (message_label()) { message_label()->SetEnabledColor(secondary_text_color); + } if (control_buttons_view_) { control_buttons_view_->SetButtonIconColors( @@ -1216,8 +1241,9 @@ AshColorProvider::ContentLayerType::kIconColorPrimary)); } - if (message_label_in_expanded_state_) + if (message_label_in_expanded_state_) { message_label_in_expanded_state_->SetEnabledColor(secondary_text_color); + } UpdateIconAndButtonsColor( message_center::MessageCenter::Get()->FindVisibleNotificationById( @@ -1271,8 +1297,9 @@ } void AshNotificationView::ToggleInlineSettings(const ui::Event& event) { - if (!inline_settings_enabled()) + if (!inline_settings_enabled()) { return; + } bool should_show_inline_settings = !inline_settings_row()->GetVisible(); PerformToggleInlineSettingsAnimation(should_show_inline_settings); @@ -1342,8 +1369,9 @@ void AshNotificationView::OnNotificationRemoved( const std::string& notification_id, bool by_user) { - if (!is_grouped_parent_view_) + if (!is_grouped_parent_view_) { return; + } RemoveGroupNotification(notification_id); } @@ -1419,8 +1447,9 @@ IsExpanded() || i < message_center_style::kMaxGroupedNotificationsInCollapsedState; - if (view->GetVisible() == show_notification_view) + if (view->GetVisible() == show_notification_view) { continue; + } view->SetVisible(show_notification_view); } @@ -1455,8 +1484,9 @@ return; } - if (!is_grouped_child_view_) + if (!is_grouped_child_view_) { background_color_ = background_color; + } top_radius_ = top_radius; bottom_radius_ = bottom_radius; @@ -1483,8 +1513,9 @@ // Grouped child notification use notification's icon for the app icon view, // so we don't need further update here. if (!notification || - (is_grouped_child_view_ && !notification->icon().IsEmpty())) + (is_grouped_child_view_ && !notification->icon().IsEmpty())) { return; + } SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor( AshColorProvider::ContentLayerType::kInvertedButtonLabelColor); @@ -1511,14 +1542,16 @@ SkColor default_color = AshColorProvider::Get()->GetControlsLayerColor( AshColorProvider::ControlsLayerType::kControlBackgroundColorActive); - if (!notification) + if (!notification) { return default_color; + } auto color_id = notification->accent_color_id(); absl::optional<SkColor> accent_color = notification->accent_color(); - if ((!color_id || !GetWidget()) && !accent_color.has_value()) + if ((!color_id || !GetWidget()) && !accent_color.has_value()) { return default_color; + } SkColor fg_color; // ColorProvider needs widget to be created. @@ -1562,16 +1595,18 @@ static_cast<PillButton*>(action_button)->SetButtonTextColor(button_color); } - if (snooze_button_) + if (snooze_button_) { snooze_button_->SetIconColor(button_color); + } } void AshNotificationView::AnimateResizeAfterRemoval( views::View* to_be_removed) { auto on_resize_complete = base::BindRepeating( [](base::WeakPtr<AshNotificationView> self) { - if (!self) + if (!self) { return; + } self->set_is_animating(false); @@ -1590,8 +1625,9 @@ auto* notification_view_controller = message_center_utils:: GetActiveNotificationViewControllerForNotificationView(this); - if (notification_view_controller) + if (notification_view_controller) { notification_view_controller->AnimateResize(); + } if (shown_in_popup_) { grouped_notifications_scroll_view_->Layout(); @@ -1628,8 +1664,9 @@ } void AshNotificationView::PerformExpandCollapseAnimation() { - if (title_row_) + if (title_row_) { title_row_->PerformExpandCollapseAnimation(); + } // Fade in `header row()` if this is not a grouped parent view. if (header_row() && header_row()->GetVisible() && !is_grouped_parent_view_) { @@ -1677,8 +1714,9 @@ if (total_grouped_notifications_) { // Ensure layout is up-to-date before animating expand button. This is used // for its bounds animation. - if (needs_layout()) + if (needs_layout()) { Layout(); + } DCHECK(!needs_layout()); expand_button_->AnimateExpandCollapse(); @@ -1787,8 +1825,9 @@ void AshNotificationView::PerformToggleInlineSettingsAnimation( bool should_show_inline_settings) { if (ui::ScopedAnimationDurationScaleMode::duration_multiplier() == - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION) + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION) { return; + } message_center_utils::InitLayerForAnimations(main_right_view_); message_center_utils::InitLayerForAnimations(inline_settings_row()); @@ -1901,8 +1940,9 @@ bool AshNotificationView::IsMessageLabelTruncated() { // True if the expanded label has more than one line. - if (message_label_in_expanded_state_->GetRequiredLines() > 1) + if (message_label_in_expanded_state_->GetRequiredLines() > 1) { return true; + } // Get the first row's width of `message_label_in_expanded_state_`'s text, // which is also the text width of this label since it has one line. If text
diff --git a/ash/system/network/network_feature_pod_controller.cc b/ash/system/network/network_feature_pod_controller.cc index c0c0041..3e114ab 100644 --- a/ash/system/network/network_feature_pod_controller.cc +++ b/ash/system/network/network_feature_pod_controller.cc
@@ -184,7 +184,8 @@ return button.release(); } -std::unique_ptr<FeatureTile> NetworkFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> NetworkFeaturePodController::CreateTile( + bool compact) { DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<FeatureTile>( base::BindRepeating(&FeaturePodControllerBase::OnIconPressed,
diff --git a/ash/system/network/network_feature_pod_controller.h b/ash/system/network/network_feature_pod_controller.h index d1e09d9..d66c4314 100644 --- a/ash/system/network/network_feature_pod_controller.h +++ b/ash/system/network/network_feature_pod_controller.h
@@ -38,7 +38,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override; void OnLabelPressed() override;
diff --git a/ash/system/network/network_info_bubble_unittest.cc b/ash/system/network/network_info_bubble_unittest.cc index 5bed3e5..173c0a2 100644 --- a/ash/system/network/network_info_bubble_unittest.cc +++ b/ash/system/network/network_info_bubble_unittest.cc
@@ -131,17 +131,17 @@ void AddDefaultNetworkWithIPAddresses() { base::Value::Dict ipv4; - ipv4.Set(shill::kAddressProperty, base::Value(kIpv4Address)); - ipv4.Set(shill::kMethodProperty, base::Value(shill::kTypeIPv4)); + ipv4.Set(shill::kAddressProperty, kIpv4Address); + ipv4.Set(shill::kMethodProperty, shill::kTypeIPv4); base::Value::Dict ipv6; - ipv6.Set(shill::kAddressProperty, base::Value(kIpv6Address)); - ipv6.Set(shill::kMethodProperty, base::Value(shill::kTypeIPv6)); + ipv6.Set(shill::kAddressProperty, kIpv6Address); + ipv6.Set(shill::kMethodProperty, shill::kTypeIPv6); network_config_helper_.network_state_helper().ip_config_test()->AddIPConfig( - kIPv4ConfigPath, base::Value(std::move(ipv4))); + kIPv4ConfigPath, std::move(ipv4)); network_config_helper_.network_state_helper().ip_config_test()->AddIPConfig( - kIPv6ConfigPath, base::Value(std::move(ipv6))); + kIPv6ConfigPath, std::move(ipv6)); base::Value::List ip_configs; ip_configs.Append(kIPv4ConfigPath);
diff --git a/ash/system/network/vpn_feature_pod_controller.cc b/ash/system/network/vpn_feature_pod_controller.cc index 5e14fe9..cfe043c 100644 --- a/ash/system/network/vpn_feature_pod_controller.cc +++ b/ash/system/network/vpn_feature_pod_controller.cc
@@ -70,7 +70,7 @@ return button_; } -std::unique_ptr<FeatureTile> VPNFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> VPNFeaturePodController::CreateTile(bool compact) { DCHECK(features::IsQsRevampEnabled()); DCHECK(!tile_); auto tile = std::make_unique<FeatureTile>(
diff --git a/ash/system/network/vpn_feature_pod_controller.h b/ash/system/network/vpn_feature_pod_controller.h index 7488860..25542eed 100644 --- a/ash/system/network/vpn_feature_pod_controller.h +++ b/ash/system/network/vpn_feature_pod_controller.h
@@ -29,7 +29,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override;
diff --git a/ash/system/notification_center/notification_center_bubble_unittest.cc b/ash/system/notification_center/notification_center_bubble_unittest.cc index a6e7eb6..eefe757b 100644 --- a/ash/system/notification_center/notification_center_bubble_unittest.cc +++ b/ash/system/notification_center/notification_center_bubble_unittest.cc
@@ -4,10 +4,12 @@ #include "ash/system/notification_center/notification_center_bubble.h" +#include <cstdint> #include <string> #include "ash/constants/ash_features.h" #include "ash/shell.h" +#include "ash/system/message_center/ash_notification_view.h" #include "ash/system/notification_center/notification_center_test_api.h" #include "ash/system/status_area_widget.h" #include "ash/system/status_area_widget_test_helper.h" @@ -16,6 +18,7 @@ #include "base/test/scoped_feature_list.h" #include "ui/display/display.h" #include "ui/display/manager/display_manager.h" +#include "ui/message_center/views/message_popup_view.h" #include "ui/message_center/views/message_view.h" namespace ash { @@ -151,4 +154,60 @@ EXPECT_TRUE(parent_notification_view->FindGroupNotificationView(id1)); } +TEST_F(NotificationCenterBubbleTest, + NotificationCollapseStatePreservedFromPopup) { + std::string id0 = test_api()->AddNotification(); + + // Manually collapse the notification. + static_cast<AshNotificationView*>( + test_api()->GetPopupViewForId(id0)->message_view()) + ->ToggleExpand(); + + // Expect `id0` to be collapsed despite the default state for it to be + // expanded. + test_api()->ToggleBubble(); + EXPECT_FALSE(test_api()->GetNotificationViewForId(id0)->IsExpanded()); +} + +TEST_F(NotificationCenterBubbleTest, + NotificationExpandStatePreservedAcrossDisplays) { + UpdateDisplay("600x500,600x500"); + + std::string id0, id1; + id0 = test_api()->AddNotification(); + id1 = test_api()->AddNotification(); + + const int64_t secondary_display_id = display_manager()->GetDisplayAt(1).id(); + + test_api()->ToggleBubbleOnDisplay(secondary_display_id); + + auto* notification_view0 = static_cast<AshNotificationView*>( + test_api()->GetNotificationViewForIdOnDisplay(id0, secondary_display_id)); + + auto* notification_view1 = static_cast<AshNotificationView*>( + test_api()->GetNotificationViewForIdOnDisplay(id1, secondary_display_id)); + + // The newest notification is expected to be expanded by default while other + // notifications are expected to be collapsed by default. + EXPECT_TRUE(notification_view1->IsExpanded()); + EXPECT_FALSE(notification_view0->IsExpanded()); + + // Toggle the expand states for both notifications so they are opposite of the + // default state. + notification_view0->ToggleExpand(); + notification_view1->ToggleExpand(); + + const int64_t primary_display_id = display_manager()->GetDisplayAt(0).id(); + test_api()->ToggleBubbleOnDisplay(primary_display_id); + + // Expect the expanded states to be preserved on the primary display after + // they were changed by the user on the secondary display. + EXPECT_FALSE(test_api() + ->GetNotificationViewForIdOnDisplay(id1, primary_display_id) + ->IsExpanded()); + EXPECT_TRUE(test_api() + ->GetNotificationViewForIdOnDisplay(id0, primary_display_id) + ->IsExpanded()); +} + } // namespace ash
diff --git a/ash/system/notification_center/notification_center_test_api.cc b/ash/system/notification_center/notification_center_test_api.cc index c0626bd..57c5a43 100644 --- a/ash/system/notification_center/notification_center_test_api.cc +++ b/ash/system/notification_center/notification_center_test_api.cc
@@ -3,12 +3,15 @@ // found in the LICENSE file. #include "ash/system/notification_center/notification_center_test_api.h" +#include <cstdint> +#include "ash/constants/ash_features.h" #include "ash/root_window_controller.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" #include "ash/system/message_center/ash_message_popup_collection.h" #include "ash/system/message_center/ash_notification_view.h" +#include "ash/system/message_center/message_popup_animation_waiter.h" #include "ash/system/message_center/unified_message_center_bubble.h" #include "ash/system/notification_center/notification_center_bubble.h" #include "ash/system/notification_center/notification_center_tray.h" @@ -30,20 +33,30 @@ NotificationCenterTestApi::NotificationCenterTestApi( NotificationCenterTray* tray) - : notification_center_tray_(tray) {} + : notification_center_tray_(tray), + primary_display_id_( + display::Screen::GetScreen()->GetPrimaryDisplay().id()) {} void NotificationCenterTestApi::ToggleBubble() { - auto event_generator = - std::make_unique<ui::test::EventGenerator>(Shell::GetPrimaryRootWindow()); + ToggleBubbleOnDisplay(primary_display_id_); +} + +void NotificationCenterTestApi::ToggleBubbleOnDisplay(int64_t display_id) { + auto event_generator = std::make_unique<ui::test::EventGenerator>( + Shell::GetRootWindowForDisplayId(display_id)); + + auto* status_area_widget = + Shell::Get() + ->GetRootWindowControllerWithDisplayId(display_id) + ->shelf() + ->status_area_widget(); gfx::Point click_location = - notification_center_tray_ - ? notification_center_tray_->GetBoundsInScreen().CenterPoint() - : Shell::Get() - ->GetPrimaryRootWindowController() - ->shelf() - ->status_area_widget() - ->unified_system_tray() + features::IsQsRevampEnabled() + ? status_area_widget->notification_center_tray() + ->GetBoundsInScreen() + .CenterPoint() + : status_area_widget->unified_system_tray() ->GetBoundsInScreen() .CenterPoint(); @@ -111,14 +124,22 @@ message_center::MessageView* NotificationCenterTestApi::GetNotificationViewForId(const std::string& id) { - // Ensure this api is only called when the notification list view exists, i.e. - // The notification center bubble is open. - DCHECK(GetNotificationListView()); - - return GetNotificationListView()->GetMessageViewForNotificationId(id); + return GetNotificationViewForIdOnDisplay(id, primary_display_id_); } -views::View* NotificationCenterTestApi::GetPopupViewForId( +message_center::MessageView* +NotificationCenterTestApi::GetNotificationViewForIdOnDisplay( + const std::string& notification_id, + const int64_t display_id) { + // Ensure this api is only called when the notification list view exists, i.e. + // The notification center bubble is open on this display. + DCHECK(GetNotificationListViewOnDisplay(display_id)); + + return GetNotificationListViewOnDisplay(display_id) + ->GetMessageViewForNotificationId(notification_id); +} + +message_center::MessagePopupView* NotificationCenterTestApi::GetPopupViewForId( const std::string& id) { // TODO(b/259459804): Move `MessagePopupCollection` to be owned by // `NotificationCenterTray` instead of `UnifiedSystemTray`. @@ -162,20 +183,27 @@ } NotificationListView* NotificationCenterTestApi::GetNotificationListView() { + return GetNotificationListViewOnDisplay(primary_display_id_); +} + +NotificationListView* +NotificationCenterTestApi::GetNotificationListViewOnDisplay( + int64_t display_id) { DCHECK(message_center::MessageCenter::Get()->IsMessageCenterVisible()); - if (notification_center_tray_) { - return notification_center_tray_->bubble_->notification_center_view_ - ->notification_list_view(); + auto* status_area_widget = + Shell::Get() + ->GetRootWindowControllerWithDisplayId(display_id) + ->shelf() + ->GetStatusAreaWidget(); + + if (features::IsQsRevampEnabled()) { + return status_area_widget->notification_center_tray() + ->bubble_->notification_center_view_->notification_list_view(); } - auto* unified_system_tray = Shell::Get() - ->GetPrimaryRootWindowController() - ->shelf() - ->GetStatusAreaWidget() - ->unified_system_tray(); - - return unified_system_tray->message_center_bubble() + return status_area_widget->unified_system_tray() + ->message_center_bubble() ->notification_center_view() ->notification_list_view(); }
diff --git a/ash/system/notification_center/notification_center_test_api.h b/ash/system/notification_center/notification_center_test_api.h index 937e71af..49feb44 100644 --- a/ash/system/notification_center/notification_center_test_api.h +++ b/ash/system/notification_center/notification_center_test_api.h
@@ -15,6 +15,7 @@ class GURL; namespace message_center { +class MessagePopupView; class MessageView; class Notification; struct NotifierId; @@ -48,6 +49,10 @@ // `NotificationCenterTray` on the primary display. void ToggleBubble(); + // Toggles the `NotificationCenterBubble` by simulating a click on the + // `NotificationCenterTray` on the specified display. + void ToggleBubbleOnDisplay(int64_t dispay_id); + // Adds a notification with custom parameters and returns the associated id. std::string AddCustomNotification( const std::u16string& title, @@ -90,9 +95,15 @@ // Should be only used when the notifications bubble is open. message_center::MessageView* GetNotificationViewForId(const std::string& id); + // Returns the notification view for the provided `notification_id` on the + // display associated with the provided `display_id`. + message_center::MessageView* GetNotificationViewForIdOnDisplay( + const std::string& notification_id, + const int64_t display_id); + // Returns the popup view associated with the provided notification id, // nullptr otherwise. - views::View* GetPopupViewForId(const std::string& id); + message_center::MessagePopupView* GetPopupViewForId(const std::string& id); // Returns the `NotificationCenterTray` in the shelf. NotificationCenterTray* GetTray(); @@ -122,6 +133,8 @@ NotificationListView* GetNotificationListView(); + NotificationListView* GetNotificationListViewOnDisplay(int64_t display_id); + std::unique_ptr<message_center::Notification> CreateNotification( const std::string& id, const std::u16string& title, @@ -133,6 +146,8 @@ int notification_id_ = 0; NotificationCenterTray* const notification_center_tray_; + + const int64_t primary_display_id_; }; } // namespace ash
diff --git a/ash/system/notification_center/notification_list_view.cc b/ash/system/notification_center/notification_list_view.cc index d1cf88d..fc195c5 100644 --- a/ash/system/notification_center/notification_list_view.cc +++ b/ash/system/notification_center/notification_list_view.cc
@@ -31,6 +31,8 @@ #include "ui/compositor/compositor.h" #include "ui/gfx/animation/linear_animation.h" #include "ui/gfx/canvas.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification_list.h" #include "ui/message_center/notification_view_controller.h" #include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/views/message_view.h" @@ -98,9 +100,16 @@ list_view_(list_view), control_view_(new NotificationSwipeControlView(message_view)) { message_view_->AddObserver(this); - if (!features::IsNotificationsRefreshEnabled()) { - message_view_->SetBackground( - views::CreateSolidBackground(SK_ColorTRANSPARENT)); + + if (features::IsQsRevampEnabled()) { + message_center::ExpandState expand_state = + MessageCenter::Get()->GetNotificationExpandState( + message_view_->notification_id()); + + if (expand_state != message_center::ExpandState::DEFAULT) { + message_view_->SetExpanded(expand_state == + message_center::ExpandState::USER_EXPANDED); + } } SetLayoutManager(std::make_unique<views::FillLayout>()); @@ -183,11 +192,15 @@ model->GetNotificationExpanded(GetNotificationId()); if (manually_expanded.has_value()) { message_view_->SetExpanded(manually_expanded.value()); - message_view_->SetManuallyExpandedOrCollapsed(true); + message_view_->SetManuallyExpandedOrCollapsed( + manually_expanded.value() + ? message_center::ExpandState::USER_EXPANDED + : message_center::ExpandState::USER_COLLAPSED); } else { // Expand the latest notification, and collapse all other notifications. - message_view_->SetExpanded(is_latest && - message_view_->IsAutoExpandingAllowed()); + message_view_->SetExpanded( + is_latest && message_view_->IsAutoExpandingAllowed() && + !message_view_->IsManuallyExpandedOrCollapsed()); } } @@ -450,7 +463,13 @@ if (!features::IsQsRevampEnabled()) { model_->ClearNotificationChanges(); for (auto* view : children()) { - AsMVC(view)->StoreExpandedState(model_.get()); + auto* mvc = AsMVC(view); + // Make sure we only store expanded state for notifications that still + // exist. + if (message_center::MessageCenter::Get()->FindVisibleNotificationById( + mvc->message_view()->notification_id())) { + mvc->StoreExpandedState(model_.get()); + } } } } @@ -462,19 +481,12 @@ auto* view = new MessageViewContainer(CreateMessageView(*notification), this); - // TODO(b/252876795): We cannot use the `UnifiedSystemTrayModel` to store - // the expanded state for notifications with QsRevamp since it is owned by - // `UnifiedSystemTray` and notifications are being completely separated - // from it. Implement a way to remember collase/expand state for - // notifications across popups and notification center. if (!features::IsQsRevampEnabled()) { view->LoadExpandedState(model_.get(), is_latest); } - // TODO(b/252876795): This is a workaround to match the pre-existing - // behavior, need to fully implement this to remember expanded states across - // popups and the message center. - if (features::IsQsRevampEnabled() && is_latest) { + if (features::IsQsRevampEnabled() && is_latest && + !view->message_view()->IsManuallyExpandedOrCollapsed()) { view->message_view()->SetExpanded( view->message_view()->IsAutoExpandingAllowed()); }
diff --git a/ash/system/notification_center/notification_list_view_unittest.cc b/ash/system/notification_center/notification_list_view_unittest.cc index 25e1eb4c..bd74459 100644 --- a/ash/system/notification_center/notification_list_view_unittest.cc +++ b/ash/system/notification_center/notification_list_view_unittest.cc
@@ -21,6 +21,7 @@ #include "ui/compositor/layer.h" #include "ui/compositor/layer_animator.h" #include "ui/message_center/message_center.h" +#include "ui/message_center/notification_list.h" #include "ui/message_center/views/message_view.h" #include "ui/message_center/views/notification_view.h" #include "ui/views/test/views_test_utils.h" @@ -413,7 +414,8 @@ EXPECT_TRUE(GetMessageViewAt(0)->IsExpanded()); GetMessageViewAt(1)->SetExpanded(true); - GetMessageViewAt(1)->SetManuallyExpandedOrCollapsed(true); + GetMessageViewAt(1)->SetManuallyExpandedOrCollapsed( + message_center::ExpandState::USER_EXPANDED); AddNotification(); @@ -478,12 +480,6 @@ } TEST_P(ParameterizedNotificationListViewTest, KeepManuallyExpanded) { - // TODO(b/252876795): Enable this test for the QsRevamp feature after expand - // statefulness is implemented. - if (IsQsRevampEnabled()) { - return; - } - AddNotification(); AddNotification(); CreateMessageListView(); @@ -496,9 +492,11 @@ // Manually expand the first notification & manually collapse the second one. GetMessageViewAt(0)->SetExpanded(true); - GetMessageViewAt(0)->SetManuallyExpandedOrCollapsed(true); + GetMessageViewAt(0)->SetManuallyExpandedOrCollapsed( + message_center::ExpandState::USER_EXPANDED); GetMessageViewAt(1)->SetExpanded(false); - GetMessageViewAt(1)->SetManuallyExpandedOrCollapsed(true); + GetMessageViewAt(1)->SetManuallyExpandedOrCollapsed( + message_center::ExpandState::USER_COLLAPSED); DestroyMessageListView();
diff --git a/ash/system/phonehub/phone_hub_notification_controller.cc b/ash/system/phonehub/phone_hub_notification_controller.cc index b95ef91e..68c24deb 100644 --- a/ash/system/phonehub/phone_hub_notification_controller.cc +++ b/ash/system/phonehub/phone_hub_notification_controller.cc
@@ -98,7 +98,9 @@ custom_view_type_ = notification.custom_view_type(); if (custom_view_type_ == kNotificationCustomCallViewType) { // Expand the action buttons row by default for Call Style notification. - SetManuallyExpandedOrCollapsed(true); + SetManuallyExpandedOrCollapsed( + !IsExpanded() ? message_center::ExpandState::USER_EXPANDED + : message_center::ExpandState::USER_COLLAPSED); SetExpanded(true); return; } @@ -192,7 +194,9 @@ custom_view_type_ = notification.custom_view_type(); if (custom_view_type_ == kNotificationCustomCallViewType) { // Expand the action buttons row by default for Call Style notification. - SetManuallyExpandedOrCollapsed(true); + SetManuallyExpandedOrCollapsed( + !IsExpanded() ? message_center::ExpandState::USER_EXPANDED + : message_center::ExpandState::USER_COLLAPSED); SetExpanded(true); return; }
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc index 8b15b4f..18f10000 100644 --- a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc +++ b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc
@@ -56,7 +56,8 @@ {SensorDisabledNotificationDelegate::Sensor::kMicrophone}, base::MakeRefCounted<PrivacyHubNotificationClickDelegate>( base::BindRepeating( - PrivacyHubNotificationController::OpenSupportUrl)), + PrivacyHubNotificationController::OpenSupportUrl, + PrivacyHubNotificationController::Sensor::kMicrophone)), ash::NotificationCatalogName::kMicrophoneMute, IDS_ASH_LEARN_MORE) { Shell::Get()->session_controller()->AddObserver(this);
diff --git a/ash/system/privacy_hub/privacy_hub_metrics.cc b/ash/system/privacy_hub/privacy_hub_metrics.cc index 5051902..af538a4 100644 --- a/ash/system/privacy_hub/privacy_hub_metrics.cc +++ b/ash/system/privacy_hub/privacy_hub_metrics.cc
@@ -33,4 +33,9 @@ PrivacyHubNavigationOrigin::kNotification); } +void LogPrivacyHubLearnMorePageOpened(PrivacyHubLearnMoreSensor sensor) { + base::UmaHistogramEnumeration(kPrivacyHubLearnMorePageOpenedHistogram, + sensor); +} + } // namespace ash::privacy_hub_metrics
diff --git a/ash/system/privacy_hub/privacy_hub_metrics.h b/ash/system/privacy_hub/privacy_hub_metrics.h index 6969d25..cb92061d 100644 --- a/ash/system/privacy_hub/privacy_hub_metrics.h +++ b/ash/system/privacy_hub/privacy_hub_metrics.h
@@ -19,6 +19,13 @@ kMaxValue = kNotification }; +// These values are persisted to logs and should not be renumbered or re-used. +enum class PrivacyHubLearnMoreSensor { + kMicrophone = 0, + kCamera = 1, + kMaxValue = kCamera +}; + static constexpr char kPrivacyHubMicrophoneEnabledFromSettingsHistogram[] = "ChromeOS.PrivacyHub.Microphone.Settings.Enabled"; static constexpr char kPrivacyHubMicrophoneEnabledFromNotificationHistogram[] = @@ -29,6 +36,8 @@ "ChromeOS.PrivacyHub.Camera.Notification.Enabled"; static constexpr char kPrivacyHubOpenedHistogram[] = "ChromeOS.PrivacyHub.Opened"; +static constexpr char kPrivacyHubLearnMorePageOpenedHistogram[] = + "ChromeOS.PrivacyHub.LearnMorePage.Opened"; // Report microphone mute events from system and notifications. ASH_EXPORT void LogMicrophoneEnabledFromSettings(bool enabled); @@ -41,6 +50,11 @@ // Report that Privacy Hub has been opened from a notification. ASH_EXPORT void LogPrivacyHubOpenedFromNotification(); +// Report that the user opened the learn more page for Privacy Hub from a +// microphone notification. +ASH_EXPORT void LogPrivacyHubLearnMorePageOpened( + PrivacyHubLearnMoreSensor sensor); + } // namespace ash::privacy_hub_metrics #endif // ASH_SYSTEM_PRIVACY_HUB_PRIVACY_HUB_METRICS_H_
diff --git a/ash/system/privacy_hub/privacy_hub_notification_controller.cc b/ash/system/privacy_hub/privacy_hub_notification_controller.cc index 67993cb..0580bd8 100644 --- a/ash/system/privacy_hub/privacy_hub_notification_controller.cc +++ b/ash/system/privacy_hub/privacy_hub_notification_controller.cc
@@ -121,7 +121,20 @@ Shell::Get()->system_tray_model()->client()->ShowPrivacyHubSettings(); } -void PrivacyHubNotificationController::OpenSupportUrl() { +void PrivacyHubNotificationController::OpenSupportUrl(Sensor sensor) { + switch (sensor) { + case Sensor::kMicrophone: + privacy_hub_metrics::LogPrivacyHubLearnMorePageOpened( + privacy_hub_metrics::PrivacyHubLearnMoreSensor::kMicrophone); + break; + case Sensor::kCamera: + privacy_hub_metrics::LogPrivacyHubLearnMorePageOpened( + privacy_hub_metrics::PrivacyHubLearnMoreSensor::kCamera); + break; + case Sensor::kLocation: + LOG(DFATAL) << "Location doesn't have a learn more button"; + return; + } NewWindowDelegate::GetPrimary()->OpenUrl( GURL(kLearnMoreUrl), NewWindowDelegate::OpenUrlFrom::kUserInteraction, NewWindowDelegate::Disposition::kNewForegroundTab);
diff --git a/ash/system/privacy_hub/privacy_hub_notification_controller.h b/ash/system/privacy_hub/privacy_hub_notification_controller.h index 85cd53f..e98e878f 100644 --- a/ash/system/privacy_hub/privacy_hub_notification_controller.h +++ b/ash/system/privacy_hub/privacy_hub_notification_controller.h
@@ -55,8 +55,9 @@ // a notification. static void OpenPrivacyHubSettingsPage(); - // Open the support page for Privacy Hub. - static void OpenSupportUrl(); + // Open the support page for Privacy Hub and logs the interaction together + // with what `sensor` was in use by the user. + static void OpenSupportUrl(Sensor sensor); private: // Show all notifications that are currently active and combine them if
diff --git a/ash/system/privacy_hub/privacy_hub_notification_controller_unittest.cc b/ash/system/privacy_hub/privacy_hub_notification_controller_unittest.cc index 4cc5a12..264a818 100644 --- a/ash/system/privacy_hub/privacy_hub_notification_controller_unittest.cc +++ b/ash/system/privacy_hub/privacy_hub_notification_controller_unittest.cc
@@ -9,8 +9,8 @@ #include "ash/constants/ash_features.h" #include "ash/public/cpp/sensor_disabled_notification_delegate.h" +#include "ash/public/cpp/test/test_new_window_delegate.h" #include "ash/public/cpp/test/test_system_tray_client.h" -#include "ash/shelf/shelf.h" #include "ash/shell.h" #include "ash/system/privacy_hub/camera_privacy_switch_controller.h" #include "ash/system/privacy_hub/microphone_privacy_switch_controller.h" @@ -63,6 +63,16 @@ base::RunLoop run_loop_; }; +class MockNewWindowDelegate + : public testing::NiceMock<ash::TestNewWindowDelegate> { + public: + // TestNewWindowDelegate: + MOCK_METHOD(void, + OpenUrl, + (const GURL& url, OpenUrlFrom from, Disposition disposition), + (override)); +}; + } // namespace using Sensor = PrivacyHubNotificationController::Sensor; @@ -72,6 +82,11 @@ PrivacyHubNotificationControllerTest() : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { scoped_feature_list_.InitAndEnableFeature(features::kCrosPrivacyHubV2); + auto delegate = std::make_unique<MockNewWindowDelegate>(); + new_window_delegate_ = delegate.get(); + window_delegate_provider_ = + std::make_unique<ash::TestNewWindowDelegateProvider>( + std::move(delegate)); } ~PrivacyHubNotificationControllerTest() override = default; @@ -158,11 +173,15 @@ notification_waiter.Wait(); } + MockNewWindowDelegate* new_window_delegate() { return new_window_delegate_; } + private: base::raw_ptr<PrivacyHubNotificationController> controller_; const FakeSensorDisabledNotificationDelegate delegate_; const base::HistogramTester histogram_tester_; base::test::ScopedFeatureList scoped_feature_list_; + base::raw_ptr<MockNewWindowDelegate> new_window_delegate_ = nullptr; + std::unique_ptr<ash::TestNewWindowDelegateProvider> window_delegate_provider_; }; TEST_F(PrivacyHubNotificationControllerTest, ShowCameraNotification) { @@ -350,4 +369,35 @@ 1); } +TEST_F(PrivacyHubNotificationControllerTest, OpenPrivacyHubSupportPage) { + using privacy_hub_metrics::PrivacyHubLearnMoreSensor; + + auto test_sensor = [histogram_tester = &histogram_tester()]( + Sensor privacy_hub_sensor, + PrivacyHubLearnMoreSensor lean_more_sensor) { + EXPECT_EQ(histogram_tester->GetBucketCount( + privacy_hub_metrics::kPrivacyHubLearnMorePageOpenedHistogram, + lean_more_sensor), + 0); + + PrivacyHubNotificationController::OpenSupportUrl(privacy_hub_sensor); + + EXPECT_EQ(histogram_tester->GetBucketCount( + privacy_hub_metrics::kPrivacyHubLearnMorePageOpenedHistogram, + lean_more_sensor), + 1); + }; + + EXPECT_CALL(*new_window_delegate(), OpenUrl).Times(2); + + test_sensor(Sensor::kMicrophone, PrivacyHubLearnMoreSensor::kMicrophone); + test_sensor(Sensor::kCamera, PrivacyHubLearnMoreSensor::kCamera); + + if (DCHECK_IS_ON()) { + EXPECT_DEATH( + PrivacyHubNotificationController::OpenSupportUrl(Sensor::kLocation), + ""); + } +} + } // namespace ash
diff --git a/ash/system/privacy_screen/privacy_screen_feature_pod_controller.cc b/ash/system/privacy_screen/privacy_screen_feature_pod_controller.cc index 30c6c671..ceae4882 100644 --- a/ash/system/privacy_screen/privacy_screen_feature_pod_controller.cc +++ b/ash/system/privacy_screen/privacy_screen_feature_pod_controller.cc
@@ -39,7 +39,8 @@ return button_; } -std::unique_ptr<FeatureTile> PrivacyScreenFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> PrivacyScreenFeaturePodController::CreateTile( + bool compact) { DCHECK(!tile_); DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<FeatureTile>(
diff --git a/ash/system/privacy_screen/privacy_screen_feature_pod_controller.h b/ash/system/privacy_screen/privacy_screen_feature_pod_controller.h index 46edb5f..b2b7328a 100644 --- a/ash/system/privacy_screen/privacy_screen_feature_pod_controller.h +++ b/ash/system/privacy_screen/privacy_screen_feature_pod_controller.h
@@ -31,7 +31,7 @@ // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override;
diff --git a/ash/system/rotation/rotation_lock_feature_pod_controller.cc b/ash/system/rotation/rotation_lock_feature_pod_controller.cc index bea45bbf..3979078d 100644 --- a/ash/system/rotation/rotation_lock_feature_pod_controller.cc +++ b/ash/system/rotation/rotation_lock_feature_pod_controller.cc
@@ -8,6 +8,7 @@ #include "ash/constants/ash_features.h" #include "ash/constants/quick_settings_catalogs.h" +#include "ash/public/cpp/ash_view_ids.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" @@ -22,15 +23,20 @@ RotationLockFeaturePodController::RotationLockFeaturePodController() { DCHECK(Shell::Get()); - Shell::Get()->tablet_mode_controller()->AddObserver(this); Shell::Get()->screen_orientation_controller()->AddObserver(this); } RotationLockFeaturePodController::~RotationLockFeaturePodController() { if (Shell::Get()->screen_orientation_controller()) Shell::Get()->screen_orientation_controller()->RemoveObserver(this); - if (Shell::Get()->tablet_mode_controller()) - Shell::Get()->tablet_mode_controller()->RemoveObserver(this); +} + +// static +bool RotationLockFeaturePodController::CalculateButtonVisibility() { + // Auto-rotation is supported in both tablet mode and in clamshell mode with + // `kSupportsClamshellAutoRotation` set, however the button is shown only if + // the device is in tablet mode. + return Shell::Get()->tablet_mode_controller()->is_in_tablet_physical_state(); } FeaturePodButton* RotationLockFeaturePodController::CreateButton() { @@ -45,20 +51,27 @@ return button_; } -std::unique_ptr<FeatureTile> RotationLockFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> RotationLockFeaturePodController::CreateTile( + bool compact) { DCHECK(!tile_); DCHECK(features::IsQsRevampEnabled()); - // TODO(b/251724698): Create the tile as FeatureTile::TileType::kCompact - // after adding logic to shrink the Cast tile to compact when auto-rotation - // is allowed. Also remove the call to SetSubLabelVisibility(). auto tile = std::make_unique<FeatureTile>( base::BindRepeating(&RotationLockFeaturePodController::OnIconPressed, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr()), + /*is_togglable=*/true, + compact ? FeatureTile::TileType::kCompact + : FeatureTile::TileType::kPrimary); tile_ = tile.get(); - // The tile label is always "Auto rotate" and there is no sub-label. + tile_->SetID(VIEW_ID_AUTOROTATE_FEATURE_TILE); + + // The tile label is always "Auto rotate" and there is no sub-label when the + // tile is `TileType::kPrimary`. tile_->SetLabel( l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ROTATION_LOCK_AUTO)); - tile_->SetSubLabelVisibility(false); + if (!compact) { + tile_->SetSubLabelVisibility(false); + } + // UpdateTile() will update visibility. tile_->SetVisible(false); UpdateTile(); @@ -77,14 +90,6 @@ Shell::Get()->screen_orientation_controller()->ToggleUserRotationLock(); } -void RotationLockFeaturePodController::OnTabletPhysicalStateChanged() { - if (features::IsQsRevampEnabled()) { - UpdateTile(); - } else { - UpdateButton(); - } -} - void RotationLockFeaturePodController::OnUserRotationLockChanged() { if (features::IsQsRevampEnabled()) { UpdateTile(); @@ -95,20 +100,16 @@ void RotationLockFeaturePodController::UpdateButton() { DCHECK(!features::IsQsRevampEnabled()); - // Even though auto-rotation is also supported when the device is not in a - // tablet physical state but kSupportsClamshellAutoRotation is set. The "Auto - // rotate" feature pod button in the system tray menu is not expected to be - // shown in the case. - const bool is_auto_rotation_allowed = - Shell::Get()->tablet_mode_controller()->is_in_tablet_physical_state(); - if (!button_->GetVisible() && is_auto_rotation_allowed) + bool target_visibility = CalculateButtonVisibility(); + if (!button_->GetVisible() && target_visibility) { TrackVisibilityUMA(); + } + button_->SetVisible(target_visibility); - button_->SetVisible(is_auto_rotation_allowed); - - if (!is_auto_rotation_allowed) + if (!target_visibility) { return; + } auto* screen_orientation_controller = Shell::Get()->screen_orientation_controller(); @@ -153,18 +154,14 @@ void RotationLockFeaturePodController::UpdateTile() { DCHECK(features::IsQsRevampEnabled()); - // Auto-rotation is also supported when the device is not in a tablet physical - // state but kSupportsClamshellAutoRotation is set. The "Auto rotate" feature - // tile in the system tray menu is not expected to be shown in the case. - const bool is_auto_rotation_allowed = - Shell::Get()->tablet_mode_controller()->is_in_tablet_physical_state(); + bool target_visibility = CalculateButtonVisibility(); - if (!tile_->GetVisible() && is_auto_rotation_allowed) { + if (!tile_->GetVisible() && target_visibility) { TrackVisibilityUMA(); } - tile_->SetVisible(is_auto_rotation_allowed); + tile_->SetVisible(target_visibility); - if (!is_auto_rotation_allowed) { + if (!target_visibility) { return; }
diff --git a/ash/system/rotation/rotation_lock_feature_pod_controller.h b/ash/system/rotation/rotation_lock_feature_pod_controller.h index f63697b..aaa0ff3 100644 --- a/ash/system/rotation/rotation_lock_feature_pod_controller.h +++ b/ash/system/rotation/rotation_lock_feature_pod_controller.h
@@ -8,7 +8,6 @@ #include "ash/ash_export.h" #include "ash/constants/quick_settings_catalogs.h" #include "ash/display/screen_orientation_controller.h" -#include "ash/public/cpp/tablet_mode_observer.h" #include "ash/system/unified/feature_pod_controller_base.h" #include "base/memory/weak_ptr.h" @@ -23,7 +22,6 @@ // is enabled). class ASH_EXPORT RotationLockFeaturePodController : public FeaturePodControllerBase, - public TabletModeObserver, public ScreenOrientationController::Observer { public: RotationLockFeaturePodController(); @@ -35,15 +33,16 @@ ~RotationLockFeaturePodController() override; + // Referenced by `UnifiedSystemTrayController` to know whether to construct a + // Primary or Compact tile. + static bool CalculateButtonVisibility(); + // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override; - // TabletModeObserver: - void OnTabletPhysicalStateChanged() override; - // ScreenOrientationController::Observer: void OnUserRotationLockChanged() override;
diff --git a/ash/system/scheduled_feature/scheduled_feature.cc b/ash/system/scheduled_feature/scheduled_feature.cc index 3676771f..79ac645 100644 --- a/ash/system/scheduled_feature/scheduled_feature.cc +++ b/ash/system/scheduled_feature/scheduled_feature.cc
@@ -40,16 +40,26 @@ } // namespace +base::Time ScheduledFeature::Clock::Now() const { + return base::Time::Now(); +} + +base::TimeTicks ScheduledFeature::Clock::NowTicks() const { + return base::TimeTicks::Now(); +} + ScheduledFeature::ScheduledFeature( const std::string prefs_path_enabled, const std::string prefs_path_schedule_type, const std::string prefs_path_custom_start_time, const std::string prefs_path_custom_end_time) - : prefs_path_enabled_(prefs_path_enabled), + : timer_(std::make_unique<base::OneShotTimer>()), + prefs_path_enabled_(prefs_path_enabled), prefs_path_schedule_type_(prefs_path_schedule_type), prefs_path_custom_start_time_(prefs_path_custom_start_time), prefs_path_custom_end_time_(prefs_path_custom_end_time), - geolocation_controller_(ash::GeolocationController::Get()) { + geolocation_controller_(ash::GeolocationController::Get()), + clock_(&default_clock_) { Shell::Get()->session_controller()->AddObserver(this); aura::Env::GetInstance()->AddObserver(this); chromeos::PowerManagerClient::Get()->AddObserver(this); @@ -98,7 +108,7 @@ bool ScheduledFeature::IsNowWithinSunsetSunrise() const { // The times below are all on the same calendar day. - const base::Time now = GetNow(); + const base::Time now = clock_->Now(); return now < geolocation_controller_->GetSunriseTime() || now > geolocation_controller_->GetSunsetTime(); } @@ -168,12 +178,11 @@ /*keep_manual_toggles_during_schedules=*/true); } -void ScheduledFeature::SetClockForTesting(base::Clock* clock) { +void ScheduledFeature::SetClockForTesting(const Clock* clock) { + CHECK(clock); clock_ = clock; -} - -base::Time ScheduledFeature::GetNow() const { - return clock_ ? clock_->Now() : base::Time::Now(); + CHECK(!timer_->IsRunning()); + timer_ = std::make_unique<base::OneShotTimer>(clock_); } bool ScheduledFeature::MaybeRestoreSchedule() { @@ -185,7 +194,7 @@ return false; ScheduleTargetState& target_state = iter->second; - const base::Time now = GetNow(); + const base::Time now = clock_->Now(); // It may be that the device was suspended for a very long time that the // target time is no longer valid. if (target_state.target_time <= now) @@ -266,7 +275,7 @@ bool keep_manual_toggles_during_schedules) { switch (GetScheduleType()) { case ScheduleType::kNone: - timer_.Stop(); + timer_->Stop(); RefreshFeatureState(); return; case ScheduleType::kSunsetToSunrise: @@ -296,7 +305,7 @@ } // NOTE: Users can set any weird combinations. - const base::Time now = GetNow(); + const base::Time now = clock_->Now(); if (end_time <= start_time) { // Example: // Start: 9:00 PM, End: 6:00 AM. @@ -407,7 +416,7 @@ DCHECK(active_user_pref_service_); const bool new_status = !GetEnabled(); - const base::Time target_time = GetNow() + delay; + const base::Time target_time = clock_->Now() + delay; per_user_schedule_target_state_[active_user_pref_service_] = ScheduleTargetState{target_time, new_status}; @@ -415,9 +424,9 @@ VLOG(1) << "Setting " << GetFeatureName() << " to toggle to " << (new_status ? "enabled" : "disabled") << " at " << base::TimeFormatTimeOfDay(target_time); - timer_.Start(FROM_HERE, delay, - base::BindOnce(&ScheduledFeature::SetEnabled, - base::Unretained(this), new_status)); + timer_->Start(FROM_HERE, delay, + base::BindOnce(&ScheduledFeature::SetEnabled, + base::Unretained(this), new_status)); } } // namespace ash
diff --git a/ash/system/scheduled_feature/scheduled_feature.h b/ash/system/scheduled_feature/scheduled_feature.h index 5734395..f2ca61d 100644 --- a/ash/system/scheduled_feature/scheduled_feature.h +++ b/ash/system/scheduled_feature/scheduled_feature.h
@@ -15,6 +15,7 @@ #include "base/containers/flat_map.h" #include "base/memory/weak_ptr.h" #include "base/time/clock.h" +#include "base/time/tick_clock.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "chromeos/dbus/power/power_manager_client.h" @@ -35,6 +36,16 @@ public SessionObserver, public chromeos::PowerManagerClient::Observer { public: + // May be overridden for testing purposes (see SetClockForTesting()). By + // default, returns system time. + class Clock : public base::Clock, public base::TickClock { + public: + // base::Clock: + base::Time Now() const override; + // base::TickClock: + base::TimeTicks NowTicks() const override; + }; + // `prefs_path_custom_start_time` and `prefs_path_custom_end_time` can be // empty strings. Supplying only one of the custom time prefs is invalid, // while supplying both of them enables the custom scheduling support. @@ -50,7 +61,7 @@ PrefService* active_user_pref_service() const { return active_user_pref_service_; } - base::OneShotTimer* timer() { return &timer_; } + base::OneShotTimer* timer() { return timer_.get(); } bool GetEnabled() const; ScheduleType GetScheduleType() const; @@ -76,7 +87,7 @@ // chromeos::PowerManagerClient::Observer: void SuspendDone(base::TimeDelta sleep_duration) override; - void SetClockForTesting(base::Clock* clock); + void SetClockForTesting(const Clock* clock); protected: // Called by `Refresh()` and `RefreshScheduleTimer()` to refresh the feature @@ -86,10 +97,6 @@ private: virtual const char* GetFeatureName() const = 0; - // Gets now time from the `clock_`, used for testing, or `base::Time::Now()` - // if `clock_` does not exist. - base::Time GetNow() const; - // Attempts restoring a previously stored schedule for the current user if // possible and returns true if so, false otherwise. bool MaybeRestoreSchedule(); @@ -154,8 +161,9 @@ per_user_schedule_target_state_; // The timer that schedules the start and end of this feature when the - // schedule type is either kSunsetToSunrise or kCustom. - base::OneShotTimer timer_; + // schedule type is either kSunsetToSunrise or kCustom. Safe to assume this is + // never null; this is only reinitialized when the caller sets a new clock. + std::unique_ptr<base::OneShotTimer> timer_; // True only until this feature is initialized from the very first user // session. After that, it is set to false. @@ -180,8 +188,10 @@ // added twice if it is already an observer. bool is_observing_geolocation_ = false; - // Optional Used in tests to override the time of "Now". - base::Clock* clock_ = nullptr; // Not owned. + const Clock default_clock_; + // May be reset in tests to override the time of "Now"; otherwise, points to + // `default_clock_`. Should never be null. + const Clock* clock_ = nullptr; // Not owned. }; } // namespace ash
diff --git a/ash/system/scheduled_feature/scheduled_feature_unittest.cc b/ash/system/scheduled_feature/scheduled_feature_unittest.cc index c757e04..837ccb7 100644 --- a/ash/system/scheduled_feature/scheduled_feature_unittest.cc +++ b/ash/system/scheduled_feature/scheduled_feature_unittest.cc
@@ -7,6 +7,8 @@ #include <memory> #include <sstream> #include <string> +#include <utility> +#include <vector> #include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" @@ -29,8 +31,11 @@ #include "base/strings/pattern.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" +#include "base/test/simple_test_tick_clock.h" #include "base/time/time.h" +#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" +#include "testing/gmock/include/gmock/gmock.h" #include "ui/compositor/layer.h" #include "ui/gfx/geometry/vector3d_f.h" @@ -38,9 +43,14 @@ namespace { +using ::testing::ElementsAre; +using ::testing::Pair; + constexpr char kUser1Email[] = "user1@featuredschedule"; constexpr char kUser2Email[] = "user2@featuredschedule"; +const char* kFeaturePrefName = prefs::kNightLightEnabled; + enum AmPm { kAM, kPM }; Geoposition CreateGeoposition(double latitude, @@ -55,6 +65,45 @@ return position; } +// Records all changes made to the feature state from the time that +// PrefChangeObserver is constructed (turned on at 2 PM, turned off at 5 PM, +// turned back on at 11 PM, etc). Allows tests to not only verify that the +// feature changed status at the appropriate times, but also that it did not +// change at an unintended time. For example, if the feature is expected to turn +// on at 2 PM and it's now 12 PM, we want to make sure that it did not turn off +// then back on again at some point in the middle (say 1 PM). +class PrefChangeObserver { + public: + PrefChangeObserver(PrefService* pref_service, const base::Clock* clock) + : clock_(clock) { + pref_registrar_.Init(pref_service); + pref_registrar_.Add( + kFeaturePrefName, + base::BindRepeating(&PrefChangeObserver::OnEnabledPrefChanged, + base::Unretained(this))); + } + ~PrefChangeObserver() = default; + + // Elements appear in chronological order: + // <Time of the status change, the status of the feature at the time> + const std::vector<std::pair<TimeOfDay, bool>>& changes() const { + return changes_; + } + + void ClearHistory() { changes_.clear(); } + + private: + void OnEnabledPrefChanged() { + changes_.emplace_back( + TimeOfDay::FromTime(clock_->Now()), + pref_registrar_.prefs()->GetBoolean(kFeaturePrefName)); + } + + PrefChangeRegistrar pref_registrar_; + const base::Clock* const clock_; + std::vector<std::pair<TimeOfDay, bool>> changes_; +}; + class TestScheduledFeature : public ScheduledFeature { public: TestScheduledFeature(const std::string prefs_path_enabled, @@ -72,7 +121,8 @@ const char* GetFeatureName() const override { return "TestFeature"; } }; -class ScheduledFeatureTest : public NoSessionAshTestBase { +class ScheduledFeatureTest : public NoSessionAshTestBase, + public ScheduledFeature::Clock { public: ScheduledFeatureTest() = default; ScheduledFeatureTest(const ScheduledFeatureTest& other) = delete; @@ -108,14 +158,13 @@ // Set the clock of geolocation controller to our test clock to control the // time now. geolocation_controller_ = ash::Shell::Get()->geolocation_controller(); - geolocation_controller()->SetClockForTesting(&test_clock_); + geolocation_controller()->SetClockForTesting(this); // Every feature that is auto scheduled by default needs to set test clock. // Otherwise the tests will fails `DCHECK_GE(start_time, now)` in // `ScheduledFeature::RefreshScheduleTimer()` when the new user session // is entered and `InitFromUserPrefs()` triggers `RefreshScheduleTimer()`. - ash::Shell::Get()->dark_light_mode_controller()->SetClockForTesting( - &test_clock_); + ash::Shell::Get()->dark_light_mode_controller()->SetClockForTesting(this); CreateTestUserSessions(); @@ -124,11 +173,11 @@ // Use user prefs of NightLight, which is an example of ScheduledFeature. feature_ = std::make_unique<TestScheduledFeature>( - prefs::kNightLightEnabled, prefs::kNightLightScheduleType, + kFeaturePrefName, prefs::kNightLightScheduleType, prefs::kNightLightCustomStartTime, prefs::kNightLightCustomEndTime); ASSERT_FALSE(feature_->GetEnabled()); - feature_->SetClockForTesting(&test_clock_); + feature_->SetClockForTesting(this); feature_->OnActiveUserPrefServiceChanged( Shell::Get()->session_controller()->GetActivePrefService()); @@ -145,6 +194,11 @@ NoSessionAshTestBase::TearDown(); } + // ScheduledFeature::Clock: + base::Time Now() const override { return test_clock_.Now(); } + + base::TimeTicks NowTicks() const override { return tick_clock_.NowTicks(); } + void CreateTestUserSessions() { auto* session_controller_client = GetSessionControllerClient(); session_controller_client->Reset(); @@ -180,6 +234,57 @@ return TimeOfDay(hour * 60).SetClock(&test_clock_); } + // It is infeasible to initialize AshTestBase with "mock" time and fast + // forward the mock TaskEnvironment in these test cases. Why: The AshTestBase + // harness also instantiates a large portion of the UI stack (even though it's + // irrelevant to these tests), which causes TaskEnvironment::FastForwardBy() + // to block for long periods of time. The test cases ultimately take too long. + // + // This implementation is a workaround that only fast forwards the custom + // test "clocks" that are visible to the ScheduledFeature and its relevant + // dependencies. It also runs the internal ScheduledFeature "timer" as time + // progresses, so test cases may call this and the related methods below as if + // they were using TaskEnvironment::FastForwardBy() and the end result will + // look the same to them. + void FastForwardBy(base::TimeDelta amount) { + while (amount.is_positive()) { + base::TimeDelta advance_increment; + if (feature()->timer()->IsRunning() && + feature()->timer()->desired_run_time() <= + tick_clock_.NowTicks() + amount) { + // Emulates the internal timer firing at its scheduled time. + advance_increment = + feature()->timer()->desired_run_time() - tick_clock_.NowTicks(); + AdvanceTimeBy(advance_increment); + feature()->timer()->FireNow(); + } else { + advance_increment = amount; + AdvanceTimeBy(advance_increment); + } + ASSERT_LE(advance_increment, amount); + amount -= advance_increment; + } + } + + // Fast forwards to the next point in time that the specified `time_of_day` + // is hit. Examples: + // 1) now = 2 PM time_of_day = 5 PM, advances 3 hours + // 2) now = 7 PM time_of_day = 5 PM, advances 22 hours (the next day) + void FastForwardTo(TimeOfDay time_of_day) { + base::Time target_time = time_of_day.SetClock(&test_clock_).ToTimeToday(); + const base::Time now = test_clock_.Now(); + if (target_time < now) { + target_time += base::Days(1); + ASSERT_GT(target_time, now); + } + FastForwardBy(target_time - now); + } + + void AdvanceTimeBy(base::TimeDelta amount) { + test_clock_.Advance(amount); + tick_clock_.Advance(amount); + } + // Fires the timer of the scheduler to request geoposition and wait for all // observers to receive the latest geoposition from the server. void FireTimerToFetchGeoposition() { @@ -208,7 +313,10 @@ private: std::unique_ptr<TestScheduledFeature> feature_; GeolocationController* geolocation_controller_; + // The `test_clock_` and `tick_clock_` are advanced in unison so that the + // ScheduledFeature sees time progressing consistently in all facets. base::SimpleTestClock test_clock_; + base::SimpleTestTickClock tick_clock_; base::OneShotTimer* timer_ptr_; TestGeolocationUrlLoaderFactory* factory_; Geoposition position_; @@ -279,7 +387,7 @@ // types. TEST_F(ScheduledFeatureTest, ScheduleNoneToCustomTransition) { // Now is 6:00 PM. - test_clock()->SetNow(MakeTimeOfDay(6, AmPm::kPM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(6, AmPm::kPM)); SetFeatureEnabled(false); feature()->SetScheduleType(ScheduleType::kNone); // Start time is at 3:00 PM and end time is at 8:00 PM. @@ -300,25 +408,37 @@ // hours scheduling the end. feature()->SetScheduleType(ScheduleType::kCustom); EXPECT_TRUE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(2), feature()->timer()->GetCurrentDelay()); + PrefChangeObserver change_log(user1_pref_service(), test_clock()); + FastForwardTo(MakeTimeOfDay(8, AmPm::kPM)); + EXPECT_FALSE(GetEnabled()); + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(8, AmPm::kPM), false))); + + // First reset back to 6 p.m. the next day: + FastForwardTo(MakeTimeOfDay(6, AmPm::kPM)); + ASSERT_TRUE(GetEnabled()); // If the user changes the schedule type to "none", the feature status - // should not change, but the timer should not be running. + // should not change. feature()->SetScheduleType(ScheduleType::kNone); EXPECT_TRUE(GetEnabled()); - EXPECT_FALSE(feature()->timer()->IsRunning()); + // Since schedule type is none, the feature should not switch off at the + // scheduled end. + FastForwardTo(MakeTimeOfDay(8, AmPm::kPM)); + EXPECT_TRUE(GetEnabled()); } // Tests what happens when the time now reaches the end of the feature // interval when the feature mode is on. TEST_F(ScheduledFeatureTest, TestCustomScheduleReachingEndTime) { - test_clock()->SetNow(MakeTimeOfDay(6, AmPm::kPM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(6, AmPm::kPM)); feature()->SetCustomStartTime(MakeTimeOfDay(3, AmPm::kPM)); feature()->SetCustomEndTime(MakeTimeOfDay(8, AmPm::kPM)); feature()->SetScheduleType(ScheduleType::kCustom); EXPECT_TRUE(GetEnabled()); + PrefChangeObserver change_log(user1_pref_service(), test_clock()); + // Simulate reaching the end time by triggering the timer's user task. Make // sure that the feature ended. // @@ -328,13 +448,13 @@ // start end & now // // Now is 8:00 PM. - test_clock()->SetNow(MakeTimeOfDay(8, AmPm::kPM).ToTimeToday()); - feature()->timer()->FireNow(); + FastForwardTo(MakeTimeOfDay(8, AmPm::kPM)); EXPECT_FALSE(GetEnabled()); - // The timer should still be running, but now scheduling the start at 3:00 PM - // tomorrow which is 19 hours from "now" (8:00 PM). - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(19), feature()->timer()->GetCurrentDelay()); + // The feature should be scheduled to start again at 3:00 PM tomorrow. + FastForwardTo(MakeTimeOfDay(3, AmPm::kPM)); + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(8, AmPm::kPM), false), + Pair(MakeTimeOfDay(3, AmPm::kPM), true))); } // Tests that user toggles from the system menu or system settings override any @@ -347,7 +467,7 @@ // | | | // start end now // - test_clock()->SetNow(MakeTimeOfDay(11, AmPm::kPM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(11, AmPm::kPM)); feature()->SetCustomStartTime(MakeTimeOfDay(3, AmPm::kPM)); feature()->SetCustomEndTime(MakeTimeOfDay(8, AmPm::kPM)); feature()->SetScheduleType(ScheduleType::kCustom); @@ -359,18 +479,30 @@ // button must override any automatic schedule. SetFeatureEnabled(true); EXPECT_TRUE(GetEnabled()); - // The timer should still be running, but the feature should automatically - // turn off at 8:00 PM tomorrow, which is 21 hours from now (11:00 PM). - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(21), feature()->timer()->GetCurrentDelay()); + + PrefChangeObserver change_log(user1_pref_service(), test_clock()); + // The feature should automatically turn off at 8:00 PM tomorrow. + FastForwardTo(MakeTimeOfDay(8, AmPm::kPM)); + EXPECT_FALSE(GetEnabled()); + + // Manually reset the feature back to on. + SetFeatureEnabled(true); + EXPECT_TRUE(GetEnabled()); // Manually turning it back off should also be respected, and this time the // start is scheduled at 3:00 PM tomorrow after 19 hours from "now" (8:00 // PM). SetFeatureEnabled(false); EXPECT_FALSE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(16), feature()->timer()->GetCurrentDelay()); + FastForwardTo(MakeTimeOfDay(3, AmPm::kPM)); + EXPECT_TRUE(GetEnabled()); + EXPECT_THAT( + change_log.changes(), + ElementsAre( + Pair(MakeTimeOfDay(8, AmPm::kPM), false), + Pair(MakeTimeOfDay(8, AmPm::kPM), true), // Manual toggle on + Pair(MakeTimeOfDay(8, AmPm::kPM), false), // Manual toggle off + Pair(MakeTimeOfDay(3, AmPm::kPM), true))); } // Tests that changing the custom start and end times, in such a way that @@ -382,33 +514,38 @@ // | | | // now start end // - test_clock()->SetNow(MakeTimeOfDay(4, AmPm::kPM).ToTimeToday()); // 4:00 PM. + FastForwardTo(MakeTimeOfDay(4, AmPm::kPM)); // 4:00 PM. SetFeatureEnabled(false); feature()->SetScheduleType(ScheduleType::kNone); feature()->SetCustomStartTime(MakeTimeOfDay(6, AmPm::kPM)); // 6:00 PM. feature()->SetCustomEndTime(MakeTimeOfDay(10, AmPm::kPM)); // 10:00 PM. // Since now is outside the feature interval, changing the schedule type - // to kCustom, shouldn't affect the status. Validate the timer is running - // with a 2-hour delay. + // to kCustom, shouldn't affect the status. Validate the feature turns on then + // off at the scheduled times. feature()->SetScheduleType(ScheduleType::kCustom); EXPECT_FALSE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(2), feature()->timer()->GetCurrentDelay()); + PrefChangeObserver change_log(user1_pref_service(), test_clock()); + FastForwardBy(base::Days(1)); + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(6, AmPm::kPM), true), + Pair(MakeTimeOfDay(10, AmPm::kPM), false))); + change_log.ClearHistory(); // Change the start time in such a way that doesn't change the status, but // despite that, confirm that schedule has been updated. + ASSERT_FALSE(GetEnabled()); feature()->SetCustomStartTime(MakeTimeOfDay(7, AmPm::kPM)); // 7:00 PM. EXPECT_FALSE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(3), feature()->timer()->GetCurrentDelay()); // Changing the end time in a similar fashion to the above and expect no // change. feature()->SetCustomEndTime(MakeTimeOfDay(11, AmPm::kPM)); // 11:00 PM. EXPECT_FALSE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(3), feature()->timer()->GetCurrentDelay()); + FastForwardBy(base::Days(1)); + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(7, AmPm::kPM), true), + Pair(MakeTimeOfDay(11, AmPm::kPM), false))); } // Tests that the feature should turn on at sunset time and turn off at sunrise @@ -417,35 +554,28 @@ EXPECT_FALSE(GetEnabled()); // Set time now to 10:00 AM. - base::Time current_time = MakeTimeOfDay(10, AmPm::kAM).ToTimeToday(); - test_clock()->SetNow(current_time); - EXPECT_FALSE(feature()->timer()->IsRunning()); + FastForwardTo(MakeTimeOfDay(10, AmPm::kAM)); feature()->SetScheduleType(ScheduleType::kSunsetToSunrise); EXPECT_FALSE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(geolocation_controller()->GetSunsetTime() - current_time, - feature()->timer()->GetCurrentDelay()); + + const PrefChangeObserver change_log(user1_pref_service(), test_clock()); // Firing a timer should to advance the time to sunset and automatically turn // on the feature. - current_time = geolocation_controller()->GetSunsetTime(); - test_clock()->SetNow(current_time); - feature()->timer()->FireNow(); - EXPECT_TRUE(feature()->timer()->IsRunning()); + const TimeOfDay sunset_time = + TimeOfDay::FromTime(geolocation_controller()->GetSunsetTime()); + FastForwardTo(sunset_time); EXPECT_TRUE(GetEnabled()); - EXPECT_EQ( - geolocation_controller()->GetSunriseTime() + base::Days(1) - current_time, - feature()->timer()->GetCurrentDelay()); // Firing a timer should advance the time to sunrise and automatically turn // off the feature. - current_time = geolocation_controller()->GetSunriseTime(); - test_clock()->SetNow(current_time); - feature()->timer()->FireNow(); + const TimeOfDay sunrise_time = + TimeOfDay::FromTime(geolocation_controller()->GetSunriseTime()); + FastForwardTo(sunrise_time); EXPECT_FALSE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(geolocation_controller()->GetSunsetTime() - current_time, - feature()->timer()->GetCurrentDelay()); + + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(sunset_time, true), Pair(sunrise_time, false))); } // Tests that scheduled start time and end time of sunset-to-sunrise feature @@ -490,27 +620,23 @@ ASSERT_LT(sunset_time1 - base::Days(1), sunrise_time1); // Set time now to be 4 hours before sunset. - test_clock()->SetNow(sunset_time1 - base::Hours(4)); + FastForwardTo(TimeOfDay::FromTime(sunset_time1 - base::Hours(4))); // Expect that timer is running and the start is scheduled after 4 hours. EXPECT_FALSE(feature()->GetEnabled()); + feature()->SetScheduleType(ScheduleType::kSunsetToSunrise); EXPECT_FALSE(feature()->GetEnabled()); EXPECT_TRUE(IsFeatureObservingGeoposition()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(4), feature()->timer()->GetCurrentDelay()); // Simulate reaching sunset. - test_clock()->SetNow(sunset_time1); // Now is sunset time of the position1. - feature()->timer()->FireNow(); + FastForwardBy(base::Hours(4)); // Now is sunset time of the position1. EXPECT_TRUE(feature()->GetEnabled()); - // Timer is running scheduling the end at sunrise of the second day. - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(sunrise_time1 + base::Days(1) - test_clock()->Now(), - feature()->timer()->GetCurrentDelay()); // Simulate reaching sunrise. - test_clock()->SetNow(sunrise_time1); // Now is sunrise time of the position1 + FastForwardTo(TimeOfDay::FromTime( + sunrise_time1)); // Now is sunrise time of the position1 + EXPECT_FALSE(feature()->GetEnabled()); // Now simulate user changing position. // Position 2 sunset and sunrise times. @@ -542,26 +668,21 @@ // Expect that the scheduled end delay has been updated to sunrise of the // same (second) day in location 2, and the status hasn't changed. EXPECT_TRUE(feature()->GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(sunrise_time2 + base::Days(1) - test_clock()->Now(), - feature()->timer()->GetCurrentDelay()); // Simulate reaching sunrise. - test_clock()->SetNow(sunrise_time2 + - base::Days(1)); // Now is sunrise time of the position2. - feature()->timer()->FireNow(); + FastForwardTo(TimeOfDay::FromTime( + sunrise_time2)); // Now is sunrise time of the position2. EXPECT_FALSE(feature()->GetEnabled()); // Timer is running scheduling the start at the sunset of the next day. - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(sunset_time2 + base::Days(1) - test_clock()->Now(), - feature()->timer()->GetCurrentDelay()); + FastForwardTo(TimeOfDay::FromTime(sunrise_time2)); + EXPECT_TRUE(feature()->GetEnabled()); } // Tests that on device resume from sleep, the feature status is updated // correctly if the time has changed meanwhile. TEST_F(ScheduledFeatureTest, CustomScheduleOnResume) { // Now is 4:00 PM. - test_clock()->SetNow(MakeTimeOfDay(4, AmPm::kPM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(4, AmPm::kPM)); feature()->SetEnabled(false); // Start time is at 6:00 PM and end time is at 10:00 PM. The feature should be // off. @@ -573,21 +694,23 @@ feature()->SetCustomStartTime(MakeTimeOfDay(6, AmPm::kPM)); feature()->SetCustomEndTime(MakeTimeOfDay(10, AmPm::kPM)); feature()->SetScheduleType(ScheduleType::kCustom); + ASSERT_FALSE(feature()->GetEnabled()); - EXPECT_FALSE(feature()->GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - // The feature should be enabled in 2 hours. - EXPECT_EQ(base::Hours(2), feature()->timer()->GetCurrentDelay()); + PrefChangeObserver change_log(user1_pref_service(), test_clock()); // Now simulate that the device was suspended for 3 hours, and the time now // is 7:00 PM when the devices was resumed. Expect that the feature turns on. - test_clock()->SetNow(MakeTimeOfDay(7, AmPm::kPM).ToTimeToday()); + AdvanceTimeBy(base::Hours(3)); // 7:00 PM feature()->SuspendDone(base::TimeDelta::Max()); EXPECT_TRUE(feature()->GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - // The feature should be disabled in 3 hours. - EXPECT_EQ(base::Hours(3), feature()->timer()->GetCurrentDelay()); + // The feature should be disabled at originally scheduled time. + FastForwardTo(MakeTimeOfDay(10, AmPm::kPM)); + EXPECT_FALSE(feature()->GetEnabled()); + + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(7, AmPm::kPM), true), + Pair(MakeTimeOfDay(10, AmPm::kPM), false))); } // The following tests ensure that the feature schedule is correctly @@ -598,7 +721,7 @@ // Case 1: "Now" is less than both "end" and "start". TEST_F(ScheduledFeatureTest, CustomScheduleInvertedStartAndEndTimesCase1) { // Now is 4:00 AM. - test_clock()->SetNow(MakeTimeOfDay(4, AmPm::kAM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(4, AmPm::kAM)); SetFeatureEnabled(false); // Start time is at 9:00 PM and end time is at 6:00 AM. "Now" is less than // both. The feature should be on. @@ -612,15 +735,17 @@ feature()->SetScheduleType(ScheduleType::kCustom); EXPECT_TRUE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - // The feature should end in two hours. - EXPECT_EQ(base::Hours(2), feature()->timer()->GetCurrentDelay()); + PrefChangeObserver change_log(user1_pref_service(), test_clock()); + FastForwardBy(base::Days(1)); + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(6, AmPm::kAM), false), + Pair(MakeTimeOfDay(9, AmPm::kPM), true))); } // Case 2: "Now" is between "end" and "start". TEST_F(ScheduledFeatureTest, CustomScheduleInvertedStartAndEndTimesCase2) { // Now is 6:00 AM. - test_clock()->SetNow(MakeTimeOfDay(6, AmPm::kAM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(6, AmPm::kAM)); SetFeatureEnabled(false); // Start time is at 9:00 PM and end time is at 4:00 AM. "Now" is between both. // The feature should be off. @@ -634,15 +759,17 @@ feature()->SetScheduleType(ScheduleType::kCustom); EXPECT_FALSE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - // The feature should start in 15 hours. - EXPECT_EQ(base::Hours(15), feature()->timer()->GetCurrentDelay()); + PrefChangeObserver change_log(user1_pref_service(), test_clock()); + FastForwardBy(base::Days(1)); + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(9, AmPm::kPM), true), + Pair(MakeTimeOfDay(4, AmPm::kAM), false))); } // Case 3: "Now" is greater than both "start" and "end". TEST_F(ScheduledFeatureTest, CustomScheduleInvertedStartAndEndTimesCase3) { // Now is 11:00 PM. - test_clock()->SetNow(MakeTimeOfDay(11, AmPm::kPM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(11, AmPm::kPM)); SetFeatureEnabled(false); // Start time is at 9:00 PM and end time is at 4:00 AM. "Now" is greater than // both. the feature should be on. @@ -656,9 +783,11 @@ feature()->SetScheduleType(ScheduleType::kCustom); EXPECT_TRUE(GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - // The feature should end in 5 hours. - EXPECT_EQ(base::Hours(5), feature()->timer()->GetCurrentDelay()); + PrefChangeObserver change_log(user1_pref_service(), test_clock()); + FastForwardBy(base::Days(1)); + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(4, AmPm::kAM), false), + Pair(MakeTimeOfDay(9, AmPm::kPM), true))); } // Tests that manual changes to the feature status while a schedule is being @@ -681,7 +810,7 @@ // 2pm 4pm 7pm 10pm 9am // - test_clock()->SetNow(MakeTimeOfDay(2, kPM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(2, kPM)); feature()->SetCustomStartTime(MakeTimeOfDay(3, kPM)); feature()->SetCustomEndTime(MakeTimeOfDay(8, kPM)); feature()->SetScheduleType(ScheduleType::kCustom); @@ -690,20 +819,18 @@ SwitchActiveUser(kUser1Email); struct { - base::Time fake_now; + TimeOfDay fake_now; bool user_1_expected_status; bool user_2_expected_status; } kTestCases[] = { - {MakeTimeOfDay(2, kPM).ToTimeToday(), false, false}, - {MakeTimeOfDay(4, kPM).ToTimeToday(), true, false}, - {MakeTimeOfDay(7, kPM).ToTimeToday(), true, true}, - {MakeTimeOfDay(10, kPM).ToTimeToday(), false, true}, - {MakeTimeOfDay(9, kAM).ToTimeToday() + - base::Days(1), // 9:00 AM tomorrow. + {MakeTimeOfDay(2, kPM), false, false}, + {MakeTimeOfDay(4, kPM), true, false}, + {MakeTimeOfDay(7, kPM), true, true}, + {MakeTimeOfDay(10, kPM), false, true}, + {MakeTimeOfDay(9, kAM), // 9:00 AM tomorrow. false, false}, }; - bool user_1_previous_status = false; for (const auto& test_case : kTestCases) { // Each test case begins when user_1 is active. const bool user_1_toggled_status = !test_case.user_1_expected_status; @@ -711,10 +838,7 @@ // Apply the test's case fake time, and fire the timer if there's a change // expected in the feature's status. - test_clock()->SetNow(test_case.fake_now); - if (user_1_previous_status != test_case.user_1_expected_status) - feature()->timer()->FireNow(); - user_1_previous_status = test_case.user_1_expected_status; + FastForwardTo(test_case.fake_now); // The untoggled states for both users should match the expected ones // according to their schedules. @@ -753,7 +877,7 @@ TEST_F(ScheduledFeatureTest, ManualStatusToggleCanPersistAfterResumeFromSuspend) { - test_clock()->SetNow(MakeTimeOfDay(11, kAM).ToTimeToday()); + FastForwardTo(MakeTimeOfDay(11, kAM)); feature()->SetCustomStartTime(MakeTimeOfDay(3, kPM)); feature()->SetCustomEndTime(MakeTimeOfDay(8, kPM)); @@ -764,25 +888,28 @@ // turn back off at 8:00 PM. feature()->SetEnabled(true); EXPECT_TRUE(feature()->GetEnabled()); - EXPECT_TRUE(feature()->timer()->IsRunning()); - EXPECT_EQ(base::Hours(9), feature()->timer()->GetCurrentDelay()); + + PrefChangeObserver change_log(user1_pref_service(), test_clock()); // Simulate suspend and then resume at 2:00 PM (which is outside the user's // custom schedule). However, the manual toggle to on should be kept. - test_clock()->SetNow(MakeTimeOfDay(2, kPM).ToTimeToday()); + AdvanceTimeBy(base::Hours(3)); feature()->SuspendDone(base::TimeDelta{}); EXPECT_TRUE(feature()->GetEnabled()); // Suspend again and resume at 5:00 PM (which is within the user's custom // schedule). The schedule should be applied normally. - test_clock()->SetNow(MakeTimeOfDay(5, kPM).ToTimeToday()); + AdvanceTimeBy(base::Hours(3)); feature()->SuspendDone(base::TimeDelta{}); EXPECT_TRUE(feature()->GetEnabled()); // Suspend and resume at 9:00 PM and expect the feature to be off. - test_clock()->SetNow(MakeTimeOfDay(9, kPM).ToTimeToday()); + AdvanceTimeBy(base::Hours(4)); feature()->SuspendDone(base::TimeDelta{}); EXPECT_FALSE(feature()->GetEnabled()); + + EXPECT_THAT(change_log.changes(), + ElementsAre(Pair(MakeTimeOfDay(9, AmPm::kPM), false))); } } // namespace
diff --git a/ash/system/time/time_of_day.cc b/ash/system/time/time_of_day.cc index 352bc76..e82580f1 100644 --- a/ash/system/time/time_of_day.cc +++ b/ash/system/time/time_of_day.cc
@@ -32,7 +32,7 @@ return offset_minutes_from_zero_hour_ == rhs.offset_minutes_from_zero_hour_; } -TimeOfDay& TimeOfDay::SetClock(base::Clock* clock) { +TimeOfDay& TimeOfDay::SetClock(const base::Clock* clock) { clock_ = clock; return *this; } @@ -63,4 +63,8 @@ return clock_ ? clock_->Now() : base::Time::Now(); } +std::ostream& operator<<(std::ostream& os, const TimeOfDay& time_of_day) { + return os << base::Minutes(time_of_day.offset_minutes_from_zero_hour()); +} + } // namespace ash
diff --git a/ash/system/time/time_of_day.h b/ash/system/time/time_of_day.h index c502c3c1..02859da 100644 --- a/ash/system/time/time_of_day.h +++ b/ash/system/time/time_of_day.h
@@ -5,6 +5,7 @@ #ifndef ASH_SYSTEM_TIME_TIME_OF_DAY_H_ #define ASH_SYSTEM_TIME_TIME_OF_DAY_H_ +#include <ostream> #include <string> #include "ash/ash_export.h" @@ -39,7 +40,7 @@ // Sets `clock_` with a given `clock`, but this class does not own it. // The clock is used to determine current time in `GetNow()`. - TimeOfDay& SetClock(base::Clock* clock); + TimeOfDay& SetClock(const base::Clock* clock); // Converts to an actual point in time today. If this fail for some reason, // base::Time() will be returned. @@ -56,9 +57,12 @@ int offset_minutes_from_zero_hour_; // Optional Used in tests to override the time of "Now". - base::Clock* clock_ = nullptr; // Not owned. + const base::Clock* clock_ = nullptr; // Not owned. }; +ASH_EXPORT std::ostream& operator<<(std::ostream& os, + const TimeOfDay& time_of_day); + } // namespace ash #endif // ASH_SYSTEM_TIME_TIME_OF_DAY_H_
diff --git a/ash/system/unified/feature_pod_controller_base.cc b/ash/system/unified/feature_pod_controller_base.cc index 4bbc642..230ef36d 100644 --- a/ash/system/unified/feature_pod_controller_base.cc +++ b/ash/system/unified/feature_pod_controller_base.cc
@@ -4,6 +4,7 @@ #include "ash/system/unified/feature_pod_controller_base.h" +#include "ash/constants/ash_features.h" #include "ash/system/unified/feature_pod_button.h" #include "ash/system/unified/feature_tile.h" #include "ash/system/unified/quick_settings_metrics_util.h" @@ -12,8 +13,11 @@ // TODO(b/252871301): Remove after implementing every FeatureTile and making // this function pure virtual. -std::unique_ptr<FeatureTile> FeaturePodControllerBase::CreateTile() { - return std::make_unique<FeatureTile>(); +std::unique_ptr<FeatureTile> FeaturePodControllerBase::CreateTile( + bool compact) { + return std::make_unique<FeatureTile>(compact + ? FeatureTile::TileType::kCompact + : FeatureTile::TileType::kPrimary); } void FeaturePodControllerBase::OnLabelPressed() {
diff --git a/ash/system/unified/feature_pod_controller_base.h b/ash/system/unified/feature_pod_controller_base.h index 23b1ed1..9c2264ea 100644 --- a/ash/system/unified/feature_pod_controller_base.h +++ b/ash/system/unified/feature_pod_controller_base.h
@@ -28,10 +28,11 @@ // this). virtual FeaturePodButton* CreateButton() = 0; - // Creates FeatureTile view. - // TODO(b/252871301): Make this function pure virtual after implementing + // Creates FeatureTile view. `compact` determines whether to present a Primary + // or Compact tile. + // TODO(b/252871301): Make function pure virtual after implementing // every feature tile. - virtual std::unique_ptr<FeatureTile> CreateTile(); + virtual std::unique_ptr<FeatureTile> CreateTile(bool compact); // Returns the feature catalog name which is used for UMA tracking. Please // remember to call the corresponding tracking method (`TrackToggleUMA` and
diff --git a/ash/system/unified/feature_tile_unittest.cc b/ash/system/unified/feature_tile_unittest.cc index b632720..07ac937 100644 --- a/ash/system/unified/feature_tile_unittest.cc +++ b/ash/system/unified/feature_tile_unittest.cc
@@ -22,11 +22,8 @@ class MockFeaturePodController : public FeaturePodControllerBase { public: - explicit MockFeaturePodController( - FeatureTile::TileType type = FeatureTile::TileType::kPrimary) - : type_(type) {} - MockFeaturePodController(bool togglable, FeatureTile::TileType type) - : togglable_(togglable), type_(type) {} + MockFeaturePodController() = default; + explicit MockFeaturePodController(bool togglable) : togglable_(togglable) {} MockFeaturePodController(const MockFeaturePodController&) = delete; MockFeaturePodController& operator=(const MockFeaturePodController&) = delete; @@ -37,11 +34,13 @@ return new FeaturePodButton(/*controller=*/this); } - std::unique_ptr<FeatureTile> CreateTile() override { + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override { auto tile = std::make_unique<FeatureTile>( base::BindRepeating(&FeaturePodControllerBase::OnIconPressed, weak_ptr_factory_.GetWeakPtr()), - togglable_, type_); + togglable_, + compact ? FeatureTile::TileType::kCompact + : FeatureTile::TileType::kPrimary); tile->SetVectorIcon(vector_icons::kDogfoodIcon); tile_ = tile.get(); return tile; @@ -89,7 +88,6 @@ bool was_label_pressed_ = false; bool togglable_ = false; bool toggled_ = false; - FeatureTile::TileType type_ = FeatureTile::TileType::kPrimary; base::WeakPtrFactory<MockFeaturePodController> weak_ptr_factory_{this}; }; @@ -123,8 +121,8 @@ }; TEST_F(FeatureTileTest, PrimaryTile_LaunchSurface) { - auto mock_controller = std::make_unique<MockFeaturePodController>( - /*togglable=*/false, FeatureTile::TileType::kPrimary); + auto mock_controller = + std::make_unique<MockFeaturePodController>(/*togglable=*/false); auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); EXPECT_FALSE(tile->drill_in_button()); @@ -141,8 +139,8 @@ } TEST_F(FeatureTileTest, PrimaryTile_Toggle) { - auto mock_controller = std::make_unique<MockFeaturePodController>( - /*togglable=*/true, FeatureTile::TileType::kPrimary); + auto mock_controller = + std::make_unique<MockFeaturePodController>(/*togglable=*/true); auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); EXPECT_FALSE(tile->drill_in_button()); @@ -164,8 +162,8 @@ } TEST_F(FeatureTileTest, PrimaryTile_DrillIn) { - auto mock_controller = std::make_unique<MockFeaturePodController>( - /*togglable=*/false, FeatureTile::TileType::kPrimary); + auto mock_controller = + std::make_unique<MockFeaturePodController>(/*togglable=*/false); auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); mock_controller->CreateDrillInButton(); @@ -187,8 +185,8 @@ } TEST_F(FeatureTileTest, PrimaryTile_ToggleWithDrillIn) { - auto mock_controller = std::make_unique<MockFeaturePodController>( - /*togglable=*/true, FeatureTile::TileType::kPrimary); + auto mock_controller = + std::make_unique<MockFeaturePodController>(/*togglable=*/true); auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); mock_controller->CreateDrillInButton(); @@ -218,8 +216,9 @@ TEST_F(FeatureTileTest, CompactTile_LaunchSurface) { auto mock_controller = std::make_unique<MockFeaturePodController>( - /*togglable=*/false, FeatureTile::TileType::kCompact); - auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); + /*togglable=*/false); + auto* tile = + widget_->SetContentsView(mock_controller->CreateTile(/*compact=*/true)); // Ensure icon hasn't been pressed. EXPECT_FALSE(tile->IsToggled()); @@ -234,8 +233,9 @@ TEST_F(FeatureTileTest, CompactTile_Toggle) { auto mock_controller = std::make_unique<MockFeaturePodController>( - /*togglable=*/true, FeatureTile::TileType::kCompact); - auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); + /*togglable=*/true); + auto* tile = + widget_->SetContentsView(mock_controller->CreateTile(/*compact=*/true)); // Ensure icon hasn't been pressed. EXPECT_FALSE(tile->IsToggled()); @@ -252,8 +252,4 @@ EXPECT_FALSE(tile->IsToggled()); } -// Tests that certain primary tiles switch to their compact versions after a -// tablet mode change. -// TODO(b/251724698): Implement tablet mode change behavior. - } // namespace ash
diff --git a/ash/system/unified/feature_tiles_container_view_unittest.cc b/ash/system/unified/feature_tiles_container_view_unittest.cc index f714597..d1ed5c9 100644 --- a/ash/system/unified/feature_tiles_container_view_unittest.cc +++ b/ash/system/unified/feature_tiles_container_view_unittest.cc
@@ -28,22 +28,22 @@ class MockFeaturePodController : public FeaturePodControllerBase { public: - explicit MockFeaturePodController(FeatureTile::TileType type) : type_(type) {} - + MockFeaturePodController() = default; MockFeaturePodController(const MockFeaturePodController&) = delete; MockFeaturePodController& operator=(const MockFeaturePodController&) = delete; - ~MockFeaturePodController() override = default; FeaturePodButton* CreateButton() override { return new FeaturePodButton(/*controller=*/this); } - std::unique_ptr<FeatureTile> CreateTile() override { + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override { auto tile = std::make_unique<FeatureTile>( base::BindRepeating(&FeaturePodControllerBase::OnIconPressed, weak_ptr_factory_.GetWeakPtr()), - /*togglable=*/true, type_); + /*togglable=*/true, + compact ? FeatureTile::TileType::kCompact + : FeatureTile::TileType::kPrimary); tile->SetVectorIcon(vector_icons::kDogfoodIcon); return tile; } @@ -56,8 +56,6 @@ void OnLabelPressed() override {} private: - FeatureTile::TileType type_; - base::WeakPtrFactory<MockFeaturePodController> weak_ptr_factory_{this}; }; @@ -128,16 +126,15 @@ int GetPageCount() { return container()->page_count(); } - void FillContainerWithTiles(int pages) { - auto tile_controller = std::make_unique<MockFeaturePodController>( - FeatureTile::TileType::kPrimary); + void FillContainerWithPrimaryTiles(int pages) { + auto mock_controller = std::make_unique<MockFeaturePodController>(); std::vector<std::unique_ptr<FeatureTile>> tiles; size_t number_of_tiles = pages * container()->displayable_rows() * kMaxPrimaryTilesPerRow; while (tiles.size() < number_of_tiles) { - tiles.push_back(tile_controller->CreateTile()); + tiles.push_back(mock_controller->CreateTile()); } AddTiles(std::move(tiles)); @@ -170,45 +167,38 @@ // Tests that rows are dynamically added by adding `FeatureTile` elements to the // container. TEST_F(FeatureTilesContainerViewTest, FeatureTileRows) { - std::unique_ptr<MockFeaturePodController> primary_tile_controller = - std::make_unique<MockFeaturePodController>( - FeatureTile::TileType::kPrimary); - std::unique_ptr<MockFeaturePodController> compact_tile_controller = - std::make_unique<MockFeaturePodController>( - FeatureTile::TileType::kCompact); + auto mock_controller = std::make_unique<MockFeaturePodController>(); // Expect one row by adding two primary tiles. std::vector<std::unique_ptr<FeatureTile>> two_primary_tiles; - two_primary_tiles.push_back(primary_tile_controller->CreateTile()); - two_primary_tiles.push_back(primary_tile_controller->CreateTile()); + two_primary_tiles.push_back(mock_controller->CreateTile()); + two_primary_tiles.push_back(mock_controller->CreateTile()); container()->AddTiles(std::move(two_primary_tiles)); EXPECT_EQ(GetRowCount(), 1); // Expect one other row by adding a primary and two compact tiles. std::vector<std::unique_ptr<FeatureTile>> one_primary_two_compact_tiles; + one_primary_two_compact_tiles.push_back(mock_controller->CreateTile()); one_primary_two_compact_tiles.push_back( - primary_tile_controller->CreateTile()); + mock_controller->CreateTile(/*compact=*/true)); one_primary_two_compact_tiles.push_back( - compact_tile_controller->CreateTile()); - one_primary_two_compact_tiles.push_back( - compact_tile_controller->CreateTile()); + mock_controller->CreateTile(/*compact=*/true)); container()->AddTiles(std::move(one_primary_two_compact_tiles)); EXPECT_EQ(GetRowCount(), 2); // Expect one other row by adding a single primary tile. std::vector<std::unique_ptr<FeatureTile>> one_primary_tile; - one_primary_tile.push_back(primary_tile_controller->CreateTile()); + one_primary_tile.push_back(mock_controller->CreateTile()); container()->AddTiles(std::move(one_primary_tile)); EXPECT_EQ(GetRowCount(), 3); } TEST_F(FeatureTilesContainerViewTest, ChangeTileVisibility) { // Create 3 full-size tiles. Normally they would require 2 rows. - auto tile_controller = std::make_unique<MockFeaturePodController>( - FeatureTile::TileType::kPrimary); - std::unique_ptr<FeatureTile> tile1 = tile_controller->CreateTile(); - std::unique_ptr<FeatureTile> tile2 = tile_controller->CreateTile(); - std::unique_ptr<FeatureTile> tile3 = tile_controller->CreateTile(); + auto mock_controller = std::make_unique<MockFeaturePodController>(); + std::unique_ptr<FeatureTile> tile1 = mock_controller->CreateTile(); + std::unique_ptr<FeatureTile> tile2 = mock_controller->CreateTile(); + std::unique_ptr<FeatureTile> tile3 = mock_controller->CreateTile(); // Make the first tile invisible. FeatureTile* tile1_ptr = tile1.get(); @@ -234,22 +224,21 @@ } TEST_F(FeatureTilesContainerViewTest, PageCountUpdated) { - auto tile_controller = std::make_unique<MockFeaturePodController>( - FeatureTile::TileType::kPrimary); + auto mock_controller = std::make_unique<MockFeaturePodController>(); // Set the container height to have two displayable rows per page. SetRowsFromHeight(kFeatureTileHeight * 2); - // Add five tiles to the container. std::vector<std::unique_ptr<FeatureTile>> tiles; // Get pointer of one tile so we can make invisible later. - std::unique_ptr<FeatureTile> tile1 = tile_controller->CreateTile(); + std::unique_ptr<FeatureTile> tile1 = mock_controller->CreateTile(); FeatureTile* tile1_ptr = tile1.get(); tiles.push_back(std::move(tile1)); + // Add a total of five tiles to the container. while (tiles.size() < 5) { - tiles.push_back(tile_controller->CreateTile()); + tiles.push_back(mock_controller->CreateTile()); } // Since a row fits two primary tiles, expect two pages for five primary @@ -270,7 +259,7 @@ // TODO(b/263185068): Use EventGenerator. TEST_F(FeatureTilesContainerViewTest, PaginationGesture) { constexpr int kNumberOfPages = 4; - FillContainerWithTiles(kNumberOfPages); + FillContainerWithPrimaryTiles(kNumberOfPages); gfx::Point container_origin = container()->GetBoundsInScreen().origin(); ui::GestureEvent swipe_left_begin( @@ -336,7 +325,7 @@ TEST_F(FeatureTilesContainerViewTest, PaginationScroll) { constexpr int kNumberOfFingers = 2; constexpr int kNumberOfPages = 4; - FillContainerWithTiles(kNumberOfPages); + FillContainerWithPrimaryTiles(kNumberOfPages); gfx::Point container_origin = container()->GetBoundsInScreen().origin(); @@ -384,7 +373,7 @@ // TODO(b/263185068): Use EventGenerator. TEST_F(FeatureTilesContainerViewTest, PaginationMouseWheel) { constexpr int kNumberOfPages = 4; - FillContainerWithTiles(kNumberOfPages); + FillContainerWithPrimaryTiles(kNumberOfPages); gfx::Point container_origin = container()->GetBoundsInScreen().origin(); ui::MouseWheelEvent wheel_up(gfx::Vector2d(0, 1000), container_origin, @@ -422,7 +411,7 @@ TEST_F(FeatureTilesContainerViewTest, PaginationDots) { constexpr int kNumberOfPages = 4; - FillContainerWithTiles(kNumberOfPages); + FillContainerWithPrimaryTiles(kNumberOfPages); // Expect the current_page to increase with each pagination dot click. int current_page = pagination_model()->selected_page(); @@ -435,7 +424,7 @@ TEST_F(FeatureTilesContainerViewTest, ResetPagination) { constexpr int kNumberOfPages = 4; - FillContainerWithTiles(kNumberOfPages); + FillContainerWithPrimaryTiles(kNumberOfPages); // Expect page with index 2 to be selected after clicking its dot. LeftClickOn(GetPageIndicatorButtons()[2]);
diff --git a/ash/system/unified/quiet_mode_feature_pod_controller.cc b/ash/system/unified/quiet_mode_feature_pod_controller.cc index 7d75c18..5473ed8 100644 --- a/ash/system/unified/quiet_mode_feature_pod_controller.cc +++ b/ash/system/unified/quiet_mode_feature_pod_controller.cc
@@ -6,6 +6,7 @@ #include "ash/constants/ash_features.h" #include "ash/constants/quick_settings_catalogs.h" +#include "ash/public/cpp/ash_view_ids.h" #include "ash/public/cpp/notifier_metadata.h" #include "ash/public/cpp/notifier_settings_controller.h" #include "ash/resources/vector_icons/vector_icons.h" @@ -47,16 +48,22 @@ MessageCenter::Get()->RemoveObserver(this); } +// static +bool QuietModeFeaturePodController::CalculateButtonVisibility() { + auto* session_controller = Shell::Get()->session_controller(); + return session_controller->ShouldShowNotificationTray() && + !session_controller->IsScreenLocked(); +} + FeaturePodButton* QuietModeFeaturePodController::CreateButton() { DCHECK(!button_); button_ = new FeaturePodButton(this); button_->SetVectorIcon(kUnifiedMenuDoNotDisturbIcon); - const bool visible = - Shell::Get()->session_controller()->ShouldShowNotificationTray() && - !Shell::Get()->session_controller()->IsScreenLocked(); - button_->SetVisible(visible); - if (visible) + const bool target_visibility = CalculateButtonVisibility(); + button_->SetVisible(target_visibility); + if (target_visibility) { TrackVisibilityUMA(); + } button_->SetLabel( l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NOTIFICATIONS_LABEL)); @@ -69,20 +76,21 @@ return button_; } -std::unique_ptr<FeatureTile> QuietModeFeaturePodController::CreateTile() { +std::unique_ptr<FeatureTile> QuietModeFeaturePodController::CreateTile( + bool compact) { DCHECK(features::IsQsRevampEnabled()); - // TODO(b/263423627): Tile should be compact if applicable. auto tile = std::make_unique<FeatureTile>( base::BindRepeating(&FeaturePodControllerBase::OnIconPressed, weak_ptr_factory_.GetWeakPtr()), - /*is_togglable=*/true, FeatureTile::TileType::kPrimary); + /*is_togglable=*/true, + compact ? FeatureTile::TileType::kCompact + : FeatureTile::TileType::kPrimary); tile_ = tile.get(); + tile_->SetID(VIEW_ID_DND_FEATURE_TILE); - auto* session_controller = Shell::Get()->session_controller(); - const bool visible = session_controller->ShouldShowNotificationTray() && - !session_controller->IsScreenLocked(); - tile_->SetVisible(visible); - if (visible) { + const bool target_visibility = CalculateButtonVisibility(); + tile_->SetVisible(target_visibility); + if (target_visibility) { TrackVisibilityUMA(); } @@ -90,12 +98,13 @@ tile_->SetVectorIcon(kUnifiedMenuDoNotDisturbIcon); tile_->SetLabel( l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DO_NOT_DISTURB)); - tile_->SetSubLabelVisibility(false); + if (!compact) { + tile_->SetSubLabelVisibility(false); + } tile_->SetTooltipText(l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NOTIFICATIONS_TOGGLE_TOOLTIP, GetQuietModeStateTooltip())); - NotifierSettingsController::Get()->AddNotifierSettingsObserver(this); - OnQuietModeChanged(MessageCenter::Get()->IsQuietMode()); + return tile; }
diff --git a/ash/system/unified/quiet_mode_feature_pod_controller.h b/ash/system/unified/quiet_mode_feature_pod_controller.h index df10b41..76053d8 100644 --- a/ash/system/unified/quiet_mode_feature_pod_controller.h +++ b/ash/system/unified/quiet_mode_feature_pod_controller.h
@@ -36,9 +36,13 @@ ~QuietModeFeaturePodController() override; + // Referenced by `UnifiedSystemTrayController` to know whether to construct a + // Primary or Compact tile. + static bool CalculateButtonVisibility(); + // FeaturePodControllerBase: FeaturePodButton* CreateButton() override; - std::unique_ptr<FeatureTile> CreateTile() override; + std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override; QsFeatureCatalogName GetCatalogName() override; void OnIconPressed() override; void OnLabelPressed() override;
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc index 97a2292..8213ac2 100644 --- a/ash/system/unified/unified_system_tray_bubble.cc +++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -342,13 +342,7 @@ time_opened_.reset(); } -void UnifiedSystemTrayBubble::OnTabletModeStarted() { - UpdateBubbleBounds(); - tray_->CloseBubble(); -} - -void UnifiedSystemTrayBubble::OnTabletModeEnded() { - UpdateBubbleBounds(); +void UnifiedSystemTrayBubble::OnTabletPhysicalStateChanged() { tray_->CloseBubble(); }
diff --git a/ash/system/unified/unified_system_tray_bubble.h b/ash/system/unified/unified_system_tray_bubble.h index 3efca61..c8e8437a 100644 --- a/ash/system/unified/unified_system_tray_bubble.h +++ b/ash/system/unified/unified_system_tray_bubble.h
@@ -134,8 +134,7 @@ void RecordTimeToClick() override; // TabletModeObserver: - void OnTabletModeStarted() override; - void OnTabletModeEnded() override; + void OnTabletPhysicalStateChanged() override; // ShelfObserver: void OnAutoHideStateChanged(ShelfAutoHideState new_state) override;
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc index 4d916cd..db80a9c7 100644 --- a/ash/system/unified/unified_system_tray_controller.cc +++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -688,24 +688,41 @@ auto create_tile = [](std::unique_ptr<FeaturePodControllerBase> controller, std::vector<std::unique_ptr<FeaturePodControllerBase>>& controllers, - std::vector<std::unique_ptr<FeatureTile>>& tiles) { - tiles.push_back(controller->CreateTile()); + std::vector<std::unique_ptr<FeatureTile>>& tiles, + bool compact = false) { + tiles.push_back(controller->CreateTile(compact)); controllers.push_back(std::move(controller)); }; create_tile(std::make_unique<NetworkFeaturePodController>(this), feature_pod_controllers_, tiles); + + // CaptureMode and QuietMode tiles will be compact if both are visible. + bool capture_and_quiet_tiles_are_compact = + CaptureModeFeaturePodController::CalculateButtonVisibility() && + QuietModeFeaturePodController::CalculateButtonVisibility(); + create_tile(std::make_unique<CaptureModeFeaturePodController>(this), + feature_pod_controllers_, tiles, + capture_and_quiet_tiles_are_compact); + create_tile(std::make_unique<QuietModeFeaturePodController>(this), + feature_pod_controllers_, tiles, + capture_and_quiet_tiles_are_compact); + create_tile(std::make_unique<BluetoothFeaturePodController>(this), feature_pod_controllers_, tiles); - create_tile(std::make_unique<CaptureModeFeaturePodController>(this), - feature_pod_controllers_, tiles); - create_tile(std::make_unique<QuietModeFeaturePodController>(this), - feature_pod_controllers_, tiles); - create_tile(std::make_unique<AccessibilityFeaturePodController>(this), - feature_pod_controllers_, tiles); + + // Cast and RotationLock tiles will be compact if both are visible. + bool cast_and_rotation_tiles_are_compact = + CastFeaturePodController::CalculateButtonVisibility() && + RotationLockFeaturePodController::CalculateButtonVisibility(); create_tile(std::make_unique<CastFeaturePodController>(this), - feature_pod_controllers_, tiles); + feature_pod_controllers_, tiles, + cast_and_rotation_tiles_are_compact); create_tile(std::make_unique<RotationLockFeaturePodController>(), + feature_pod_controllers_, tiles, + cast_and_rotation_tiles_are_compact); + + create_tile(std::make_unique<AccessibilityFeaturePodController>(this), feature_pod_controllers_, tiles); create_tile(std::make_unique<PrivacyScreenFeaturePodController>(), feature_pod_controllers_, tiles); @@ -724,11 +741,6 @@ feature_pod_controllers_, tiles); } - // More placeholder tiles. - while (tiles.size() < 10) { - tiles.push_back(std::make_unique<FeatureTile>()); - } - quick_settings_view_->AddTiles(std::move(tiles)); }
diff --git a/ash/system/unified/unified_system_tray_unittest.cc b/ash/system/unified/unified_system_tray_unittest.cc index 903a732..a53db48 100644 --- a/ash/system/unified/unified_system_tray_unittest.cc +++ b/ash/system/unified/unified_system_tray_unittest.cc
@@ -6,6 +6,8 @@ #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/constants/ash_features.h" +#include "ash/public/cpp/ash_view_ids.h" +#include "ash/public/cpp/cast_config_controller.h" #include "ash/public/cpp/test/shell_test_api.h" #include "ash/root_window_controller.h" #include "ash/shelf/shelf.h" @@ -19,6 +21,8 @@ #include "ash/system/status_area_widget_test_helper.h" #include "ash/system/time/time_tray_item_view.h" #include "ash/system/time/time_view.h" +#include "ash/system/unified/feature_tile.h" +#include "ash/system/unified/feature_tiles_container_view.h" #include "ash/system/unified/ime_mode_view.h" #include "ash/system/unified/unified_slider_bubble_controller.h" #include "ash/system/unified/unified_system_tray_bubble.h" @@ -42,6 +46,40 @@ using message_center::MessageCenter; using message_center::Notification; +// `CastConfigController` must be overridden so a `cast_config_` object exists. +// This is required to make the cast tile visible in the +// `CastAndAutoRotateCompactTiles` unit test. Cast features will not be used. +class TestCastConfigController : public CastConfigController { + public: + TestCastConfigController() = default; + TestCastConfigController(const TestCastConfigController&) = delete; + TestCastConfigController& operator=(const TestCastConfigController&) = delete; + ~TestCastConfigController() override = default; + + // CastConfigController: + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} + bool HasMediaRouterForPrimaryProfile() const override { + return has_media_router_; + } + bool HasSinksAndRoutes() const override { return has_sinks_and_routes_; } + bool HasActiveRoute() const override { return false; } + bool AccessCodeCastingEnabled() const override { + return access_code_casting_enabled_; + } + void RequestDeviceRefresh() override {} + const std::vector<SinkAndRoute>& GetSinksAndRoutes() override { + return sinks_and_routes_; + } + void CastToSink(const std::string& sink_id) override {} + void StopCasting(const std::string& route_id) override {} + + bool has_media_router_ = true; + bool has_sinks_and_routes_ = false; + bool access_code_casting_enabled_ = false; + std::vector<SinkAndRoute> sinks_and_routes_; +}; + class UnifiedSystemTrayTest : public AshTestBase, public testing::WithParamInterface<bool> { public: @@ -56,6 +94,12 @@ feature_list_.InitAndEnableFeature(features::kQsRevamp); } AshTestBase::SetUp(); + cast_config_ = std::make_unique<TestCastConfigController>(); + } + + void TearDown() override { + cast_config_.reset(); + AshTestBase::TearDown(); } bool IsQsRevampEnabled() { return GetParam(); } @@ -137,6 +181,14 @@ return bubble ? bubble->GetBoundsInScreen() : gfx::Rect(); } + FeatureTile* GetTileById(int tile_view_id) { + views::View* tile_view = GetPrimaryUnifiedSystemTray() + ->bubble() + ->quick_settings_view() + ->GetViewByID(tile_view_id); + return static_cast<FeatureTile*>(tile_view); + } + TimeTrayItemView* time_view() { return GetPrimaryUnifiedSystemTray()->time_view_; } @@ -147,6 +199,7 @@ private: int id_ = 0; + std::unique_ptr<TestCastConfigController> cast_config_; base::test::ScopedFeatureList feature_list_; }; @@ -764,4 +817,75 @@ EXPECT_GT(464, bubble_view->height()); tray->CloseBubble(); } + +// Tests that the cast and auto-rotate tiles are presented in their compact +// version when they are both visible. +TEST_P(UnifiedSystemTrayTest, CastAndAutoRotateCompactTiles) { + // Feature tiles only exist when QsRevamp is enabled. + if (!IsQsRevampEnabled()) { + return; + } + + auto* tray = GetPrimaryUnifiedSystemTray(); + TabletModeController* tablet_mode_controller = + Shell::Get()->tablet_mode_controller(); + + // Test that the cast tile is in its primary form when in clamshell mode, + // when the auto-rotate tile is not visible. + EXPECT_FALSE(tablet_mode_controller->IsInTabletMode()); + tray->ShowBubble(); + + FeatureTile* cast_tile = GetTileById(VIEW_ID_CAST_MAIN_VIEW); + ASSERT_TRUE(cast_tile); + EXPECT_TRUE(cast_tile->GetVisible()); + EXPECT_EQ(cast_tile->tile_type(), FeatureTile::TileType::kPrimary); + + FeatureTile* autorotate_tile = GetTileById(VIEW_ID_AUTOROTATE_FEATURE_TILE); + EXPECT_FALSE(autorotate_tile->GetVisible()); + + tray->CloseBubble(); + + // Test that cast and auto-rotate tiles are compact in tablet mode. + tablet_mode_controller->SetEnabledForTest(true); + EXPECT_TRUE(tablet_mode_controller->IsInTabletMode()); + + tray->ShowBubble(); + + cast_tile = GetTileById(VIEW_ID_CAST_MAIN_VIEW); + EXPECT_TRUE(cast_tile->GetVisible()); + EXPECT_EQ(cast_tile->tile_type(), FeatureTile::TileType::kCompact); + + autorotate_tile = GetTileById(VIEW_ID_AUTOROTATE_FEATURE_TILE); + EXPECT_TRUE(autorotate_tile->GetVisible()); + EXPECT_EQ(autorotate_tile->tile_type(), FeatureTile::TileType::kCompact); + + tray->CloseBubble(); +} + +// Tests that the screen capture and DND tiles are presented in their compact +// version when they are both visible. +TEST_P(UnifiedSystemTrayTest, CaptureAndDNDCompactTiles) { + // Feature tiles only exist when QsRevamp is enabled. + if (!IsQsRevampEnabled()) { + return; + } + + auto* tray = GetPrimaryUnifiedSystemTray(); + + tray->ShowBubble(); + + FeatureTile* capture_tile = GetTileById(VIEW_ID_SCREEN_CAPTURE_FEATURE_TILE); + EXPECT_TRUE(capture_tile->GetVisible()); + EXPECT_EQ(capture_tile->tile_type(), FeatureTile::TileType::kCompact); + + FeatureTile* dnd_tile = GetTileById(VIEW_ID_DND_FEATURE_TILE); + EXPECT_TRUE(dnd_tile->GetVisible()); + EXPECT_EQ(dnd_tile->tile_type(), FeatureTile::TileType::kCompact); + + tray->CloseBubble(); + + // TODO(b/266000781): Add test cases for when one tile is visible but the + // other is not, to test they show in their primary forms. +} + } // namespace ash
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc index c0b0af1..9414fd8 100644 --- a/ash/wallpaper/wallpaper_controller_unittest.cc +++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -722,6 +722,8 @@ AccountId::FromUserEmailGaiaId(kChildEmail, kChildEmail); private: + // TODO(esum): Use ash::InProcessImageDecoder here instead and exercise actual + // decoding in these tests. data_decoder::test::InProcessDataDecoder in_process_data_decoder_; };
diff --git a/ash/webui/common/resources/network/apn_list.html b/ash/webui/common/resources/network/apn_list.html index 70e9f0e1..7e0818f 100644 --- a/ash/webui/common/resources/network/apn_list.html +++ b/ash/webui/common/resources/network/apn_list.html
@@ -42,7 +42,6 @@ <apn-list-item apn="[[item]]" is-connected="[[isApnConnected_(index)]]" - is-auto-detected="[[isApnAutoDetected_(index)]]" should-disallow-disabling-removing="[[shouldDisallowDisablingRemoving_(item)]]" should-disallow-enabling="[[shouldDisallowEnabling_(item)]]" guid="[[guid]]">
diff --git a/ash/webui/common/resources/network/apn_list.js b/ash/webui/common/resources/network/apn_list.js index 308f26ca..641dc25 100644 --- a/ash/webui/common/resources/network/apn_list.js +++ b/ash/webui/common/resources/network/apn_list.js
@@ -70,12 +70,6 @@ type: Object, value: ApnDetailDialogMode.CREATE, }, - - /** @private */ - isConnectedApnAutoDetected_: { - type: Boolean, - value: false, - }, }; } @@ -95,7 +89,6 @@ return []; } - this.isConnectedApnAutoDetected_ = false; const connectedApn = this.managedCellularProperties.connectedApn; const customApnList = this.managedCellularProperties.customApnList; @@ -105,7 +98,6 @@ } if (!customApnList || customApnList.length === 0) { - this.isConnectedApnAutoDetected_ = true; return [connectedApn]; } @@ -116,8 +108,6 @@ if (connectedApnIndex != -1) { customApnList.splice(connectedApnIndex, 1); - } else { - this.isConnectedApnAutoDetected_ = true; } return [connectedApn, ...customApnList]; @@ -135,16 +125,6 @@ } /** - * Returns true if the APN is automatically detected. - * @param {number} index index in the APNs array. - * @return {boolean} - * @private - */ - isApnAutoDetected_(index) { - return this.isApnConnected_(index) && this.isConnectedApnAutoDetected_; - } - - /** * Returns true if currentApn is the only enabled default APN and there is * at least one enabled attach APN. * @param {!ApnProperties} currentApn
diff --git a/ash/webui/common/resources/network/apn_list_item.html b/ash/webui/common/resources/network/apn_list_item.html index 0b7ce74..c57f9cb 100644 --- a/ash/webui/common/resources/network/apn_list_item.html +++ b/ash/webui/common/resources/network/apn_list_item.html
@@ -45,7 +45,7 @@ <div id="labelWrapper"> <div id="label" aria-hidden="true"> <div id="apnName">[[apn.accessPointName]]</div> - <div id="autoDetected" hidden="[[!isAutoDetected]]"> + <div id="autoDetected" hidden="[[apn.id]]"> [[i18n('apnAutoDetected')]] </div> </div>
diff --git a/ash/webui/common/resources/network/apn_list_item.js b/ash/webui/common/resources/network/apn_list_item.js index dada4dac..27a5dd1 100644 --- a/ash/webui/common/resources/network/apn_list_item.js +++ b/ash/webui/common/resources/network/apn_list_item.js
@@ -48,11 +48,6 @@ value: true, }, - isAutoDetected: { - type: Boolean, - value: true, - }, - shouldDisallowDisablingRemoving: { type: Boolean, value: false, @@ -101,8 +96,7 @@ detail: /** @type {!ApnEventData} */ ({ apn: this.apn, // Only allow editing if the APN is a custom APN. - mode: this.isAutoDetected ? ApnDetailDialogMode.VIEW : - ApnDetailDialogMode.EDIT, + mode: this.apn.id ? ApnDetailDialogMode.EDIT : ApnDetailDialogMode.VIEW, }), })); }
diff --git a/ash/webui/personalization_app/mojom/personalization_app.mojom b/ash/webui/personalization_app/mojom/personalization_app.mojom index ff5b2342..4809683 100644 --- a/ash/webui/personalization_app/mojom/personalization_app.mojom +++ b/ash/webui/personalization_app/mojom/personalization_app.mojom
@@ -7,6 +7,7 @@ import "mojo/public/mojom/base/big_buffer.mojom"; import "mojo/public/mojom/base/file_path.mojom"; import "mojo/public/mojom/base/string16.mojom"; +import "mojo/public/mojom/base/time.mojom"; import "skia/public/mojom/skcolor.mojom"; import "url/mojom/url.mojom"; @@ -96,6 +97,9 @@ // URL to the bytes of the album's displayed cover photo. url.mojom.Url preview; + + // Latest modification timestamp used to sort albums. + mojo_base.mojom.Time timestamp; }; // Represents the server-provided response to a Google Photos albums request.
diff --git a/ash/webui/personalization_app/resources/BUILD.gn b/ash/webui/personalization_app/resources/BUILD.gn index ef93dde..9cf854e 100644 --- a/ash/webui/personalization_app/resources/BUILD.gn +++ b/ash/webui/personalization_app/resources/BUILD.gn
@@ -25,6 +25,7 @@ "js/ambient/ambient_controller.ts", "js/ambient/ambient_interface_provider.ts", "js/ambient/ambient_observer.ts", + "js/ambient/ambient_preview_base.ts", "js/ambient/ambient_reducers.ts", "js/ambient/ambient_state.ts", "js/ambient/utils.ts", @@ -72,8 +73,9 @@ web_component_files = [ "js/ambient/album_list_element.ts", "js/ambient/albums_subpage_element.ts", + "js/ambient/ambient_preview_large_element.ts", + "js/ambient/ambient_preview_small_element.ts", "js/ambient/art_album_dialog_element.ts", - "js/ambient/ambient_preview_element.ts", "js/ambient/ambient_subpage_element.ts", "js/ambient/ambient_zero_state_svg_element.ts", "js/ambient/ambient_weather_element.ts",
diff --git a/ash/webui/personalization_app/resources/js/ambient/album_list_element.ts b/ash/webui/personalization_app/resources/js/ambient/album_list_element.ts index da43159..61a80bf5 100644 --- a/ash/webui/personalization_app/resources/js/ambient/album_list_element.ts +++ b/ash/webui/personalization_app/resources/js/ambient/album_list_element.ts
@@ -14,10 +14,9 @@ import {AmbientModeAlbum, TopicSource} from '../personalization_app.mojom-webui.js'; import {WithPersonalizationStore} from '../personalization_store.js'; -import {getCountText} from '../utils.js'; +import {getCountText, isRecentHighlightsAlbum} from '../utils.js'; import {getTemplate} from './album_list_element.html.js'; -import {isRecentHighlightsAlbum} from './utils.js'; export interface AlbumList { $: {grid: IronListElement};
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts index 18ffa8e3..7a88b07 100644 --- a/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts +++ b/ash/webui/personalization_app/resources/js/ambient/ambient_observer.ts
@@ -8,11 +8,10 @@ import {logGooglePhotosPreviewsLoadTime} from '../personalization_metrics_logger.js'; import {Paths} from '../personalization_router_element.js'; import {PersonalizationStore} from '../personalization_store.js'; -import {isNonEmptyArray} from '../utils.js'; +import {isNonEmptyArray, isRecentHighlightsAlbum} from '../utils.js'; import {setAlbumsAction, setAmbientModeEnabledAction, setAmbientUiVisibilityAction, setAnimationThemeAction, setGooglePhotosAlbumsPreviewsAction, setTemperatureUnitAction, setTopicSourceAction} from './ambient_actions.js'; import {getAmbientProvider} from './ambient_interface_provider.js'; -import {isRecentHighlightsAlbum} from './utils.js'; /** @fileoverview listens for updates on ambient mode changes. */
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_base.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_base.ts new file mode 100644 index 0000000..1bc38a64 --- /dev/null +++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_base.ts
@@ -0,0 +1,208 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview A base polymer element that previews the current selected + * screensaver. Extend this element and provide a template to make a full + * polymer element. + */ + +import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; +import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; +import {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js'; + +import {setErrorAction} from '../personalization_actions.js'; +import {AmbientModeAlbum, TopicSource} from '../personalization_app.mojom-webui.js'; +import {WithPersonalizationStore} from '../personalization_store.js'; +import {isNonEmptyArray} from '../utils.js'; + +import {AmbientObserver} from './ambient_observer.js'; +import {getPhotoCount, getTopicSourceName} from './utils.js'; + +/** + * Removes the resolution suffix at the end of an image (from character '=' to + * the end) and replace it with a new resolution suffix. + */ +function replaceResolutionSuffix(url: string, resolution: string): string { + return url.replace(/=w[\w-]+$/, resolution); +} + +export class AmbientPreviewBase extends WithPersonalizationStore { + static get properties(): PolymerElementProperties { + return { + ambientModeEnabled_: Boolean, + albums_: { + type: Array, + value: null, + }, + topicSource_: { + type: Object, + value: null, + }, + previewAlbums_: { + type: Array, + computed: 'computePreviewAlbums_(albums_, topicSource_)', + }, + firstPreviewAlbum_: { + type: AmbientModeAlbum, + computed: 'computeFirstPreviewAlbum_(previewAlbums_)', + }, + loading_: { + type: Boolean, + computed: + 'computeLoading_(ambientModeEnabled_, albums_, topicSource_, googlePhotosAlbumsPreviews_)', + observer: 'onLoadingChanged_', + }, + googlePhotosAlbumsPreviews_: { + type: Array, + value: null, + }, + isAmbientSubpageUiChangeEnabled_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('isAmbientSubpageUiChangeEnabled'); + }, + }, + isAmbientModeManaged_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('isAmbientModeManaged'); + }, + }, + }; + } + + protected ambientModeEnabled_: boolean|null; + protected googlePhotosAlbumsPreviews_: Url[]|null; + protected isAmbientSubpageUiChangeEnabled_: boolean; + protected previewAlbums_: AmbientModeAlbum[]|null; + protected topicSource_: TopicSource|null; + + private albums_: AmbientModeAlbum[]|null; + private firstPreviewAlbum_: AmbientModeAlbum|null; + private isAmbientModeManaged_: boolean; + private loading_: boolean; + + private loadingTimeoutId_: number|null = null; + + override ready() { + super.ready(); + AmbientObserver.initAmbientObserverIfNeeded(); + } + + override connectedCallback() { + super.connectedCallback(); + this.watch( + 'ambientModeEnabled_', state => state.ambient.ambientModeEnabled); + this.watch('albums_', state => state.ambient.albums); + this.watch( + 'googlePhotosAlbumsPreviews_', + state => state.ambient.googlePhotosAlbumsPreviews); + this.watch('topicSource_', state => state.ambient.topicSource); + this.updateFromStore(); + } + + private computeLoading_(): boolean { + return this.ambientModeEnabled_ === null || this.albums_ === null || + this.topicSource_ === null || this.googlePhotosAlbumsPreviews_ === null; + } + + private onLoadingChanged_(value: boolean) { + if (!value && this.loadingTimeoutId_) { + window.clearTimeout(this.loadingTimeoutId_); + this.loadingTimeoutId_ = null; + return; + } + if (value && !this.loadingTimeoutId_) { + this.loadingTimeoutId_ = window.setTimeout( + () => this.dispatch( + setErrorAction({message: this.i18n('ambientModeNetworkError')})), + 60 * 1000); + } + } + + private computePreviewAlbums_(): AmbientModeAlbum[]|null { + return (this.albums_ || []) + .filter( + album => album.topicSource === this.topicSource_ && album.checked && + album.url); + } + + private computeFirstPreviewAlbum_(): AmbientModeAlbum|null { + if (isNonEmptyArray(this.previewAlbums_)) { + return this.previewAlbums_[0]; + } + return null; + } + + private getPreviewContainerClass_(): string { + const classes = []; + + if (this.ambientModeEnabled_ || this.loading_) { + classes.push('zero-state-disabled'); + } + + if (!this.ambientModeEnabled_) { + classes.push('ambient-mode-disabled'); + } + + /* TODO(b/253470553): Remove this condition after Ambient subpage UI change + * is released. */ + if (!this.isAmbientSubpageUiChangeEnabled_) { + classes.push('pre-ui-change'); + } + return classes.join(' '); + } + + private getPreviewImage_(album: AmbientModeAlbum|null): string { + // Replace the resolution suffix appended at the end of the images + // with a new resolution suffix of 512px so that we do not download very + // large images. This won't impact images with no resolution suffix. + return album && album.url ? + replaceResolutionSuffix(album.url.url, '=s512') : + ''; + } + + private getPreviewTextAriaLabel_(): string { + return `${this.i18n('currentlySet')} ${this.getAlbumTitle_()} ${ + this.getAlbumDescription_()}`; + } + + private getAlbumTitle_(): string { + return this.firstPreviewAlbum_ ? this.firstPreviewAlbum_.title : ''; + } + + private getAlbumDescription_(): string { + if (!isNonEmptyArray(this.previewAlbums_) || this.topicSource_ === null) { + return ''; + } + switch (this.previewAlbums_.length) { + case 1: + // For only 1 selected album, album description includes image source + // and number of photos in the album (only applicable for Google + // Photos). + const topicSourceDesc = getTopicSourceName(this.topicSource_); + // TODO(b/223834394): replace dot separator symbol • with an icon/image. + return this.topicSource_ === TopicSource.kArtGallery ? + topicSourceDesc : + `${topicSourceDesc} • ${ + getPhotoCount(this.previewAlbums_[0].numberOfPhotos)}`; + case 2: + case 3: + // For 2-3 selected albums, album description includes the titles of all + // selected albums except the first one already shown in album title + // text. + const albumTitles = + this.previewAlbums_.slice(1).map(album => album.title); + return albumTitles.join(', '); + default: + // For more than 3 selected albums, album description includes the title + // of the second album and the number of remaining albums. + // For example: Sweden 2020, +2 more albums. + return this.i18n( + 'ambientModeMultipleAlbumsDesc', this.previewAlbums_[1].title, + this.previewAlbums_.length - 2); + } + } +}
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_element.html deleted file mode 100644 index 85713a1..0000000 --- a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_element.html +++ /dev/null
@@ -1,492 +0,0 @@ -<style include="common cros-button-style"> - :host([main-page]) #container { - border: 1px solid var(--cros-separator-color); - border-radius: 16px; - display: grid; - grid-template-areas: - '. slot slot slot .' - '. image image image .' - '. . . . .' - '. message message message .' - '. mainpage-desc . collage .' - '. . . . .'; - grid-template-columns: 20px auto 192px auto 20px; - grid-template-rows: auto minmax(158px, 220px) 20px 192px auto 20px; - height: 100%; - } - - :host([main-page]) #container.zero-state-disabled { - grid-template-areas: - '. slot .' - '. image .' - '. . .' - '. collage .' - '. mainpage-desc .' - '. . .'; - grid-template-columns: 20px minmax(0,1fr) 20px; - grid-template-rows: auto minmax(158px, 220px) 20px 130px auto 18px; - } - - :host([main-page]) #container.pre-ui-change { - grid-template-areas: - '. slot slot slot .' - '. image image image .' - '. . . . .' - '. message message message .' - '. mainpage-desc . collage .' - '. . . . .'; - grid-template-columns: 20px minmax(0,1fr) 16px 106px 20px; - grid-template-rows: auto minmax(158px, 220px) 20px 106px auto 24px; - } - - :host([main-page]) #container.pre-ui-change.zero-state-disabled { - grid-template-rows: auto minmax(158px, 220px) 20px auto 106px 24px; - } - - #messageContainer { - align-items: center; - display: flex; - flex-direction: column; - grid-area: message; - justify-content: space-between; - } - - #messageContainer.pre-ui-change .text { - color: var(--cros-text-color-secondary); - font: var(--cros-body-1-font); - line-height: 1.5; - margin-top: 12px; - text-align: center; - width: unset; - } - - #messageContainer .text { - color: var(--cros-sys-on_primary_container, var(--cros-text-color-secondary)); - font: var(--cros-body-1-font); - line-height: 1.5; - margin-top: 56px; - text-align: center; - width: 128px; - } - - #messageContainer cr-button { - margin-bottom: 50px; - margin-top: 8px; - } - - ambient-zero-state-svg { - position: absolute; - z-index: -10000; - } - - #messageContainer.pre-ui-change cr-button { - margin-top: 20px; - } - - :host([main-page]) #zeroStateTextContainer, - :host(:not([main-page])) #messageContainer { - display: none; - } - - /* TODO(b/253470553): Remove after Ambient subpage UI change is released. */ - :host(:not([main-page])) #container.pre-ui-change { - border: none; - display: grid; - grid-template-areas: - '. . .' - 'image . subpage-desc' - 'image . buttons' - '. . .'; - grid-template-columns: 224px 32px minmax(0,1fr); - grid-template-rows: 20px 118px 34px 20px; - } - - :host(:not([main-page])) #container.ambient-mode-disabled { - grid-template-areas: - 'image . subpage-desc' - '. . .'; - grid-template-columns: 224px 32px minmax(0,1fr); - grid-template-rows: 152px 20px; - } - - :host(:not([main-page])) #container { - border: none; - display: grid; - grid-template-areas: - 'image . subpage-desc' - 'image . buttons' - '. . .'; - grid-template-columns: 224px 32px minmax(0,1fr); - grid-template-rows: 118px 34px 20px; - } - - :host([main-page]) #buttonContainer, - :host([main-page]) .currently-set-text { - display: none; - } - - :host(:not([main-page])) #buttonContainer, - :host(:not([main-page])) .currently-set-text { - display: inline-flex; - } - - :host([main-page]) #imageContainer, - :host([main-page]) #imagePlaceholder { - display: flex; - height: 100%; - justify-self: center; - max-width: 360px; - min-width: 252px; - width: 100%; - } - - ::slotted(div[id='ambientLabel']) { - align-items: center; - background: none; - border: none; - display: flex; - flex-flow: row nowrap; - grid-area: slot; - justify-content: space-between; - margin-top: 12px; - } - - .album-info-mainpage, - .album-info-subpage, - .zero-state-info-subpage { - display: none; - } - - :host([main-page]) .album-info-mainpage { - display: flex; - grid-area: mainpage-desc; - justify-content: center; - } - - :host(:not([main-page])) .album-info-subpage, - :host(:not([main-page])) .zero-state-info-subpage { - display: flex; - grid-area: subpage-desc; - justify-content: center; - } - - :host([main-page]) .album-info-mainpage:not(.pre-ui-change) span { - margin-inline: auto; - } - - #imageContainer, - #imagePlaceholder { - grid-area: image; - } - - #imageContainer[ambient-mode-managed] img.disabled { - opacity: var(--cros-disabled-opacity); - } - - #imageContainer img.disabled { - /** - * Use 50% for image instead of default cros-disabled-opacity. - * TODO(b/236415314) get this into design system as a semantic value. - */ - opacity: 50%; - } - - :host(:not([main-page])) #collageContainer, - :host(:not([main-page])) #collagePlaceholder { - display: none; - } - - :host([main-page]) #albumTitle { - color: var(--cros-text-color-primary); - font: var(--cros-display-7-font); - margin-top: 16px; - } - - :host([main-page]) #albumTitle.pre-ui-change { - margin-top: 4px; - } - - :host([main-page]) #albumDescription { - color: var(--cros-text-color-secondary); - font: var(--cros-body-2-font); - margin-top: 2px; - } - - :host([main-page]) #albumDescription.pre-ui-change { - margin-top: 4px; - } - - :host([main-page]) #collageContainer, - :host([main-page]) #collagePlaceholder { - border-radius: 12px; - display: grid; - gap: 2px; - grid-area: collage; - overflow: hidden; - } - - :host([main-page]) #collageContainer { - border: 1px solid rgba(0, 0, 0, 0.08); - } - - #collageContainer { - grid-template-columns: repeat(2, minmax(0,1fr)); - grid-template-rows: repeat(2, minmax(0,1fr)); - } - - #collageContainer.collage-1 .collage-item:first-child { - grid-row: 1 / 3; - } - - #collageContainer.collage-1 .collage-item:first-child, - #collageContainer.collage-2 .collage-item:first-child, - #collageContainer.collage-2 .collage-item:nth-child(2), - #collageContainer.collage-3 .collage-item:nth-child(3) { - grid-column: 1 / 3; - } - - .collage-item { - height: 100%; - object-fit: cover; - width: 100%; - } - - #buttonContainer { - grid-area: buttons; - } - - #buttonContainer .text { - margin-inline-start: 8px; - } - #buttonContainer .previewButtonDisabled { - cursor: wait; - pointer-events: none; - } - - #buttonContainer cr-button { - border-color: var(--cros-button-stroke-color-secondary); - border-radius: 16px; - } - - #buttonContainer .spinner { - height: 20px; - width: 20px; - } - - :host(:not([main-page])) #thumbnailContainer, - :host(:not([main-page])) #thumbnailPlaceholder { - display: none; - } - - :host([main-page]) #thumbnailContainer, - :host([main-page]) #thumbnailPlaceholder { - display: grid; - grid-area: collage; - justify-self: center; - max-width: 360px; - min-width: 252px; - overflow: hidden; - width: 100%; - } - - .thumbnail-item { - height: 100%; - overflow: hidden; - width: 100%; - } - - .thumbnail-item img { - height: 100%; - object-fit: fill; - width: 100%; - } - - #thumbnailContainer.thumbnail-1 .thumbnail-item { - border-radius: 60px; - } - - #thumbnailContainer.thumbnail-2 { - column-gap: 12px; - grid-template-columns: 130px minmax(0,1fr); - } - - #thumbnailContainer.thumbnail-2 .thumbnail-item:first-of-type { - clip-path: url(#squiggleClip); - } - - #thumbnailContainer.thumbnail-2 .thumbnail-item:last-of-type { - border-radius: 60px; - } - - #thumbnailContainer.thumbnail-3 { - column-gap: 8px; - grid-template-columns: minmax(0,1fr) 32px 32px; - } - - #thumbnailContainer.thumbnail-3 .thumbnail-item:first-of-type { - border-radius: 60px; - } - - #thumbnailContainer.thumbnail-3 .thumbnail-item:last-of-type img, - #thumbnailContainer.thumbnail-3 .thumbnail-item:nth-last-of-type(2) img { - border-radius: 16px; - object-fit: none; - } -</style> -<div class$="[[getPreviewContainerClass_(ambientModeEnabled_, loading_)]]" id="container"> - <slot></slot> - <template is="dom-if" if="[[loading_]]"> - <div id="imagePlaceholder" class="placeholder"></div> - <template is="dom-if" if="[[isAmbientSubpageUiChangeEnabled_]]"> - <div id="thumbnailPlaceholder" class="placeholder"></div> - </template> - <div id="textPlaceholder" class="preview-text-placeholder album-info-mainpage album-info-subpage"> - <div class="placeholder currently-set-text"></div> - <div class="placeholder"></div> - <div class="placeholder"></div> - </div> - <div id="collagePlaceholder" class="placeholder"></div> - </template> - <template is="dom-if" if="[[!loading_]]"> - <template is="dom-if" if="[[!ambientModeEnabled_]]"> - <div id="imageContainer" class="preview-image-container" ambient-mode-managed$="[[isAmbientModeManaged_]]" aria-hidden="true"> - <div class="preview-image-border"></div> - <img class="preview-image disabled" src="//personalization/images/slideshow.png"> - </div> - <h3 id="zeroStateTextContainer" - class="preview-text-container zero-state-info-subpage" - aria-label$="$i18n{ambientModeMainPageZeroStateMessage}"> - <span class="text"> - $i18n{ambientModeMainPageZeroStateMessage} - </span> - </h3> - <template is="dom-if" if="[[!isAmbientSubpageUiChangeEnabled_]]"> - <div id="messageContainer" class="pre-ui-change"> - <span class="text" id="turnOnDescription"> - $i18n{ambientModeMainPageZeroStateMessage} - </span> - <cr-button class="primary" on-click="onClickAmbientModeButton_" - aria-describedby="turnOnDescription"> - <div>$i18n{ambientModeTurnOnLabel}</div> - </cr-button> - </div> - </template> - <template is="dom-if" if="[[isAmbientSubpageUiChangeEnabled_]]"> - <div id="messageContainer"> - <ambient-zero-state-svg></ambient-zero-state-svg> - <template is="dom-if" if="[[!isAmbientModeManaged_]]"> - <span class="text" id="turnOnDescription"> - $i18n{ambientModeMainPageZeroStateMessageV2} - </span> - <cr-button class="primary" on-click="onClickAmbientModeButton_" - aria-describedby="turnOnDescription"> - <div>$i18n{ambientModeTurnOnLabel}</div> - </cr-button> - </template> - <template is="dom-if" if="[[isAmbientModeManaged_]]"> - <span class="text" id="turnOnDescription"> - $i18n{ambientModeMainPageEnterpriseUserMessage} - </span> - <cr-button class="primary"> - <!-- TODO(b/258838122): on-click behavior --> - <div>$i18n{ambientModeLearnMoreLabel}</div> - </cr-button> - </template> - </div> - </template> - </template> - <template is="dom-if" if="[[ambientModeEnabled_]]"> - <!-- TODO(b/226235802) - Add failed/error state when no previewAlbums available. - Currently, we show blank containers --> - <template is="dom-if" if="[[previewAlbums_]]"> - <div id="imageContainer" class="preview-image-container"> - <div class="preview-image-border"></div> - <template is="dom-if" if="[[clickable]]"> - <img class="preview-image clickable" is="cr-auto-img" - on-click="onClickPreviewImage_" - on-keypress="onClickPreviewImage_" - auto-src="[[getPreviewImage_(firstPreviewAlbum_)]]" - alt$="[[getAlbumTitle_(firstPreviewAlbum_)]]" - is-google-photos> - </template> - <template is="dom-if" if="[[!clickable]]"> - <img class="preview-image" is="cr-auto-img" - auto-src="[[getPreviewImage_(firstPreviewAlbum_)]]" - alt$="[[getAlbumTitle_(firstPreviewAlbum_)]]" - is-google-photos> - </template> - </div> - <template is="dom-if" if="[[isAmbientSubpageUiChangeEnabled_]]"> - <div id="thumbnailContainer" aria-hidden="true" - class$="[[getThumbnailContainerClass_(collageImages_)]]" - on-click="onClickPhotoCollage_" - on-keypress="onClickPhotoCollage_"> - <template is="dom-repeat" items="[[collageImages_]]"> - <div class="thumbnail-item"> - <img is="cr-auto-img" auto-src="[[item.url]]" is-google-photos> - </div> - </template> - </div> - <!-- Use inline svg in order to reference the clip path by url() --> - <svg width="0" height="0" viewBox="0 0 130 130" fill="none" xmlns="http://www.w3.org/2000/svg"> - <defs> - <clipPath id="squiggleClip"> - <path d="M 1.4375 72.371094 C -0.332031 69.402344 -0.476562 65.738281 1.054688 62.640625 L 3.210938 58.28125 C 4.125 56.429688 4.457031 54.339844 4.15625 52.296875 L 3.457031 47.484375 C 2.957031 44.066406 4.226562 40.625 6.824219 38.347656 L 10.484375 35.148438 C 12.039062 33.785156 13.144531 31.984375 13.652344 29.980469 L 14.84375 25.265625 C 15.691406 21.914062 18.179688 19.222656 21.453125 18.113281 L 26.058594 16.554688 C 28.015625 15.894531 29.726562 14.652344 30.960938 12.996094 L 33.867188 9.097656 C 35.929688 6.324219 39.261719 4.789062 42.710938 5.019531 L 47.5625 5.339844 C 49.625 5.480469 51.679688 4.984375 53.453125 3.925781 L 57.628906 1.4375 C 60.597656 -0.332031 64.261719 -0.476562 67.359375 1.054688 L 71.71875 3.210938 C 73.570312 4.125 75.660156 4.457031 77.703125 4.15625 L 82.515625 3.457031 C 85.933594 2.957031 89.375 4.226562 91.652344 6.824219 L 94.851562 10.484375 C 96.214844 12.039062 98.015625 13.144531 100.019531 13.652344 L 104.734375 14.84375 C 108.085938 15.691406 110.777344 18.179688 111.886719 21.453125 L 113.445312 26.058594 C 114.105469 28.015625 115.347656 29.726562 117.003906 30.960938 L 120.902344 33.867188 C 123.675781 35.929688 125.210938 39.261719 124.980469 42.710938 L 124.660156 47.5625 C 124.519531 49.625 125.015625 51.679688 126.074219 53.453125 L 128.5625 57.628906 C 130.332031 60.597656 130.476562 64.261719 128.945312 67.359375 L 126.792969 71.71875 C 125.875 73.570312 125.542969 75.660156 125.84375 77.703125 L 126.542969 82.515625 C 127.042969 85.933594 125.773438 89.375 123.175781 91.652344 L 119.515625 94.851562 C 117.960938 96.214844 116.855469 98.015625 116.347656 100.019531 L 115.15625 104.734375 C 114.308594 108.085938 111.820312 110.777344 108.546875 111.886719 L 103.941406 113.445312 C 101.984375 114.105469 100.273438 115.347656 99.039062 117.003906 L 96.132812 120.902344 C 94.070312 123.675781 90.738281 125.210938 87.289062 124.980469 L 82.4375 124.660156 C 80.375 124.519531 78.320312 125.015625 76.546875 126.074219 L 72.371094 128.5625 C 69.402344 130.332031 65.738281 130.476562 62.640625 128.945312 L 58.28125 126.792969 C 56.429688 125.875 54.339844 125.542969 52.296875 125.84375 L 47.484375 126.542969 C 44.066406 127.042969 40.625 125.773438 38.347656 123.175781 L 35.148438 119.515625 C 33.785156 117.960938 31.984375 116.855469 29.980469 116.347656 L 25.265625 115.15625 C 21.914062 114.308594 19.222656 111.820312 18.113281 108.546875 L 16.554688 103.941406 C 15.894531 101.984375 14.652344 100.273438 12.996094 99.039062 L 9.097656 96.132812 C 6.324219 94.070312 4.789062 90.738281 5.019531 87.289062 L 5.339844 82.4375 C 5.480469 80.375 4.984375 78.320312 3.925781 76.546875 Z M 1.4375 72.371094 "></path> - </clipPath> - </defs> - </svg> - <div id="buttonContainer" hidden$="[[!isScreenSaverPreviewEnabled_()]]"> - <cr-button class$="[[getScreenSaverPreviewClass_(ambientUiVisibility_)]]" on-click="startScreenSaverPreview_"> - <iron-icon icon="personalization:fullscreen" hidden$="[[screenSaverPreviewActive_]]"></iron-icon> - <paper-spinner-lite active class="spinner" hidden$="[[!screenSaverPreviewActive_]]"></paper-spinner-lite> - <div class="text">[[getScreenSaverPreviewText_(ambientUiVisibility_)]]</div> - </cr-button> - </div> - <h3 id="textContainer" class="preview-text-container album-info-mainpage album-info-subpage" - aria-label$="[[getPreviewTextAriaLabel_(firstPreviewAlbum_, topicSource_, previewAlbums_)]]"> - <span id="currentlySet" class="currently-set-text" aria-hidden="true"> - $i18n{currentlySet} - </span> - <span id="albumTitle" aria-hidden="true" title="[[getAlbumTitle_(firstPreviewAlbum_)]]"> - [[getAlbumTitle_(firstPreviewAlbum_)]] - </span> - <span id="albumDescription" aria-hidden="true"> - [[getAlbumDescription_(topicSource_, previewAlbums_)]] - </span> - </h3> - </template> - <template is="dom-if" if="[[!isAmbientSubpageUiChangeEnabled_]]"> - <h3 id="textContainer" class="preview-text-container album-info-mainpage album-info-subpage pre-ui-change" - aria-label$="[[getPreviewTextAriaLabel_(firstPreviewAlbum_, topicSource_, previewAlbums_)]]"> - <span id="currentlySet" class="currently-set-text" aria-hidden="true"> - $i18n{currentlySet} - </span> - <span id="albumTitle" aria-hidden="true" title="[[getAlbumTitle_(firstPreviewAlbum_)]]"> - [[getAlbumTitle_(firstPreviewAlbum_)]] - </span> - <span id="albumDescription" aria-hidden="true"> - [[getAlbumDescription_(topicSource_, previewAlbums_)]] - </span> - </h3> - <div id="buttonContainer" hidden$="[[!isScreenSaverPreviewEnabled_()]]"> - <cr-button class$="[[getScreenSaverPreviewClass_(ambientUiVisibility_)]]" on-click="startScreenSaverPreview_"> - <iron-icon icon="personalization:fullscreen" hidden$="[[screenSaverPreviewActive_]]"></iron-icon> - <paper-spinner-lite active class="spinner" hidden$="[[!screenSaverPreviewActive_]]"></paper-spinner-lite> - <div class="text">[[getScreenSaverPreviewText_(ambientUiVisibility_)]]</div> - </cr-button> - </div> - <div aria-hidden="true" - class$="[[getCollageContainerClass_(collageImages_)]]" - on-click="onClickPhotoCollage_" - on-keypress="onClickPhotoCollage_" - id="collageContainer"> - <template is="dom-repeat" items="[[collageImages_]]"> - <img class="collage-item" is="cr-auto-img" - auto-src="[[item.url]]" is-google-photos> - </template> - </div> - </template> - </template> - </template> - </template> -</div>
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_element.ts deleted file mode 100644 index 4988b50..0000000 --- a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_element.ts +++ /dev/null
@@ -1,352 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview A polymer component that previews the current selected - * screensaver. - */ - -import 'chrome://resources/cr_elements/cr_auto_img/cr_auto_img.js'; -import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; -import './ambient_zero_state_svg_element.js'; -import '../../css/common.css.js'; -import '../../css/cros_button_style.css.js'; - -import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; -import {assert} from 'chrome://resources/js/assert_ts.js'; -import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; - -import {setErrorAction} from '../personalization_actions.js'; -import {AmbientModeAlbum, AmbientUiVisibility, TopicSource} from '../personalization_app.mojom-webui.js'; -import {logAmbientModeOptInUMA} from '../personalization_metrics_logger.js'; -import {Paths, PersonalizationRouter} from '../personalization_router_element.js'; -import {WithPersonalizationStore} from '../personalization_store.js'; -import {isNonEmptyArray} from '../utils.js'; - -import {setAmbientModeEnabled, startScreenSaverPreview} from './ambient_controller.js'; -import {getAmbientProvider} from './ambient_interface_provider.js'; -import {AmbientObserver} from './ambient_observer.js'; -import {getTemplate} from './ambient_preview_element.html.js'; -import {getPhotoCount, getTopicSourceName} from './utils.js'; - -/** - * Removes the resolution suffix at the end of an image (from character '=' to - * the end) and replace it with a new resolution suffix. - */ -function replaceResolutionSuffix(url: string, resolution: string): string { - return url.replace(/=w[\w-]+$/, resolution); -} - -export class AmbientPreview extends WithPersonalizationStore { - static get is() { - return 'ambient-preview'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - clickable: { - type: Boolean, - value: false, - }, - ambientModeEnabled_: Boolean, - albums_: { - type: Array, - value: null, - }, - topicSource_: { - type: Object, - value: null, - }, - previewAlbums_: { - type: Array, - computed: 'computePreviewAlbums_(albums_, topicSource_)', - }, - firstPreviewAlbum_: { - type: AmbientModeAlbum, - computed: 'computeFirstPreviewAlbum_(previewAlbums_)', - }, - loading_: { - type: Boolean, - computed: - 'computeLoading_(ambientModeEnabled_, albums_, topicSource_, googlePhotosAlbumsPreviews_)', - observer: 'onLoadingChanged_', - }, - googlePhotosAlbumsPreviews_: { - type: Array, - value: null, - }, - collageImages_: { - type: Array, - computed: - 'computeCollageImages_(topicSource_, previewAlbums_, googlePhotosAlbumsPreviews_)', - }, - ambientUiVisibility_: { - type: AmbientUiVisibility, - value: null, - }, - screenSaverPreviewActive_: { - type: Boolean, - computed: 'computeScreenSaverPreviewActive_(ambientUiVisibility_)', - }, - isAmbientSubpageUiChangeEnabled_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('isAmbientSubpageUiChangeEnabled'); - }, - }, - isAmbientModeManaged_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('isAmbientModeManaged'); - }, - }, - }; - } - - clickable: boolean; - - private ambientModeEnabled_: boolean|null; - private albums_: AmbientModeAlbum[]|null; - private topicSource_: TopicSource|null; - private previewAlbums_: AmbientModeAlbum[]|null; - private firstPreviewAlbum_: AmbientModeAlbum|null; - private loading_: boolean; - private googlePhotosAlbumsPreviews_: Url[]|null; - private collageImages_: Url[]; - private ambientUiVisibility_: AmbientUiVisibility|null; - private screenSaverPreviewActive_: boolean; - private isAmbientSubpageUiChangeEnabled_: boolean; - private isAmbientModeManaged_: boolean; - - private loadingTimeoutId_: number|null = null; - - override ready() { - super.ready(); - AmbientObserver.initAmbientObserverIfNeeded(); - } - - override connectedCallback() { - super.connectedCallback(); - this.watch( - 'ambientModeEnabled_', state => state.ambient.ambientModeEnabled); - this.watch('albums_', state => state.ambient.albums); - this.watch( - 'googlePhotosAlbumsPreviews_', - state => state.ambient.googlePhotosAlbumsPreviews); - this.watch('topicSource_', state => state.ambient.topicSource); - this.watch( - 'ambientUiVisibility_', state => state.ambient.ambientUiVisibility); - this.updateFromStore(); - } - - private isScreenSaverPreviewEnabled_() { - return loadTimeData.getBoolean('isScreenSaverPreviewEnabled'); - } - - private startScreenSaverPreview_(event: Event) { - event.stopPropagation(); - startScreenSaverPreview(getAmbientProvider()); - } - - private getScreenSaverPreviewClass_(): string { - return this.screenSaverPreviewActive_ ? 'previewButtonDisabled' : - 'previewButton'; - } - - private getScreenSaverPreviewText_(): string { - return this.screenSaverPreviewActive_ ? - this.i18n('screenSaverPreviewDownloading') : - this.i18n('screenSaverPreviewButton'); - } - - private computeScreenSaverPreviewActive_(): boolean { - return this.ambientUiVisibility_ === AmbientUiVisibility.kPreview; - } - - private computeLoading_(): boolean { - return this.ambientModeEnabled_ === null || this.albums_ === null || - this.topicSource_ === null || this.googlePhotosAlbumsPreviews_ === null; - } - - private onLoadingChanged_(value: boolean) { - if (!value && this.loadingTimeoutId_) { - window.clearTimeout(this.loadingTimeoutId_); - this.loadingTimeoutId_ = null; - return; - } - if (value && !this.loadingTimeoutId_) { - this.loadingTimeoutId_ = window.setTimeout( - () => this.dispatch( - setErrorAction({message: this.i18n('ambientModeNetworkError')})), - 60 * 1000); - } - } - - /** Enable ambient mode and navigates to the ambient subpage. */ - private async onClickAmbientModeButton_(event: Event) { - assert(this.ambientModeEnabled_ === false); - event.stopPropagation(); - logAmbientModeOptInUMA(); - await setAmbientModeEnabled( - /*ambientModeEnabled=*/ true, getAmbientProvider(), this.getStore()); - PersonalizationRouter.instance().goToRoute(Paths.AMBIENT); - } - - /** Navigates to the ambient subpage. */ - private onClickPreviewImage_(event: Event) { - event.stopPropagation(); - PersonalizationRouter.instance().goToRoute(Paths.AMBIENT); - } - - /** - * Navigate directly to photo selection subpage. Should only be possible to - * call this function if |topic_source| is set and photo collage is visible. - */ - private onClickPhotoCollage_(event: Event) { - assert(typeof this.topicSource_ === 'number', 'topic source required'); - event.stopPropagation(); - PersonalizationRouter.instance().selectAmbientAlbums(this.topicSource_); - } - - /** - * Return the array of images that form the collage. - * When topic source is Google Photos: - * - if |googlePhotosAlbumsPreviews_| is non-empty but contains fewer than 4 - * images, only return one of them; otherwise return the first 4. - * - if ||googlePhotosAlbumsPreviews_| is empty: - * - if |previewAlbums_| contains fewer than 4 albums, return one of - * their previews; otherwise return the first 4. - * - * If isAmbientSubpageUiChangeEnabled flag is on, max number of collage image - * will be 3 instead of 4. - */ - private computeCollageImages_(): Url[] { - const maxLength = - loadTimeData.getBoolean('isAmbientSubpageUiChangeEnabled') ? 3 : 4; - switch (this.topicSource_) { - case TopicSource.kArtGallery: - return (this.previewAlbums_ || []) - .map(album => album.url) - .slice(0, maxLength); - case TopicSource.kGooglePhotos: - if (isNonEmptyArray(this.googlePhotosAlbumsPreviews_)) { - return this.googlePhotosAlbumsPreviews_.length < maxLength ? - [this.googlePhotosAlbumsPreviews_[0]] : - this.googlePhotosAlbumsPreviews_.slice(0, maxLength); - } - if (isNonEmptyArray(this.previewAlbums_)) { - return this.previewAlbums_.length < maxLength ? - [this.previewAlbums_[0].url] : - this.previewAlbums_.map(album => album.url).slice(0, maxLength); - } - } - return []; - } - - private computePreviewAlbums_(): AmbientModeAlbum[]|null { - return (this.albums_ || []) - .filter( - album => album.topicSource === this.topicSource_ && album.checked && - album.url); - } - - private computeFirstPreviewAlbum_(): AmbientModeAlbum|null { - if (isNonEmptyArray(this.previewAlbums_)) { - return this.previewAlbums_[0]; - } - return null; - } - - private getPreviewContainerClass_(): string { - const classes = []; - if (this.ambientModeEnabled_ || this.loading_) { - classes.push('zero-state-disabled'); - } - - if (!this.ambientModeEnabled_) { - classes.push('ambient-mode-disabled'); - } - - /* TODO(b/253470553): Remove this condition after Ambient subpage UI change - * is released. */ - if (!loadTimeData.getBoolean('isAmbientSubpageUiChangeEnabled')) { - classes.push('pre-ui-change'); - } - return classes.join(' '); - } - - private getThumbnailContainerClass_(): string { - return `thumbnail-${this.collageImages_.length} clickable`; - } - - private getCollageContainerClass_(): string { - return `collage-${this.collageImages_.length} clickable`; - } - - private getCollageItems_(): AmbientModeAlbum[] { - if (!isNonEmptyArray(this.previewAlbums_)) { - return []; - } - return this.previewAlbums_.length < 5 ? this.previewAlbums_ : - this.previewAlbums_.slice(0, 4); - } - - private getPreviewImage_(album: AmbientModeAlbum|null): string { - // Replace the resolution suffix appended at the end of the images - // with a new resolution suffix of 512px. This won't impact images - // with no resolution suffix. - return album && album.url ? - replaceResolutionSuffix(album.url.url, '=s512') : - ''; - } - - private getPreviewTextAriaLabel_(): string { - return `${this.i18n('currentlySet')} ${this.getAlbumTitle_()} ${ - this.getAlbumDescription_()}`; - } - - private getAlbumTitle_(): string { - return this.firstPreviewAlbum_ ? this.firstPreviewAlbum_.title : ''; - } - - private getAlbumDescription_(): string { - if (!isNonEmptyArray(this.previewAlbums_) || this.topicSource_ === null) { - return ''; - } - switch (this.previewAlbums_.length) { - case 1: - // For only 1 selected album, album description includes image source - // and number of photos in the album (only applicable for Google - // Photos). - const topicSourceDesc = getTopicSourceName(this.topicSource_); - // TODO(b/223834394): replace dot separator symbol • with an icon/image. - return this.topicSource_ === TopicSource.kArtGallery ? - topicSourceDesc : - `${topicSourceDesc} • ${ - getPhotoCount(this.previewAlbums_[0].numberOfPhotos)}`; - case 2: - case 3: - // For 2-3 selected albums, album description includes the titles of all - // selected albums except the first one already shown in album title - // text. - const albumTitles = - this.previewAlbums_.slice(1).map(album => album.title); - return albumTitles.join(', '); - default: - // For more than 3 selected albums, album description includes the title - // of the second album and the number of remaining albums. - // For example: Sweden 2020, +2 more albums. - return this.i18n( - 'ambientModeMultipleAlbumsDesc', this.previewAlbums_[1].title, - this.previewAlbums_.length - 2); - } - } -} - -customElements.define(AmbientPreview.is, AmbientPreview);
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.html new file mode 100644 index 0000000..1d03f5e --- /dev/null +++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.html
@@ -0,0 +1,434 @@ +<style include="common cros-button-style"> + #container { + border: 1px solid var(--cros-separator-color); + border-radius: 16px; + display: grid; + grid-template-areas: + '. slot slot slot .' + '. image image image .' + '. . . . .' + '. message message message .' + '. mainpage-desc . collage .' + '. . . . .'; + grid-template-columns: 20px auto 192px auto 20px; + grid-template-rows: auto minmax(158px, 220px) 20px 192px auto 20px; + height: 100%; + } + + #container.zero-state-disabled { + grid-template-areas: + '. slot .' + '. image .' + '. . .' + '. collage .' + '. mainpage-desc .' + '. . .'; + grid-template-columns: 20px minmax(0,1fr) 20px; + grid-template-rows: auto minmax(158px, 220px) 20px 130px auto 18px; + } + + #container.pre-ui-change { + grid-template-areas: + '. slot slot slot .' + '. image image image .' + '. . . . .' + '. message message message .' + '. mainpage-desc . collage .' + '. . . . .'; + grid-template-columns: 20px minmax(0, 1fr) 16px 106px 20px; + grid-template-rows: auto minmax(158px, 220px) 20px 106px auto 24px; + } + + #container.pre-ui-change.zero-state-disabled { + grid-template-rows: auto minmax(158px, 220px) 20px auto 106px 24px; + } + + #ambientLabel { + align-items: center; + background: none; + border: none; + display: flex; + flex-flow: row nowrap; + grid-area: slot; + justify-content: space-between; + margin-top: 12px; + } + + #ambientSubpageLink { + --cr-icon-button-size: 48px; + /* Make the arrow align with the thumbnail image */ + margin-inline-end: -18px; + } + + #ambientLabel>h2 { + color: var(--cros-text-color-primary); + font: var(--personalization-app-label-font); + margin: 14px 0; + } + + #ambientLabel.enterprise { + opacity: var(--cros-disabled-opacity); + } + + #messageContainer { + align-items: center; + display: flex; + flex-direction: column; + grid-area: message; + justify-content: space-between; + } + + #messageContainer.pre-ui-change .text { + color: var(--cros-text-color-secondary); + font: var(--cros-body-1-font); + line-height: 1.5; + margin-top: 12px; + text-align: center; + width: unset; + } + + #messageContainer .text { + color: var(--cros-sys-on_primary_container, var(--cros-text-color-secondary)); + font: var(--cros-body-1-font); + line-height: 1.5; + margin-top: 56px; + text-align: center; + width: 128px; + } + + #messageContainer cr-button { + margin-bottom: 50px; + margin-top: 8px; + } + + ambient-zero-state-svg { + position: absolute; + z-index: -10000; + } + + #messageContainer.pre-ui-change cr-button { + margin-top: 20px; + } + + #imageContainer, + #imagePlaceholder { + display: flex; + height: 100%; + justify-self: center; + max-width: 360px; + min-width: 252px; + width: 100%; + } + + .album-info-mainpage { + display: flex; + grid-area: mainpage-desc; + justify-content: center; + } + + .album-info-mainpage:not(.pre-ui-change) span { + margin-inline: auto; + } + + #imageContainer, + #imagePlaceholder { + grid-area: image; + } + + #imageContainer[ambient-mode-managed] img.disabled { + opacity: var(--cros-disabled-opacity); + } + + #imageContainer img.disabled { + /** + * Use 50% for image instead of default cros-disabled-opacity. + * TODO(b/236415314) get this into design system as a semantic value. + */ + opacity: 50%; + } + + #albumTitle { + color: var(--cros-text-color-primary); + font: var(--cros-display-7-font); + margin-top: 16px; + } + + #albumTitle.pre-ui-change { + margin-top: 4px; + } + + #albumDescription { + color: var(--cros-text-color-secondary); + font: var(--cros-body-2-font); + margin-top: 2px; + } + + #albumDescription.pre-ui-change { + margin-top: 4px; + } + + #collageContainer, + #collagePlaceholder { + border-radius: 12px; + display: grid; + gap: 2px; + grid-area: collage; + overflow: hidden; + } + + #collageContainer { + border: 1px solid rgba(0, 0, 0, 0.08); + grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-template-rows: repeat(2, minmax(0, 1fr)); + } + + #collageContainer.collage-1 .collage-item:first-child { + grid-row: 1 / 3; + } + + #collageContainer.collage-1 .collage-item:first-child, + #collageContainer.collage-2 .collage-item:first-child, + #collageContainer.collage-2 .collage-item:nth-child(2), + #collageContainer.collage-3 .collage-item:nth-child(3) { + grid-column: 1 / 3; + } + + .collage-item { + height: 100%; + object-fit: cover; + width: 100%; + } + + #buttonContainer { + grid-area: buttons; + } + + #buttonContainer .text { + margin-inline-start: 8px; + } + + #buttonContainer .preview-button-disabled { + cursor: wait; + pointer-events: none; + } + + #buttonContainer cr-button { + border-color: var(--cros-button-stroke-color-secondary); + border-radius: 16px; + } + + #buttonContainer .spinner { + height: 20px; + width: 20px; + } + + #thumbnailContainer, + #thumbnailPlaceholder { + display: grid; + grid-area: collage; + justify-self: center; + max-width: 360px; + min-width: 252px; + overflow: hidden; + width: 100%; + } + + .thumbnail-item { + height: 100%; + overflow: hidden; + width: 100%; + } + + .thumbnail-item img { + height: 100%; + object-fit: fill; + width: 100%; + } + + #thumbnailContainer.thumbnail-1 .thumbnail-item { + border-radius: 60px; + } + + #thumbnailContainer.thumbnail-2 { + column-gap: 12px; + grid-template-columns: 130px minmax(0, 1fr); + } + + #thumbnailContainer.thumbnail-2 .thumbnail-item:first-of-type { + clip-path: url(#squiggleClip); + } + + #thumbnailContainer.thumbnail-2 .thumbnail-item:last-of-type { + border-radius: 60px; + } + + #thumbnailContainer.thumbnail-3 { + column-gap: 8px; + grid-template-columns: minmax(0, 1fr) 32px 32px; + } + + #thumbnailContainer.thumbnail-3 .thumbnail-item:first-of-type { + border-radius: 60px; + } + + #thumbnailContainer.thumbnail-3 .thumbnail-item:last-of-type img, + #thumbnailContainer.thumbnail-3 .thumbnail-item:nth-last-of-type(2) img { + border-radius: 16px; + object-fit: none; + } + +</style> +<div class$="[[getPreviewContainerClass_(ambientModeEnabled_, loading_)]]" + id="container"> + <template is="dom-if" if="[[!isAmbientModeManaged_]]"> + <div id="ambientLabel"> + <h2 on-click="onClickAmbientSubpageLink_" class="clickable"> + $i18n{screensaverLabel} + </h2> + <cr-icon-button aria-label="$i18n{ariaLabelChangeScreensaver}" + class="tast-open-subpage" + id="ambientSubpageLink" + iron-icon="cr:chevron-right" + on-click="onClickAmbientSubpageLink_"> + </cr-icon-button> + </div> + </template> + <template is="dom-if" if="[[isAmbientModeManaged_]]"> + <div id="ambientLabel" class="enterprise"> + <h2>$i18n{screensaverLabel}</h2> + <cr-icon-button disabled + id="ambientSubpageLink" + iron-icon="cr:chevron-right"> + </cr-icon-button> + </div> + </template> + <template is="dom-if" if="[[loading_]]"> + <div id="imagePlaceholder" class="placeholder"></div> + <template is="dom-if" if="[[isAmbientSubpageUiChangeEnabled_]]"> + <div id="thumbnailPlaceholder" class="placeholder"></div> + </template> + <div id="textPlaceholder" + class="preview-text-placeholder album-info-mainpage"> + <div class="placeholder"></div> + <div class="placeholder"></div> + </div> + <div id="collagePlaceholder" class="placeholder"></div> + </template> + <template is="dom-if" if="[[!loading_]]"> + <template is="dom-if" if="[[!ambientModeEnabled_]]"> + <div id="imageContainer" class="preview-image-container" + ambient-mode-managed$="[[isAmbientModeManaged_]]" aria-hidden="true"> + <div class="preview-image-border"></div> + <img class="preview-image disabled" + src="//personalization/images/slideshow.png"> + </div> + <template is="dom-if" if="[[!isAmbientSubpageUiChangeEnabled_]]"> + <div id="messageContainer" class="pre-ui-change"> + <span class="text" id="turnOnDescription"> + $i18n{ambientModeMainPageZeroStateMessage} + </span> + <cr-button class="primary" on-click="onClickAmbientModeButton_" + aria-describedby="turnOnDescription"> + <div>$i18n{ambientModeTurnOnLabel}</div> + </cr-button> + </div> + </template> + <template is="dom-if" if="[[isAmbientSubpageUiChangeEnabled_]]"> + <div id="messageContainer"> + <ambient-zero-state-svg></ambient-zero-state-svg> + <template is="dom-if" if="[[!isAmbientModeManaged_]]"> + <span class="text" id="turnOnDescription"> + $i18n{ambientModeMainPageZeroStateMessageV2} + </span> + <cr-button class="primary" on-click="onClickAmbientModeButton_" + aria-describedby="turnOnDescription"> + <div>$i18n{ambientModeTurnOnLabel}</div> + </cr-button> + </template> + <template is="dom-if" if="[[isAmbientModeManaged_]]"> + <span class="text" id="turnOnDescription"> + $i18n{ambientModeMainPageEnterpriseUserMessage} + </span> + <cr-button class="primary"> + <!-- TODO(b/258838122): on-click behavior --> + <div>$i18n{ambientModeLearnMoreLabel}</div> + </cr-button> + </template> + </div> + </template> + </template> + <template is="dom-if" if="[[ambientModeEnabled_]]"> + <!-- TODO(b/226235802) - Add failed/error state when no previewAlbums available. + Currently, we show blank containers --> + <template is="dom-if" if="[[previewAlbums_]]"> + <div id="imageContainer" class="preview-image-container"> + <div class="preview-image-border"></div> + <img alt$="[[getAlbumTitle_(firstPreviewAlbum_)]]" + auto-src="[[getPreviewImage_(firstPreviewAlbum_)]]" + class="preview-image clickable" + is-google-photos + is="cr-auto-img" + on-click="onClickPreviewImage_" + on-keypress="onClickPreviewImage_"> + </div> + <template is="dom-if" if="[[isAmbientSubpageUiChangeEnabled_]]"> + <div id="thumbnailContainer" aria-hidden="true" + class$="[[getThumbnailContainerClass_(collageImages_)]]" + on-click="onClickPhotoCollage_" + on-keypress="onClickPhotoCollage_"> + <template is="dom-repeat" items="[[collageImages_]]"> + <div class="thumbnail-item"> + <img is="cr-auto-img" auto-src="[[item.url]]" is-google-photos> + </div> + </template> + </div> + <!-- Use inline svg in order to reference the clip path by url() --> + <svg width="0" height="0" viewBox="0 0 130 130" fill="none" + xmlns="http://www.w3.org/2000/svg"> + <defs> + <clipPath id="squiggleClip"> + <path + d="M 1.4375 72.371094 C -0.332031 69.402344 -0.476562 65.738281 1.054688 62.640625 L 3.210938 58.28125 C 4.125 56.429688 4.457031 54.339844 4.15625 52.296875 L 3.457031 47.484375 C 2.957031 44.066406 4.226562 40.625 6.824219 38.347656 L 10.484375 35.148438 C 12.039062 33.785156 13.144531 31.984375 13.652344 29.980469 L 14.84375 25.265625 C 15.691406 21.914062 18.179688 19.222656 21.453125 18.113281 L 26.058594 16.554688 C 28.015625 15.894531 29.726562 14.652344 30.960938 12.996094 L 33.867188 9.097656 C 35.929688 6.324219 39.261719 4.789062 42.710938 5.019531 L 47.5625 5.339844 C 49.625 5.480469 51.679688 4.984375 53.453125 3.925781 L 57.628906 1.4375 C 60.597656 -0.332031 64.261719 -0.476562 67.359375 1.054688 L 71.71875 3.210938 C 73.570312 4.125 75.660156 4.457031 77.703125 4.15625 L 82.515625 3.457031 C 85.933594 2.957031 89.375 4.226562 91.652344 6.824219 L 94.851562 10.484375 C 96.214844 12.039062 98.015625 13.144531 100.019531 13.652344 L 104.734375 14.84375 C 108.085938 15.691406 110.777344 18.179688 111.886719 21.453125 L 113.445312 26.058594 C 114.105469 28.015625 115.347656 29.726562 117.003906 30.960938 L 120.902344 33.867188 C 123.675781 35.929688 125.210938 39.261719 124.980469 42.710938 L 124.660156 47.5625 C 124.519531 49.625 125.015625 51.679688 126.074219 53.453125 L 128.5625 57.628906 C 130.332031 60.597656 130.476562 64.261719 128.945312 67.359375 L 126.792969 71.71875 C 125.875 73.570312 125.542969 75.660156 125.84375 77.703125 L 126.542969 82.515625 C 127.042969 85.933594 125.773438 89.375 123.175781 91.652344 L 119.515625 94.851562 C 117.960938 96.214844 116.855469 98.015625 116.347656 100.019531 L 115.15625 104.734375 C 114.308594 108.085938 111.820312 110.777344 108.546875 111.886719 L 103.941406 113.445312 C 101.984375 114.105469 100.273438 115.347656 99.039062 117.003906 L 96.132812 120.902344 C 94.070312 123.675781 90.738281 125.210938 87.289062 124.980469 L 82.4375 124.660156 C 80.375 124.519531 78.320312 125.015625 76.546875 126.074219 L 72.371094 128.5625 C 69.402344 130.332031 65.738281 130.476562 62.640625 128.945312 L 58.28125 126.792969 C 56.429688 125.875 54.339844 125.542969 52.296875 125.84375 L 47.484375 126.542969 C 44.066406 127.042969 40.625 125.773438 38.347656 123.175781 L 35.148438 119.515625 C 33.785156 117.960938 31.984375 116.855469 29.980469 116.347656 L 25.265625 115.15625 C 21.914062 114.308594 19.222656 111.820312 18.113281 108.546875 L 16.554688 103.941406 C 15.894531 101.984375 14.652344 100.273438 12.996094 99.039062 L 9.097656 96.132812 C 6.324219 94.070312 4.789062 90.738281 5.019531 87.289062 L 5.339844 82.4375 C 5.480469 80.375 4.984375 78.320312 3.925781 76.546875 Z M 1.4375 72.371094 "> + </path> + </clipPath> + </defs> + </svg> + <h3 id="textContainer" + class="preview-text-container album-info-mainpage" + aria-label$="[[getPreviewTextAriaLabel_(firstPreviewAlbum_, topicSource_, previewAlbums_)]]"> + <span id="albumTitle" aria-hidden="true" + title="[[getAlbumTitle_(firstPreviewAlbum_)]]"> + [[getAlbumTitle_(firstPreviewAlbum_)]] + </span> + <span id="albumDescription" aria-hidden="true"> + [[getAlbumDescription_(topicSource_, previewAlbums_)]] + </span> + </h3> + </template> + <template is="dom-if" if="[[!isAmbientSubpageUiChangeEnabled_]]"> + <h3 id="textContainer" + class="preview-text-container album-info-mainpage pre-ui-change" + aria-label$="[[getPreviewTextAriaLabel_(firstPreviewAlbum_, topicSource_, previewAlbums_)]]"> + <span id="albumTitle" aria-hidden="true" + title="[[getAlbumTitle_(firstPreviewAlbum_)]]"> + [[getAlbumTitle_(firstPreviewAlbum_)]] + </span> + <span id="albumDescription" aria-hidden="true"> + [[getAlbumDescription_(topicSource_, previewAlbums_)]] + </span> + </h3> + <div aria-hidden="true" + class$="[[getCollageContainerClass_(collageImages_)]]" + on-click="onClickPhotoCollage_" + on-keypress="onClickPhotoCollage_" + id="collageContainer"> + <template is="dom-repeat" items="[[collageImages_]]"> + <img class="collage-item" is="cr-auto-img" + auto-src="[[item.url]]" is-google-photos> + </template> + </div> + </template> + </template> + </template> + </template> +</div>
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.ts new file mode 100644 index 0000000..8a73b151 --- /dev/null +++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_large_element.ts
@@ -0,0 +1,130 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview A polymer element that previews ambient settings in a large + * card. Shows an album cover image, some additional preview images in a + * collage, and informational text about the selected albums. Currently used on + * the personalization app main page. + */ + +import 'chrome://resources/cr_elements/cr_auto_img/cr_auto_img.js'; +import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; +import './ambient_zero_state_svg_element.js'; +import '../../css/common.css.js'; +import '../../css/cros_button_style.css.js'; + +import {assert} from 'chrome://resources/js/assert_ts.js'; +import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; + +import {TopicSource} from '../personalization_app.mojom-webui.js'; +import {logAmbientModeOptInUMA} from '../personalization_metrics_logger.js'; +import {Paths, PersonalizationRouter} from '../personalization_router_element.js'; +import {isNonEmptyArray} from '../utils.js'; + +import {setAmbientModeEnabled} from './ambient_controller.js'; +import {getAmbientProvider} from './ambient_interface_provider.js'; +import {AmbientPreviewBase} from './ambient_preview_base.js'; +import {getTemplate} from './ambient_preview_large_element.html.js'; + +export class AmbientPreviewLarge extends AmbientPreviewBase { + static get is() { + return 'ambient-preview-large'; + } + + static get template() { + return getTemplate(); + } + + static override get properties() { + return { + googlePhotosAlbumsPreviews_: { + type: Array, + value: null, + }, + collageImages_: { + type: Array, + computed: + 'computeCollageImages_(topicSource_, previewAlbums_, googlePhotosAlbumsPreviews_)', + }, + }; + } + + private collageImages_: Url[]; + + /** + * Return the array of images that form the collage. + * When topic source is Google Photos: + * - if `googlePhotosAlbumsPreviews_` is non-empty but contains fewer than 4 + * images, only return one of them; otherwise return the first 4. + * - if `googlePhotosAlbumsPreviews_` is empty: + * - e.g. user selected art gallery albums + * - if `previewAlbums_` contains fewer than 4 albums, return one of + * their previews; otherwise return the first 4. + * + * If isAmbientSubpageUiChangeEnabled flag is on, max number of collage image + * will be 3 instead of 4. + */ + private computeCollageImages_(): Url[] { + const maxLength = this.isAmbientSubpageUiChangeEnabled_ ? 3 : 4; + switch (this.topicSource_) { + case TopicSource.kArtGallery: + return (this.previewAlbums_ || []) + .map(album => album.url) + .slice(0, maxLength); + case TopicSource.kGooglePhotos: + if (isNonEmptyArray(this.googlePhotosAlbumsPreviews_)) { + return this.googlePhotosAlbumsPreviews_.length < maxLength ? + [this.googlePhotosAlbumsPreviews_[0]] : + this.googlePhotosAlbumsPreviews_.slice(0, maxLength); + } + if (isNonEmptyArray(this.previewAlbums_)) { + return this.previewAlbums_.length < maxLength ? + [this.previewAlbums_[0].url] : + this.previewAlbums_.map(album => album.url).slice(0, maxLength); + } + } + return []; + } + + private onClickAmbientSubpageLink_() { + PersonalizationRouter.instance().goToRoute(Paths.AMBIENT); + } + + /** Enable ambient mode and navigates to the ambient subpage. */ + private async onClickAmbientModeButton_(event: Event) { + assert(this.ambientModeEnabled_ === false); + event.stopPropagation(); + logAmbientModeOptInUMA(); + await setAmbientModeEnabled( + /*ambientModeEnabled=*/ true, getAmbientProvider(), this.getStore()); + PersonalizationRouter.instance().goToRoute(Paths.AMBIENT); + } + + /** Navigates to the ambient subpage. */ + private onClickPreviewImage_(event: Event) { + event.stopPropagation(); + PersonalizationRouter.instance().goToRoute(Paths.AMBIENT); + } + + /** + * Navigate directly to photo selection subpage. Should only be possible to + * call this function if |topic_source| is set and photo collage is visible. + */ + private onClickPhotoCollage_(event: Event) { + assert(typeof this.topicSource_ === 'number', 'topic source required'); + event.stopPropagation(); + PersonalizationRouter.instance().selectAmbientAlbums(this.topicSource_); + } + + private getThumbnailContainerClass_(): string { + return `thumbnail-${this.collageImages_.length} clickable`; + } + + private getCollageContainerClass_(): string { + return `collage-${this.collageImages_.length} clickable`; + } +} + +customElements.define(AmbientPreviewLarge.is, AmbientPreviewLarge);
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.html new file mode 100644 index 0000000..9f3dfa2 --- /dev/null +++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.html
@@ -0,0 +1,153 @@ +<style include="common cros-button-style"> + /* TODO(b/253470553): Remove after Ambient subpage UI change is released. */ + #container.pre-ui-change { + border: none; + display: grid; + grid-template-areas: + '. . .' + 'image . subpage-desc' + 'image . buttons' + '. . .'; + grid-template-columns: 224px 32px minmax(0, 1fr); + grid-template-rows: 20px 118px 34px 20px; + } + + #container.ambient-mode-disabled { + grid-template-areas: + 'image . subpage-desc' + '. . .'; + grid-template-columns: 224px 32px minmax(0, 1fr); + grid-template-rows: 152px 20px; + } + + #container { + border: none; + display: grid; + grid-template-areas: + 'image . subpage-desc' + 'image . buttons' + '. . .'; + grid-template-columns: 224px 32px minmax(0, 1fr); + grid-template-rows: 118px 34px 20px; + } + + #buttonContainer, + .currently-set-text { + display: inline-flex; + } + + .album-info-subpage, + .zero-state-info-subpage { + display: flex; + grid-area: subpage-desc; + justify-content: center; + } + + #imageContainer, + #imagePlaceholder { + grid-area: image; + } + + #imageContainer[ambient-mode-managed] img.disabled { + opacity: var(--cros-disabled-opacity); + } + + #imageContainer img.disabled { + /** + * Use 50% for image instead of default cros-disabled-opacity. + * TODO(b/236415314) get this into design system as a semantic value. + */ + opacity: 50%; + } + + #buttonContainer { + grid-area: buttons; + } + + #buttonContainer .text { + margin-inline-start: 8px; + } + + #buttonContainer .disabled { + cursor: wait; + pointer-events: none; + } + + #buttonContainer cr-button { + border-color: var(--cros-button-stroke-color-secondary); + border-radius: 16px; + } + + #buttonContainer .spinner { + height: 20px; + width: 20px; + } + +</style> +<div class$="[[getPreviewContainerClass_(ambientModeEnabled_, loading_)]]" + id="container"> + <template is="dom-if" if="[[loading_]]" restamp> + <div id="imagePlaceholder" class="placeholder"></div> + <div id="textPlaceholder" + class="preview-text-placeholder album-info-subpage"> + <div class="placeholder currently-set-text"></div> + <div class="placeholder"></div> + <div class="placeholder"></div> + </div> + </template> + <template is="dom-if" if="[[!loading_]]" restamp> + <template is="dom-if" if="[[!ambientModeEnabled_]]" restamp> + <div id="imageContainer" class="preview-image-container" ambient-mode-managed$="[[isAmbientModeManaged_]]" aria-hidden="true"> + <div class="preview-image-border"></div> + <img class="preview-image disabled" src="//personalization/images/slideshow.png"> + </div> + <h3 id="zeroStateTextContainer" + class="preview-text-container zero-state-info-subpage" + aria-label$="$i18n{ambientModeMainPageZeroStateMessage}"> + <span class="text"> + $i18n{ambientModeMainPageZeroStateMessage} + </span> + </h3> + </template> + <template is="dom-if" if="[[ambientModeEnabled_]]"> + <!-- TODO(b/226235802) - Add failed/error state when no previewAlbums available. + Currently, we show blank containers --> + <template is="dom-if" if="[[previewAlbums_]]"> + <div id="imageContainer" class="preview-image-container"> + <div class="preview-image-border"></div> + <img class="preview-image" is="cr-auto-img" + auto-src="[[getPreviewImage_(firstPreviewAlbum_)]]" + alt$="[[getAlbumTitle_(firstPreviewAlbum_)]]" + is-google-photos> + </div> + <h3 id="textContainer" + class="preview-text-container album-info-subpage pre-ui-change" + aria-label$="[[getPreviewTextAriaLabel_(firstPreviewAlbum_, topicSource_, previewAlbums_)]]"> + <span id="currentlySet" class="currently-set-text" aria-hidden="true"> + $i18n{currentlySet} + </span> + <span id="albumTitle" aria-hidden="true" + title="[[getAlbumTitle_(firstPreviewAlbum_)]]"> + [[getAlbumTitle_(firstPreviewAlbum_)]] + </span> + <span id="albumDescription" aria-hidden="true"> + [[getAlbumDescription_(topicSource_, previewAlbums_)]] + </span> + </h3> + <div id="buttonContainer" hidden$="[[!isScreenSaverPreviewEnabled_()]]"> + <cr-button + class$="[[getScreenSaverPreviewClass_(ambientUiVisibility_)]]" + on-click="startScreenSaverPreview_"> + <iron-icon icon="personalization:fullscreen" + hidden$="[[screenSaverPreviewActive_]]"></iron-icon> + <paper-spinner-lite active class="spinner" + hidden$="[[!screenSaverPreviewActive_]]"></paper-spinner-lite> + <div class="text"> + [[getScreenSaverPreviewText_(ambientUiVisibility_)]] + </div> + </cr-button> + </div> + </template> + </template> + </template> +</div>
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.ts new file mode 100644 index 0000000..646adbdb --- /dev/null +++ b/ash/webui/personalization_app/resources/js/ambient/ambient_preview_small_element.ts
@@ -0,0 +1,90 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview A polymer element that previews ambient settings in a small + * container. Shows a cover image from a chosen album and text describing it. + * Currently used on the ambient settings page. + */ + +import 'chrome://resources/cr_elements/cr_auto_img/cr_auto_img.js'; +import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; +import './ambient_zero_state_svg_element.js'; +import '../../css/common.css.js'; +import '../../css/cros_button_style.css.js'; + +import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; + +import {AmbientUiVisibility} from '../personalization_app.mojom-webui.js'; + +import {startScreenSaverPreview} from './ambient_controller.js'; +import {getAmbientProvider} from './ambient_interface_provider.js'; +import {AmbientPreviewBase} from './ambient_preview_base.js'; +import {getTemplate} from './ambient_preview_small_element.html.js'; + +export interface AmbientPreviewSmall { + $: { + container: HTMLDivElement, + }; +} + +export class AmbientPreviewSmall extends AmbientPreviewBase { + static get is() { + return 'ambient-preview-small'; + } + + static get template() { + return getTemplate(); + } + + static override get properties() { + return { + screenSaverPreviewActive_: { + type: Boolean, + computed: 'computeScreenSaverPreviewActive_(ambientUiVisibility_)', + }, + ambientUiVisibility_: { + type: Number, + value: null, + }, + }; + } + + private screenSaverPreviewActive_: boolean; + private ambientUiVisibility_: AmbientUiVisibility|null; + + override connectedCallback() { + super.connectedCallback(); + this.watch( + 'ambientUiVisibility_', state => state.ambient.ambientUiVisibility); + this.updateFromStore(); + } + + private computeScreenSaverPreviewActive_(): boolean { + return this.ambientUiVisibility_ === AmbientUiVisibility.kPreview; + } + + private isScreenSaverPreviewEnabled_() { + return loadTimeData.getBoolean('isScreenSaverPreviewEnabled'); + } + + private startScreenSaverPreview_(event: Event) { + event.stopPropagation(); + startScreenSaverPreview(getAmbientProvider()); + } + + private getScreenSaverPreviewClass_(): string { + return this.screenSaverPreviewActive_ ? 'preview-button-disabled' : + 'preview-button'; + } + + private getScreenSaverPreviewText_(): string { + return this.screenSaverPreviewActive_ ? + this.i18n('screenSaverPreviewDownloading') : + this.i18n('screenSaverPreviewButton'); + } +} + +customElements.define(AmbientPreviewSmall.is, AmbientPreviewSmall);
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html index 8be72204..b2b659bd 100644 --- a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html +++ b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.html
@@ -26,10 +26,10 @@ grid-area: zeroState; } /* TODO(b/253470553): Remove after Ambient subpage UI change is released. */ - ambient-preview.pre-ui-change { + ambient-preview-small.pre-ui-change { margin: 20px 8px 0 8px; } - ambient-preview { + ambient-preview-small { grid-area: preview; margin: 0 8px; } @@ -97,19 +97,19 @@ </style> <div id="container"> <template is="dom-if" if="[[isAmbientSubpageUiChangeEnabled_]]"> - <ambient-preview></ambient-preview> + <ambient-preview-small></ambient-preview-small> </template> <!-- restamp to avoid layout issues with iron-list resizing while hidden --> <template is="dom-if" if="[[shouldShowMainSettings_(path)]]" restamp> <div id="mainSettings"> - <template is="dom-if" if="[[loadingAmbientMode_(ambientModeEnabled_)]]"> + <template is="dom-if" if="[[isLoadingAmbientMode_(ambientModeEnabled_)]]"> <div id="toggleRowPlaceholder" class="ambient-toggle-row-container"> <div class="ambient-toggle-row"> <div class="ambient-primary-text-placeholder placeholder"></div> </div> </div> </template> - <template is="dom-if" if="[[!loadingAmbientMode_(ambientModeEnabled_)]]"> + <template is="dom-if" if="[[!isLoadingAmbientMode_(ambientModeEnabled_)]]"> <toggle-row id="ambientToggleRow" checked="[[ambientModeEnabled_]]" on-click="onClickAmbientModeButton_" on-change="onToggleStateChanged_"> </toggle-row> @@ -117,7 +117,7 @@ <template is="dom-if" if="[[ambientModeEnabled_]]"> <!-- TODO(b/253470553): Remove after Ambient subpage UI change is released. --> <template is="dom-if" if="[[!isAmbientSubpageUiChangeEnabled_]]"> - <ambient-preview class="pre-ui-change"></ambient-preview> + <ambient-preview-small class="pre-ui-change"></ambient-preview-small> </template> <template is="dom-if" if="[[loadingSettings_]]"> <div id="animationThemePlaceholder"> @@ -172,11 +172,8 @@ </ambient-weather-unit> </template> </template> - <template is="dom-if" if="[[!ambientModeEnabled_]]"> - <!-- TODO(b/253470693): Remove after Ambient subpage UI change is released. --> - <template is="dom-if" if="[[!isAmbientSubpageUiChangeEnabled_]]"> - <ambient-zero-state id="zeroState"></ambient-zero-state> - </template> + <template is="dom-if" if="[[shouldShowZeroState_(ambientModeEnabled_, isAmbientSubpageUiChangeEnabled_)]]"> + <ambient-zero-state id="zeroState"></ambient-zero-state> </template> </div> </template>
diff --git a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts index 3852542..a5871c2 100644 --- a/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts +++ b/ash/webui/personalization_app/resources/js/ambient/ambient_subpage_element.ts
@@ -10,7 +10,7 @@ import '../../css/common.css.js'; import './albums_subpage_element.js'; import './ambient_weather_element.js'; -import './ambient_preview_element.js'; +import './ambient_preview_small_element.js'; import './animation_theme_list_element.js'; import './toggle_row_element.js'; import './topic_source_list_element.js'; @@ -191,7 +191,13 @@ return path === Paths.AMBIENT_ALBUMS; } - private loadingAmbientMode_(): boolean { + private shouldShowZeroState_(): boolean { + // TODO(b/253470693): Remove after Ambient subpage UI change is released. + return this.ambientModeEnabled_ === false && + !this.isAmbientSubpageUiChangeEnabled_; + } + + private isLoadingAmbientMode_(): boolean { return this.ambientModeEnabled_ === null; }
diff --git a/ash/webui/personalization_app/resources/js/ambient/utils.ts b/ash/webui/personalization_app/resources/js/ambient/utils.ts index 4b9fcba..cd3f1360 100644 --- a/ash/webui/personalization_app/resources/js/ambient/utils.ts +++ b/ash/webui/personalization_app/resources/js/ambient/utils.ts
@@ -8,7 +8,7 @@ import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; -import {AmbientModeAlbum, TopicSource} from '../personalization_app.mojom-webui.js'; +import {TopicSource} from '../personalization_app.mojom-webui.js'; /** * Returns photo count string. @@ -23,13 +23,6 @@ } /** - * Returns whether the given album is Recent Highlights. - */ -export function isRecentHighlightsAlbum(album: AmbientModeAlbum): boolean { - return album.id === 'RecentHighlights'; -} - -/** * Returns the topic source name. */ export function getTopicSourceName(topicSource: TopicSource): string {
diff --git a/ash/webui/personalization_app/resources/js/personalization_app.ts b/ash/webui/personalization_app/resources/js/personalization_app.ts index 86b095b5..872a95a 100644 --- a/ash/webui/personalization_app/resources/js/personalization_app.ts +++ b/ash/webui/personalization_app/resources/js/personalization_app.ts
@@ -14,7 +14,8 @@ import './ambient/animation_theme_item_element.js'; import './ambient/animation_theme_list_element.js'; import './ambient/art_album_dialog_element.js'; -import './ambient/ambient_preview_element.js'; +import './ambient/ambient_preview_large_element.js'; +import './ambient/ambient_preview_small_element.js'; import './ambient/ambient_subpage_element.js'; import './ambient/ambient_weather_element.js'; import './ambient/toggle_row_element.js'; @@ -53,7 +54,8 @@ export {AmbientActionName, AmbientActions, SetAlbumsAction, setAlbumsAction, SetAlbumSelectedAction, setAlbumSelectedAction, SetAmbientModeEnabledAction, setAmbientModeEnabledAction, SetAnimationThemeAction, setAnimationThemeAction, SetGooglePhotosAlbumsPreviewsAction, setGooglePhotosAlbumsPreviewsAction, SetTemperatureUnitAction, setTemperatureUnitAction, SetTopicSourceAction, setTopicSourceAction} from './ambient/ambient_actions.js'; export {setAmbientProviderForTesting} from './ambient/ambient_interface_provider.js'; export {AmbientObserver} from './ambient/ambient_observer.js'; -export {AmbientPreview} from './ambient/ambient_preview_element.js'; +export {AmbientPreviewLarge} from './ambient/ambient_preview_large_element.js'; +export {AmbientPreviewSmall} from './ambient/ambient_preview_small_element.js'; export {AmbientSubpage} from './ambient/ambient_subpage_element.js'; export {AmbientWeatherUnit} from './ambient/ambient_weather_element.js'; export {AnimationThemeItem} from './ambient/animation_theme_item_element.js';
diff --git a/ash/webui/personalization_app/resources/js/personalization_main_element.html b/ash/webui/personalization_app/resources/js/personalization_main_element.html index 671af73..40fbca2 100644 --- a/ash/webui/personalization_app/resources/js/personalization_main_element.html +++ b/ash/webui/personalization_app/resources/js/personalization_main_element.html
@@ -29,21 +29,6 @@ margin-top: 16px; } - #ambientSubpageLink { - --cr-icon-button-size: 48px; - /* Make the arrow align with the thumbnail image */ - margin-inline-end: -18px; - } - - #ambientLabel > h2 { - color: var(--cros-text-color-primary); - font: var(--personalization-app-label-font); - margin: 14px 0; - } - - #ambientLabel.enterprise { - opacity: var(--cros-disabled-opacity); - } </style> <div id="container"> <user-preview path="[[path]]"> @@ -55,31 +40,8 @@ </template> </wallpaper-preview> <template is="dom-if" if="[[isAmbientModeAllowed_()]]"> - <ambient-preview clickable="[[clickable_]]" main-page> - <template is="dom-if" if="[[!isAmbientModeManaged_]]"> - <div id="ambientLabel"> - <h2 on-click="onClickAmbientSubpageLink_" class="clickable"> - $i18n{screensaverLabel} - </h2> - <cr-icon-button id="ambientSubpageLink" - iron-icon="cr:chevron-right" - on-click="onClickAmbientSubpageLink_" - class="tast-open-subpage" - aria-label="$i18n{ariaLabelChangeScreensaver}"> - </cr-icon-button> - </div> - </template> - <template is="dom-if" if="[[isAmbientModeManaged_]]"> - <div id="ambientLabel" class="enterprise"> - <h2> - $i18n{screensaverLabel} - </h2> - <cr-icon-button id="ambientSubpageLink" - iron-icon="cr:chevron-right" disabled> - </cr-icon-button> - </div> - </template> - </ambient-preview> + <ambient-preview-large> + </ambient-preview-large> </template> </div> <template is="dom-if" if="[[isRgbKeyboardSupported_()]]">
diff --git a/ash/webui/personalization_app/resources/js/personalization_main_element.ts b/ash/webui/personalization_app/resources/js/personalization_main_element.ts index 20a7d05..98d9051 100644 --- a/ash/webui/personalization_app/resources/js/personalization_main_element.ts +++ b/ash/webui/personalization_app/resources/js/personalization_main_element.ts
@@ -7,12 +7,12 @@ * the personalization hub. */ -import '../css/cros_button_style.css.js'; +import './ambient/ambient_preview_large_element.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; import {getTemplate} from './personalization_main_element.html.js'; -import {isAmbientModeAllowed, Paths, PersonalizationRouter} from './personalization_router_element.js'; +import {isAmbientModeAllowed} from './personalization_router_element.js'; import {WithPersonalizationStore} from './personalization_store.js'; export class PersonalizationMain extends WithPersonalizationStore { @@ -27,14 +27,6 @@ static get properties() { return { path: String, - clickable_: { - type: Boolean, - value: true, - }, - isAmbientModeManaged_: { - type: Boolean, - value: loadTimeData.getBoolean('isAmbientModeManaged'), - }, }; } @@ -49,10 +41,6 @@ private isRgbKeyboardSupported_(): boolean { return loadTimeData.getBoolean('isRgbKeyboardSupported'); } - - private onClickAmbientSubpageLink_() { - PersonalizationRouter.instance().goToRoute(Paths.AMBIENT); - } } customElements.define(PersonalizationMain.is, PersonalizationMain);
diff --git a/ash/webui/personalization_app/resources/js/utils.ts b/ash/webui/personalization_app/resources/js/utils.ts index c2bde11..5cc1cd2 100644 --- a/ash/webui/personalization_app/resources/js/utils.ts +++ b/ash/webui/personalization_app/resources/js/utils.ts
@@ -10,6 +10,8 @@ import {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js'; import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; +import {AmbientModeAlbum, GooglePhotosAlbum} from './personalization_app.mojom-webui.js'; + export type PersonalizationAppSelectionEvent = MouseEvent&{type: 'click'}|KeyboardEvent&{key: 'Enter'}; @@ -102,3 +104,11 @@ .toString(STRING_LENGTH) .padStart(PADDING_LENGTH, '0')}`; } + +/** + * Returns whether the given album is Recent Highlights. + */ +export function isRecentHighlightsAlbum(album: AmbientModeAlbum| + GooglePhotosAlbum): boolean { + return album.id === 'RecentHighlights'; +}
diff --git a/ash/webui/personalization_app/resources/js/wallpaper/google_photos_albums_element.ts b/ash/webui/personalization_app/resources/js/wallpaper/google_photos_albums_element.ts index 00ae477..74bf3f1a 100644 --- a/ash/webui/personalization_app/resources/js/wallpaper/google_photos_albums_element.ts +++ b/ash/webui/personalization_app/resources/js/wallpaper/google_photos_albums_element.ts
@@ -22,7 +22,7 @@ import {PersonalizationRouter} from '../personalization_router_element.js'; import {PersonalizationStateError} from '../personalization_state.js'; import {WithPersonalizationStore} from '../personalization_store.js'; -import {getCountText} from '../utils.js'; +import {getCountText, isNonEmptyArray, isRecentHighlightsAlbum} from '../utils.js'; import {getTemplate} from './google_photos_albums_element.html.js'; import {getLoadingPlaceholders} from './utils.js'; @@ -107,7 +107,7 @@ /** The list of owned albums. */ private albums_: GooglePhotosAlbum[]|null|undefined; - /** The concatenation of |albums_| and |albumsShared_| for display. */ + /** Merged |albums_| and |albumsShared_| for display. */ private albumsForDisplay_: GooglePhotosAlbum[]; /** Whether the list of owned albums is currently loading. */ @@ -168,6 +168,27 @@ } } + private mergeAlbumsByTimestamp_( + owned: GooglePhotosAlbums['albums_'], + shared: GooglePhotosAlbums['albumsShared_']) { + if (!isNonEmptyArray(owned)) { + owned = []; + } + if (!isNonEmptyArray(shared)) { + shared = []; + } + // If the Recent Highlights album exists, it will be the first element in + // the owned albums, i.e. owned[0]. + let recentHighlights: GooglePhotosAlbum|undefined; + if (isNonEmptyArray(owned) && isRecentHighlightsAlbum(owned[0])) { + recentHighlights = owned.shift(); + } + const albums = (owned).concat(shared).sort( + (a, b) => Number(b.timestamp.internalValue) - + Number(a.timestamp.internalValue)); + return recentHighlights ? [recentHighlights].concat(albums) : albums; + } + /** Invoked on changes to |albums_| or |albumsShared_|. */ private onAlbumsChanged_( albums: GooglePhotosAlbums['albums_'], @@ -205,16 +226,13 @@ return; } - // Concatenate owned and shared albums. - const newAlbums = (albums || []).concat(albumsShared || []); - // NOTE: |albumsForDisplay_| is updated in place to avoid resetting the // scroll position of the grid which would otherwise occur during - // reassignment but it will be deeply equal to |newAlbums| after updating. + // reassignment but it will be deeply equal to |newList| after updating. this.updateList( /*propertyPath=*/ 'albumsForDisplay_', /*identityGetter=*/ (album: GooglePhotosAlbum) => album.id, - /*newList=*/ newAlbums, + /*newList=*/ this.mergeAlbumsByTimestamp_(albums, albumsShared), /*identityBasedUpdate=*/ true); }
diff --git a/ash/webui/personalization_app/test/personalization_app_browsertest.js b/ash/webui/personalization_app/test/personalization_app_browsertest.js index b5972d8..d58738f 100644 --- a/ash/webui/personalization_app/test/personalization_app_browsertest.js +++ b/ash/webui/personalization_app/test/personalization_app_browsertest.js
@@ -152,7 +152,7 @@ () => { const preview = document.querySelector('personalization-router') .shadowRoot.querySelector('personalization-main') - .shadowRoot.querySelector('ambient-preview'); + .shadowRoot.querySelector('ambient-preview-large'); assertTrue(!!preview); testDone(); }); @@ -163,6 +163,7 @@ const ambientSubpageLink = document.querySelector('personalization-router') .shadowRoot.querySelector('personalization-main') + .shadowRoot.querySelector('ambient-preview-large') .shadowRoot.querySelector('#ambientSubpageLink'); assertTrue(!!ambientSubpageLink); testDone();
diff --git a/ash/wm/desks/desk_action_view.cc b/ash/wm/desks/desk_action_view.cc index c6d2fee..7859d28 100644 --- a/ash/wm/desks/desk_action_view.cc +++ b/ash/wm/desks/desk_action_view.cc
@@ -35,9 +35,7 @@ CloseButton::Type::kMediumFloating))) { SetOrientation(views::BoxLayout::Orientation::kHorizontal); SetBetweenChildSpacing(kButtonSpacing); - SetBackground( - views::CreateSolidBackground(AshColorProvider::Get()->GetBaseLayerColor( - AshColorProvider::BaseLayerType::kTransparent80))); + SetBackground(views::CreateThemedSolidBackground(kColorAshShieldAndBase80)); close_all_button_->SetTooltipText( l10n_util::GetStringUTF16(IDS_ASH_DESKS_CLOSE_ALL_DESCRIPTION)); @@ -69,13 +67,6 @@ SetBetweenChildSpacing(visible ? kButtonSpacing : 0); } -void DeskActionView::OnThemeChanged() { - views::BoxLayoutView::OnThemeChanged(); - background()->SetNativeControlColor( - AshColorProvider::Get()->GetBaseLayerColor( - AshColorProvider::BaseLayerType::kTransparent80)); -} - BEGIN_METADATA(DeskActionView, views::BoxLayoutView) END_METADATA
diff --git a/ash/wm/desks/desk_action_view.h b/ash/wm/desks/desk_action_view.h index f29104d8..257a5465 100644 --- a/ash/wm/desks/desk_action_view.h +++ b/ash/wm/desks/desk_action_view.h
@@ -39,9 +39,6 @@ void SetCombineDesksButtonVisibility(bool visible); private: - // views::BoxLayoutView: - void OnThemeChanged() override; - CloseButton* combine_desks_button_; CloseButton* close_all_button_; };
diff --git a/ash/wm/float/float_controller.cc b/ash/wm/float/float_controller.cc index 56f08fd8..6021777 100644 --- a/ash/wm/float/float_controller.cc +++ b/ash/wm/float/float_controller.cc
@@ -90,6 +90,10 @@ // Shows the given floated window. void ShowFloatedWindow(aura::Window* floated_window) { DCHECK(floated_window); + if (floated_window->IsVisible()) { + return; + } + ScopedAnimationDisabler disabler(floated_window); floated_window->Show(); } @@ -403,7 +407,7 @@ ->GetDisplayNearestWindow(floated_window->GetRootWindow()) .bounds()); - // Check which corner to magnetize to based on which quadrent of the display + // Check which corner to magnetize to based on which quadrant of the display // the mouse/touch was released. If it somehow falls outside, then magnetize // to the previous location. gfx::RectF display_bounds_left, display_bounds_right;
diff --git a/ash/wm/multi_display/DIR_METADATA b/ash/wm/multi_display/DIR_METADATA new file mode 100644 index 0000000..1d65c216d --- /dev/null +++ b/ash/wm/multi_display/DIR_METADATA
@@ -0,0 +1,10 @@ +team_email: "chromeos-wm-corexp@google.com" +buganizer: { + component_id:1252581 +} +buganizer_public: { + component_id:1253107 +} +monorail { + component: "UI>Shell>WindowManager>MultiDisplay" +} \ No newline at end of file
diff --git a/ash/wm/multi_display/multi_display_metrics_controller.cc b/ash/wm/multi_display/multi_display_metrics_controller.cc new file mode 100644 index 0000000..b097942 --- /dev/null +++ b/ash/wm/multi_display/multi_display_metrics_controller.cc
@@ -0,0 +1,86 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/multi_display/multi_display_metrics_controller.h" + +#include "ash/shell.h" +#include "ash/wm/mru_window_tracker.h" +#include "base/metrics/histogram_functions.h" +#include "ui/aura/window.h" + +namespace ash { + +namespace { + +constexpr base::TimeDelta kTimerDuration = base::Minutes(1); + +} // namespace + +MultiDisplayMetricsController::MultiDisplayMetricsController() = default; + +MultiDisplayMetricsController::~MultiDisplayMetricsController() = default; + +void MultiDisplayMetricsController::OnWindowMovedOrResized( + aura::Window* window) { + if (!timer_.IsRunning()) { + return; + } + + if (!windows_.Contains(window)) { + return; + } + + timer_.Stop(); + RecordHistogram(/*user_moved_window=*/true); +} + +void MultiDisplayMetricsController::OnDisplayMetricsChanged( + const display::Display& display, + uint32_t changed_metrics) { + const bool rotation_changed = changed_metrics & DISPLAY_METRIC_ROTATION; + const bool work_area_changed = changed_metrics & DISPLAY_METRIC_WORK_AREA; + if (!rotation_changed && !work_area_changed) { + return; + } + + timer_.Stop(); + windows_.RemoveAll(); + + auto windows = + Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(kAllDesks); + if (windows.empty()) { + return; + } + + // Store the MRU windows that existed at the time of this display change. This + // is so if a user creates a new window after the display change, and then + // moves or resizes it, it would not count. + for (aura::Window* window : windows) { + windows_.Add(window); + } + last_display_change_type_ = rotation_changed ? DisplayChangeType::kRotated + : DisplayChangeType::kWorkArea; + timer_.Start(FROM_HERE, kTimerDuration, this, + &MultiDisplayMetricsController::OnTimerFinished); +} + +void MultiDisplayMetricsController::OnTimerFinished() { + RecordHistogram(/*user_moved_window=*/false); +} + +void MultiDisplayMetricsController::RecordHistogram(bool user_moved_window) { + windows_.RemoveAll(); + std::string histogram_name; + switch (last_display_change_type_) { + case DisplayChangeType::kRotated: + histogram_name = kRotatedHistogram; + break; + case DisplayChangeType::kWorkArea: + histogram_name = kWorkAreaChangedHistogram; + break; + } + base::UmaHistogramBoolean(histogram_name, user_moved_window); +} + +} // namespace ash
diff --git a/ash/wm/multi_display/multi_display_metrics_controller.h b/ash/wm/multi_display/multi_display_metrics_controller.h new file mode 100644 index 0000000..fb32c8f2 --- /dev/null +++ b/ash/wm/multi_display/multi_display_metrics_controller.h
@@ -0,0 +1,76 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WM_MULTI_DISPLAY_MULTI_DISPLAY_METRICS_CONTROLLER_H_ +#define ASH_WM_MULTI_DISPLAY_MULTI_DISPLAY_METRICS_CONTROLLER_H_ + +#include "ash/ash_export.h" +#include "base/timer/timer.h" +#include "ui/aura/window_tracker.h" +#include "ui/display/display_observer.h" + +namespace aura { +class Window; +} // namespace aura + +namespace ash { + +// This class listens to certain display changes and starts a timer to see if +// users resize or reposition app windows after the display change. These +// metrics are used to see if users like the remapping logic our window manager +// provides. +class ASH_EXPORT MultiDisplayMetricsController + : public display::DisplayObserver { + public: + // Histogram names of the boolean histogram. + constexpr static char kRotatedHistogram[] = + "Ash.MultiDisplay.WindowsMovedAfterRemap.DisplayRotated"; + constexpr static char kWorkAreaChangedHistogram[] = + "Ash.MultiDisplay.WindowsMovedAfterRemap.DisplayWorkAreaChanged"; + + MultiDisplayMetricsController(); + MultiDisplayMetricsController(const MultiDisplayMetricsController&) = delete; + MultiDisplayMetricsController& operator=( + const MultiDisplayMetricsController&) = delete; + ~MultiDisplayMetricsController() override; + + // Called from `ToplevelWindowEventHandler` when a window drag has + // successfully started. + void OnWindowMovedOrResized(aura::Window* window); + + // display::DisplayObserver: + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t changed_metrics) override; + + private: + friend class MultiDisplayMetricsControllerTest; + + // Type of display change that can trigger some metrics. A different type will + // be written to a different histogram. + enum class DisplayChangeType { + kRotated = 0, + kWorkArea, + }; + + // Called when the timer has ended. Records histograms. + void OnTimerFinished(); + + void RecordHistogram(bool user_moved_window); + + // The windows that were open at the time of the display change. Empty if the + // timer is not running. + aura::WindowTracker windows_; + + DisplayChangeType last_display_change_type_ = DisplayChangeType::kRotated; + + // Runs for one minute after a display change of interest. Records histograms + // on timer end. + base::OneShotTimer timer_; + + display::ScopedDisplayObserver display_observer_{this}; +}; + +} // namespace ash + +#endif // ASH_WM_MULTI_DISPLAY_MULTI_DISPLAY_METRICS_CONTROLLER_H_
diff --git a/ash/wm/multi_display/multi_display_metrics_controller_unittest.cc b/ash/wm/multi_display/multi_display_metrics_controller_unittest.cc new file mode 100644 index 0000000..fb329fb --- /dev/null +++ b/ash/wm/multi_display/multi_display_metrics_controller_unittest.cc
@@ -0,0 +1,213 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/multi_display/multi_display_metrics_controller.h" + +#include "ash/accessibility/magnifier/docked_magnifier_controller.h" +#include "ash/display/screen_orientation_controller_test_api.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "base/test/metrics/histogram_tester.h" +#include "ui/display/test/display_manager_test_api.h" +#include "ui/wm/core/window_util.h" + +namespace ash { + +class MultiDisplayMetricsControllerTest : public AshTestBase { + public: + MultiDisplayMetricsControllerTest() = default; + MultiDisplayMetricsControllerTest(const MultiDisplayMetricsControllerTest&) = + delete; + MultiDisplayMetricsControllerTest& operator=( + const MultiDisplayMetricsControllerTest&) = delete; + ~MultiDisplayMetricsControllerTest() override = default; + + void MaybeFireTimerNow() { + base::OneShotTimer* timer = + &Shell::Get()->multi_display_metrics_controller()->timer_; + if (timer->IsRunning()) { + timer->FireNow(); + } + } + + // Helpers to move and resize a given window using the event generator. + // Asserts that the window bounds have changed. + void MoveWindow(aura::Window* window) { + wm::ActivateWindow(window); + + const gfx::Rect old_bounds = window->GetBoundsInScreen(); + const gfx::Point point_on_header_in_screen(old_bounds.CenterPoint().x(), + old_bounds.y() + 10); + GetEventGenerator()->set_current_screen_location(point_on_header_in_screen); + GetEventGenerator()->DragMouseBy(10, 10); + const gfx::Rect expected_new_bounds = old_bounds + gfx::Vector2d(10, 10); + ASSERT_EQ(expected_new_bounds, window->GetBoundsInScreen()); + } + + void ResizeWindow(aura::Window* window) { + wm::ActivateWindow(window); + + const gfx::Rect old_bounds = window->GetBoundsInScreen(); + GetEventGenerator()->set_current_screen_location(old_bounds.bottom_right()); + GetEventGenerator()->DragMouseBy(5, 5); + gfx::Rect expected_new_bounds(old_bounds); + expected_new_bounds.Outset(gfx::Outsets::TLBR(0, 0, 5, 5)); + ASSERT_EQ(expected_new_bounds, window->GetBoundsInScreen()); + } + + // AshTestBase: + void SetUp() override { + AshTestBase::SetUp(); + for (int i = 0; i < 4; ++i) { + test_windows_.push_back(CreateAppWindow()); + } + } + + void TearDown() override { + test_windows_.clear(); + AshTestBase::TearDown(); + } + + protected: + // Most tests in this suite use multiple windows per test. This vector stores + // the needed app windows, which are resizable by default and would be in the + // MRU list. + std::vector<std::unique_ptr<aura::Window>> test_windows_; + + base::HistogramTester histogram_tester_; +}; + +TEST_F(MultiDisplayMetricsControllerTest, DisplayRotated) { + // Rotate the display. Do a double rotation so our move and resize helpers + // work properly. + const 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 orientation_test_api( + Shell::Get()->screen_orientation_controller()); + orientation_test_api.SetDisplayRotation( + display::Display::ROTATE_90, display::Display::RotationSource::ACTIVE); + orientation_test_api.SetDisplayRotation( + display::Display::ROTATE_0, display::Display::RotationSource::ACTIVE); + + MoveWindow(test_windows_[0].get()); + MaybeFireTimerNow(); + histogram_tester_.ExpectUniqueSample( + MultiDisplayMetricsController::kRotatedHistogram, static_cast<int>(true), + 1); +} + +TEST_F(MultiDisplayMetricsControllerTest, DisplaySizeChanged) { + UpdateDisplay("800x600"); + + UpdateDisplay("2000x1000"); + MoveWindow(test_windows_[0].get()); + MaybeFireTimerNow(); + histogram_tester_.ExpectUniqueSample( + MultiDisplayMetricsController::kWorkAreaChangedHistogram, + static_cast<int>(true), 1); +} + +TEST_F(MultiDisplayMetricsControllerTest, DisplayWorkAreaChanged) { + // We will use the docked magnifier to modify the work area in this test. + DockedMagnifierController* docked_magnifier_controller = + Shell::Get()->docked_magnifier_controller(); + docked_magnifier_controller->SetEnabled(true); + ASSERT_GT(docked_magnifier_controller->GetMagnifierHeightForTesting(), 0); + + MoveWindow(test_windows_[0].get()); + + MaybeFireTimerNow(); + histogram_tester_.ExpectUniqueSample( + MultiDisplayMetricsController::kWorkAreaChangedHistogram, + static_cast<int>(true), 1); +} + +// The following tests use display size change to test several edge cases. The +// logic between all the display changes is the same and display size changed is +// the simplest scenario to test. + +// Tests that if no windows are moved or resized after a display change, the +// histogram reflects that. +TEST_F(MultiDisplayMetricsControllerTest, NoWindowsMovedOrResized) { + UpdateDisplay("800x600"); + + UpdateDisplay("2000x1000"); + MaybeFireTimerNow(); + histogram_tester_.ExpectUniqueSample( + MultiDisplayMetricsController::kWorkAreaChangedHistogram, + static_cast<int>(false), 1); +} + +TEST_F(MultiDisplayMetricsControllerTest, MultipleWindowsMoved) { + UpdateDisplay("800x600"); + + UpdateDisplay("2000x1000"); + + // Move a couple of different windows after resizing a display. Test that we + // only record it once. + MoveWindow(test_windows_[0].get()); + MoveWindow(test_windows_[1].get()); + MoveWindow(test_windows_[2].get()); + MoveWindow(test_windows_[3].get()); + + MaybeFireTimerNow(); + histogram_tester_.ExpectUniqueSample( + MultiDisplayMetricsController::kWorkAreaChangedHistogram, + static_cast<int>(true), 1); +} + +// Tests that resizing window after a display changes records properly. +TEST_F(MultiDisplayMetricsControllerTest, WindowsResized) { + UpdateDisplay("800x600"); + + UpdateDisplay("2000x1000"); + ResizeWindow(test_windows_[0].get()); + + MaybeFireTimerNow(); + histogram_tester_.ExpectUniqueSample( + MultiDisplayMetricsController::kWorkAreaChangedHistogram, + static_cast<int>(true), 1); +} + +TEST_F(MultiDisplayMetricsControllerTest, MultipleDisplayChanges) { + UpdateDisplay("800x600"); + + UpdateDisplay("1200x800"); + UpdateDisplay("2000x1000"); + UpdateDisplay("3000x2000"); + + // Move the window after changing the display size multiple times. Test that + // we only record it once. + MoveWindow(test_windows_[0].get()); + + MaybeFireTimerNow(); + histogram_tester_.ExpectUniqueSample( + MultiDisplayMetricsController::kWorkAreaChangedHistogram, + static_cast<int>(true), 1); +} + +// Tests that windows that are added after a display change and then moved +// and/or resized do not count. +TEST_F(MultiDisplayMetricsControllerTest, WindowAddedAfterDisplayChangeMoved) { + UpdateDisplay("800x600"); + + UpdateDisplay("1200x800"); + + // Add a new window after the display has changed and move the window. + auto new_window = CreateAppWindow(); + MoveWindow(new_window.get()); + ResizeWindow(new_window.get()); + + // Verify we don't record the window change, since it was added after the + // display change. + MaybeFireTimerNow(); + histogram_tester_.ExpectUniqueSample( + MultiDisplayMetricsController::kWorkAreaChangedHistogram, + static_cast<int>(false), 1); +} + +} // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_cue.cc b/ash/wm/tablet_mode/tablet_mode_multitask_cue.cc index 9819abe..d1f77f96 100644 --- a/ash/wm/tablet_mode/tablet_mode_multitask_cue.cc +++ b/ash/wm/tablet_mode/tablet_mode_multitask_cue.cc
@@ -10,6 +10,7 @@ #include "ash/wm/window_util.h" #include "chromeos/ui/wm/features.h" #include "ui/aura/client/aura_constants.h" +#include "ui/views/animation/animation_builder.h" #include "ui/wm/public/activation_client.h" namespace ash { @@ -22,7 +23,9 @@ constexpr int kCueWidth = 48; constexpr int kCueHeight = 4; +// Cue timing values. constexpr base::TimeDelta kCueDismissTimeout = base::Seconds(6); +constexpr base::TimeDelta kFadeDuration = base::Milliseconds(100); constexpr SkColor kCueColor = SK_ColorGRAY; @@ -46,7 +49,7 @@ void TabletModeMultitaskCue::MaybeShowCue(aura::Window* active_window) { DCHECK(active_window); - // Only show or dismiss the cue when activating app windows in the MRU list. + // Only show or dismiss the cue when activating app windows. // TODO(hewer): Review and update logic when `gained_active` is a NON_APP // window and `lost_active` is an app. if (static_cast<AppType>(active_window->GetProperty( @@ -55,8 +58,8 @@ } // `UpdateCueBounds()` does not currently re-parent the layer, so it must be - // dismissed before it can be shown again. May change when animations are - // implemented. + // dismissed before it can be shown again. If the user activates a floatable + // or non-maximizable window, any existing cue should still be dismissed. DismissCue(); // Floated windows do not have the multitask menu. @@ -71,6 +74,7 @@ cue_layer_ = std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR); cue_layer_->SetColor(kCueColor); cue_layer_->SetRoundedCornerRadius(gfx::RoundedCornersF(kCornerRadius)); + cue_layer_->SetOpacity(0.0f); window_->layer()->Add(cue_layer_.get()); @@ -81,8 +85,20 @@ window_observation_.Observe(window_); WindowState::Get(window_)->AddObserver(this); + // Because `DismissCue()` is called beforehand, there should not be any + // animation currently running. + DCHECK(!cue_layer_->GetAnimator()->is_animating()); + + // Fade the cue in. + views::AnimationBuilder() + .SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET) + .Once() + .SetDuration(kFadeDuration) + .SetOpacity(cue_layer_.get(), 1.0f, gfx::Tween::LINEAR); + cue_dismiss_timer_.Start(FROM_HERE, kCueDismissTimeout, this, - &TabletModeMultitaskCue::DismissCue); + &TabletModeMultitaskCue::OnTimerFinished); } void TabletModeMultitaskCue::DismissCue() { @@ -136,4 +152,21 @@ kCueYOffset, kCueWidth, kCueHeight)); } +void TabletModeMultitaskCue::OnTimerFinished() { + // If no cue or the animation is already fading out, return. + if (!cue_layer_ || cue_layer_->GetAnimator()->GetTargetOpacity() == 0.0f) { + return; + } + + // Fade the cue out. + views::AnimationBuilder() + .SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET) + .OnEnded(base::BindOnce(&TabletModeMultitaskCue::DismissCue, + base::Unretained(this))) + .Once() + .SetDuration(kFadeDuration) + .SetOpacity(cue_layer_.get(), 0.0f, gfx::Tween::LINEAR); +} + } // namespace ash \ No newline at end of file
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_cue.h b/ash/wm/tablet_mode/tablet_mode_multitask_cue.h index ebb9df2..4e7911f 100644 --- a/ash/wm/tablet_mode/tablet_mode_multitask_cue.h +++ b/ash/wm/tablet_mode/tablet_mode_multitask_cue.h
@@ -57,10 +57,16 @@ void FireCueDismissTimerForTesting() { cue_dismiss_timer_.FireNow(); } private: + friend class TabletModeMultitaskCueTest; + // Updates the bounds of the cue relative to the window if the window is // still available. void UpdateCueBounds(); + // Fades the cue out over a short duration if it is still active, then cleans + // up via `DismissCue`. If already fading out, returns immediately. + void OnTimerFinished(); + // The app window that the cue is associated with. aura::Window* window_ = nullptr;
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_cue_unittest.cc b/ash/wm/tablet_mode/tablet_mode_multitask_cue_unittest.cc index faa8dada..5f11c20 100644 --- a/ash/wm/tablet_mode/tablet_mode_multitask_cue_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_multitask_cue_unittest.cc
@@ -10,6 +10,8 @@ #include "ash/wm/tablet_mode/tablet_mode_window_manager.h" #include "base/test/scoped_feature_list.h" #include "chromeos/ui/wm/features.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/compositor/test/layer_animation_stopped_waiter.h" namespace ash { @@ -49,15 +51,17 @@ // Tests that the cue layer is created properly. TEST_F(TabletModeMultitaskCueTest, BasicShowCue) { auto window = CreateAppWindow(); + gfx::Rect window_bounds = window->bounds(); auto* multitask_cue = GetMultitaskCue(); ASSERT_TRUE(multitask_cue); ui::Layer* cue_layer = multitask_cue->cue_layer_for_testing(); ASSERT_TRUE(cue_layer); - EXPECT_EQ( - gfx::Rect((800 - kCueWidth) / 2, kCueYOffset, kCueWidth, kCueHeight), - cue_layer->bounds()); + + EXPECT_EQ(gfx::Rect((window_bounds.width() - kCueWidth) / 2, kCueYOffset, + kCueWidth, kCueHeight), + cue_layer->bounds()); } // Tests that the cue bounds are updated properly after a window is split. @@ -66,11 +70,12 @@ SplitViewController::Get(Shell::GetPrimaryRootWindow()); auto window1 = CreateAppWindow(); + split_view_controller->SnapWindow( window1.get(), SplitViewController::SnapPosition::kPrimary); - gfx::Rect split_bounds((396 - kCueWidth) / 2, kCueYOffset, kCueWidth, - kCueHeight); + gfx::Rect split_bounds((window1->bounds().width() - kCueWidth) / 2, + kCueYOffset, kCueWidth, kCueHeight); ui::Layer* cue_layer = GetMultitaskCue()->cue_layer_for_testing(); ASSERT_TRUE(cue_layer); @@ -87,15 +92,55 @@ // Tests that the `OneShotTimer` properly dismisses the cue after firing. TEST_F(TabletModeMultitaskCueTest, DismissTimerFiring) { + ui::ScopedAnimationDurationScaleMode non_zero_duration_mode( + ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + auto window = CreateAppWindow(); auto* multitask_cue = GetMultitaskCue(); ui::Layer* cue_layer = multitask_cue->cue_layer_for_testing(); ASSERT_TRUE(cue_layer); + // Wait for fade in to finish. + ui::LayerAnimationStoppedWaiter animation_waiter; + animation_waiter.Wait(cue_layer); + multitask_cue->FireCueDismissTimerForTesting(); - cue_layer = multitask_cue->cue_layer_for_testing(); - EXPECT_FALSE(cue_layer); + + // Wait for fade out to finish. + animation_waiter.Wait(cue_layer); + EXPECT_FALSE(multitask_cue->cue_layer_for_testing()); +} + +// Tests that the cue dismisses properly during the fade out animation. +TEST_F(TabletModeMultitaskCueTest, DismissEarly) { + ui::ScopedAnimationDurationScaleMode non_zero_duration_mode( + ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + + auto window = CreateAppWindow(); + + auto* multitask_cue = GetMultitaskCue(); + ui::Layer* cue_layer = multitask_cue->cue_layer_for_testing(); + ASSERT_TRUE(cue_layer); + + // Wait for fade in to finish. + ui::LayerAnimationStoppedWaiter().Wait(cue_layer); + + multitask_cue->FireCueDismissTimerForTesting(); + multitask_cue->DismissCue(); + EXPECT_FALSE(multitask_cue->cue_layer_for_testing()); +} + +// Tests that the cue dismisses properly when the float keyboard accelerator is +// pressed. +TEST_F(TabletModeMultitaskCueTest, FloatWindow) { + auto window = CreateAppWindow(); + + PressAndReleaseKey(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN); + + auto* multitask_cue = GetMultitaskCue(); + ASSERT_TRUE(multitask_cue); + EXPECT_FALSE(multitask_cue->cue_layer_for_testing()); } } // namespace ash \ No newline at end of file
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc index fca6174e..95abcb3 100644 --- a/ash/wm/toplevel_window_event_handler.cc +++ b/ash/wm/toplevel_window_event_handler.cc
@@ -7,6 +7,7 @@ #include "ash/constants/app_types.h" #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" +#include "ash/wm/multi_display/multi_display_metrics_controller.h" #include "ash/wm/multitask_menu_nudge_controller.h" #include "ash/wm/resize_shadow.h" #include "ash/wm/resize_shadow_controller.h" @@ -661,6 +662,8 @@ return false; window_resizer_ = std::make_unique<ScopedWindowResizer>( this, std::move(resizer), grab_capture); + Shell::Get()->multi_display_metrics_controller()->OnWindowMovedOrResized( + window); return true; }
diff --git a/base/BUILD.gn b/base/BUILD.gn index 125fe6e..d4980a4 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -3081,6 +3081,8 @@ "allocator/dispatcher/testing/observer_mock.h", "allocator/dispatcher/testing/tools.h", "allocator/dispatcher/tls_unittest.cc", + "allocator/partition_allocator/pointers/raw_ptr_unittest.cc", + "allocator/partition_allocator/pointers/raw_ref_unittest.cc", "at_exit_unittest.cc", "atomicops_unittest.cc", "auto_reset_unittest.cc", @@ -3196,8 +3198,6 @@ "memory/platform_shared_memory_region_unittest.cc", "memory/ptr_util_unittest.cc", "memory/raw_ptr_asan_unittest.cc", - "memory/raw_ptr_unittest.cc", - "memory/raw_ref_unittest.cc", "memory/ref_counted_memory_unittest.cc", "memory/ref_counted_unittest.cc", "memory/safe_ref_unittest.cc", @@ -4005,6 +4005,7 @@ nocompile_test("base_nocompile_tests") { sources = [ "allocator/partition_allocator/partition_alloc_base/thread_annotations_pa_unittest.nc", + "allocator/partition_allocator/pointers/raw_ptr_unittest.nc", "callback_list_unittest.nc", "containers/buffer_iterator_unittest.nc", "containers/checked_iterators_unittest.nc", @@ -4016,7 +4017,6 @@ "functional/callback_unittest.nc", "functional/function_ref_unittest.nc", "functional/overloaded_unittest.nc", - "memory/raw_ptr_unittest.nc", "memory/ref_counted_unittest.nc", "memory/weak_ptr_unittest.nc", "metrics/field_trial_params_unittest.nc",
diff --git a/base/allocator/partition_allocator/DEPS b/base/allocator/partition_allocator/DEPS index 1e2b78b..95734f12 100644 --- a/base/allocator/partition_allocator/DEPS +++ b/base/allocator/partition_allocator/DEPS
@@ -154,4 +154,9 @@ "gtest_prod_util\.h$": [ "+testing/gtest/include/gtest/gtest_prod.h", ], + "raw_(ptr|ref)_unittest\.cc$": [ + "+base", + "+third_party/abseil-cpp/absl/types/optional.h", + "+third_party/abseil-cpp/absl/types/variant.h", + ] }
diff --git a/base/allocator/partition_allocator/address_space_randomization.cc b/base/allocator/partition_allocator/address_space_randomization.cc index 907853e..dcaa8d3 100644 --- a/base/allocator/partition_allocator/address_space_randomization.cc +++ b/base/allocator/partition_allocator/address_space_randomization.cc
@@ -10,9 +10,7 @@ #include "build/build_config.h" #if BUILDFLAG(IS_WIN) -#include <windows.h> // Must be in front of other Windows header files. - -#include <versionhelpers.h> +#include <windows.h> #endif namespace partition_alloc { @@ -24,26 +22,10 @@ random <<= 32ULL; random |= static_cast<uintptr_t>(internal::RandomValue()); -// The ASLRMask() and ASLROffset() constants will be suitable for the -// OS and build configuration. -#if BUILDFLAG(IS_WIN) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) - // Windows >= 8.1 has the full 47 bits. Use them where available. - static bool windows_81 = false; - static bool windows_81_initialized = false; - if (!windows_81_initialized) { - windows_81 = IsWindows8Point1OrGreater(); - windows_81_initialized = true; - } - if (!windows_81) { - random &= internal::ASLRMaskBefore8_10(); - } else { - random &= internal::ASLRMask(); - } - random += internal::ASLROffset(); -#else + // The ASLRMask() and ASLROffset() constants will be suitable for the + // OS and build configuration. random &= internal::ASLRMask(); random += internal::ASLROffset(); -#endif // BUILDFLAG(IS_WIN) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) #else // PA_CONFIG(HAS_64_BITS_POINTERS) #if BUILDFLAG(IS_WIN) // On win32 host systems the randomization plus huge alignment causes
diff --git a/base/allocator/partition_allocator/address_space_randomization.h b/base/allocator/partition_allocator/address_space_randomization.h index e761256..e4767ca7 100644 --- a/base/allocator/partition_allocator/address_space_randomization.h +++ b/base/allocator/partition_allocator/address_space_randomization.h
@@ -56,16 +56,12 @@ #elif BUILDFLAG(IS_WIN) - // Windows 8.10 and newer support the full 48 bit address range. Older - // versions of Windows only support 44 bits. Since ASLROffset() is non-zero - // and may cause a carry, use 47 and 43 bit masks. See + // Windows 8.10 and newer support the full 48 bit address range. Since + // ASLROffset() is non-zero and may cause a carry, use 47 bit masks. See // http://www.alex-ionescu.com/?p=246 constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() { return AslrMask(47); } - constexpr PA_ALWAYS_INLINE uintptr_t ASLRMaskBefore8_10() { - return AslrMask(43); - } // Try not to map pages into the range where Windows loads DLLs by default. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() { return 0x80000000ULL;
diff --git a/base/allocator/partition_allocator/address_space_randomization_unittest.cc b/base/allocator/partition_allocator/address_space_randomization_unittest.cc index d8211de..196e7e3d 100644 --- a/base/allocator/partition_allocator/address_space_randomization_unittest.cc +++ b/base/allocator/partition_allocator/address_space_randomization_unittest.cc
@@ -17,8 +17,6 @@ #if BUILDFLAG(IS_WIN) #include <windows.h> #include "base/win/windows_version.h" -// versionhelpers.h must be included after windows.h. -#include <versionhelpers.h> #endif namespace partition_alloc { @@ -28,12 +26,6 @@ uintptr_t GetMask() { uintptr_t mask = internal::ASLRMask(); #if defined(ARCH_CPU_64_BITS) -// Sanitizers use their own ASLR mask constant. -#if BUILDFLAG(IS_WIN) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) - if (!IsWindows8Point1OrGreater()) { - mask = internal::ASLRMaskBefore8_10(); - } -#endif // BUILDFLAG(IS_WIN) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)) #elif defined(ARCH_CPU_32_BITS) #if BUILDFLAG(IS_WIN) BOOL is_wow64 = FALSE;
diff --git a/base/allocator/partition_allocator/page_allocator_internals_win.h b/base/allocator/partition_allocator/page_allocator_internals_win.h index f3bb119..7c73ccda 100644 --- a/base/allocator/partition_allocator/page_allocator_internals_win.h +++ b/base/allocator/partition_allocator/page_allocator_internals_win.h
@@ -5,8 +5,6 @@ #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_ #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_ -#include <versionhelpers.h> - #include <cstdint> #include "base/allocator/partition_allocator/oom.h" @@ -18,17 +16,6 @@ namespace partition_alloc::internal { -namespace { - -// On Windows, discarded pages are not returned to the system immediately and -// not guaranteed to be zeroed when returned to the application. -using DiscardVirtualMemoryFunction = DWORD(WINAPI*)(PVOID virtualAddress, - SIZE_T size); -DiscardVirtualMemoryFunction s_discard_virtual_memory = - reinterpret_cast<DiscardVirtualMemoryFunction>(-1); - -} // namespace - // |VirtualAlloc| will fail if allocation at the hint address is blocked. constexpr bool kHintIsAdvisory = false; std::atomic<int32_t> s_allocPageErrorCode{ERROR_SUCCESS}; @@ -237,27 +224,10 @@ } void DiscardSystemPagesInternal(uintptr_t address, size_t length) { - if (s_discard_virtual_memory == - reinterpret_cast<DiscardVirtualMemoryFunction>(-1)) { - // DiscardVirtualMemory's minimum supported client is Windows 8.1 Update. - // So skip GetProcAddress("DiscardVirtualMemory") if windows version is - // smaller than Windows 8.1. - if (IsWindows8Point1OrGreater()) { - s_discard_virtual_memory = - reinterpret_cast<DiscardVirtualMemoryFunction>(GetProcAddress( - GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory")); - } else { - s_discard_virtual_memory = nullptr; - } - } - void* ptr = reinterpret_cast<void*>(address); // Use DiscardVirtualMemory when available because it releases faster than // MEM_RESET. - DWORD ret = 1; - if (s_discard_virtual_memory) { - ret = s_discard_virtual_memory(ptr, length); - } + DWORD ret = DiscardVirtualMemory(ptr, length); // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on // failure. if (ret) {
diff --git a/base/allocator/partition_allocator/pointers/raw_ptr.h b/base/allocator/partition_allocator/pointers/raw_ptr.h index a8e02a06..a8f38e2 100644 --- a/base/allocator/partition_allocator/pointers/raw_ptr.h +++ b/base/allocator/partition_allocator/pointers/raw_ptr.h
@@ -1680,23 +1680,21 @@ template <typename U, typename V, typename R1, typename R2> friend PA_ALWAYS_INLINE bool operator==(const raw_ptr<U, R1>& lhs, const raw_ptr<V, R2>& rhs); - template <typename U> - friend PA_ALWAYS_INLINE bool operator!=(const raw_ptr& lhs, - const raw_ptr<U, Traits>& rhs) { - return !(lhs == rhs); - } - template <typename U, typename V, typename R> - friend PA_ALWAYS_INLINE bool operator<(const raw_ptr<U, R>& lhs, - const raw_ptr<V, R>& rhs); - template <typename U, typename V, typename R> - friend PA_ALWAYS_INLINE bool operator>(const raw_ptr<U, R>& lhs, - const raw_ptr<V, R>& rhs); - template <typename U, typename V, typename R> - friend PA_ALWAYS_INLINE bool operator<=(const raw_ptr<U, R>& lhs, - const raw_ptr<V, R>& rhs); - template <typename U, typename V, typename R> - friend PA_ALWAYS_INLINE bool operator>=(const raw_ptr<U, R>& lhs, - const raw_ptr<V, R>& rhs); + template <typename U, typename V, typename R1, typename R2> + friend PA_ALWAYS_INLINE bool operator!=(const raw_ptr<U, R1>& lhs, + const raw_ptr<V, R2>& rhs); + template <typename U, typename V, typename R1, typename R2> + friend PA_ALWAYS_INLINE bool operator<(const raw_ptr<U, R1>& lhs, + const raw_ptr<V, R2>& rhs); + template <typename U, typename V, typename R1, typename R2> + friend PA_ALWAYS_INLINE bool operator>(const raw_ptr<U, R1>& lhs, + const raw_ptr<V, R2>& rhs); + template <typename U, typename V, typename R1, typename R2> + friend PA_ALWAYS_INLINE bool operator<=(const raw_ptr<U, R1>& lhs, + const raw_ptr<V, R2>& rhs); + template <typename U, typename V, typename R1, typename R2> + friend PA_ALWAYS_INLINE bool operator>=(const raw_ptr<U, R1>& lhs, + const raw_ptr<V, R2>& rhs); // Comparisons with U*. These operators also handle the case where the RHS is // T*. @@ -1814,27 +1812,33 @@ return lhs.GetForComparison() == rhs.GetForComparison(); } -template <typename U, typename V, typename Traits> -PA_ALWAYS_INLINE bool operator<(const raw_ptr<U, Traits>& lhs, - const raw_ptr<V, Traits>& rhs) { +template <typename U, typename V, typename Traits1, typename Traits2> +PA_ALWAYS_INLINE bool operator!=(const raw_ptr<U, Traits1>& lhs, + const raw_ptr<V, Traits2>& rhs) { + return !(lhs == rhs); +} + +template <typename U, typename V, typename Traits1, typename Traits2> +PA_ALWAYS_INLINE bool operator<(const raw_ptr<U, Traits1>& lhs, + const raw_ptr<V, Traits2>& rhs) { return lhs.GetForComparison() < rhs.GetForComparison(); } -template <typename U, typename V, typename Traits> -PA_ALWAYS_INLINE bool operator>(const raw_ptr<U, Traits>& lhs, - const raw_ptr<V, Traits>& rhs) { +template <typename U, typename V, typename Traits1, typename Traits2> +PA_ALWAYS_INLINE bool operator>(const raw_ptr<U, Traits1>& lhs, + const raw_ptr<V, Traits2>& rhs) { return lhs.GetForComparison() > rhs.GetForComparison(); } -template <typename U, typename V, typename Traits> -PA_ALWAYS_INLINE bool operator<=(const raw_ptr<U, Traits>& lhs, - const raw_ptr<V, Traits>& rhs) { +template <typename U, typename V, typename Traits1, typename Traits2> +PA_ALWAYS_INLINE bool operator<=(const raw_ptr<U, Traits1>& lhs, + const raw_ptr<V, Traits2>& rhs) { return lhs.GetForComparison() <= rhs.GetForComparison(); } -template <typename U, typename V, typename Traits> -PA_ALWAYS_INLINE bool operator>=(const raw_ptr<U, Traits>& lhs, - const raw_ptr<V, Traits>& rhs) { +template <typename U, typename V, typename Traits1, typename Traits2> +PA_ALWAYS_INLINE bool operator>=(const raw_ptr<U, Traits1>& lhs, + const raw_ptr<V, Traits2>& rhs) { return lhs.GetForComparison() >= rhs.GetForComparison(); }
diff --git a/base/memory/raw_ptr_unittest.cc b/base/allocator/partition_allocator/pointers/raw_ptr_unittest.cc similarity index 97% rename from base/memory/raw_ptr_unittest.cc rename to base/allocator/partition_allocator/pointers/raw_ptr_unittest.cc index b40db68..b18b2cb3 100644 --- a/base/memory/raw_ptr_unittest.cc +++ b/base/allocator/partition_allocator/pointers/raw_ptr_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/memory/raw_ptr.h" +#include "base/allocator/partition_allocator/pointers/raw_ptr.h" #include <climits> #include <cstddef> @@ -19,11 +19,11 @@ #include "base/allocator/partition_allocator/partition_alloc_buildflags.h" #include "base/allocator/partition_allocator/partition_alloc_config.h" #include "base/allocator/partition_allocator/partition_alloc_constants.h" +#include "base/allocator/partition_allocator/pointers/raw_ref.h" #include "base/allocator/partition_allocator/tagging.h" #include "base/cpu.h" #include "base/logging.h" #include "base/memory/raw_ptr_asan_service.h" -#include "base/memory/raw_ref.h" #include "base/task/thread_pool.h" #include "base/test/bind.h" #include "base/test/gtest_util.h" @@ -1211,6 +1211,47 @@ CountingRawPtrHasCounts()); } +// Two `raw_ptr`s with different `TraitBundle`s should still hit +// `GetForComparison()` (as opposed to `GetForExtraction()`) in their +// comparison operators. We use `CountingRawPtr` and +// `CountingRawPtrMayDangle` to contrast two different `TraitBundle`s. +TEST_F(RawPtrTest, OperatorsUseGetForComparison) { + int x = 123; + CountingRawPtr<int> ptr1 = &x; + CountingRawPtrMayDangle<int> ptr2 = &x; + + RawPtrCountingImpl::ClearCounters(); + RawPtrCountingMayDangleImpl::ClearCounters(); + + EXPECT_TRUE(ptr1 == ptr2); + EXPECT_FALSE(ptr1 != ptr2); + EXPECT_THAT((CountingRawPtrExpectations{ + .get_for_extraction_cnt = 0, + .get_for_comparison_cnt = 2, + }), + CountingRawPtrHasCounts()); + EXPECT_THAT((CountingRawPtrExpectations{ + .get_for_extraction_cnt = 0, + .get_for_comparison_cnt = 2, + }), + MayDangleCountingRawPtrHasCounts()); + + EXPECT_FALSE(ptr1 < ptr2); + EXPECT_FALSE(ptr1 > ptr2); + EXPECT_TRUE(ptr1 <= ptr2); + EXPECT_TRUE(ptr1 >= ptr2); + EXPECT_THAT((CountingRawPtrExpectations{ + .get_for_extraction_cnt = 0, + .get_for_comparison_cnt = 6, + }), + CountingRawPtrHasCounts()); + EXPECT_THAT((CountingRawPtrExpectations{ + .get_for_extraction_cnt = 0, + .get_for_comparison_cnt = 6, + }), + MayDangleCountingRawPtrHasCounts()); +} + // This test checks how the std library handles collections like // std::vector<raw_ptr<T>>. //
diff --git a/base/memory/raw_ptr_unittest.nc b/base/allocator/partition_allocator/pointers/raw_ptr_unittest.nc similarity index 98% rename from base/memory/raw_ptr_unittest.nc rename to base/allocator/partition_allocator/pointers/raw_ptr_unittest.nc index 6b53941c..d1ef160 100644 --- a/base/memory/raw_ptr_unittest.nc +++ b/base/allocator/partition_allocator/pointers/raw_ptr_unittest.nc
@@ -11,7 +11,7 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" -#include "base/memory/raw_ptr.h" +#include "base/allocator/partition_allocator/pointers/raw_ptr.h" namespace {
diff --git a/base/memory/raw_ref_unittest.cc b/base/allocator/partition_allocator/pointers/raw_ref_unittest.cc similarity index 99% rename from base/memory/raw_ref_unittest.cc rename to base/allocator/partition_allocator/pointers/raw_ref_unittest.cc index be5b5ee..0f2d1de 100644 --- a/base/memory/raw_ref_unittest.cc +++ b/base/allocator/partition_allocator/pointers/raw_ref_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/memory/raw_ref.h" +#include "base/allocator/partition_allocator/pointers/raw_ref.h" #include <functional> #include <type_traits>
diff --git a/base/fuchsia/system_build_info_unittest.cc b/base/fuchsia/system_build_info_unittest.cc index dd7c487..15244b7 100644 --- a/base/fuchsia/system_build_info_unittest.cc +++ b/base/fuchsia/system_build_info_unittest.cc
@@ -11,11 +11,7 @@ // Ensures that when FetchAndCacheSystemInfo() has not been called in the // process that a DCHECK fires to alert the developer. -// -// TODO(crbug.com/1326674) Ensure the test passes on Fuchsia bots and -// re-enable. -TEST(BuildInfoDeathTest, - DISABLED_GetCachedBuildInfo_DcheckIfNotAlreadyFetched) { +TEST(BuildInfoDeathTest, GetCachedBuildInfo_DcheckIfNotAlreadyFetched) { // Clear the cached build info to force an error condition. ClearCachedSystemInfoForTesting(); @@ -29,9 +25,7 @@ EXPECT_TRUE(FetchAndCacheSystemInfo()); } -// TODO(crbug.com/1326674) Ensure the test passes on Fuchsia bots and -// re-enable. -TEST(BuildInfoTest, DISABLED_GetCachedBuildInfo_CheckExpectedValues) { +TEST(BuildInfoTest, GetCachedBuildInfo_CheckExpectedValues) { // Ensure the cached BuildInfo is in a known state. ClearCachedSystemInfoForTesting(); ASSERT_TRUE(FetchAndCacheSystemInfo());
diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc index 1d967d0..7b6d955d 100644 --- a/base/message_loop/message_pump_libevent.cc +++ b/base/message_loop/message_pump_libevent.cc
@@ -44,9 +44,7 @@ #if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL) bool g_use_epoll = false; -BASE_FEATURE(kMessagePumpEpoll, - "MessagePumpEpoll", - FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kMessagePumpEpoll, "MessagePumpEpoll", FEATURE_ENABLED_BY_DEFAULT); #endif } // namespace
diff --git a/base/process/process.h b/base/process/process.h index 8af76bc..7ff9c93e 100644 --- a/base/process/process.h +++ b/base/process/process.h
@@ -248,6 +248,13 @@ void InitializePriority(); #endif // BUILDFLAG(IS_CHROMEOS) +#if BUILDFLAG(IS_MAC) + // Sets the `task_role_t` of the current task (the calling process) to + // TASK_DEFAULT_APPLICATION, if the MacSetDefaultTaskRole feature is + // enabled. + static void SetCurrentTaskDefaultRole(); +#endif // BUILDFLAG(IS_MAC) + private: #if BUILDFLAG(IS_CHROMEOS) // Cleans up process state. If OneGroupPerRenderer is enabled, it cleans up
diff --git a/base/process/process_mac.cc b/base/process/process_mac.cc index 326b22b8..67be45d4 100644 --- a/base/process/process_mac.cc +++ b/base/process/process_mac.cc
@@ -6,6 +6,7 @@ #include <mach/mach.h> #include <stddef.h> +#include <sys/resource.h> #include <sys/sysctl.h> #include <sys/time.h> #include <unistd.h> @@ -14,11 +15,18 @@ #include <memory> #include "base/cxx17_backports.h" +#include "base/feature_list.h" #include "base/mac/mach_logging.h" #include "base/memory/free_deleter.h" namespace base { +// Enables setting the task role of every child process to +// TASK_DEFAULT_APPLICATION. +BASE_FEATURE(kMacSetDefaultTaskRole, + "MacSetDefaultTaskRole", + FEATURE_DISABLED_BY_DEFAULT); + Time Process::CreationTime() const { int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, Pid()}; size_t len = 0; @@ -91,4 +99,17 @@ return true; } +// static +void Process::SetCurrentTaskDefaultRole() { + if (!base::FeatureList::IsEnabled(kMacSetDefaultTaskRole)) { + return; + } + + task_category_policy category_policy; + category_policy.role = TASK_DEFAULT_APPLICATION; + task_policy_set(mach_task_self(), TASK_CATEGORY_POLICY, + reinterpret_cast<task_policy_t>(&category_policy), + TASK_CATEGORY_POLICY_COUNT); +} + } // namespace base
diff --git a/base/task/thread_pool/thread_group_unittest.cc b/base/task/thread_pool/thread_group_unittest.cc index feaa868..19b60d9 100644 --- a/base/task/thread_pool/thread_group_unittest.cc +++ b/base/task/thread_pool/thread_group_unittest.cc
@@ -741,6 +741,7 @@ thread_group_->JoinForTesting(); EXPECT_EQ(1U, task_source->HasOneRef()); // Prevent TearDown() from calling JoinForTesting() again. + mock_pooled_task_runner_delegate_.SetThreadGroup(nullptr); thread_group_ = nullptr; }
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc index 90be63a..41e713ce 100644 --- a/base/trace_event/trace_event_impl.cc +++ b/base/trace_event/trace_event_impl.cc
@@ -41,7 +41,7 @@ TraceTimestamp TraceTimestampTraits<::base::TimeTicks>::ConvertTimestampToTraceTimeNs( const ::base::TimeTicks& ticks) { - return {TrackEvent::GetTraceClockId(), + return {static_cast<uint32_t>(TrackEvent::GetTraceClockId()), static_cast<uint64_t>(ticks.since_origin().InNanoseconds())}; }
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py index d6e603e..63707ea 100755 --- a/build/android/gradle/generate_gradle.py +++ b/build/android/gradle/generate_gradle.py
@@ -225,11 +225,11 @@ def JavaFiles(self): if self._java_files is None: - java_sources_file = self.DepsInfo().get('java_sources_file') + target_sources_file = self.DepsInfo().get('target_sources_file') java_files = [] - if java_sources_file: - java_sources_file = _RebasePath(java_sources_file) - java_files = build_utils.ReadSourcesList(java_sources_file) + if target_sources_file: + target_sources_file = _RebasePath(target_sources_file) + java_files = build_utils.ReadSourcesList(target_sources_file) self._java_files = java_files return self._java_files
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index d9eeb3a..1cb6c57 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -3215,15 +3215,15 @@ # be the name of the main APK target. # supports_android: Optional. True if target can run on Android. # requires_android: Optional. True if target can only run on Android. - # java_files: Optional list of Java source file paths for this target. + # source_files: Optional list of Java source file paths for this target. # javac_args: Optional list of extra arguments to pass to javac. # errorprone_args: Optional list of extra arguments to pass to. # srcjar_deps: Optional list of .srcjar targets (not file paths). The Java # source files they contain will also be compiled for this target. - # java_sources_file: Optional path to a file which will be written with - # the content of java_files. If not provided, the file will be written + # target_sources_file: Optional path to a file which will be written with + # the content of source_files. If not provided, the file will be written # under $target_gen_dir/$main_target_name.sources. Ignored if - # java_files is empty. If not + # sources_files is empty. If not # jar_path: Optional path to a prebuilt .jar file for this target. # Mutually exclusive with java_files and srcjar_deps. # output_name: Optional output name for the final jar path. Used to
diff --git a/build/config/fuchsia/test/minimum.shard.test-cml b/build/config/fuchsia/test/minimum.shard.test-cml index e0e36d7..f1cde581 100644 --- a/build/config/fuchsia/test/minimum.shard.test-cml +++ b/build/config/fuchsia/test/minimum.shard.test-cml
@@ -9,7 +9,7 @@ children: [ { name: "build-info-service", - url: "fuchsia-pkg://fuchsia.com/build-info-service#meta/build-info.cm", + url: "fuchsia-pkg://fuchsia.com/fake-build-info#meta/fake_build_info.cm", }, { name: "intl_property_manager", @@ -18,14 +18,9 @@ ], offer: [ { - directory: "build-info", - from: "parent", - to: "#build-info-service", - }, - { protocol: "fuchsia.logger.LogSink", from: "parent", - to: [ "#build-info-service", "#intl_property_manager" ], + to: [ "#intl_property_manager" ], } ], use: [ @@ -77,7 +72,7 @@ facets: { "fuchsia.test": { "deprecated-allowed-packages": [ - "build-info-service", + "fake-build-info", "intl_property_manager", ], },
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 2611d2d..86009fc 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -11.20230123.1.1 +11.20230123.3.1
diff --git a/build/fuchsia/test/ffx_integration.py b/build/fuchsia/test/ffx_integration.py index 3067fad4..2c0960e 100644 --- a/build/fuchsia/test/ffx_integration.py +++ b/build/fuchsia/test/ffx_integration.py
@@ -62,7 +62,14 @@ def __exit__(self, exc_type, exc_val, exc_tb) -> bool: if self._new_value != self._old_value: - run_ffx_command(['config', 'remove', self._name]) + + # Allow removal of config to fail. + remove_cmd = run_ffx_command(['config', 'remove', self._name], + check=False) + if remove_cmd.returncode != 0: + logging.warning('Error when removing ffx config %s', + self._name) + if self._old_value is not None: # Explicitly set the value back only if removing the new value # doesn't already restore the old value.
diff --git a/build_overrides/partition_alloc.gni b/build_overrides/partition_alloc.gni index aa6433b..e1fa5fe9 100644 --- a/build_overrides/partition_alloc.gni +++ b/build_overrides/partition_alloc.gni
@@ -80,8 +80,5 @@ enable_mte_checked_ptr_support_default = false put_ref_count_in_previous_slot_default = true - -# TODO(keishi): Slow check is enabled temporarily for a few canary releases to -# check for bugs. -enable_backup_ref_ptr_slow_checks_default = true +enable_backup_ref_ptr_slow_checks_default = false enable_dangling_raw_ptr_checks_default = false
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni index eb78f58..b2e2fa1 100644 --- a/buildtools/deps_revisions.gni +++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@ declare_args() { # Used to cause full rebuilds on libc++ rolls. This should be kept in sync # with the libcxx_revision vars in //DEPS. - libcxx_revision = "cf803236eb29c7b6192ad129ad23ad80a3d99239" + libcxx_revision = "885d5d1cd59a7c88cee3c83fc71be5812c8e6bbd" }
diff --git a/chrome/VERSION b/chrome/VERSION index 6b192b5..5d7c262 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=111 MINOR=0 -BUILD=5556 +BUILD=5558 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index c9e5bd9..b9074b2 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -3043,7 +3043,6 @@ "//chrome/browser/ui/android/searchactivityutils:unit_device_javatests", "//chrome/browser/ui/android/signin:unit_device_javatests", "//chrome/browser/ui/messages/android:unit_device_javatests", - "//chrome/browser/user_education:unit_device_javatests", "//chrome/browser/video_tutorials/internal:unit_device_javatests", "//components/browser_ui/bottomsheet/android/internal:unit_device_javatests", "//components/browser_ui/contacts_picker/android:unit_device_javatests",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java index d9d6a98..31bab708c 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
@@ -347,6 +347,68 @@ } /** + * Returns the value that corresponds to Surface-0 based on incognito status. + * + * @param context {@link Context} used to retrieve color. + * @param isIncognito Whether the color is used for incognito mode. + * @return The value that corresponds to Surface-0. + */ + private static int getSurfaceColorElev0(Context context, boolean isIncognito) { + if (isIncognito) { + return context.getColor(org.chromium.chrome.R.color.default_bg_color_dark); + } + + return ChromeColors.getSurfaceColor( + context, org.chromium.chrome.R.dimen.default_elevation_0); + } + + /** + * Returns the value that corresponds to Surface-5 based on incognito status. + * + * @param context {@link Context} used to retrieve color. + * @param isIncognito Whether the color is used for incognito mode. + * @return The value that corresponds to Surface-5. + */ + private static int getSurfaceColorElev5(Context context, boolean isIncognito) { + if (isIncognito) { + return context.getColor( + org.chromium.chrome.R.color.default_bg_color_dark_elev_5_baseline); + } + + return ChromeColors.getSurfaceColor( + context, org.chromium.chrome.R.dimen.default_elevation_5); + } + + /** + * Returns the color for the tab container based on experiment arm, incognito mode, and + * foreground status. + * + * @param context {@link Context} used to retrieve color. + * @param isIncognito Whether the color is used for incognito mode. + * @param foreground Whether the tab is in the foreground. + * @return The color for the tab container. + */ + public static int getTabStripContainerColor( + Context context, boolean isIncognito, boolean foreground) { + if (foreground) { + if (TabUiFeatureUtilities.isTabStripFolioEnabled()) { + return ChromeColors.getDefaultThemeColor(context, isIncognito); + } else if (TabUiFeatureUtilities.isTabStripDetachedEnabled()) { + return getTabStripDetachedTabColor(context, isIncognito); + } + } else { + if (TabUiFeatureUtilities.isTabStripFolioEnabled()) { + return getSurfaceColorElev0(context, isIncognito); + } else if (TabUiFeatureUtilities.isTabStripDetachedEnabled()) { + return getSurfaceColorElev5(context, isIncognito); + } + } + + // Should be unreachable as TSR should never be enabled without the folio or detached arm. + return Color.TRANSPARENT; + } + + /** * Returns the color used for tab grid dialog background based on the incognito mode. * * @param context {@link Context} used to retrieve color.
diff --git a/chrome/android/java/res/layout/autofill_card_unmask_prompt_card_details.xml b/chrome/android/java/res/layout/autofill_card_unmask_prompt_card_details.xml index e253f5e8..55dc07c 100644 --- a/chrome/android/java/res/layout/autofill_card_unmask_prompt_card_details.xml +++ b/chrome/android/java/res/layout/autofill_card_unmask_prompt_card_details.xml
@@ -5,7 +5,6 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/card_container" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -13,7 +12,6 @@ <org.chromium.ui.widget.ChromeImageView android:id="@+id/card_icon" - app:srcCompat="@drawable/visa_card" android:layout_width="32dp" android:layout_height="20dp" android:layout_alignParentStart="true"
diff --git a/chrome/android/java/res/layout/autofill_card_unmask_prompt_new.xml b/chrome/android/java/res/layout/autofill_card_unmask_prompt_new.xml index 67ff1acc..91dd4c4 100644 --- a/chrome/android/java/res/layout/autofill_card_unmask_prompt_new.xml +++ b/chrome/android/java/res/layout/autofill_card_unmask_prompt_new.xml
@@ -90,8 +90,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="9dp" - android:layout_marginHorizontal="20dp" - android:visibility="gone" /> + android:layout_marginHorizontal="20dp" /> <LinearLayout android:layout_width="wrap_content"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index bd6fc5cf..55757f55 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -50,6 +50,8 @@ <dimen name="contextual_search_padded_button_width"> @dimen/overlay_panel_padded_button_width </dimen> + <!-- This is in sp because we want the chip width to scale with the font it holds. --> + <dimen name="contextual_search_chip_max_width">115sp</dimen> <dimen name="contextual_search_chip_list_chip_spacing">4dp</dimen> <dimen name="contextual_search_chip_list_side_padding">16dp</dimen> <!-- Padding at the end of the Bar. -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java index 56ff2fd..eb6687b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java
@@ -23,7 +23,8 @@ private final CardUnmaskPrompt mCardUnmaskPrompt; private CardUnmaskBridge(long nativeCardUnmaskPromptViewAndroid, String title, - String instructions, String confirmButtonLabel, int cvcIconId, int googlePayIconId, + String instructions, int cardIconId, String cardName, String cardLastFourDigits, + String cardExpiration, String confirmButtonLabel, int cvcIconId, int googlePayIconId, boolean isVirtualCard, boolean shouldRequestExpirationDate, boolean shouldOfferWebauthn, boolean defaultUseScreenlockChecked, long successMessageDurationMilliseconds, WindowAndroid windowAndroid) { @@ -36,22 +37,26 @@ new Handler().post(() -> dismissed()); } else { mCardUnmaskPrompt = new CardUnmaskPrompt(activity, this, title, instructions, - confirmButtonLabel, cvcIconId, googlePayIconId, isVirtualCard, - shouldRequestExpirationDate, shouldOfferWebauthn, defaultUseScreenlockChecked, + cardIconId, cardName, cardLastFourDigits, cardExpiration, confirmButtonLabel, + cvcIconId, googlePayIconId, isVirtualCard, shouldRequestExpirationDate, + shouldOfferWebauthn, defaultUseScreenlockChecked, successMessageDurationMilliseconds); } } + // TODO (crbug.com/1356735): Sync down the credit card directly from native instead of adding + // more and more arguments. @CalledByNative private static CardUnmaskBridge create(long nativeUnmaskPrompt, String title, - String instructions, String confirmButtonLabel, int cvcIconId, int googlePayIconId, + String instructions, int cardIconId, String cardName, String cardLastFourDigits, + String cardExpiration, String confirmButtonLabel, int cvcIconId, int googlePayIconId, boolean isVirtualCard, boolean shouldRequestExpirationDate, boolean shouldOfferWebauthn, boolean defaultUseScreenlockChecked, long successMessageDurationMilliseconds, WindowAndroid windowAndroid) { - return new CardUnmaskBridge(nativeUnmaskPrompt, title, instructions, confirmButtonLabel, - cvcIconId, googlePayIconId, isVirtualCard, shouldRequestExpirationDate, - shouldOfferWebauthn, defaultUseScreenlockChecked, - successMessageDurationMilliseconds, windowAndroid); + return new CardUnmaskBridge(nativeUnmaskPrompt, title, instructions, cardIconId, cardName, + cardLastFourDigits, cardExpiration, confirmButtonLabel, cvcIconId, googlePayIconId, + isVirtualCard, shouldRequestExpirationDate, shouldOfferWebauthn, + defaultUseScreenlockChecked, successMessageDurationMilliseconds, windowAndroid); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java index 4c6a260c..802ae9d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
@@ -35,7 +35,6 @@ import androidx.core.view.ViewCompat; import org.chromium.base.task.AsyncTask; -import org.chromium.build.BuildConfig; import org.chromium.chrome.R; import org.chromium.chrome.browser.autofill.AutofillUiUtils.ErrorType; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -43,9 +42,9 @@ import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogProperties; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.widget.ChromeImageView; import java.util.Calendar; -import java.util.Locale; /** * A prompt that bugs users to enter their CVC when unmasking a Wallet instrument (credit card). @@ -148,7 +147,8 @@ } public CardUnmaskPrompt(Context context, CardUnmaskPromptDelegate delegate, String title, - String instructions, String confirmButtonLabel, int cvcDrawableId, + String instructions, int cardIconId, String cardName, String cardLastFourDigits, + String cardExpiration, String confirmButtonLabel, int cvcDrawableId, int googlePayDrawableId, boolean isVirtualCard, boolean shouldRequestExpirationDate, boolean shouldOfferWebauthn, boolean defaultUseScreenlockChecked, long successMessageDurationMilliseconds) { @@ -161,23 +161,15 @@ ChromeFeatureList.AUTOFILL_TOUCH_TO_FILL_FOR_CREDIT_CARDS_ANDROID)) { mMainView = inflater.inflate(R.layout.autofill_card_unmask_prompt_new, null); - // TODO (crbug.com/1356735): These mock card details are added to demo the UI. Remove - // when actual card details are synced from native. Only shown in debug builds. - if (BuildConfig.ENABLE_ASSERTS) { - ViewGroup cardDetails = - (ViewGroup) mMainView.findViewById(R.id.card_details_container); - cardDetails.setVisibility(View.VISIBLE); - - String cardName = "Chase Sapphire Preferred Ultimate Rewards Card"; - String lastFour = "....1234"; - String expiration = "12/2029"; - ((TextView) mMainView.findViewById(R.id.card_name)) - .setText(String.format(Locale.ROOT, "%s", cardName)); - ((TextView) mMainView.findViewById(R.id.card_last_four)) - .setText(String.format(Locale.ROOT, "%s", lastFour)); - ((TextView) mMainView.findViewById(R.id.card_expiration)) - .setText(String.format(Locale.ROOT, "%s", expiration)); + // Populate card details. + if (cardIconId != 0) { + ChromeImageView cardIconView = + (ChromeImageView) mMainView.findViewById(R.id.card_icon); + cardIconView.setImageDrawable(context.getDrawable(cardIconId)); } + ((TextView) mMainView.findViewById(R.id.card_name)).setText(cardName); + ((TextView) mMainView.findViewById(R.id.card_last_four)).setText(cardLastFourDigits); + ((TextView) mMainView.findViewById(R.id.card_expiration)).setText(cardExpiration); } else { mMainView = inflater.inflate(R.layout.autofill_card_unmask_prompt, null); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java index 4c051f9a..cf3c5d3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -15,7 +15,6 @@ import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; import org.chromium.base.ActivityState; @@ -39,7 +38,6 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.ToolbarManager; import org.chromium.chrome.browser.toolbar.top.ToolbarLayout; -import org.chromium.components.browser_ui.widget.chips.ChipProperties; import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator; import org.chromium.components.browser_ui.widget.scrim.ScrimProperties; import org.chromium.ui.base.LocalizationUtils; @@ -676,8 +674,7 @@ int quickActionCategory, @CardTag int cardTagEnum, @Nullable List<String> relatedSearchesInBar, boolean showDefaultSearchInBar) { onSearchTermResolved(searchTerm, null, thumbnailUrl, quickActionUri, quickActionCategory, - cardTagEnum, relatedSearchesInBar, showDefaultSearchInBar, - ChipProperties.SHOW_WHOLE_TEXT /* defaultQueryInBarTextMaxWidthPx */); + cardTagEnum, relatedSearchesInBar, showDefaultSearchInBar); } /** @@ -691,16 +688,15 @@ * or {@code 0}. * @param relatedSearchesInBar Related Searches suggestions to be displayed in the Bar. * @param showDefaultSearchInBar Whether the first query is the default query in the bar. - * @param defaultQueryInBarTextMaxWidthPx The bar's default query text max width in pixels. */ @Override public void onSearchTermResolved(String searchTerm, @Nullable String pronunciation, String thumbnailUrl, String quickActionUri, int quickActionCategory, @CardTag int cardTagEnum, @Nullable List<String> relatedSearchesInBar, - boolean showDefaultSearchInBar, @Px int defaultQueryInBarTextMaxWidthPx) { + boolean showDefaultSearchInBar) { boolean hadInBarSuggestions = getRelatedSearchesInBarControl().hasReleatedSearchesToShow(); getRelatedSearchesInBarControl().setRelatedSearchesSuggestions( - relatedSearchesInBar, showDefaultSearchInBar, defaultQueryInBarTextMaxWidthPx); + relatedSearchesInBar, showDefaultSearchInBar); if (ChromeFeatureList.isEnabled(ChromeFeatureList.RELATED_SEARCHES_IN_BAR)) { if (getRelatedSearchesInBarControl().hasReleatedSearchesToShow() != hadInBarSuggestions) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelCoordinator.java index de91d30..9a0c922 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelCoordinator.java
@@ -169,8 +169,7 @@ @Override public void onSearchTermResolved(String searchTerm, @Nullable String pronunciation, String thumbnailUrl, String quickActionUri, int quickActionCategory, int cardTagEnum, - @Nullable List<String> inBarRelatedSearches, boolean showDefaultSearchInBar, - int defaultQueryInBarTextMaxWidthPx) {} + @Nullable List<String> inBarRelatedSearches, boolean showDefaultSearchInBar) {} @Override public void setCaption(String caption) {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface.java index e08ddd1..006077d7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelInterface.java
@@ -8,7 +8,6 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; -import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState; @@ -42,7 +41,7 @@ void onSearchTermResolved(String searchTerm, @Nullable String pronunciation, String thumbnailUrl, String quickActionUri, int quickActionCategory, @CardTag int cardTagEnum, @Nullable List<String> inBarRelatedSearches, - boolean showDefaultSearchInBar, @Px int defaultQueryInBarTextMaxWidthPx); + boolean showDefaultSearchInBar); void setCaption(String caption); void ensureCaption(); void hideCaption();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/RelatedSearchesControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/RelatedSearchesControl.java index 272bcc1..ba0eb50 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/RelatedSearchesControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/RelatedSearchesControl.java
@@ -9,7 +9,6 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; -import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -75,8 +74,6 @@ /** Whether the first query is the default query. */ private boolean mDisplayDefaultQuery; - private @Px int mDefaultQueryTextMaxWidthPx = ChipProperties.SHOW_WHOLE_TEXT; - /** Whether the view is visible. */ private boolean mIsVisible; @@ -208,10 +205,9 @@ * Sets the Related Searches suggestions to show in this view. * @param relatedSearches An {@code List} of suggested queries or {@code null} when none. * @param firstQueryIsDefault Whether the first query is the default query. - * @param defaultQueryTextMaxWidthPx The default query text max width in pixels. */ - void setRelatedSearchesSuggestions(@Nullable List<String> relatedSearches, - boolean displayDefaultQuery, @Px int defaultQueryTextMaxWidthPx) { + void setRelatedSearchesSuggestions( + @Nullable List<String> relatedSearches, boolean displayDefaultQuery) { if (mControlView == null) { mControlView = new RelatedSearchesControlView(mOverlayPanel, mContext, mViewContainer, mResourceLoader, R.layout.contextual_search_related_searches_view, @@ -222,7 +218,6 @@ mRelatedSearchesSuggestions = relatedSearches; mChips.clear(); mDisplayDefaultQuery = displayDefaultQuery; - mDefaultQueryTextMaxWidthPx = defaultQueryTextMaxWidthPx; if (hasReleatedSearchesToShow()) { show(); } else { @@ -493,7 +488,9 @@ ChipsCoordinator.buildChipListItem(index, suggestion, selectedCallback); if (index == 0 && mDisplayDefaultQuery) { - chip.model.set(ChipProperties.TEXT_MAX_WIDTH_PX, mDefaultQueryTextMaxWidthPx); + chip.model.set(ChipProperties.TEXT_MAX_WIDTH_PX, + mContext.getResources().getDimensionPixelSize( + R.dimen.contextual_search_chip_max_width)); } mChips.add(chip); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java index 7923f06..e076d07 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -124,6 +124,7 @@ // Visibility Constants private static final float TAB_STACK_WIDTH_DP = 4.f; private static final float TAB_OVERLAP_WIDTH_DP = 24.f; + private static final float TAB_OVERLAP_WIDTH_LARGE_DP = 28.f; private static final float TAB_WIDTH_SMALL = 108.f; private static final float TAB_WIDTH_MEDIUM = 156.f; private static final float MAX_TAB_WIDTH_DP = 265.f; @@ -148,6 +149,9 @@ private static final float NEW_TAB_BUTTON_DESIRED_TOUCH_TARGET_SIZE = 48.f; private static final float NEW_TAB_BUTTON_DEFAULT_PRESSED_OPACITY = 0.2f; private static final float NEW_TAB_BUTTON_DARK_DETACHED_OPACITY = 0.15f; + static final float TAB_OPACITY_HIDDEN = 0.f; + static final float TAB_OPACITY_VISIBLE_BACKGROUND = 0.55f; + static final float TAB_OPACITY_VISIBLE_FOREGROUND = 1.f; static final float BACKGROUND_TAB_BRIGHTNESS_DEFAULT = 1.f; static final float BACKGROUND_TAB_BRIGHTNESS_DIMMED = 0.65f; static final float DIVIDER_HIDDEN_OPACITY = 0.f; @@ -253,7 +257,9 @@ */ public StripLayoutHelper(Context context, LayoutUpdateHost updateHost, LayoutRenderHost renderHost, boolean incognito, CompositorButton modelSelectorButton) { - mTabOverlapWidth = TAB_OVERLAP_WIDTH_DP; + mTabOverlapWidth = ChromeFeatureList.sTabStripRedesign.isEnabled() + ? TAB_OVERLAP_WIDTH_LARGE_DP + : TAB_OVERLAP_WIDTH_DP; if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { if (TabUiFeatureUtilities.isTabStripFolioEnabled()) { mNewTabButtonWidth = NEW_TAB_BUTTON_BACKGROUND_WIDTH_DP_FOLIO; @@ -702,6 +708,11 @@ setAccessibilityDescription(stripTab, getTabById(id)); setAccessibilityDescription(findTabById(prevId), getTabById(prevId)); } + + StripLayoutTab selectedTab = findTabById(id); + StripLayoutTab prevTab = findTabById(prevId); + selectedTab.setContainerOpacity(TAB_OPACITY_VISIBLE_FOREGROUND); + if (prevTab != null) prevTab.setContainerOpacity(TAB_OPACITY_HIDDEN); } /** @@ -873,8 +884,11 @@ for (int i = 1; i < mStripTabs.length; i++) { final StripLayoutTab prevTab = mStripTabs[i - 1]; final StripLayoutTab currTab = mStripTabs[i]; - if (prevTab.getId() == selectedTabId || currTab.getId() == selectedTabId) { - // Dividers adjacent to the selected tab are hidden. + if (prevTab.getId() == selectedTabId || currTab.getId() == selectedTabId + || currTab.getContainerOpacity() > TAB_OPACITY_HIDDEN) { + // Dividers adjacent to selected tab are hidden. Additionally, when tab containers + // are visible for grouped tabs in edit mode, tab dividers are unneeded and + // therefore hidden. currTab.setDividerOpacity(DIVIDER_HIDDEN_OPACITY); } else { // All other dividers are visible. @@ -1496,6 +1510,9 @@ StripLayoutTab tab = new StripLayoutTab( mContext, id, this, mTabLoadTrackerHost, mRenderHost, mUpdateHost, mIncognito); tab.setHeight(mHeight); + if (id == mModel.getTabAt(mModel.index()).getId()) { + tab.setContainerOpacity(TAB_OPACITY_VISIBLE_FOREGROUND); + } pushStackerPropertiesToTab(tab); return tab; } @@ -1836,6 +1853,12 @@ float endValue = attached ? FOLIO_ATTACHED_BOTTOM_MARGIN_DP : FOLIO_DETACHED_BOTTOM_MARGIN_DP; + if (animationList == null) { + tab.setBottomMargin(endValue); + tab.setFolioAttached(attached); + return; + } + ArrayList<Animator> attachAnimationList = new ArrayList<>(); CompositorAnimator dropAnimation = CompositorAnimator.ofFloatProperty( mUpdateHost.getAnimationHandler(), tab, StripLayoutTab.BOTTOM_MARGIN, startValue, @@ -1855,12 +1878,7 @@ AnimatorSet set = new AnimatorSet(); set.playSequentially(attachAnimationList); - - if (animationList == null) { - set.end(); - } else { - animationList.add(set); - } + animationList.add(set); } @VisibleForTesting @@ -1911,7 +1929,9 @@ mModel, TabModelUtils.getTabIndexById(mModel, mInteractingTab.getId()), false); // 5. Dim the background tabs and fade-out the new tab & model selector buttons. - setBackgroundTabsDimmed(true); + if (!ChromeFeatureList.sTabStripRedesign.isEnabled()) { + setBackgroundTabsDimmed(true); + } setCompositorButtonsVisible(false); // 6. Fast expand to make sure this tab is visible. If tabs are not cascaded, the selected @@ -1924,7 +1944,11 @@ } else if (TabUiFeatureUtilities.isTabletTabGroupsEnabled(mContext)) { Tab tab = getTabById(mInteractingTab.getId()); computeAndUpdateTabGroupMargins(true, animationList); - setTabGroupDimmed(mTabGroupModelFilter.getRootId(tab), false); + if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { + setTabGroupContainersVisible(mTabGroupModelFilter.getRootId(tab), true); + } else { + setTabGroupDimmed(mTabGroupModelFilter.getRootId(tab), false); + } performHapticFeedback(tab); } @@ -1959,8 +1983,12 @@ mInteractingTab.setOffsetX(0f); } - // 3. Un-dim the background tabs and fade-in the new tab & model selector buttons. - setBackgroundTabsDimmed(false); + // 3. Reset the background tabs and fade-in the new tab & model selector buttons. + if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { + setBackgroundTabContainersVisible(false); + } else { + setBackgroundTabsDimmed(false); + } setCompositorButtonsVisible(true); // 4. Clear any tab group margins if they are enabled. @@ -2167,6 +2195,34 @@ } } + private void setTabContainerVisible(StripLayoutTab tab, boolean visible) { + if (tab != mInteractingTab) { + float opacity = visible ? TAB_OPACITY_VISIBLE_BACKGROUND : TAB_OPACITY_HIDDEN; + tab.setContainerOpacity(opacity); + + if (TabUiFeatureUtilities.isTabStripFolioEnabled()) { + updateFolioTabAttachState(tab, !visible, null); + } + } + } + + private void setBackgroundTabContainersVisible(boolean visible) { + for (int i = 0; i < mStripTabs.length; i++) { + final StripLayoutTab tab = mStripTabs[i]; + setTabContainerVisible(tab, visible); + } + } + + private void setTabGroupContainersVisible(int groupId, boolean visible) { + for (int i = 0; i < mStripTabs.length; i++) { + final StripLayoutTab tab = mStripTabs[i]; + + if (mTabGroupModelFilter.getRootId(getTabById(tab.getId())) == groupId) { + setTabContainerVisible(tab, visible); + } + } + } + /** * This method checks whether or not interacting tab has met the conditions to be moved out of * its tab group. It moves tab out of group if so and returns the new index for the interacting @@ -2183,7 +2239,12 @@ if (Math.abs(offset) > mTabMarginWidth * REORDER_OVERLAP_SWITCH_PERCENTAGE) { final int tabId = mInteractingTab.getId(); - setTabGroupDimmed(mTabGroupModelFilter.getRootId(getTabById(tabId)), true); + if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { + setTabGroupContainersVisible( + mTabGroupModelFilter.getRootId(getTabById(tabId)), false); + } else { + setTabGroupDimmed(mTabGroupModelFilter.getRootId(getTabById(tabId)), true); + } mTabGroupModelFilter.moveTabOutOfGroupInDirection(tabId, towardEnd); RecordUserAction.record("MobileToolbarReorderTab.TabRemovedFromGroup"); return curIndex; @@ -2253,7 +2314,11 @@ // 1.b. Set tab group dim as necessary. int groupId = mTabGroupModelFilter.getRootId( getTabById(mStripTabs[curIndex + (towardEnd ? 1 : -1)].getId())); - setTabGroupDimmed(groupId, !mHoveringOverGroup); + if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { + setTabGroupContainersVisible(groupId, mHoveringOverGroup); + } else { + setTabGroupDimmed(groupId, !mHoveringOverGroup); + } } // 2. If we are hovering, attempt to merge to the hovered group. @@ -2285,7 +2350,11 @@ // If past threshold, un-dim hovered group and trigger reorder. if (Math.abs(offset) > threshold) { - setTabGroupDimmed(groupId, true); + if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { + setTabGroupContainersVisible(groupId, false); + } else { + setTabGroupDimmed(groupId, true); + } int destIndex = towardEnd ? curIndex + 1 + numTabsToSkip : curIndex - numTabsToSkip; return destIndex;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java index 8d096be96..5488bcf6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
@@ -178,7 +178,9 @@ // Animation/Timer Constants private static final int ANIM_TAB_CLOSE_BUTTON_FADE_MS = 150; - // Close button width + // Close Button Constants + // Close button padding value comes from the built-in padding in the source png. + private static final int CLOSE_BUTTON_PADDING_DP = 7; private static final int CLOSE_BUTTON_WIDTH_DP = 36; private static final int CLOSE_BUTTON_WIDTH_SCROLLING_STRIP_DP = 48; @@ -188,7 +190,7 @@ // Divider Constants // TODO(crbug.com/1373632): Temp value until the 9-patches are updated. - private static final int DIVIDER_OFFSET_X = 9; + private static final int DIVIDER_OFFSET_X = 13; @VisibleForTesting static final float DIVIDER_FOLIO_LIGHT_OPACITY = 0.2f; @@ -207,6 +209,7 @@ private boolean mFolioAttached = true; private final boolean mIncognito; private float mBottomMargin; + private float mContainerOpacity; private float mContentOffsetX; private float mDividerOpacity; private float mVisiblePercentage = 1.f; @@ -379,15 +382,10 @@ * @return The tint color resource that represents the tab background. */ public int getTint(boolean foreground) { + // TODO(https://crbug.com/1408276): Avoid calculating every time. Instead, store the tab's + // color and only re-determine when the color could have changed (i.e. on selection). if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { - // Inactive tabs have no container in TSR. Return arbitrary color to avoid calculation. - if (!foreground) return Color.TRANSPARENT; - - if (TabUiFeatureUtilities.isTabStripFolioEnabled()) { - return ChromeColors.getDefaultThemeColor(mContext, mIncognito); - } else if (TabUiFeatureUtilities.isTabStripDetachedEnabled()) { - return TabUiThemeProvider.getTabStripDetachedTabColor(mContext, mIncognito); - } + return TabUiThemeProvider.getTabStripContainerColor(mContext, mIncognito, foreground); } if (foreground) { @@ -575,18 +573,21 @@ } /** - * @param foreground Whether or not this tab is a foreground tab. - * @return The fraction (from 0.f to 1.f) of how opaque the tab should be. + * @param opacity The fraction (from 0.f to 1.f) of how opaque the tab container should be. */ - public float getOpacity(boolean foreground) { + public void setContainerOpacity(float opacity) { + mContainerOpacity = opacity; + } + + /** + * @return The fraction (from 0.f to 1.f) of how opaque the tab container should be. + */ + public float getContainerOpacity() { if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { - if (foreground) { - return 1.0f; - } else { - return 0.0f; - } + return mContainerOpacity; + } else { + return 1.f; } - return 1.0f; } /** @@ -883,6 +884,10 @@ return mClosePlacement; } + public int getCloseButtonPadding() { + return CLOSE_BUTTON_PADDING_DP; + } + // TODO(dtrainor): Don't animate this if we're selecting or deselecting this tab. private void checkCloseButtonVisibility(boolean animate) { boolean shouldShow =
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 4424ff0..d6cc5ff9 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
@@ -208,10 +208,10 @@ st.getDrawX() * mDpToPx, st.getDrawY() * mDpToPx, st.getWidth() * mDpToPx, st.getHeight() * mDpToPx, st.getContentOffsetX() * mDpToPx, st.getContentOffsetY() * mDpToPx, st.getDividerOffsetX() * mDpToPx, - st.getBottomMargin() * mDpToPx, st.getCloseButton().getOpacity(), - st.getDividerOpacity(), st.isLoading(), st.getLoadingSpinnerRotation(), - st.getBrightness(), st.getOpacity(isSelected), layerTitleCache, - resourceManager); + st.getBottomMargin() * mDpToPx, st.getCloseButtonPadding() * mDpToPx, + st.getCloseButton().getOpacity(), st.getDividerOpacity(), st.isLoading(), + st.getLoadingSpinnerRotation(), st.getBrightness(), st.getContainerOpacity(), + layerTitleCache, resourceManager); } } @@ -255,8 +255,8 @@ int handleOutlineTint, boolean foreground, boolean closePressed, float toolbarWidth, float x, float y, float width, float height, float contentOffsetX, float contentOffsetY, float dividerOffsetX, float bottomOffsetY, - float closeButtonAlpha, float dividerAlpha, boolean isLoading, - float spinnerRotation, float brightness, float opacity, + float closeButtonPadding, float closeButtonAlpha, float dividerAlpha, + boolean isLoading, float spinnerRotation, float brightness, float opacity, LayerTitleCache layerTitleCache, ResourceManager resourceManager); void setContentTree( long nativeTabStripSceneLayer, TabStripSceneLayer caller, SceneLayer contentTree);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java index 58b266eb..782d3b4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -33,9 +33,6 @@ private static final String RELATED_SEARCHES_CONFIG_DEFAULT_STAMP = "1Rs"; static final String RELATED_SEARCHES_SHOW_DEFAULT_QUERY_CHIP_PARAM_NAME = "default_query_chip"; - static final String RELATED_SEARCHES_DEFAULT_QUERY_CHIP_MAX_WIDTH_SP_PARAM_NAME = - "default_query_max_width_sp"; - private static final int RELATED_SEARCHES_DEFAULT_QUERY_CHIP_DEFAULT_MAX_WIDTH_SP = 115; static final String CONTEXTUAL_SEARCH_MINIMUM_PAGE_HEIGHT_NAME = "contextual_search_minimum_page_height_dp"; @@ -94,14 +91,6 @@ RELATED_SEARCHES_SHOW_DEFAULT_QUERY_CHIP_PARAM_NAME, true); } - /* Return the max width of the bar's default chip in Sp. */ - static int getDefaultChipWidthSpInBar() { - return ChromeFeatureList.getFieldTrialParamByFeatureAsInt( - ChromeFeatureList.RELATED_SEARCHES_IN_BAR, - RELATED_SEARCHES_DEFAULT_QUERY_CHIP_MAX_WIDTH_SP_PARAM_NAME, - RELATED_SEARCHES_DEFAULT_QUERY_CHIP_DEFAULT_MAX_WIDTH_SP); - } - /** Return The minimum height dp for the contextual search page. */ static int getContextualSearchMinimumBasePageHeightDp() { return ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java index 203ab01..73c542a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -8,7 +8,6 @@ import android.net.Uri; import android.os.Handler; import android.text.TextUtils; -import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -16,7 +15,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; import org.chromium.base.Callback; @@ -811,7 +809,6 @@ boolean showDefaultSearchInBar = ContextualSearchFieldTrial.showDefaultChipInBar(); List<String> inBarRelatedSearches = buildRelatedSearches(searchTerm, showDefaultSearchInBar); - int defaultQueryWidthSpInBar = ContextualSearchFieldTrial.getDefaultChipWidthSpInBar(); // Check if the searchTerm is a composite (used for Definitions for pronunciation). // The middle-dot character is returned by the server and marks the beginning of the @@ -832,8 +829,7 @@ mSearchPanel.onSearchTermResolved(message, pronunciation, resolvedSearchTerm.thumbnailUrl(), resolvedSearchTerm.quickActionUri(), resolvedSearchTerm.quickActionCategory(), - resolvedSearchTerm.cardTagEnum(), inBarRelatedSearches, showDefaultSearchInBar, - spToPx(defaultQueryWidthSpInBar)); + resolvedSearchTerm.cardTagEnum(), inBarRelatedSearches, showDefaultSearchInBar); if (!TextUtils.isEmpty(resolvedSearchTerm.caption())) { setCaption(resolvedSearchTerm.caption()); } @@ -1866,18 +1862,6 @@ } /** - * Converts scale-independent pixels (sp) to pixels on the screen (px). - * - * @param sp Scale-independent pixels. - * @return The physical pixels on the screen which correspond to the - * scale-independent pixels. - */ - private @Px int spToPx(int sp) { - return (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_SP, sp, mActivity.getResources().getDisplayMetrics()); - } - - /** * Returns whether the View of the Base Page is too small to show our Overlay Panel. * @param viewHeightLimitPixels The required height in pixels. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorder.java index 8a38c5b..69675e7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorder.java
@@ -82,7 +82,8 @@ public void onTabClosing() { long timestamp = SystemClock.uptimeMillis(); boolean hadInteraction = hadInteraction(); - boolean hadFormInteraction = hadFormInteraction(); + boolean hadFormInteractionInSession = hadFormInteractionInSession(); + boolean hadFormInteractionInActivePage = hadFormInteractionInActivePage(); boolean hadNavigationInteraction = hadNavigationInteraction(); Log.d(TAG, @@ -96,7 +97,9 @@ pref.writeBoolean( ChromePreferenceKeys.CUSTOM_TABS_LAST_CLOSE_TAB_INTERACTION, hadInteraction); RecordHistogram.recordBooleanHistogram( - "CustomTabs.HadInteractionOnClose.Form", hadFormInteraction); + "CustomTabs.HadInteractionOnClose.Form", hadFormInteractionInSession); + RecordHistogram.recordBooleanHistogram( + "CustomTabs.HadInteractionOnClose.FormStillActive", hadFormInteractionInActivePage); RecordHistogram.recordBooleanHistogram( "CustomTabs.HadInteractionOnClose.Navigation", hadNavigationInteraction); } @@ -109,11 +112,17 @@ * More details see chrome/browser/android/customtabs/tab_interaction_recorder_android.h */ public boolean hadInteraction() { - return hadFormInteraction() || hadNavigationInteraction(); + return hadFormInteractionInSession() || hadNavigationInteraction(); } - private boolean hadFormInteraction() { - return TabInteractionRecorderJni.get().hadFormInteraction(mNativeTabInteractionRecorder); + private boolean hadFormInteractionInActivePage() { + return TabInteractionRecorderJni.get().hadFormInteractionInActivePage( + mNativeTabInteractionRecorder); + } + + private boolean hadFormInteractionInSession() { + return TabInteractionRecorderJni.get().hadFormInteractionInSession( + mNativeTabInteractionRecorder); } private boolean hadNavigationInteraction() { @@ -156,7 +165,8 @@ TabInteractionRecorder getFromTab(Tab tab); TabInteractionRecorder createForTab(Tab tab); boolean didGetUserInteraction(long nativeTabInteractionRecorderAndroid); - boolean hadFormInteraction(long nativeTabInteractionRecorderAndroid); + boolean hadFormInteractionInActivePage(long nativeTabInteractionRecorderAndroid); + boolean hadFormInteractionInSession(long nativeTabInteractionRecorderAndroid); boolean hadNavigationInteraction(long nativeTabInteractionRecorderAndroid); void reset(long nativeTabInteractionRecorderAndroid); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java index 9b0f2c4..c25a9b0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -25,7 +25,6 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.Supplier; import org.chromium.chrome.R; -import org.chromium.chrome.browser.BackPressHelper; import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.fonts.FontPreloader; import org.chromium.chrome.browser.metrics.UmaUtils; @@ -129,15 +128,6 @@ */ private FirstRunPagerAdapter mPagerAdapter; - @Override - protected void onPreCreate() { - super.onPreCreate(); - BackPressHelper.create(this, getOnBackPressedDispatcher(), () -> { - handleBackPressed(); - return true; - }); - } - private boolean isFlowKnown() { return mFreProperties != null; } @@ -427,7 +417,8 @@ } } - private void handleBackPressed() { + @Override + public void handleBackPress() { // Terminate if we are still waiting for the native or for Android EDU / GAIA Child checks. if (!mPostNativeAndPolicyPagesCreated) { abortFirstRunExperience();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivityBase.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivityBase.java index 23ccc16..047284c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivityBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivityBase.java
@@ -17,8 +17,12 @@ import org.chromium.base.IntentUtils; import org.chromium.base.Log; import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.OneshotSupplierImpl; +import org.chromium.chrome.browser.BackPressHelper; +import org.chromium.chrome.browser.back_press.BackPressManager; import org.chromium.chrome.browser.customtabs.CustomTabsConnection; import org.chromium.chrome.browser.init.AsyncInitializationActivity; import org.chromium.chrome.browser.metrics.SimpleStartupForegroundSessionDetector; @@ -26,12 +30,14 @@ import org.chromium.chrome.browser.policy.PolicyServiceFactory; import org.chromium.chrome.browser.profiles.ProfileManagerUtils; import org.chromium.chrome.browser.signin.services.FREMobileIdentityConsistencyFieldTrial; +import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; import org.chromium.components.policy.PolicyService; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.AccountManagerFacadeProvider; /** Base class for First Run Experience. */ -public abstract class FirstRunActivityBase extends AsyncInitializationActivity { +public abstract class FirstRunActivityBase + extends AsyncInitializationActivity implements BackPressHandler { private static final String TAG = "FirstRunActivity"; public static final String EXTRA_COMING_FROM_CHROME_ICON = "Extra.ComingFromChromeIcon"; @@ -58,6 +64,11 @@ private final FirstRunAppRestrictionInfo mFirstRunAppRestrictionInfo; private final OneshotSupplierImpl<PolicyService> mPolicyServiceSupplier; + private final ObservableSupplierImpl<Boolean> mBackPressStateSupplier = + new ObservableSupplierImpl<>() { + // Always intercept back press. + { set(true); } + }; private PolicyLoadListener mPolicyLoadListener; private final long mStartTime; @@ -100,6 +111,19 @@ } } + @Override + protected void onPreCreate() { + super.onPreCreate(); + if (BackPressManager.isSecondaryActivityEnabled()) { + BackPressHelper.create(this, getOnBackPressedDispatcher(), this); + } else { + BackPressHelper.create(this, getOnBackPressedDispatcher(), () -> { + handleBackPress(); + return true; + }); + } + } + // Activity: @Override public void onPause() { @@ -140,6 +164,17 @@ mFirstRunAppRestrictionInfo.destroy(); } + @Override + public ObservableSupplier<Boolean> getHandleBackPressChangedSupplier() { + return mBackPressStateSupplier; + } + + /** + * Called when back press is intercepted. + */ + @Override + public abstract void handleBackPress(); + protected void flushPersistentData() { if (mNativeInitialized) { ProfileManagerUtils.flushPersistentDataForAllProfiles();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java index 4d25043b..38a41a02 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
@@ -22,7 +22,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.R; -import org.chromium.chrome.browser.BackPressHelper; import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.enterprise.util.EnterpriseInfo; import org.chromium.ui.base.LocalizationUtils; @@ -74,15 +73,6 @@ } @Override - protected void onPreCreate() { - super.onPreCreate(); - BackPressHelper.create(this, getOnBackPressedDispatcher(), () -> { - abortFirstRunExperience(); - return true; - }); - } - - @Override public void triggerLayoutInflation() { super.triggerLayoutInflation(); @@ -224,6 +214,11 @@ } } + @Override + public void handleBackPress() { + abortFirstRunExperience(); + } + private void abortFirstRunExperience() { finish(); notifyCustomTabCallbackFirstRunIfNecessary(getIntent(), false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java index 4e9a925..c5b4329 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -66,6 +66,8 @@ import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.night_mode.WebContentsDarkModeMessageController; import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController; +import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleDelegate; +import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionRationaleBottomSheet; import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionRationaleDialogController; import org.chromium.chrome.browser.ntp.NewTabPageLaunchOrigin; import org.chromium.chrome.browser.ntp.NewTabPageUtils; @@ -676,11 +678,22 @@ } if (!didTriggerPromo) { - mNotificationPermissionController = new NotificationPermissionController(mWindowAndroid, - new NotificationPermissionRationaleDialogController( - mActivity, mModalDialogManagerSupplier.get())); + RationaleDelegate rationaleUIDelegate; + + if (NotificationPermissionController.shouldUseBottomSheetRationaleUi()) { + rationaleUIDelegate = new NotificationPermissionRationaleBottomSheet( + mActivity, getBottomSheetController()); + } else { + rationaleUIDelegate = new NotificationPermissionRationaleDialogController( + mActivity, mModalDialogManagerSupplier.get()); + } + + mNotificationPermissionController = + new NotificationPermissionController(mWindowAndroid, rationaleUIDelegate); + NotificationPermissionController.attach( mWindowAndroid, mNotificationPermissionController); + didTriggerPromo = mNotificationPermissionController.requestPermissionIfNeeded( false /* contextual */); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index 9205f51..3a633d790 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -1408,11 +1408,11 @@ mActivityTabProvider); ToggleTabStackButton toggleTabStackButton = mControlContainer.findViewById(R.id.tab_switcher_button); - mToggleTabStackButtonCoordinator = new ToggleTabStackButtonCoordinator(mActivity, - toggleTabStackButton, userEducationHelper, - mIncognitoStateProvider::isIncognitoSelected, mIntentMetadataOneshotSupplier, - mPromoShownOneshotSupplier, mLayoutStateProviderSupplier, - mToolbar::setNewTabButtonHighlight, mActivityTabProvider); + mToggleTabStackButtonCoordinator = + new ToggleTabStackButtonCoordinator(mActivity, toggleTabStackButton, + userEducationHelper, mIncognitoStateProvider::isIncognitoSelected, + mPromoShownOneshotSupplier, mLayoutStateProviderSupplier, + mToolbar::setNewTabButtonHighlight, mActivityTabProvider); TraceEvent.end("ToolbarManager.initializeWithNative"); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRelatedSearchesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRelatedSearchesTest.java index 2f404ee..43a9c3d7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRelatedSearchesTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRelatedSearchesTest.java
@@ -182,10 +182,6 @@ testValues.addFieldTrialParamOverride(ChromeFeatureList.RELATED_SEARCHES_IN_BAR, ContextualSearchFieldTrial.RELATED_SEARCHES_SHOW_DEFAULT_QUERY_CHIP_PARAM_NAME, "true"); - testValues.addFieldTrialParamOverride(ChromeFeatureList.RELATED_SEARCHES_IN_BAR, - ContextualSearchFieldTrial - .RELATED_SEARCHES_DEFAULT_QUERY_CHIP_MAX_WIDTH_SP_PARAM_NAME, - "60"); FeatureList.setTestValues(testValues); mFakeServer.reset();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTest.java index 9a53f1e5..c94065b7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTest.java
@@ -17,10 +17,8 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.app.ChromeActivity; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.util.browser.Features; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.resources.dynamics.DynamicResourceLoader; @@ -87,7 +85,6 @@ @SmallTest @Feature({"ContextualSearch"}) @Restriction(Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE) - @Features.DisableFeatures(ChromeFeatureList.SNOOZABLE_IPH) public void testTextTapFollowedByNonTextTap() { Assert.assertEquals(0, mPanelManager.getRequestPanelShowCount());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsRenderTest.java index c3494af..4d0baff8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsRenderTest.java
@@ -21,7 +21,6 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils; import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType; @@ -34,7 +33,6 @@ import org.chromium.chrome.test.util.OmniboxTestUtils; import org.chromium.chrome.test.util.OmniboxTestUtils.SuggestionInfo; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.omnibox.AutocompleteMatch; import org.chromium.components.omnibox.AutocompleteMatchBuilder; import org.chromium.components.omnibox.AutocompleteResult; @@ -53,7 +51,6 @@ @RunWith(ParameterizedRunner.class) @ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@EnableFeatures(ChromeFeatureList.ENABLE_IPH) public class OmniboxPedalsRenderTest { @ParameterAnnotations.ClassParameter private static List<ParameterSet> sClassParams =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/read_later/ReadLaterContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/read_later/ReadLaterContextMenuTest.java index fad06d5..047595b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/read_later/ReadLaterContextMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/read_later/ReadLaterContextMenuTest.java
@@ -49,14 +49,12 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.offlinepages.RequestCoordinatorBridge; import org.chromium.chrome.browser.offlinepages.RequestCoordinatorBridgeJni; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; -import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.contextmenu.ContextMenuUtils; import org.chromium.components.feature_engagement.FeatureConstants; import org.chromium.components.feature_engagement.Tracker; @@ -67,7 +65,6 @@ /** Integration tests for showing IPH bubbles for read later. */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@Features.EnableFeatures({ChromeFeatureList.ENABLE_IPH}) @Batch(Batch.PER_CLASS) public class ReadLaterContextMenuTest { @Rule @@ -114,7 +111,6 @@ @Test @MediumTest @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) - @Features.DisableFeatures(ChromeFeatureList.SNOOZABLE_IPH) public void testShowIPHOnContextMenuLinkCopied() throws Throwable { when(mTracker.shouldTriggerHelpUI( FeatureConstants.READ_LATER_APP_MENU_BOOKMARK_THIS_PAGE_FEATURE))
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java index 5536fa8..ee78c7d0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/ToolbarButtonIphTest.java
@@ -43,7 +43,6 @@ import org.chromium.chrome.browser.toolbar.ToolbarManager; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; -import org.chromium.chrome.test.util.browser.Features; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.FeatureConstants; @@ -55,7 +54,6 @@ /** Integration tests for showing IPH bubbles on the toolbar. */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@Features.EnableFeatures({ChromeFeatureList.ENABLE_IPH}) public class ToolbarButtonIphTest { @Rule public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java index c5034e63..74bd6fbb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeSmokeTest.java
@@ -31,7 +31,6 @@ import org.chromium.chrome.test.pagecontroller.utils.UiAutomatorUtils; import org.chromium.chrome.test.pagecontroller.utils.UiLocatorHelper; -import java.util.Arrays; import java.util.concurrent.Callable; /** @@ -78,7 +77,9 @@ } return false; }, - "One of " + Arrays.toString(locators) + " should have been visible."), + "No Chrome views on screen. (i.e. Chrome has crashed " + + "on startup). Look at earlier logs for the actual " + + "crash stacktrace."), TIMEOUT_MS, UI_CHECK_INTERVAL); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java index 35a3785c..5983d10 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -104,7 +104,7 @@ private static final float TAB_WIDTH_1 = 140.f; private static final float TAB_WIDTH_2 = 160.f; private static final float TAB_WIDTH_SMALL = 108.f; - private static final float TAB_OVERLAP_WIDTH = 24.f; + private static final float TAB_OVERLAP_WIDTH = 28.f; private static final float TAB_WIDTH_MEDIUM = 156.f; private static final float TAB_MARGIN_WIDTH = 95.f; private static final long TIMESTAMP = 5000; @@ -379,8 +379,8 @@ // Set mWidth value to 800.f mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP); mStripLayoutHelper.getNewTabButton().setX(NEW_TAB_BTN_X); - // newTabBtn.X(700.f) - tab.width(160.f) + mTabOverlapWidth(24.f) + 1 - when(tabs[4].getDrawX()).thenReturn(565.f); + // newTabBtn.X(700.f) - tab.width(160.f) + mTabOverlapWidth(28.f) + 1 + when(tabs[4].getDrawX()).thenReturn(569.f); mStripLayoutHelper.setStripLayoutTabsForTest(tabs); // Act @@ -522,8 +522,8 @@ mStripLayoutHelper.scrollTabToView(TIMESTAMP, false); - int expectedFinalX = -1004; // delta(optimalRight(-980) - scrollOffset(0) - // - tabOverlapWidth(24)) + scrollOffset(0) + int expectedFinalX = -968; // delta(optimalRight(-940) - scrollOffset(0) + // - tabOverlapWidth(28)) + scrollOffset(0) assertEquals(expectedFinalX, mStripLayoutHelper.getScroller().getFinalX()); } @@ -542,8 +542,8 @@ mStripLayoutHelper.scrollTabToView(TIMESTAMP, false); - int expectedFinalX = -956; // delta(optimalRight(-932) - scrollOffset(0) - // - tabOverlapWidth(24)) + scrollOffset(0) + int expectedFinalX = -920; // delta(optimalRight(-892) - scrollOffset(0) + // - tabOverlapWidth(28)) + scrollOffset(0) assertEquals(expectedFinalX, mStripLayoutHelper.getScroller().getFinalX()); } @@ -602,7 +602,7 @@ mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH_LANDSCAPE, SCREEN_HEIGHT, false, TIMESTAMP); // Assert: finalX value before orientation change. - int initialFinalX = -1494; + int initialFinalX = -1458; assertEquals(initialFinalX, mStripLayoutHelper.getScroller().getFinalX()); // Act: change orientation. @@ -610,7 +610,7 @@ mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, true, TIMESTAMP); // Assert: finalX value after orientation change. - int expectedFinalX = -956; // delta(optimalRight(-932) - tabOverlapWidth(24)) - + int expectedFinalX = -920; // delta(optimalRight(-892) - tabOverlapWidth(28)) - // scrollOffset(1000) + scrollOffset(1000) assertEquals(expectedFinalX, mStripLayoutHelper.getScroller().getFinalX()); } @@ -631,7 +631,7 @@ mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH_LANDSCAPE, SCREEN_HEIGHT, false, TIMESTAMP); // Assert: finalX value before orientation change. - int initialFinalX = -1494; + int initialFinalX = -1458; assertEquals(initialFinalX, mStripLayoutHelper.getScroller().getFinalX()); // Act: change orientation. @@ -723,8 +723,8 @@ mStripLayoutHelper.tabCreated(TIMESTAMP, 11, 11, selected, false, onStartup); // Assert: We don't scroll to the created tab. The selected tab is not already visible, so - // we scroll to it. Offset = -(1 tab width) = -166. - float expectedOffset = -166f; + // we scroll to it. Offset = -(1 tab width) = -162. + float expectedOffset = -162f; assertEquals("We should scroll to the selected tab", expectedOffset, mStripLayoutHelper.getScrollOffset(), EPSILON); } @@ -1215,6 +1215,7 @@ @Test @Feature("Tab Groups on Tab Strip") + @Features.DisableFeatures(ChromeFeatureList.TAB_STRIP_REDESIGN) public void testReorder_SetBackgroundTabsDimmed() { // Mock 5 tabs. initializeTest(false, false, true, 0, 5); @@ -1241,6 +1242,7 @@ @Test @Feature("Tab Groups on Tab Strip") + @Features.DisableFeatures(ChromeFeatureList.TAB_STRIP_REDESIGN) public void testReorder_SetSelectedTabGroupNotDimmed() { // Mock 5 tabs. Group the first two tabs. initializeTest(false, false, true, 0, 5); @@ -1271,6 +1273,38 @@ } @Test + @Feature("Tab Strip Redesign") + public void testReorder_SetSelectedTabGroupContainersVisible() { + // Mock 5 tabs. Group the first two tabs. + initializeTest(false, false, true, 2, 5); + mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP); + groupTabs(0, 2); + + // Start reorder mode on third tab. Drag to hover over the tab group. + // -100 < -marginWidth = -95 + mStripLayoutHelper.startReorderModeAtIndexForTesting(2); + float dragDistance = -100f; + float startX = mStripLayoutHelper.getLastReorderX(); + mStripLayoutHelper.drag(TIMESTAMP, startX + dragDistance, 0f, dragDistance, 0f, 0f, 0f); + + // Verify hovered group tab containers are visible. + StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabs(); + float expectedHidden = StripLayoutHelper.TAB_OPACITY_HIDDEN; + float expectedVisibleBackground = StripLayoutHelper.TAB_OPACITY_VISIBLE_BACKGROUND; + float expectedVisibleForeground = StripLayoutHelper.TAB_OPACITY_VISIBLE_FOREGROUND; + assertEquals("Container in hovered group should be visible.", expectedVisibleBackground, + tabs[0].getContainerOpacity(), EPSILON); + assertEquals("Container in hovered group should be visible.", expectedVisibleBackground, + tabs[1].getContainerOpacity(), EPSILON); + assertEquals("Selected container should be visible.", expectedVisibleForeground, + tabs[2].getContainerOpacity(), EPSILON); + assertEquals("Background containers should not be visible.", expectedHidden, + tabs[3].getContainerOpacity(), EPSILON); + assertEquals("Background containers should not be visible.", expectedHidden, + tabs[4].getContainerOpacity(), EPSILON); + } + + @Test @Feature("Tab Groups on Tab Strip") public void testReorder_HapticFeedback() { // Mock 5 tabs. @@ -1512,7 +1546,7 @@ // Assert: Animations completed. The tab width is not resized and drawX does not change. float expectedDrawX = - -474.f; // Since we are focused on the last tab, start tabs are off screen. + -442.f; // Since we are focused on the last tab, start tabs are off screen. StripLayoutTab[] updatedTabs = mStripLayoutHelper.getStripLayoutTabs(); for (StripLayoutTab stripTab : updatedTabs) { assertEquals("Unexpected tab width after resize.", 156.f, stripTab.getWidth(), 0.0); @@ -1569,13 +1603,13 @@ // Assert: Animations completed. The tab width is resized, tab.drawX is changed and // newTabButton.drawX is also changed. float expectedDrawX = 0.f; - float expectedWidthAfterResize = 262.f; + float expectedWidthAfterResize = 264.666f; StripLayoutTab[] updatedTabs = mStripLayoutHelper.getStripLayoutTabs(); for (int i = 0; i < updatedTabs.length; i++) { StripLayoutTab stripTab = updatedTabs[i]; assertEquals("Unexpected tab width after resize.", expectedWidthAfterResize, - stripTab.getWidth(), 0.0); - assertEquals("Unexpected tab position.", expectedDrawX, stripTab.getDrawX(), 0.0); + stripTab.getWidth(), 0.1f); + assertEquals("Unexpected tab position.", expectedDrawX, stripTab.getDrawX(), 0.1f); expectedDrawX += (expectedWidthAfterResize - TAB_OVERLAP_WIDTH); } assertEquals("NewTabButton position is incorrect.", 743.f,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTabTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTabTest.java index 870f82f..7b826c31 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTabTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTabTest.java
@@ -101,8 +101,8 @@ mNormalTab.getTint(true)); // Normal inactive tab color. - expectedColor = Color.TRANSPARENT; - assertEquals("Folio inactive tab containers should be transparent.", expectedColor, + expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_0); + assertEquals("Folio inactive tab containers should be Surface-0.", expectedColor, mNormalTab.getTint(false)); // Incognito active tab color. @@ -111,8 +111,8 @@ mIncognitoTab.getTint(true)); // Incognito inactive tab color. - expectedColor = Color.TRANSPARENT; - assertEquals("Folio inactive tab containers should be transparent.", expectedColor, + expectedColor = mContext.getColor(R.color.default_bg_color_dark); + assertEquals("Incognito inactive folio should be baseline Surface-0.", expectedColor, mIncognitoTab.getTint(false)); } @@ -129,8 +129,8 @@ mNormalTab.getTint(true)); // Normal inactive tab color. - expectedColor = Color.TRANSPARENT; - assertEquals("Detached inactive tab containers should be transparent.", expectedColor, + expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5); + assertEquals("Detached inactive tab containers should be Surface-5.", expectedColor, mNormalTab.getTint(false)); // Incognito active tab color. @@ -139,8 +139,8 @@ mIncognitoTab.getTint(true)); // Incognito inactive tab color. - expectedColor = Color.TRANSPARENT; - assertEquals("Detached inactive tab containers should be transparent.", expectedColor, + expectedColor = mContext.getColor(R.color.default_bg_color_dark_elev_5_baseline); + assertEquals("Detached incognito inactive should be baseline Surface-5.", expectedColor, mIncognitoTab.getTint(false)); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java index 422bd84..246dc47 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/features/TabInteractionRecorderUnitTest.java
@@ -55,7 +55,8 @@ @Test public void hadFormInteractionOnTabClosing() { - mTestNative.paramHadFormInteraction = true; + mTestNative.paramHadFormInteractionInSession = true; + mTestNative.paramHadFormInteractionInActivePage = true; TabInteractionRecorder.getFromTab(mTab).onTabClosing(); Assert.assertTrue("Shared pref <CUSTOM_TABS_LAST_CLOSE_TAB_INTERACTION> is not recorded.", @@ -83,7 +84,8 @@ @Test public void noInteractionOnTabClosing() { - mTestNative.paramHadFormInteraction = false; + mTestNative.paramHadFormInteractionInSession = false; + mTestNative.paramHadFormInteractionInActivePage = false; mTestNative.paramHadNavigationInteraction = false; TabInteractionRecorder.getFromTab(mTab).onTabClosing(); @@ -99,7 +101,8 @@ class TestNativeInteractionRecorder implements TabInteractionRecorder.Natives { public boolean paramDidGetUserInteraction; - public boolean paramHadFormInteraction; + public boolean paramHadFormInteractionInSession; + public boolean paramHadFormInteractionInActivePage; public boolean paramHadNavigationInteraction; @Override @@ -119,8 +122,13 @@ } @Override - public boolean hadFormInteraction(long nativeTabInteractionRecorderAndroid) { - return paramHadFormInteraction; + public boolean hadFormInteractionInSession(long nativeTabInteractionRecorderAndroid) { + return paramHadFormInteractionInSession; + } + + @Override + public boolean hadFormInteractionInActivePage(long nativeTabInteractionRecorderAndroid) { + return paramHadFormInteractionInActivePage; } @Override @@ -130,7 +138,8 @@ @Override public void reset(long nativeTabInteractionRecorderAndroid) { - paramHadFormInteraction = false; + paramHadFormInteractionInSession = false; + paramHadFormInteractionInActivePage = false; paramHadNavigationInteraction = false; paramDidGetUserInteraction = false; }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/read_later/ReadLaterIPHControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/read_later/ReadLaterIPHControllerUnitTest.java index 7a7aa116..9374e54 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/read_later/ReadLaterIPHControllerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/read_later/ReadLaterIPHControllerUnitTest.java
@@ -33,14 +33,12 @@ import org.chromium.chrome.browser.user_education.IPHCommand; import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.chrome.test.util.browser.Features.JUnitProcessor; /** Unit test for {@link ReadLaterIPHController}. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) @DisableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) -@EnableFeatures({ChromeFeatureList.ENABLE_IPH}) public class ReadLaterIPHControllerUnitTest { @Rule public TestRule mFeaturesProcessor = new JUnitProcessor();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java index 5b2dd178b..b20cc83 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java
@@ -84,7 +84,6 @@ @Config(manifest = Config.NONE) @LooperMode(LooperMode.Mode.LEGACY) @DisableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) -@EnableFeatures(ChromeFeatureList.ENABLE_IPH) public class StartSurfaceToolbarMediatorUnitTest { private PropertyModel mPropertyModel; private StartSurfaceToolbarMediator mMediator;
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 0b824f6..0e7f5eb 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -2566,6 +2566,10 @@ desc="Footer link in the Download Bubble"> Show all downloads </message> + <message name="IDS_DOWNLOAD_BUBBLE_FOOTER_TOOLTIP" + desc="Tooltip label for the button to open all downloads"> + Show all downloads in a new tab + </message> <message name="IDS_DOWNLOAD_BUBBLE_DOWNLOAD_STATUS_MESSAGE_WITH_SEPARATOR" desc="The download status and message are separated by a symbol, in this case bullet •, with a white space before it and a white space after it. If the bullet • resembles another symbol in the language, please translate the bullet • as a symbol (A) that is not easily mistaken for a number or letter in the language and (B) that is typically used to separate elements."> <ph name="STATUS">$1<ex>100/120 MB</ex></ph> • <ph name="MESSAGE">$2<ex>Opening in 10 seconds...</ex></ph> @@ -5869,6 +5873,40 @@ <message name="IDS_WEB_APP_WINDOW_CONTROLS_OVERLAY_DISABLED_ALERT" desc="Status change notification that the title bar is showing after window controls overlay is disabled"> Title bar is now showing </message> + + <!-- App Home WebUI strings. --> + <message name="IDS_APP_HOME_TITLE" desc="Title of the new App Home page"> + Apps + </message> + + <message name="IDS_APP_HOME_OPEN_IN_WINDOW" desc="Label of menu entry for toggling an app to open in window from App Home context menu"> + Open in window + </message> + + <message name="IDS_ACCNAME_APP_HOME_OPEN_IN_WINDOW_CHECKBOX" desc="Accessibility label for the Open in window checkbox for App Home"> + Enable opening app in window + </message> + + <message name="IDS_APP_HOME_LAUNCH_AT_STARTUP" desc="Label of menu entry for toggling an app to run on startup from App Home context menu"> + Launch at startup + </message> + + <message name="IDS_ACCNAME_APP_HOME_LAUNCH_AT_STARTUP_CHECKBOX" desc="Accessibility label for the Launch at startup checkbox for App Home"> + Enable launching app at startup + </message> + + <message name="IDS_APP_HOME_CREATE_SHORTCUT" desc="Menu entry label for creating a shortcut for an app from context menu on App Home"> + Create shortcut + </message> + + <message name="IDS_APP_HOME_UNINSTALL_APP" desc="Menu entry label for uninstalling an app from context menu on App Home"> + Uninstall + </message> + + <message name="IDS_APP_HOME_APP_SETTINGS" desc="Menu entry label for navigation to App Settings page for an app from context menu on App Home"> + App settings + </message> + <!-- End App Home WebUI strings. --> <message name="IDS_WEB_APP_SETTINGS_TITLE" desc="Title of web app settings page"> App Settings @@ -10618,9 +10656,6 @@ <message name="IDS_SAVE_PAGE_DESC_COMPLETE" desc="In the Save Page dialog, the description of saving both the HTML and all shown resources."> Webpage, Complete </message> - <message name="IDS_SAVE_PAGE_DESC_WEB_BUNDLE_FILE" desc="In the Save Page dialog, the description of saving both the HTML and all shown resources into a single Web Bundle file."> - Webpage, Single File (Web Bundle) - </message> <!-- General app failure messages --> <message name="IDS_PROFILE_ERROR_DIALOG_TITLE" desc="The title of the dialog shown when there's an error page"> @@ -14008,6 +14043,9 @@ <message name="IDS_VERIFY_SHEET_TITLE" desc="Header shown to the user while signing in happens."> Verifying… </message> + <message name="IDS_VERIFY_SHEET_TITLE_AUTO_SIGNIN" desc="Header for auto sign-in sheet. Sheet is shown to notify the user that they are signing in to a website using an account from an identity provider." translateable="false"> + Signing in to <ph name="SITE_ETLD_PLUS_ONE">$1<ex>rp.example</ex></ph> with <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">$2<ex>idp.example</ex></ph> + </message> <!-- Input overlay strings --> <if expr="chromeos_ash">
diff --git a/chrome/app/generated_resources_grd/IDS_ACCNAME_APP_HOME_LAUNCH_AT_STARTUP_CHECKBOX.png.sha1 b/chrome/app/generated_resources_grd/IDS_ACCNAME_APP_HOME_LAUNCH_AT_STARTUP_CHECKBOX.png.sha1 new file mode 100644 index 0000000..05802c7 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_ACCNAME_APP_HOME_LAUNCH_AT_STARTUP_CHECKBOX.png.sha1
@@ -0,0 +1 @@ +66ee04872de139ef4109a6bc584e4d487ecd8525 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_ACCNAME_APP_HOME_OPEN_IN_WINDOW_CHECKBOX.png.sha1 b/chrome/app/generated_resources_grd/IDS_ACCNAME_APP_HOME_OPEN_IN_WINDOW_CHECKBOX.png.sha1 new file mode 100644 index 0000000..05802c7 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_ACCNAME_APP_HOME_OPEN_IN_WINDOW_CHECKBOX.png.sha1
@@ -0,0 +1 @@ +66ee04872de139ef4109a6bc584e4d487ecd8525 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_APP_HOME_APP_SETTINGS.png.sha1 b/chrome/app/generated_resources_grd/IDS_APP_HOME_APP_SETTINGS.png.sha1 new file mode 100644 index 0000000..66cd9c30 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_APP_HOME_APP_SETTINGS.png.sha1
@@ -0,0 +1 @@ +d9859dd7ccacc1fab0c47adfde2165fc753f4418 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_APP_HOME_CREATE_SHORTCUT.png.sha1 b/chrome/app/generated_resources_grd/IDS_APP_HOME_CREATE_SHORTCUT.png.sha1 new file mode 100644 index 0000000..66cd9c30 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_APP_HOME_CREATE_SHORTCUT.png.sha1
@@ -0,0 +1 @@ +d9859dd7ccacc1fab0c47adfde2165fc753f4418 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_APP_HOME_LAUNCH_AT_STARTUP.png.sha1 b/chrome/app/generated_resources_grd/IDS_APP_HOME_LAUNCH_AT_STARTUP.png.sha1 new file mode 100644 index 0000000..66cd9c30 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_APP_HOME_LAUNCH_AT_STARTUP.png.sha1
@@ -0,0 +1 @@ +d9859dd7ccacc1fab0c47adfde2165fc753f4418 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_APP_HOME_OPEN_IN_WINDOW.png.sha1 b/chrome/app/generated_resources_grd/IDS_APP_HOME_OPEN_IN_WINDOW.png.sha1 new file mode 100644 index 0000000..66cd9c30 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_APP_HOME_OPEN_IN_WINDOW.png.sha1
@@ -0,0 +1 @@ +d9859dd7ccacc1fab0c47adfde2165fc753f4418 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_APP_HOME_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_APP_HOME_TITLE.png.sha1 new file mode 100644 index 0000000..0c9de85 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_APP_HOME_TITLE.png.sha1
@@ -0,0 +1 @@ +d112e7df1fbf10968b53d5523d582fe9f147f3cd \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_APP_HOME_UNINSTALL_APP.png.sha1 b/chrome/app/generated_resources_grd/IDS_APP_HOME_UNINSTALL_APP.png.sha1 new file mode 100644 index 0000000..66cd9c30 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_APP_HOME_UNINSTALL_APP.png.sha1
@@ -0,0 +1 @@ +d9859dd7ccacc1fab0c47adfde2165fc753f4418 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_FOOTER_TOOLTIP.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_FOOTER_TOOLTIP.png.sha1 new file mode 100644 index 0000000..d1257afe --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_FOOTER_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +c3cd5682d772637c4a87391ba07f9b4e0651ff78 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_SAVE_PAGE_DESC_WEB_BUNDLE_FILE.png.sha1 b/chrome/app/generated_resources_grd/IDS_SAVE_PAGE_DESC_WEB_BUNDLE_FILE.png.sha1 deleted file mode 100644 index e237874..0000000 --- a/chrome/app/generated_resources_grd/IDS_SAVE_PAGE_DESC_WEB_BUNDLE_FILE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -f900ca5539368f68460ce5caf3cb0221a8ef7c4f \ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index 89c0b00..da41b61 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -2156,6 +2156,10 @@ <message name="IDS_SETTINGS_BRUSCHETTA_SHARED_PATHS_REMOVE_FAILURE_DIALOG_MESSAGE" translateable="false" desc="Message to show user when unsharing a Bruschetta shared folder fails. Do not translate 'Bruschetta'."> Couldn't unshare because an application is using this folder. The folder will be unshared when Bruschetta is next shut down. </message> + <message name="IDS_SETTINGS_BRUSCHETTA_SUBTEXT" desc="Description for the section for enabling and managing Bruschetta (codename)."> + Run Bruschetta on your device. + </message> + <!-- Android apps page (OS settings) --> <message name="IDS_SETTINGS_ANDROID_APPS_LABEL" desc="The text associated with the primary section setting."> Google Play Store
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_BRUSCHETTA_SUBTEXT.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_BRUSCHETTA_SUBTEXT.png.sha1 new file mode 100644 index 0000000..45e1332 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_BRUSCHETTA_SUBTEXT.png.sha1
@@ -0,0 +1 @@ +7f4f06fdfbdb05907b7f8d935bc5e4a56fe7b7a4 \ No newline at end of file
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp index 78f98a3..0ec975b2 100644 --- a/chrome/app/profiles_strings.grdp +++ b/chrome/app/profiles_strings.grdp
@@ -761,9 +761,12 @@ <message name="IDS_FRE_ACCEPT_SIGN_IN_BUTTON_TITLE" desc="The title of the button giving the users the choice to sign in to Chrome"> Sign in </message> - <message name="IDS_FRE_MANAGED_DESCRIPTION" desc="The disclaimer explaining to the users that their device is managed by their organisation"> + <message name="IDS_FRE_MANAGED_DESCRIPTION" desc="The disclaimer explaining to the users that their device is managed by their organization"> Your device is managed by your organization. Administrators can access the data in any profile on this device. </message> + <message name="IDS_FRE_MANAGED_BY_DESCRIPTION" desc="The disclaimer explaining to the users that their device is managed by an administrator"> + Your device is managed by <ph name="DOMAIN">$1<ex>example.com</ex></ph>. Administrators can access the data in any profile on this device. + </message> </if> </if>
diff --git a/chrome/app/profiles_strings_grdp/IDS_FRE_MANAGED_BY_DESCRIPTION.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_FRE_MANAGED_BY_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..2ecfd71 --- /dev/null +++ b/chrome/app/profiles_strings_grdp/IDS_FRE_MANAGED_BY_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +65d52ef7c5cc53fb94c09d212f2400b8f2426c8a \ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 61bc14ae..67b78ac 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -462,12 +462,24 @@ <message name="IDS_IBAN_NICKNAME" desc="Label for the field containing the nickname of the IBAN (International Bank Account Number) to be saved."> Nickname </message> + <message name="IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN" desc="The (accessibility) title of a button, which brings up a menu of actions that can be taken on a stored IBAN (International Bank Account Number). The IBAN is described by its nickname."> + More actions for <ph name="IBAN_DESCRIPTION">$1<ex>My Doctor's IBAN</ex></ph> + </message> + <message name="IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN_DESCRIPTION" desc="The (accessibility) IBAN (International Bank Account Number) description from the last 4 digits of the IBAN value."> + IBAN ending in <ph name="LAST_FOUR_DIGITS">$1<ex>1234</ex></ph> + </message> <message name="IDS_SETTINGS_ADD_IBAN_TITLE" desc="The title for the dialog that's shown when editing an IBAN (International Bank Account Number)."> Add IBAN </message> <message name="IDS_SETTINGS_EDIT_IBAN_TITLE" desc="The title for the dialog that's shown when entering the information for a new IBAN (International Bank Account Number)."> Edit IBAN </message> + <message name="IDS_SETTINGS_IBAN_EDIT" desc="Label for a context menu item that edits the selected IBAN (International Bank Account Number)." meaning="Edit selected IBAN."> + Edit + </message> + <message name="IDS_SETTINGS_IBAN_REMOVE" desc="Label for a context menu item that removes the selected IBAN (International Bank Account Number)." meaning="Remove selected IBAN."> + Remove + </message> <message name="IDS_SETTINGS_UPI_ID_LABEL" desc="A label which appears next to UPI IDs, when they are listed as stored payment info, but it is visually separate from the UPI ID. It lets the user know this is a UPI ID (e.g. as opposed to a credit card number). UPI is a system for payments in India. A UPI ID is an email-like string."> UPI ID </message> @@ -2366,54 +2378,6 @@ <message name="IDS_SETTINGS_SAFETY_CHECK_TOAST_UNDO_BUTTON_LABEL" desc="After the user has modified permissions for a website, a toast popup message is shown with this text next to a description of the action taken. The user can click this text to undo the action. For example, this text would be next to a descriptiton that says 'Allowed notification permissions for example.com'."> Undo </message> - <if expr="is_win and _google_chrome"> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_PRIMARY_LABEL" desc="'Unwanted software protection' is an element in safety check that finds harmful software installed on the computer and allows users to remove it."> - Device software - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_BUTTON_ARIA_LABEL" desc="Accessiblity text for the button that allows users to review and remove harmful software found on their computer."> - Review device software - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITHOUT_TIMESTAMP" desc="This text describes that Chrome can check if any known harmful software is installed on the user's computer."> - Chrome can check your computer for harmful software - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_SECONDS" desc="This text describes that Chrome did not find any known harmful software installed on the user's computer, and that it checked for harmful softwrae the last time a certain time ago."> - Chrome didn't find harmful software on your computer • Checked just now - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_MINUTES" desc="This text describes that Chrome did not find any known harmful software installed on the user's computer, and that it checked for harmful softwrae the last time a certain time ago."> - {NUM_MINS, plural, - =1 {Chrome didn't find harmful software on your computer • Checked 1 minute ago} - other {Chrome didn't find harmful software on your computer • Checked {NUM_MINS} minutes ago}} - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_HOURS" desc="This text describes that Chrome did not find any known harmful software installed on the user's computer, and that it checked for harmful softwrae the last time a certain time ago."> - {NUM_HOURS, plural, - =1 {Chrome didn't find harmful software on your computer • Checked 1 hour ago} - other {Chrome didn't find harmful software on your computer • Checked {NUM_HOURS} hours ago}} - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_YESTERDAY" desc="This text describes that Chrome did not find any known harmful software installed on the user's computer, and that it checked for harmful softwrae the last time a certain time ago."> - Chrome didn't find harmful software on your computer • Checked yesterday - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_DAYS" desc="This text describes that Chrome did not find any known harmful software installed on the user's computer, and that it checked for harmful softwrae the last time a certain time ago."> - {NUM_DAYS, plural, - =1 {Chrome didn't find harmful software on your computer • Checked 1 day ago} - other {Chrome didn't find harmful software on your computer • Checked {NUM_DAYS} days ago}} - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_INFECTED" desc="This text describes that Chrome found harmful software on the computer."> - Chrome found harmful software on your computer - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_SCANNING" desc="This text describes that Chrome is currently checking the user's device for unwanted software. This takes a couple of minutes."> - Chrome is checking your computer for harmful software... - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_REMOVING" desc="This text describes that Chrome is currently removing unwanted software frrom the user.s device. This takes a couple of minutes."> - Chrome is removing harmful software from your computer... - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_DISABLED_BY_ADMIN" desc="This text describes that Chrome can't check for unwanted software because an administrator disabled the feature."> - <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>Your administrator<ph name="END_LINK"></a></ph> has turned off checking for harmful software - </message> - <message name="IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_ERROR" desc="This text describes that Chrome can't check for unwanted software due to an error."> - Something went wrong. Click for more details. - </message> - </if> - <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_LABEL" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions. Actions include browser-initiated DNS prefetching, TCP and SSL preconnection, and prerendering of webpages."> Preload pages for faster browsing and searching </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN.png.sha1 new file mode 100644 index 0000000..8b46e97 --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN.png.sha1
@@ -0,0 +1 @@ +a556e59262afcace8c5056088ee76023ee55cb5f \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN_DESCRIPTION.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..4192b1a --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +d60db63f1cb84f5756a7fddf6bac6a29961016b5 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_IBAN_EDIT.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_IBAN_EDIT.png.sha1 new file mode 100644 index 0000000..ddcdf56 --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_IBAN_EDIT.png.sha1
@@ -0,0 +1 @@ +57a6b7d8b464aaef803d9a0219ef7176990ec865 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_IBAN_REMOVE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_IBAN_REMOVE.png.sha1 new file mode 100644 index 0000000..3c43a19 --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_IBAN_REMOVE.png.sha1
@@ -0,0 +1 @@ +f41f9a6327e870b83179e2b4b275e0d9d9303015 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_DISABLED_BY_ADMIN.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_DISABLED_BY_ADMIN.png.sha1 deleted file mode 100644 index e8e574ad..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_DISABLED_BY_ADMIN.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -90f455f5744fd37fe398ab57e53ef505f5aa4f6c \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_ERROR.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_ERROR.png.sha1 deleted file mode 100644 index 41c9ce6f..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_ERROR.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -41144fd6c22a8c10b7cc1d267cfadcc78c727147 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_INFECTED.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_INFECTED.png.sha1 deleted file mode 100644 index efb3985..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_INFECTED.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1f2af97c2f771f0b72c650db480762605b730538 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITHOUT_TIMESTAMP.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITHOUT_TIMESTAMP.png.sha1 deleted file mode 100644 index 9a3b8dad..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITHOUT_TIMESTAMP.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -eeeb82e78c21d58a6505511c768f114f74cfa31c \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_DAYS.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_DAYS.png.sha1 deleted file mode 100644 index 7f3f5810..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_DAYS.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -3d4c3ebbc6017492d2ca963ea0243bbccf855169 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_HOURS.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_HOURS.png.sha1 deleted file mode 100644 index 117063e73..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_HOURS.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -40af9b1e9bbc69c8ee745144366c07784db7e57f \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_MINUTES.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_MINUTES.png.sha1 deleted file mode 100644 index 1ff52a3..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_MINUTES.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -f3e09f69321fdcc7ebfdf5d89d6e69bb5219da86 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_SECONDS.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_SECONDS.png.sha1 deleted file mode 100644 index 508f5f57..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_SECONDS.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -a3421d121404b222789e63e9342841d1f03ec326 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_YESTERDAY.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_YESTERDAY.png.sha1 deleted file mode 100644 index 704fb430..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_YESTERDAY.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -bb74422e7cf1de229c0b4c1c51395ed613655309 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_REMOVING.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_REMOVING.png.sha1 deleted file mode 100644 index a4030fe..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_REMOVING.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -f1697572e3d5ce5b83ae48265a50f20fd7f6c491 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_SCANNING.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_SCANNING.png.sha1 deleted file mode 100644 index c18a047..0000000 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_SCANNING.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -031a4e2e1300298686b3d123a8d008659f7301a6 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index b9e87a9..3df6e20 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -164,8 +164,6 @@ "assist_ranker/assist_ranker_service_factory.h", "autocomplete/autocomplete_classifier_factory.cc", "autocomplete/autocomplete_classifier_factory.h", - "autocomplete/autocomplete_scoring_model_service_factory.cc", - "autocomplete/autocomplete_scoring_model_service_factory.h", "autocomplete/chrome_autocomplete_provider_client.cc", "autocomplete/chrome_autocomplete_provider_client.h", "autocomplete/chrome_autocomplete_scheme_classifier.cc", @@ -7560,6 +7558,8 @@ if (build_with_tflite_lib) { sources += [ + "autocomplete/autocomplete_scoring_model_service_factory.cc", + "autocomplete/autocomplete_scoring_model_service_factory.h", "permissions/prediction_model_handler_provider_factory.cc", "permissions/prediction_model_handler_provider_factory.h", ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 5c21877..99f1b51e 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1904,32 +1904,11 @@ "default_query_chip", "false"}; const FeatureEntry::FeatureParam kRelatedSearchesInBarShowDefaultChip = { "default_query_chip", "true"}; -const FeatureEntry::FeatureParam - kRelatedSearchesInBarShowDefaultChipWith110SpEllipsis[] = { - {"default_query_chip", "true"}, - {"default_query_max_width_sp", "110"}}; -const FeatureEntry::FeatureParam - kRelatedSearchesInBarShowDefaultChipWith115SpEllipsis[] = { - {"default_query_chip", "true"}, - {"default_query_max_width_sp", "115"}}; -const FeatureEntry::FeatureParam - kRelatedSearchesInBarShowDefaultChipWith120SpEllipsis[] = { - {"default_query_chip", "true"}, - {"default_query_max_width_sp", "120"}}; const FeatureEntry::FeatureVariation kRelatedSearchesInBarVariations[] = { {"without default query chip", &kRelatedSearchesInBarNoShowDefaultChip, 1, nullptr}, {"with default query chip", &kRelatedSearchesInBarShowDefaultChip, 1, nullptr}, - {"with 110sp ellipsized default query chip", - kRelatedSearchesInBarShowDefaultChipWith110SpEllipsis, - std::size(kRelatedSearchesInBarShowDefaultChipWith110SpEllipsis), nullptr}, - {"with 115sp ellipsized default query chip", - kRelatedSearchesInBarShowDefaultChipWith115SpEllipsis, - std::size(kRelatedSearchesInBarShowDefaultChipWith115SpEllipsis), nullptr}, - {"with 120sp ellipsized default query chip", - kRelatedSearchesInBarShowDefaultChipWith120SpEllipsis, - std::size(kRelatedSearchesInBarShowDefaultChipWith120SpEllipsis), nullptr}, }; const FeatureEntry::FeatureParam kContextualSearchSuppressShortViewWith300Dp[] = @@ -2191,30 +2170,17 @@ }; const FeatureEntry::FeatureParam - kNotificationPermissionRationale_show_dialog_next_start_text_variant[] = { - {"always_show_rationale_before_requesting_permission", "true"}, - {"notification_permission_dialog_text_variant_2", "true"}, - {"permission_request_interval_days", "0"}, -}; - -const FeatureEntry::FeatureParam kNotificationPermissionRationale_show_dialog_next_start[] = { {"always_show_rationale_before_requesting_permission", "true"}, - {"notification_permission_dialog_text_variant_2", "false"}, {"permission_request_interval_days", "0"}, }; const FeatureEntry::FeatureVariation kNotificationPermissionRationaleVariations[] = { - {"- Show rationale dialog on next startup", + {"- Show rationale UI on next startup", kNotificationPermissionRationale_show_dialog_next_start, std::size(kNotificationPermissionRationale_show_dialog_next_start), nullptr}, - {"- Show rationale dialog on next startup - alternative copy", - kNotificationPermissionRationale_show_dialog_next_start_text_variant, - std::size( - kNotificationPermissionRationale_show_dialog_next_start_text_variant), - nullptr}, }; const FeatureEntry::FeatureParam kWebFeed_accelerator[] = { @@ -3715,9 +3681,6 @@ flag_descriptions::kEnableHardwareMirrorModeName, flag_descriptions::kEnableHardwareMirrorModeDescription, kOsCrOS, FEATURE_VALUE_TYPE(display::features::kEnableHardwareMirrorMode)}, - {"enable-dns-proxy", flag_descriptions::kEnableDnsProxyName, - flag_descriptions::kEnableDnsProxyDescription, kOsCrOS, - FEATURE_VALUE_TYPE(ash::features::kEnableDnsProxy)}, {"enable-edid-based-display-ids", flag_descriptions::kEnableEdidBasedDisplayIdsName, flag_descriptions::kEnableEdidBasedDisplayIdsDescription, kOsCrOS, @@ -3726,9 +3689,6 @@ flag_descriptions::kEnforceAshExtensionKeeplistName, flag_descriptions::kEnforceAshExtensionKeeplistDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kEnforceAshExtensionKeeplist)}, - {"dns-proxy-enable-doh", flag_descriptions::kDnsProxyEnableDOHName, - flag_descriptions::kDnsProxyEnableDOHDescription, kOsCrOS, - FEATURE_VALUE_TYPE(::features::kDnsProxyEnableDOH)}, {"hotspot", flag_descriptions::kHotspotName, flag_descriptions::kHotspotDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kHotspot)}, @@ -3816,6 +3776,9 @@ {"screen-saver-preview", flag_descriptions::kScreenSaverPreviewName, flag_descriptions::kScreenSaverPreviewDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kScreenSaverPreview)}, + {"multi-zone-rgb-keyboard", flag_descriptions::kMultiZoneRgbKeyboardName, + flag_descriptions::kMultiZoneRgbKeyboardDescription, kOsCrOS, + FEATURE_VALUE_TYPE(ash::features::kMultiZoneRgbKeyboard)}, #endif // BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS) @@ -4136,9 +4099,6 @@ feature_engagement::kIPHDemoMode, feature_engagement::kIPHDemoModeChoiceVariations, "IPH_DemoMode")}, - {"in-product-help-snooze", flag_descriptions::kInProductHelpSnoozeName, - flag_descriptions::kInProductHelpSnoozeDescription, kOsAll, - FEATURE_VALUE_TYPE(feature_engagement::kIPHSnooze)}, {"in-product-help-use-client-config", flag_descriptions::kInProductHelpUseClientConfigName, flag_descriptions::kInProductHelpUseClientConfigDescription, kOsAll, @@ -4467,6 +4427,11 @@ chrome::android::kNotificationPermissionVariant, kNotificationPermissionRationaleVariations, "NotificationPermissionVariant")}, + {"notification-permission-rationale-bottom-sheet", + flag_descriptions::kNotificationPermissionRationaleBottomSheetName, + flag_descriptions::kNotificationPermissionRationaleBottomSheetDescription, + kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kNotificationPermissionBottomSheet)}, {"feature-notification-guide-skip-check-for-low-engaged-users", flag_descriptions:: kFeatureNotificationGuideSkipCheckForLowEngagedUsersName, @@ -6931,10 +6896,6 @@ FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kLensCameraAssistedSearch, kLensCameraAssistedSearchVariations, "LensCameraAssistedSearch")}, - - {"enable-iph", flag_descriptions::kEnableIphName, - flag_descriptions::kEnableIphDescription, kOsAndroid, - FEATURE_VALUE_TYPE(feature_engagement::kEnableIPH)}, #endif // BUILDFLAG(IS_ANDROID) {"autofill-always-return-cloud-tokenized-card", @@ -7274,9 +7235,6 @@ flag_descriptions::kNearbySharingSelfShareUIName, flag_descriptions::kNearbySharingSelfShareUIDescription, kOsCrOS, FEATURE_VALUE_TYPE(features::kNearbySharingSelfShareUI)}, - {"nearby-sharing-wifilan", flag_descriptions::kNearbySharingWifiLanName, - flag_descriptions::kNearbySharingWifiLanDescription, kOsCrOS, - FEATURE_VALUE_TYPE(features::kNearbySharingWifiLan)}, #endif // BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/about_flags_browsertest.cc b/chrome/browser/about_flags_browsertest.cc index 8427f99d..0e18e34 100644 --- a/chrome/browser/about_flags_browsertest.cc +++ b/chrome/browser/about_flags_browsertest.cc
@@ -323,19 +323,6 @@ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kSwitchName)); } -class AboutFlagsUnexpiredBrowserTest : public AboutFlagsBrowserTest { - public: - AboutFlagsUnexpiredBrowserTest() { - const base::Feature* unexpire = - flags::GetUnexpireFeatureForMilestone(CHROME_VERSION_MAJOR - 1); - feature_list_.InitWithFeatures({*unexpire}, {}); - } -}; - -INSTANTIATE_TEST_SUITE_P(All, - AboutFlagsUnexpiredBrowserTest, - ::testing::Values(true)); - // Crashes on Win. http://crbug.com/1108357 #if BUILDFLAG(IS_WIN) #define MAYBE_ExpiryHidesFlag DISABLED_ExpiryHidesFlag @@ -350,14 +337,6 @@ EXPECT_FALSE(IsFlagPresent(contents, kExpiredFlagName)); } -IN_PROC_BROWSER_TEST_P(AboutFlagsUnexpiredBrowserTest, MAYBE_ExpiryHidesFlag) { - NavigateToFlagsPage(); - content::WebContents* contents = - browser()->tab_strip_model()->GetActiveWebContents(); - EXPECT_TRUE(IsFlagPresent(contents, kFlagName)); - EXPECT_TRUE(IsFlagPresent(contents, kExpiredFlagName)); -} - #if !BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_P(AboutFlagsBrowserTest, PRE_ExpiredFlagDoesntApply) { NavigateToFlagsPage();
diff --git a/chrome/browser/android/compositor/layer/tab_handle_layer.cc b/chrome/browser/android/compositor/layer/tab_handle_layer.cc index 93c412b..187e21b2 100644 --- a/chrome/browser/android/compositor/layer/tab_handle_layer.cc +++ b/chrome/browser/android/compositor/layer/tab_handle_layer.cc
@@ -42,6 +42,7 @@ float content_offset_y, float divider_offset_x, float bottom_offset_y, + float close_button_padding, float close_button_alpha, float divider_alpha, bool is_loading, @@ -210,7 +211,6 @@ } else { close_button_->SetIsDrawable(true); const float close_max_width = close_button_->bounds().width(); - int close_y; if (is_tab_strip_redesign_enabled) { close_y = content_offset_y; @@ -218,9 +218,10 @@ close_y = (tab_handle_resource->padding().y() + height) / 2 - close_button_->bounds().height() / 2; } - - int close_x = is_rtl ? padding_left - close_max_width + close_width - : width - padding_right - close_width; + int close_x = + is_rtl ? padding_left - close_max_width + close_width - + close_button_padding + : width - padding_right - close_width + close_button_padding; if (foreground_) { close_y += original_y; close_x += original_x;
diff --git a/chrome/browser/android/compositor/layer/tab_handle_layer.h b/chrome/browser/android/compositor/layer/tab_handle_layer.h index f80513d..d24b9234 100644 --- a/chrome/browser/android/compositor/layer/tab_handle_layer.h +++ b/chrome/browser/android/compositor/layer/tab_handle_layer.h
@@ -49,6 +49,7 @@ float content_offset_y, float divider_offset_x, float bottom_offset_y, + float close_button_padding, float close_button_alpha, float divider_alpha, bool is_loading,
diff --git a/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.cc index d069f47..3e51d1e 100644 --- a/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.cc +++ b/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.cc
@@ -408,6 +408,7 @@ jfloat content_offset_y, jfloat divider_offset_x, jfloat bottom_offset_y, + jfloat close_button_padding, jfloat close_button_alpha, jfloat divider_alpha, jboolean is_loading, @@ -436,8 +437,9 @@ id, close_button_resource, divider_resource, tab_handle_resource, tab_handle_outline_resource, foreground, close_pressed, toolbar_width, x, y, width, height, content_offset_x, content_offset_y, divider_offset_x, - bottom_offset_y, close_button_alpha, divider_alpha, is_loading, - spinner_rotation, brightness, opacity, tab_strip_redesign_enabled); + bottom_offset_y, close_button_padding, close_button_alpha, divider_alpha, + is_loading, spinner_rotation, brightness, opacity, + tab_strip_redesign_enabled); } scoped_refptr<TabHandleLayer> TabStripSceneLayer::GetNextLayer(
diff --git a/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.h b/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.h index 137d77b..1497cfae 100644 --- a/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.h +++ b/chrome/browser/android/compositor/scene_layer/tab_strip_scene_layer.h
@@ -149,6 +149,7 @@ jfloat content_offset_y, jfloat divider_offset_x, jfloat bottom_offset_y, + jfloat close_button_padding, jfloat close_button_alpha, jfloat divider_alpha, jboolean is_loading,
diff --git a/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc b/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc index e0ae1c0..e20f982 100644 --- a/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc +++ b/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc
@@ -111,9 +111,32 @@ web_contents()->GetController().CanGoForward(); } +bool TabInteractionRecorderAndroid::HasActiveFormInteraction() const { + bool interaction = false; + web_contents()->GetPrimaryMainFrame()->ForEachRenderFrameHostWithAction( + [&interaction](RenderFrameHost* rfh) { + if (!FormInteractionData::GetForCurrentDocument(rfh)) { + return RenderFrameHost::FrameIterationAction::kContinue; + } + if (FormInteractionData::GetForCurrentDocument(rfh) + ->GetHasFormInteractionData()) { + interaction = true; + return RenderFrameHost::FrameIterationAction::kStop; + } + return RenderFrameHost::FrameIterationAction::kContinue; + }); + return interaction; +} + void TabInteractionRecorderAndroid::ResetImpl() { - has_form_interactions_ = false; + has_form_interactions_in_session_ = false; did_get_user_interaction_ = false; + web_contents()->GetPrimaryMainFrame()->ForEachRenderFrameHost( + [](RenderFrameHost* rfh) { + if (FormInteractionData::GetForCurrentDocument(rfh)) { + FormInteractionData::DeleteForCurrentDocument(rfh); + } + }); } // content::WebContentsObserver: @@ -123,16 +146,13 @@ RenderFrameHost::LifecycleState new_state) { if (old_state == RenderFrameHost::LifecycleState::kActive) { rfh_observer_map_.erase(render_frame_host->GetGlobalId()); - } else if (new_state == RenderFrameHost::LifecycleState::kActive && - !has_form_interactions_) { + } else if (new_state == RenderFrameHost::LifecycleState::kActive) { StartObservingFrame(render_frame_host); } } void TabInteractionRecorderAndroid::DidFinishNavigation( content::NavigationHandle* navigation_handle) { - if (has_form_interactions_) - return; if (!navigation_handle->IsSameDocument() && navigation_handle->HasCommitted() && navigation_handle->GetRenderFrameHost()->IsActive()) @@ -159,7 +179,7 @@ ->SetHasFormInteractionData(); } - has_form_interactions_ = true; + has_form_interactions_in_session_ = true; rfh_observer_map_.clear(); } @@ -190,14 +210,19 @@ return did_get_user_interaction_; } -jboolean TabInteractionRecorderAndroid::HadFormInteraction(JNIEnv* env) const { - return static_cast<jboolean>(has_form_interactions()); +jboolean TabInteractionRecorderAndroid::HadFormInteractionInSession( + JNIEnv* env) const { + return has_form_interactions_in_session(); } jboolean TabInteractionRecorderAndroid::HadNavigationInteraction( JNIEnv* env) const { - return static_cast<jboolean>(did_get_user_interaction_ && - HasNavigatedFromFirstPage()); + return did_get_user_interaction_ && HasNavigatedFromFirstPage(); +} + +jboolean TabInteractionRecorderAndroid::HadFormInteractionInActivePage( + JNIEnv* env) const { + return HasActiveFormInteraction(); } void TabInteractionRecorderAndroid::Reset(JNIEnv* env) {
diff --git a/chrome/browser/android/customtabs/tab_interaction_recorder_android.h b/chrome/browser/android/customtabs/tab_interaction_recorder_android.h index 2b2e9c9..cc5757e 100644 --- a/chrome/browser/android/customtabs/tab_interaction_recorder_android.h +++ b/chrome/browser/android/customtabs/tab_interaction_recorder_android.h
@@ -83,8 +83,14 @@ // Return whether the |web_contents()| has navigated away from the first page. bool HasNavigatedFromFirstPage() const; + // Return whether there is an active render frame host which has incurred a + // form interaction. + bool HasActiveFormInteraction() const; + // Return whether the |web_contents()| has seen any form interactions. - bool has_form_interactions() const { return has_form_interactions_; } + bool has_form_interactions_in_session() const { + return has_form_interactions_in_session_; + } bool did_get_user_interaction() const { return did_get_user_interaction_; } // content::WebContentsObserver: @@ -105,7 +111,8 @@ // JNI methods jboolean DidGetUserInteraction(JNIEnv* env) const; - jboolean HadFormInteraction(JNIEnv* env) const; + jboolean HadFormInteractionInSession(JNIEnv* env) const; + jboolean HadFormInteractionInActivePage(JNIEnv* env) const; jboolean HadNavigationInteraction(JNIEnv* env) const; void Reset(JNIEnv* env); @@ -126,7 +133,7 @@ void ResetImpl(); bool did_get_user_interaction_ = false; - bool has_form_interactions_ = false; + bool has_form_interactions_in_session_ = false; std::unordered_map<content::GlobalRenderFrameHostId, std::unique_ptr<AutofillObserverImpl>, content::GlobalRenderFrameHostIdHasher>
diff --git a/chrome/browser/android/customtabs/tab_interaction_recorder_android_unittest.cc b/chrome/browser/android/customtabs/tab_interaction_recorder_android_unittest.cc index c1f612dd..78ff435 100644 --- a/chrome/browser/android/customtabs/tab_interaction_recorder_android_unittest.cc +++ b/chrome/browser/android/customtabs/tab_interaction_recorder_android_unittest.cc
@@ -183,17 +183,40 @@ std::unique_ptr<content::WebContents> contents = CreateTestWebContents(); auto* helper = TabInteractionRecorderAndroid::FromWebContents(contents.get()); - EXPECT_FALSE(helper->has_form_interactions()); + EXPECT_FALSE(helper->has_form_interactions_in_session()); EXPECT_EQ(nullptr, FormInteractionData::GetForCurrentDocument( contents->GetPrimaryMainFrame())); OnTextFieldDidChangeForAutofillManager(autofill_manager()); - EXPECT_TRUE(helper->has_form_interactions()); + EXPECT_TRUE(helper->has_form_interactions_in_session()); EXPECT_TRUE(FormInteractionData::GetForCurrentDocument( contents->GetPrimaryMainFrame()) ->FormInteractionData::GetHasFormInteractionData()); JNIEnv* env = base::android::AttachCurrentThread(); - EXPECT_TRUE(helper->HadFormInteraction(env)); + EXPECT_TRUE(helper->HadFormInteractionInSession(env)); + EXPECT_TRUE(helper->HadFormInteractionInActivePage(env)); +} + +TEST_F(TabInteractionRecorderAndroidTest, HadFormInteractionThenNavigation) { + std::unique_ptr<content::WebContents> contents = CreateTestWebContents(); + auto* helper = TabInteractionRecorderAndroid::FromWebContents(contents.get()); + + EXPECT_FALSE(helper->has_form_interactions_in_session()); + EXPECT_EQ(nullptr, FormInteractionData::GetForCurrentDocument( + contents->GetPrimaryMainFrame())); + OnTextFieldDidChangeForAutofillManager(autofill_manager()); + EXPECT_TRUE(helper->has_form_interactions_in_session()); + EXPECT_TRUE(FormInteractionData::GetForCurrentDocument( + contents->GetPrimaryMainFrame()) + ->FormInteractionData::GetHasFormInteractionData()); + + content::WebContentsTester::For(contents.get()) + ->NavigateAndCommit(GURL("https://bar.com")); + task_environment()->RunUntilIdle(); + + JNIEnv* env = base::android::AttachCurrentThread(); + EXPECT_TRUE(helper->HadFormInteractionInSession(env)); + EXPECT_FALSE(helper->HadFormInteractionInActivePage(env)); } TEST_F(TabInteractionRecorderAndroidTest, HasNavigatedFromFirstPage) { @@ -260,15 +283,16 @@ content::WebContentsTester::For(contents.get()) ->NavigateAndCommit(GURL("https://bar.com")); task_environment()->RunUntilIdle(); - EXPECT_TRUE(helper->has_form_interactions()); + EXPECT_TRUE(helper->has_form_interactions_in_session()); EXPECT_TRUE(helper->did_get_user_interaction()); EXPECT_TRUE(helper->HasNavigatedFromFirstPage()); // Assuming the record resets from Android. JNIEnv* env = base::android::AttachCurrentThread(); helper->Reset(env); - EXPECT_FALSE(helper->HadFormInteraction(env)); + EXPECT_FALSE(helper->HadFormInteractionInSession(env)); EXPECT_FALSE(helper->DidGetUserInteraction(env)); EXPECT_FALSE(helper->HadNavigationInteraction(env)); + EXPECT_FALSE(helper->HadFormInteractionInActivePage(env)); } } // namespace customtabs
diff --git a/chrome/browser/apps/app_preload_service/app_preload_service_browsertest.cc b/chrome/browser/apps/app_preload_service/app_preload_service_browsertest.cc index b96a8f2..be313121 100644 --- a/chrome/browser/apps/app_preload_service/app_preload_service_browsertest.cc +++ b/chrome/browser/apps/app_preload_service/app_preload_service_browsertest.cc
@@ -22,6 +22,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "components/user_manager/scoped_user_manager.h" #include "content/public/test/browser_test.h" +#include "net/dns/mock_host_resolver.h" namespace apps { @@ -42,9 +43,14 @@ https_server_.RegisterRequestHandler(base::BindRepeating( &AppPreloadServiceBrowserTest::HandleRequest, base::Unretained(this))); - ASSERT_TRUE(https_server()->Start()); + https_server_.AddDefaultHandlers(GetChromeTestDataDir()); + ASSERT_TRUE(https_server_.Start()); + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( ash::switches::kAlmanacApiUrl, https_server()->GetURL("/").spec()); + + // Icon URLs should remap to the test server. + host_resolver()->AddRule("meltingpot.googleusercontent.com", "127.0.0.1"); } std::unique_ptr<net::test_server::HttpResponse> HandleRequest( @@ -69,6 +75,20 @@ return nullptr; } + std::string AddIconToManifest(const std::string& manifest_template) { + GURL icon_url = https_server()->GetURL("meltingpot.googleusercontent.com", + "/web_apps/blue-192.png"); + constexpr char kIconsBlock[] = R"([{ + "src": "$1", + "sizes": "192x192", + "type": "image/png" + }])"; + std::string icon_value = base::ReplaceStringPlaceholders( + kIconsBlock, {icon_url.spec()}, nullptr); + return base::ReplaceStringPlaceholders(manifest_template, {icon_value}, + nullptr); + } + void SetManifestResponse(std::string manifest) { manifest_ = manifest; } void SetAppProvisioningResponse( @@ -106,11 +126,12 @@ "https://www.example.com/"); SetAppProvisioningResponse(response); - SetManifestResponse(R"({ + SetManifestResponse(AddIconToManifest(R"({ "id": "id", "name": "Example App", - "start_url": "/index.html" - })"); + "start_url": "/index.html", + "icons": $1 + })")); base::test::TestFuture<bool> result; auto* service = AppPreloadService::Get(profile()); @@ -166,7 +187,8 @@ constexpr char kManifest[] = R"({ "id": "manifest_id", "name": "OEM Installed app", - "start_url": "/" + "start_url": "/", + "icons": $1 })"; auto app_id = web_app::test::InstallDummyWebApp(profile(), kUserAppName, @@ -184,7 +206,7 @@ app->mutable_web_extras()->set_original_manifest_url(kOriginalManifestUrl); SetAppProvisioningResponse(response); - SetManifestResponse(kManifest); + SetManifestResponse(AddIconToManifest(kManifest)); base::test::TestFuture<bool> result; auto* service = AppPreloadService::Get(profile());
diff --git a/chrome/browser/apps/app_preload_service/web_app_preload_installer.cc b/chrome/browser/apps/app_preload_service/web_app_preload_installer.cc index 2c022f4..00a8ec3 100644 --- a/chrome/browser/apps/app_preload_service/web_app_preload_installer.cc +++ b/chrome/browser/apps/app_preload_service/web_app_preload_installer.cc
@@ -128,12 +128,15 @@ auto* provider = web_app::WebAppProvider::GetForWebApps(profile_); + base::flat_set<std::string> host_allowlist = { + "meltingpot.googleusercontent.com"}; + provider->command_manager().ScheduleCommand( std::make_unique<web_app::InstallFromManifestCommand>( webapps::WebappInstallSource::PRELOADED_OEM, /*document_url=*/GURL(app.GetWebAppManifestId()).GetWithEmptyPath(), /*manifest_url=*/app.GetWebAppOriginalManifestUrl(), - std::move(*response), GetAppId(app), + std::move(*response), GetAppId(app), std::move(host_allowlist), base::BindOnce(&WebAppPreloadInstaller::OnAppInstalled, weak_ptr_factory_.GetWeakPtr(), std::move(callback)))); }
diff --git a/chrome/browser/apps/app_preload_service/web_app_preload_installer_browsertest.cc b/chrome/browser/apps/app_preload_service/web_app_preload_installer_browsertest.cc index 19d69ee3..1caf06b 100644 --- a/chrome/browser/apps/app_preload_service/web_app_preload_installer_browsertest.cc +++ b/chrome/browser/apps/app_preload_service/web_app_preload_installer_browsertest.cc
@@ -4,6 +4,7 @@ #include "base/functional/bind.h" #include "base/strings/strcat.h" +#include "base/strings/string_util.h" #include "base/test/test_future.h" #include "chrome/browser/apps/app_preload_service/preload_app_definition.h" #include "chrome/browser/apps/app_preload_service/proto/app_provisioning.pb.h" @@ -18,6 +19,7 @@ #include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/app_update.h" #include "content/public/test/browser_test.h" +#include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" @@ -32,8 +34,12 @@ https_server_.RegisterRequestHandler( base::BindRepeating(&WebAppPreloadInstallerBrowserTest::HandleRequest, base::Unretained(this))); + https_server_.AddDefaultHandlers(GetChromeTestDataDir()); - ASSERT_TRUE(https_server()->Start()); + ASSERT_TRUE(https_server_.Start()); + + // Icon URLs should remap to the test server. + host_resolver()->AddRule("meltingpot.googleusercontent.com", "127.0.0.1"); } std::unique_ptr<net::test_server::HttpResponse> HandleRequest( @@ -49,6 +55,20 @@ return response; } + std::string AddIconToManifest(const std::string& manifest_template) { + GURL icon_url = https_server()->GetURL("meltingpot.googleusercontent.com", + "/web_apps/blue-192.png"); + constexpr char kIconsBlock[] = R"([{ + "src": "$1", + "sizes": "192x192", + "type": "image/png" + }])"; + std::string icon_value = base::ReplaceStringPlaceholders( + kIconsBlock, {icon_url.spec()}, nullptr); + return base::ReplaceStringPlaceholders(manifest_template, {icon_value}, + nullptr); + } + void SetManifestResponse(std::string manifest) { manifest_ = manifest; } Profile* profile() { return browser()->profile(); } @@ -79,11 +99,13 @@ "https://www.example.com/manifest.json"); web_extras->set_manifest_url(https_server()->GetURL("/manifest.json").spec()); - SetManifestResponse(R"({ + constexpr char kManifestTemplate[] = R"({ "name": "Example App", "start_url": "/index.html", - "scope": "/" - })"); + "scope": "/", + "icons": $1 + })"; + SetManifestResponse(AddIconToManifest(kManifestTemplate)); base::test::TestFuture<bool> result; installer.InstallApp(PreloadAppDefinition(app), result.GetCallback()); @@ -114,12 +136,13 @@ "https://www.example.com/manifest.json"); web_extras->set_manifest_url(https_server()->GetURL("/manifest.json").spec()); - SetManifestResponse(R"({ + SetManifestResponse(AddIconToManifest(R"({ "id": "manifest_id", "name": "Example App", "start_url": "/index.html", - "scope": "/" - })"); + "scope": "/", + "icons": $1 + })")); base::test::TestFuture<bool> result; installer.InstallApp(PreloadAppDefinition(app), result.GetCallback()); @@ -155,10 +178,11 @@ web_extras->set_manifest_url(https_server()->GetURL("/manifest.json").spec()); web_extras->set_original_manifest_url(kOriginalManifestUrl); - SetManifestResponse(R"({ + SetManifestResponse(AddIconToManifest(R"({ "name": "OEM Installed app", - "start_url": "/" - })"); + "start_url": "/", + "icons": $1 + })")); base::test::TestFuture<bool> result; installer.InstallApp(PreloadAppDefinition(app), result.GetCallback()); @@ -188,11 +212,12 @@ "https://www.example.com/manifest.json"); web_extras->set_manifest_url(https_server()->GetURL("/manifest.json").spec()); - SetManifestResponse(R"({ + SetManifestResponse(AddIconToManifest(R"({ "name": "Example App", "start_url": "/index.html", - "scope": "/" - })"); + "scope": "/", + "icons": $1 + })")); base::test::TestFuture<bool> result; installer.InstallApp(PreloadAppDefinition(app), result.GetCallback()); @@ -263,4 +288,42 @@ ASSERT_FALSE(found); } +IN_PROC_BROWSER_TEST_F(WebAppPreloadInstallerBrowserTest, + ManifestWithFailingIcons) { + WebAppPreloadInstaller installer(profile()); + + proto::AppProvisioningListAppsResponse_App app; + app.set_name("Example App"); + app.set_package_id("web:https://www.example.com/manifest_id"); + app.set_install_reason( + proto::AppProvisioningListAppsResponse::INSTALL_REASON_OEM); + + auto* web_extras = app.mutable_web_extras(); + web_extras->set_original_manifest_url( + "https://www.example.com/manifest.json"); + web_extras->set_manifest_url(https_server()->GetURL("/manifest.json").spec()); + + constexpr char kManifestTemplate[] = R"({ + "name": "Example App", + "start_url": "/index.html", + "scope": "/", + "icons": [{ + "src": "$1", + "sizes": "96x96", + "type": "image/png" + }] + })"; + + // The image will fail to download, which will cause the installation to fail. + GURL image_url = + https_server()->GetURL("meltingpot.googleusercontent.com", "/404"); + + SetManifestResponse(base::ReplaceStringPlaceholders( + kManifestTemplate, {image_url.spec()}, nullptr)); + + base::test::TestFuture<bool> result; + installer.InstallApp(PreloadAppDefinition(app), result.GetCallback()); + ASSERT_FALSE(result.Get()); +} + } // namespace apps
diff --git a/chrome/browser/apps/app_service/app_icon/app_icon_loader.cc b/chrome/browser/apps/app_service/app_icon/app_icon_loader.cc index 513d7908..1b7ae7b 100644 --- a/chrome/browser/apps/app_service/app_icon/app_icon_loader.cc +++ b/chrome/browser/apps/app_service/app_icon/app_icon_loader.cc
@@ -105,10 +105,9 @@ // the icon data from `icon_path`, we might resize it if the icon size doesn't // match, because it could be shown as the compress icon directly, without // calling the adaptive icon Composite function to chop and resize. -apps::IconValuePtr ReadFilesForDefaultAppAndMaybeResize( - apps::AdaptiveIconPaths icon_paths, - float icon_scale, - int icon_size_in_px) { +apps::IconValuePtr ReadFilesAndMaybeResize(apps::AdaptiveIconPaths icon_paths, + float icon_scale, + int icon_size_in_px) { auto iv = std::make_unique<apps::IconValue>(); iv->icon_type = apps::IconType::kCompressed; @@ -687,24 +686,35 @@ icon_size_in_px_ = apps_util::ConvertDipToPxForScale(size_hint_in_dip_, icon_scale_); - // Get the icon paths for the default apps. If we can't fetch the raw icon - // data from the ARC side, the icon paths for the default apps are used to get - // the icon data. - AdaptiveIconPaths default_app_paths; + AdaptiveIconPaths app_paths; const ArcAppIconDescriptor descriptor(size_hint_in_dip_, scale_factor); if (arc_prefs->IsDefault(app_id)) { - default_app_paths.icon_path = + // Get the icon paths for the default apps. If we can't fetch the raw icon + // data from the ARC side, the icon paths for the default apps are used to + // get the icon data. + app_paths.icon_path = arc_prefs->MaybeGetIconPathForDefaultApp(app_id, descriptor); - default_app_paths.foreground_icon_path = + app_paths.foreground_icon_path = arc_prefs->MaybeGetForegroundIconPathForDefaultApp(app_id, descriptor); - default_app_paths.background_icon_path = + app_paths.background_icon_path = arc_prefs->MaybeGetBackgroundIconPathForDefaultApp(app_id, descriptor); + } else { + // For the migration scenario, as ARC may take some time to startup after + // the user login, fetching the raw icon files from the ARC VM could fail. + // So try to fetch the raw icon files from the ARC on-disk cache to + // migrate the icon files from the ARC directory to the AppService + // directory. + app_paths.icon_path = arc_prefs->GetIconPath(app_id, descriptor); + app_paths.foreground_icon_path = + arc_prefs->GetForegroundIconPath(app_id, descriptor); + app_paths.background_icon_path = + arc_prefs->GetBackgroundIconPath(app_id, descriptor); } arc_prefs->RequestRawIconData( app_id, ArcAppIconDescriptor(size_hint_in_dip_, scale_factor), base::BindOnce(&AppIconLoader::OnGetArcAppCompressedIconData, - base::WrapRefCounted(this), std::move(default_app_paths))); + base::WrapRefCounted(this), std::move(app_paths))); } void AppIconLoader::GetGuestOSAppCompressedIconData( @@ -738,22 +748,21 @@ } void AppIconLoader::OnGetArcAppCompressedIconData( - AdaptiveIconPaths default_app_paths, + AdaptiveIconPaths app_icon_paths, arc::mojom::RawIconPngDataPtr icon) { auto iv = std::make_unique<IconValue>(); if (!icon || !icon->icon_png_data.has_value()) { - // If the app is not a default app, return the empty icon value. - if (default_app_paths.IsEmpty()) { + // If we can't find `app_icon_paths`, return the empty icon value. + if (app_icon_paths.IsEmpty()) { std::move(callback_).Run(std::move(iv)); return; } - // Get the raw icon data from the icon files for the default app. + // Get the raw icon data from `app_icon_paths`. base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, - base::BindOnce(&ReadFilesForDefaultAppAndMaybeResize, - std::move(default_app_paths), icon_scale_, - icon_size_in_px_), + base::BindOnce(&ReadFilesAndMaybeResize, std::move(app_icon_paths), + icon_scale_, icon_size_in_px_), std::move(callback_)); return; }
diff --git a/chrome/browser/apps/app_service/app_icon/app_icon_loader.h b/chrome/browser/apps/app_service/app_icon/app_icon_loader.h index ca9ae342..72cfee3 100644 --- a/chrome/browser/apps/app_service/app_icon/app_icon_loader.h +++ b/chrome/browser/apps/app_service/app_icon/app_icon_loader.h
@@ -167,7 +167,7 @@ ~AppIconLoader(); #if BUILDFLAG(IS_CHROMEOS_ASH) - void OnGetArcAppCompressedIconData(AdaptiveIconPaths default_app_paths, + void OnGetArcAppCompressedIconData(AdaptiveIconPaths app_icon_paths, arc::mojom::RawIconPngDataPtr icon); void OnGetGuestOSAppCompressedIconData(base::FilePath png_path,
diff --git a/chrome/browser/apps/app_service/metrics/website_metrics.cc b/chrome/browser/apps/app_service/metrics/website_metrics.cc index ffe8abc..8fbb66dd 100644 --- a/chrome/browser/apps/app_service/metrics/website_metrics.cc +++ b/chrome/browser/apps/app_service/metrics/website_metrics.cc
@@ -7,7 +7,6 @@ #include <random> #include "base/containers/contains.h" -#include "base/debug/dump_without_crashing.h" #include "base/json/values_util.h" #include "base/rand_util.h" #include "chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h" @@ -609,7 +608,6 @@ bool is_from_last_login) { if (source_id == ukm::kInvalidSourceId) { DVLOG(1) << "WebsiteMetrics::EmitUkm source id is invalid."; - base::debug::DumpWithoutCrashing(); return; }
diff --git a/chrome/browser/apps/app_service/publishers/borealis_apps.cc b/chrome/browser/apps/app_service/publishers/borealis_apps.cc index f607c12..88bc616 100644 --- a/chrome/browser/apps/app_service/publishers/borealis_apps.cc +++ b/chrome/browser/apps/app_service/publishers/borealis_apps.cc
@@ -250,6 +250,14 @@ std::move(callback)); } +void BorealisApps::GetCompressedIconData(const std::string& app_id, + int32_t size_in_dip, + ui::ResourceScaleFactor scale_factor, + LoadIconCallback callback) { + GetGuestOSAppCompressedIconData(profile_, app_id, size_in_dip, scale_factor, + std::move(callback)); +} + void BorealisApps::Launch(const std::string& app_id, int32_t event_flags, LaunchSource launch_source,
diff --git a/chrome/browser/apps/app_service/publishers/borealis_apps.h b/chrome/browser/apps/app_service/publishers/borealis_apps.h index fcf4873..1f8e101 100644 --- a/chrome/browser/apps/app_service/publishers/borealis_apps.h +++ b/chrome/browser/apps/app_service/publishers/borealis_apps.h
@@ -81,6 +81,10 @@ int32_t size_hint_in_dip, bool allow_placeholder_icon, apps::LoadIconCallback callback) override; + void GetCompressedIconData(const std::string& app_id, + int32_t size_in_dip, + ui::ResourceScaleFactor scale_factor, + LoadIconCallback callback) override; void Launch(const std::string& app_id, int32_t event_flags, LaunchSource launch_source,
diff --git a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc index f020f90..5afef50 100644 --- a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc +++ b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc
@@ -210,6 +210,14 @@ std::move(callback)); } +void PluginVmApps::GetCompressedIconData(const std::string& app_id, + int32_t size_in_dip, + ui::ResourceScaleFactor scale_factor, + LoadIconCallback callback) { + GetGuestOSAppCompressedIconData(profile_, app_id, size_in_dip, scale_factor, + std::move(callback)); +} + void PluginVmApps::Launch(const std::string& app_id, int32_t event_flags, LaunchSource launch_source,
diff --git a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h index 95c54bf3..c34ab9c 100644 --- a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h +++ b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h
@@ -53,6 +53,10 @@ int32_t size_hint_in_dip, bool allow_placeholder_icon, apps::LoadIconCallback callback) override; + void GetCompressedIconData(const std::string& app_id, + int32_t size_in_dip, + ui::ResourceScaleFactor scale_factor, + LoadIconCallback callback) override; void Launch(const std::string& app_id, int32_t event_flags, LaunchSource launch_source,
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc index b4e3725f9..5b13523 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
@@ -113,11 +113,8 @@ // Do not automatically launch the app if we shouldn't override url loading, // or if we don't have a browser, or we are already in an app browser. - bool override_for_office = - ShouldOverrideUrlLoadingForOfficeExperiment(starting_url_, url); - bool should_override = - ShouldOverrideUrlLoading(starting_url_, url) || override_for_office; - if (should_override && !InAppBrowser(web_contents)) { + if (ShouldOverrideUrlLoading(starting_url_, url) && + !InAppBrowser(web_contents)) { // Handles apps that are automatically launched and the navigation needs to // be cancelled. This only applies on the new intent picker system, because // we don't need to defer the navigation to find out preferred app anymore. @@ -132,10 +129,4 @@ return content::NavigationThrottle::PROCEED; } -bool AppsNavigationThrottle::ShouldOverrideUrlLoadingForOfficeExperiment( - const GURL& previous_url, - const GURL& current_url) { - return false; -} - } // namespace apps
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h index 2e77879..29e74783 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h
@@ -45,10 +45,6 @@ virtual ThrottleCheckResult MaybeShowCustomResult(); - virtual bool ShouldOverrideUrlLoadingForOfficeExperiment( - const GURL& previous_url, - const GURL& current_url); - bool navigate_from_link() const; GURL starting_url_;
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc index bce449d3..a5c3262f 100644 --- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc +++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
@@ -26,8 +26,6 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/intent_picker_tab_helper.h" #include "chrome/browser/ui/web_applications/web_app_launch_utils.h" -#include "chrome/browser/web_applications/chromeos_web_app_experiments.h" -#include "chrome/common/chrome_features.h" #include "components/feature_engagement/public/tracker.h" #include "components/services/app_service/public/cpp/app_launch_util.h" #include "components/services/app_service/public/cpp/intent_util.h" @@ -240,16 +238,4 @@ } } -bool ShouldOverrideUrlLoadingForOfficeExperiment(const GURL& previous_url, - const GURL& current_url) { - if (base::FeatureList::IsEnabled( - ::features::kMicrosoftOfficeWebAppExperiment)) { - if (web_app::ChromeOsWebAppExperiments::ShouldOverrideUrlLoading( - previous_url, current_url)) { - return true; - } - } - return false; -} - } // namespace apps
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h index ad5cea1..eed1e6a 100644 --- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h +++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.h
@@ -48,9 +48,6 @@ const std::string& launch_name, PickerEntryType app_type); -bool ShouldOverrideUrlLoadingForOfficeExperiment(const GURL& previous_url, - const GURL& current_url); - } // namespace apps #endif // CHROME_BROWSER_APPS_INTENT_HELPER_CHROMEOS_INTENT_PICKER_HELPERS_H_
diff --git a/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.cc b/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.cc index 904963f9..3f2d096 100644 --- a/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.cc +++ b/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.cc
@@ -313,13 +313,6 @@ return true; } -bool CommonAppsNavigationThrottle::ShouldOverrideUrlLoadingForOfficeExperiment( - const GURL& previous_url, - const GURL& current_url) { - return apps::ShouldOverrideUrlLoadingForOfficeExperiment(previous_url, - current_url); -} - bool CommonAppsNavigationThrottle::ShouldShowDisablePage( content::NavigationHandle* handle) { content::WebContents* web_contents = handle->GetWebContents();
diff --git a/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.h b/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.h index 207379a8..2eb1d3f7 100644 --- a/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.h +++ b/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.h
@@ -50,9 +50,6 @@ bool ShouldCancelNavigation(content::NavigationHandle* handle) override; bool ShouldShowDisablePage(content::NavigationHandle* handle) override; ThrottleCheckResult MaybeShowCustomResult() override; - bool ShouldOverrideUrlLoadingForOfficeExperiment( - const GURL& previous_url, - const GURL& current_url) override; // Used to create a unique timestamped URL to force reload apps. // Points to the base::DefaultTickClock by default.
diff --git a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc index 1dc3940..42ec10a1 100644 --- a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc +++ b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc
@@ -662,11 +662,14 @@ // ArcSessionManager can be terminated during test tear down, before callback // into this function. // TODO(victorhsieh): figure out the best way/place to handle this situation. - if (arc::ArcSessionManager::Get() == nullptr) + if (arc::ArcSessionManager::Get() == nullptr) { + std::move(callback).Run(nullptr); return; + } if (!IsRegistered(app_id)) { VLOG(2) << "Request to load icon for non-registered app: " << app_id << "."; + std::move(callback).Run(nullptr); return; } @@ -676,18 +679,22 @@ // icon when icon file decode failure is suffered in case app sends bad icon. request_icon_recorded_[app_id].insert(descriptor); - if (!ready_apps_.count(app_id)) + if (!ready_apps_.count(app_id)) { + std::move(callback).Run(nullptr); return; + } if (!app_connection_holder()->IsConnected()) { // AppInstance should be ready since we have app_id in ready_apps_. This // can happen in browser_tests. + std::move(callback).Run(nullptr); return; } std::unique_ptr<AppInfo> app_info = GetApp(app_id); if (!app_info) { VLOG(2) << "Failed to get app info: " << app_id << "."; + std::move(callback).Run(nullptr); return; }
diff --git a/chrome/browser/ash/app_mode/kiosk_crash_restore_browsertest.cc b/chrome/browser/ash/app_mode/kiosk_crash_restore_browsertest.cc index 85383e2..2262877 100644 --- a/chrome/browser/ash/app_mode/kiosk_crash_restore_browsertest.cc +++ b/chrome/browser/ash/app_mode/kiosk_crash_restore_browsertest.cc
@@ -97,9 +97,10 @@ g_browser_process->local_state()->SetString(prefs::kDeviceSettingsCache, encoded); - base::Value accounts(base::Value::Type::LIST); + base::Value::List accounts; accounts.Append(GetTestAppUserId()); - g_browser_process->local_state()->Set("PublicAccounts", accounts); + g_browser_process->local_state()->SetList("PublicAccounts", + std::move(accounts)); } policy::DevicePolicyBuilder device_policy_;
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc index ed0317e..046ff2ee 100644 --- a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc +++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
@@ -867,8 +867,7 @@ wpad_config.Set(shill::kWebProxyAutoDiscoveryUrlProperty, base::Value(kWebProxyAutodetectionUrl)); const std::string kIPConfigPath = "test_ip_config"; - ip_config_client->AddIPConfig(kIPConfigPath, - base::Value(std::move(wpad_config))); + ip_config_client->AddIPConfig(kIPConfigPath, std::move(wpad_config)); ash::ShillServiceClient::TestInterface* service_test = ash::ShillServiceClient::Get()->GetTestInterface();
diff --git a/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc b/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc index 765fe59..5129c5b 100644 --- a/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc +++ b/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.cc
@@ -13,7 +13,6 @@ #include "base/logging.h" #include "base/memory/singleton.h" #include "base/process/process_handle.h" -#include "chrome/services/keymaster/public/mojom/cert_store.mojom.h" #include "chromeos/ash/components/dbus/arc/arc_keymaster_client.h" #include "mojo/core/embedder/embedder.h" #include "mojo/public/cpp/bindings/pending_remote.h"
diff --git a/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.h b/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.h index faf148c..4193ab9 100644 --- a/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.h +++ b/chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.h
@@ -5,12 +5,10 @@ #ifndef CHROME_BROWSER_ASH_ARC_KEYMASTER_ARC_KEYMASTER_BRIDGE_H_ #define CHROME_BROWSER_ASH_ARC_KEYMASTER_ARC_KEYMASTER_BRIDGE_H_ -#include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h" #include "ash/components/arc/mojom/keymaster.mojom.h" #include "base/functional/callback_forward.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/ash/arc/keymaster/cert_store_bridge.h" -#include "chrome/services/keymaster/public/mojom/cert_store.mojom.h" #include "components/keyed_service/core/keyed_service.h" #include "mojo/public/cpp/bindings/remote.h" @@ -18,6 +16,8 @@ class BrowserContext; } // namespace content +class BrowserContextKeyedServiceFactory; + namespace arc { class ArcBridgeService;
diff --git a/chrome/browser/ash/arc/policy/arc_policy_bridge.cc b/chrome/browser/ash/arc/policy/arc_policy_bridge.cc index 3ee52d51..ef30941b 100644 --- a/chrome/browser/ash/arc/policy/arc_policy_bridge.cc +++ b/chrome/browser/ash/arc/policy/arc_policy_bridge.cc
@@ -572,7 +572,11 @@ void ArcPolicyBridge::GetPolicies(GetPoliciesCallback callback) { VLOG(1) << "ArcPolicyBridge::GetPolicies"; - arc_policy_for_reporting_ = GetCurrentJSONPolicies(); + std::string new_policy = GetCurrentJSONPolicies(); + if (arc_policy_for_reporting_ != new_policy) { + arc_policy_for_reporting_ = new_policy; + VLOG(1) << "Policy updated. Current policy: " << new_policy; + } for (Observer& observer : observers_) { observer.OnPolicySent(arc_policy_for_reporting_); }
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.cc b/chrome/browser/ash/bruschetta/bruschetta_util.cc index 9d61be4d..4d83a4e 100644 --- a/chrome/browser/ash/bruschetta/bruschetta_util.cc +++ b/chrome/browser/ash/bruschetta/bruschetta_util.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ash/bruschetta/bruschetta_util.h" #include "chrome/browser/ash/bruschetta/bruschetta_pref_names.h" +#include "chrome/browser/ash/guest_os/guest_os_pref_names.h" #include "chrome/browser/profiles/profile.h" #include "components/prefs/pref_service.h" @@ -78,4 +79,15 @@ prefs::PolicyEnabledState::INSTALL_ALLOWED); } +bool HasInstallableConfig(const Profile* profile, + const std::string& config_id) { + return GetInstallableConfig(profile, config_id).has_value(); +} + +bool IsInstalled(Profile* profile, const guest_os::GuestId& guest_id) { + const base::Value* value = guest_os::GetContainerPrefValue( + profile, guest_id, guest_os::prefs::kVmNameKey); + return value != nullptr; +} + } // namespace bruschetta
diff --git a/chrome/browser/ash/bruschetta/bruschetta_util.h b/chrome/browser/ash/bruschetta/bruschetta_util.h index a29f88ac..e66682f1 100644 --- a/chrome/browser/ash/bruschetta/bruschetta_util.h +++ b/chrome/browser/ash/bruschetta/bruschetta_util.h
@@ -49,6 +49,13 @@ const Profile* profile, const std::string& config_id); +// Returns true if an installable config for Bruschetta is present in the +// enterprise policy. +bool HasInstallableConfig(const Profile* profile, const std::string& config_id); + +// Returns true if Bruschetta is installed. +bool IsInstalled(Profile* profile, const guest_os::GuestId& guest_id); + } // namespace bruschetta #endif // CHROME_BROWSER_ASH_BRUSCHETTA_BRUSCHETTA_UTIL_H_
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_client.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_client.cc index d44a1a3..fd71d490 100644 --- a/chrome/browser/ash/cert_provisioning/cert_provisioning_client.cc +++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_client.cc
@@ -215,12 +215,15 @@ policy::DeviceManagementStatus status, const em::ClientCertificateProvisioningResponse& response) { absl::optional<CertProvisioningResponseErrorType> response_error; - absl::optional<int64_t> try_later; // Single step loop for convenience. do { - if (!CheckCommonClientCertProvisioningResponse(response, status, - response_error, try_later)) { + if (status != policy::DM_STATUS_SUCCESS) { + break; + } + + if (response.has_error()) { + response_error = response.error(); break; } @@ -230,8 +233,6 @@ } // One of the oneof fields must be set. - // If the server wants to indicate that there is no work to be done yet, it - // should fill the `try_again_later` field instead. if (response.next_action_response().instruction_case() == em::CertProvNextActionResponse::INSTRUCTION_NOT_SET) { status = policy::DM_STATUS_RESPONSE_DECODING_ERROR; @@ -239,15 +240,13 @@ } // Everything is ok, run |callback| with data. - std::move(callback).Run(status, response_error, try_later, + std::move(callback).Run(status, response_error, response.next_action_response()); return; } while (false); - // Something went wrong. Return error via |status|, |response_error|, - // |try_later|. - std::move(callback).Run(status, response_error, try_later, - CertProvNextActionResponse()); + // Something went wrong. Return error via |status|, |response_error|. + std::move(callback).Run(status, response_error, CertProvNextActionResponse()); } void CertProvisioningClientImpl::OnStartCsrResponse(
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_client.h b/chrome/browser/ash/cert_provisioning/cert_provisioning_client.h index 0cbb617..7a6b3a2 100644 --- a/chrome/browser/ash/cert_provisioning/cert_provisioning_client.h +++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_client.h
@@ -88,7 +88,6 @@ policy::DeviceManagementStatus status, absl::optional<enterprise_management:: ClientCertificateProvisioningResponse::Error> error, - absl::optional<int64_t> try_later, const CertProvNextActionResponse& next_action_response)>; virtual void StartOrContinue(ProvisioningProcess provisioning_process,
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_client_unittest.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_client_unittest.cc index d5241ce..e44a8a67 100644 --- a/chrome/browser/ash/cert_provisioning/cert_provisioning_client_unittest.cc +++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_client_unittest.cc
@@ -68,14 +68,12 @@ : public base::test::TestFuture< policy::DeviceManagementStatus, absl::optional<em::ClientCertificateProvisioningResponse::Error>, - absl::optional<int64_t>, CertProvisioningClient::CertProvNextActionResponse> { public: CertProvisioningClient::NextActionCallback GetNextActionCallback() { return GetCallback< policy::DeviceManagementStatus, absl::optional<em::ClientCertificateProvisioningResponse::Error>, - absl::optional<int64_t>, const CertProvisioningClient::CertProvNextActionResponse&>(); } @@ -85,11 +83,9 @@ return Get<1>(); } - absl::optional<int64_t> GetTryLater() { return Get<2>(); } - const CertProvisioningClient::CertProvNextActionResponse& GetNextActionResponse() { - return Get<3>(); + return Get<2>(); } }; @@ -665,7 +661,6 @@ ASSERT_TRUE(next_action_future.Wait()); EXPECT_EQ(next_action_future.GetStatus(), policy::DM_STATUS_SUCCESS); EXPECT_EQ(next_action_future.GetError(), absl::nullopt); - EXPECT_EQ(next_action_future.GetTryLater(), absl::nullopt); EXPECT_THAT(next_action_future.GetNextActionResponse(), EqualsProto(response.next_action_response())); } @@ -699,7 +694,6 @@ ASSERT_TRUE(next_action_future.Wait()); EXPECT_EQ(next_action_future.GetStatus(), policy::DM_STATUS_SUCCESS); EXPECT_EQ(next_action_future.GetError(), absl::make_optional(error)); - EXPECT_EQ(next_action_future.GetTryLater(), absl::nullopt); EXPECT_THAT( next_action_future.GetNextActionResponse(), EqualsProto(CertProvisioningClient::CertProvNextActionResponse())); @@ -733,7 +727,6 @@ EXPECT_EQ(next_action_future.GetStatus(), policy::DM_STATUS_SERVICE_DEVICE_NOT_FOUND); EXPECT_EQ(next_action_future.GetError(), absl::nullopt); - EXPECT_EQ(next_action_future.GetTryLater(), absl::nullopt); EXPECT_THAT( next_action_future.GetNextActionResponse(), EqualsProto(CertProvisioningClient::CertProvNextActionResponse())); @@ -768,7 +761,6 @@ EXPECT_EQ(next_action_future.GetStatus(), policy::DM_STATUS_RESPONSE_DECODING_ERROR); EXPECT_EQ(next_action_future.GetError(), absl::nullopt); - EXPECT_EQ(next_action_future.GetTryLater(), absl::nullopt); EXPECT_THAT( next_action_future.GetNextActionResponse(), EqualsProto(CertProvisioningClient::CertProvNextActionResponse())); @@ -804,14 +796,13 @@ EXPECT_EQ(next_action_future.GetStatus(), policy::DM_STATUS_RESPONSE_DECODING_ERROR); EXPECT_EQ(next_action_future.GetError(), absl::nullopt); - EXPECT_EQ(next_action_future.GetTryLater(), absl::nullopt); EXPECT_THAT( next_action_future.GetNextActionResponse(), EqualsProto(CertProvisioningClient::CertProvNextActionResponse())); } -// Checks that all "Dynamic flow" API calls forward an explicit -// `try_again_later` instruction correctly. +// Checks that all "Dynamic flow" API calls forward a `try_again_later_ms` +// instruction correctly. TEST_P(CertProvisioningClientNextActionProcessingTest, ExplicitTryLater) { CertProvisioningClientImpl cert_provisioning_client(cloud_policy_client_); @@ -829,7 +820,11 @@ cloud_policy_client_.cert_prov_calls().back(); // Make CloudPolicyClient answer the request. em::ClientCertificateProvisioningResponse response; - response.set_try_again_later(3000); + { + auto* next_action_response = response.mutable_next_action_response(); + next_action_response->set_invalidation_topic(kInvalidationTopic); + next_action_response->mutable_try_later_instruction()->set_delay_ms(3000); + } std::move(cert_prov_call.callback).Run(policy::DM_STATUS_SUCCESS, response); // Expect that the CertProvisioningClient provides the error and an empty @@ -837,10 +832,8 @@ ASSERT_TRUE(next_action_future.Wait()); EXPECT_EQ(next_action_future.GetStatus(), policy::DM_STATUS_SUCCESS); EXPECT_EQ(next_action_future.GetError(), absl::nullopt); - EXPECT_EQ(next_action_future.GetTryLater(), absl::make_optional(3000)); - EXPECT_THAT( - next_action_future.GetNextActionResponse(), - EqualsProto(CertProvisioningClient::CertProvNextActionResponse())); + EXPECT_THAT(next_action_future.GetNextActionResponse(), + EqualsProto(response.next_action_response())); } INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ash/crosapi/crosapi_util_unittest.cc b/chrome/browser/ash/crosapi/crosapi_util_unittest.cc index 113d494..2f15ae7 100644 --- a/chrome/browser/ash/crosapi/crosapi_util_unittest.cc +++ b/chrome/browser/ash/crosapi/crosapi_util_unittest.cc
@@ -165,14 +165,14 @@ ->SetInteger(ash::kReportDeviceNetworkTelemetryCollectionRateMs, kReportDeviceNetworkTelemetryCollectionRateMs); - base::Value allowlist(base::Value::Type::LIST); - base::Value ids(base::Value::Type::DICTIONARY); - ids.SetIntKey(ash::kUsbDetachableAllowlistKeyVid, 2); - ids.SetIntKey(ash::kUsbDetachableAllowlistKeyPid, 3); + base::Value::List allowlist; + base::Value::Dict ids; + ids.Set(ash::kUsbDetachableAllowlistKeyVid, 2); + ids.Set(ash::kUsbDetachableAllowlistKeyPid, 3); allowlist.Append(std::move(ids)); testing_profile_.ScopedCrosSettingsTestHelper()->GetStubbedProvider()->Set( - ash::kUsbDetachableAllowlist, std::move(allowlist)); + ash::kUsbDetachableAllowlist, base::Value(std::move(allowlist))); auto settings = browser_util::GetDeviceSettings(); testing_profile_.ScopedCrosSettingsTestHelper()
diff --git a/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc b/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc index 4ec11c6..d22dfd3 100644 --- a/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc +++ b/chrome/browser/ash/crosapi/networking_attributes_ash_unittest.cc
@@ -129,9 +129,9 @@ base::Value(shill::kTypeIPv6)); network_handler_test_helper_.ip_config_test()->AddIPConfig( - kWifiIPConfigV4Path, base::Value(std::move(ipconfig_v4_dictionary))); + kWifiIPConfigV4Path, std::move(ipconfig_v4_dictionary)); network_handler_test_helper_.ip_config_test()->AddIPConfig( - kWifiIPConfigV6Path, base::Value(std::move(ipconfig_v6_dictionary))); + kWifiIPConfigV6Path, std::move(ipconfig_v6_dictionary)); base::Value::List ip_configs; ip_configs.Append(kWifiIPConfigV4Path);
diff --git a/chrome/browser/ash/crosapi/networking_private_ash.cc b/chrome/browser/ash/crosapi/networking_private_ash.cc index b27d57d1..550b4c7 100644 --- a/chrome/browser/ash/crosapi/networking_private_ash.cc +++ b/chrome/browser/ash/crosapi/networking_private_ash.cc
@@ -166,15 +166,13 @@ // This adapter will handle the case where a list get returned. using ValueListMojoCallback = base::OnceCallback<void(absl::optional<base::Value::List>)>; -ValueDelegateCallback ValueListAdapterCallback( +using ValueListDelegateCallback = + base::OnceCallback<void(base::Value::List result)>; +ValueListDelegateCallback ValueListAdapterCallback( ValueListMojoCallback result_callback) { return base::BindOnce( - [](ValueListMojoCallback callback, std::unique_ptr<base::Value> result) { - if (result) { - std::move(callback).Run(std::move(*result).TakeList()); - } else { - std::move(callback).Run(absl::nullopt); - } + [](ValueListMojoCallback callback, base::Value::List result) { + std::move(callback).Run(std::move(result)); }, std::move(result_callback)); }
diff --git a/chrome/browser/ash/crosapi/test_controller_ash.cc b/chrome/browser/ash/crosapi/test_controller_ash.cc index bfb50b6..a96575e 100644 --- a/chrome/browser/ash/crosapi/test_controller_ash.cc +++ b/chrome/browser/ash/crosapi/test_controller_ash.cc
@@ -887,7 +887,7 @@ ::base::Value properties, AddIPConfigCallback callback) { auto* ip_config_test = ash::ShillIPConfigClient::Get()->GetTestInterface(); - ip_config_test->AddIPConfig(ip_config_path, properties); + ip_config_test->AddIPConfig(ip_config_path, std::move(properties).TakeDict()); std::move(callback).Run(); }
diff --git a/chrome/browser/ash/dbus/ash_dbus_helper.cc b/chrome/browser/ash/dbus/ash_dbus_helper.cc index b39a194..fe54e753 100644 --- a/chrome/browser/ash/dbus/ash_dbus_helper.cc +++ b/chrome/browser/ash/dbus/ash_dbus_helper.cc
@@ -20,6 +20,7 @@ #include "chromeos/ash/components/dbus/arc/arc_camera_client.h" #include "chromeos/ash/components/dbus/arc/arc_data_snapshotd_client.h" #include "chromeos/ash/components/dbus/arc/arc_keymaster_client.h" +#include "chromeos/ash/components/dbus/arc/arc_keymint_client.h" #include "chromeos/ash/components/dbus/arc/arc_midis_client.h" #include "chromeos/ash/components/dbus/arc/arc_obb_mounter_client.h" #include "chromeos/ash/components/dbus/arc/arcvm_data_migrator_client.h" @@ -140,6 +141,7 @@ InitializeDBusClient<ArcCameraClient>(bus); InitializeDBusClient<ArcDataSnapshotdClient>(bus); InitializeDBusClient<ArcKeymasterClient>(bus); + InitializeDBusClient<ArcKeyMintClient>(bus); InitializeDBusClient<ArcMidisClient>(bus); InitializeDBusClient<ArcObbMounterClient>(bus); InitializeDBusClient<ArcQuotaClient>(bus); @@ -335,6 +337,7 @@ ArcQuotaClient::Shutdown(); ArcObbMounterClient::Shutdown(); ArcMidisClient::Shutdown(); + ArcKeyMintClient::Shutdown(); ArcKeymasterClient::Shutdown(); ArcDataSnapshotdClient::Shutdown(); ArcCameraClient::Shutdown();
diff --git a/chrome/browser/ash/drive/drivefs_test_support.cc b/chrome/browser/ash/drive/drivefs_test_support.cc index 970601b..3c22ba4 100644 --- a/chrome/browser/ash/drive/drivefs_test_support.cc +++ b/chrome/browser/ash/drive/drivefs_test_support.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" +#include "components/account_id/account_id.h" #include "components/drive/drive_pref_names.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user.h" @@ -24,6 +25,8 @@ namespace drive { const char FakeDriveFsHelper::kPredefinedProfileSalt[] = "salt"; +const char FakeDriveFsHelper::kDefaultUserEmail[] = "testuser@gmail.com"; +const char FakeDriveFsHelper::kDefaultGaiaId[] = "123456"; FakeDriveFsHelper::FakeDriveFsHelper(Profile* profile, const base::FilePath& mount_path) @@ -50,11 +53,20 @@ } bool SetUpUserDataDirectoryForDriveFsTest() { + AccountId account_id = AccountId::FromUserEmailGaiaId( + FakeDriveFsHelper::kDefaultUserEmail, FakeDriveFsHelper::kDefaultGaiaId); + return SetUpUserDataDirectoryForDriveFsTest(account_id); +} + +bool SetUpUserDataDirectoryForDriveFsTest(const AccountId& account_id) { + // Account type must be GOOGLE to use Drive. + CHECK(account_id.GetAccountType() == AccountType::GOOGLE); base::Value::List known_users_list; base::Value::Dict user_dict; - user_dict.Set("account_type", "google"); - user_dict.Set("email", "testuser@gmail.com"); - user_dict.Set("gaia_id", "123456"); + user_dict.Set("account_type", + AccountId::AccountTypeToString(account_id.GetAccountType())); + user_dict.Set("email", account_id.GetUserEmail()); + user_dict.Set("gaia_id", account_id.GetGaiaId()); known_users_list.Append(std::move(user_dict)); base::Value::Dict local_state;
diff --git a/chrome/browser/ash/drive/drivefs_test_support.h b/chrome/browser/ash/drive/drivefs_test_support.h index 66bfbd31..fce9f674 100644 --- a/chrome/browser/ash/drive/drivefs_test_support.h +++ b/chrome/browser/ash/drive/drivefs_test_support.h
@@ -11,16 +11,20 @@ #include "base/functional/callback_forward.h" #include "chromeos/ash/components/drivefs/drivefs_host.h" #include "chromeos/ash/components/drivefs/fake_drivefs.h" +#include "components/account_id/account_id.h" class Profile; namespace drive { bool SetUpUserDataDirectoryForDriveFsTest(); +bool SetUpUserDataDirectoryForDriveFsTest(const AccountId& account_id); class FakeDriveFsHelper { public: static const char kPredefinedProfileSalt[]; + static const char kDefaultUserEmail[]; + static const char kDefaultGaiaId[]; FakeDriveFsHelper(Profile* profile, const base::FilePath& mount_path);
diff --git a/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.cc b/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.cc index c7f1643..8ea657d 100644 --- a/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.cc +++ b/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.cc
@@ -6,12 +6,14 @@ #include <utility> +#include "ash/constants/ash_features.h" #include "base/files/file_enumerator.h" #include "base/files/file_util.h" #include "base/functional/bind.h" #include "base/task/sequenced_task_runner.h" #include "chrome/browser/ash/drive/drive_integration_service.h" #include "chrome/browser/ash/drive/file_system_util.h" +#include "components/drive/file_errors.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "mojo/public/cpp/bindings/callback_helpers.h" @@ -23,8 +25,7 @@ #include "storage/browser/file_system/native_file_util.h" #include "storage/common/file_system/file_system_util.h" -namespace drive { -namespace internal { +namespace drive::internal { namespace { class DriveFsFileUtil : public storage::LocalFileUtil { @@ -176,6 +177,30 @@ return; } + if (ash::features::IsDriveFsBulkPinningEnabled()) { + base::FilePath drive_path; + if (drive_integration_service->GetRelativeDrivePath(path_, &drive_path)) { + // TODO(b/266168982): In the case this is a folder, only the folder will + // get unpinned leaving all the children pinned. When the new method is + // exposed (or parameter on the existing method) update the + // implementation here. + drive_integration_service->GetDriveFsInterface()->SetPinned( + drive_path, /*pinned*/ false, + base::BindOnce(&DeleteOperation::OnUnpinFile, + base::Unretained(this))); + return; + } + } + + blocking_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&DeleteOperation::Delete, base::Unretained(this))); + } + + void OnUnpinFile(drive::FileError error) { + LOG_IF(ERROR, error != drive::FILE_ERROR_OK) + << "Failed to unpin file before deleting it: " + << drive::FileErrorToString(error); blocking_task_runner_->PostTask( FROM_HERE, base::BindOnce(&DeleteOperation::Delete, base::Unretained(this))); @@ -238,5 +263,4 @@ context->task_runner())))); } -} // namespace internal -} // namespace drive +} // namespace drive::internal
diff --git a/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.h b/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.h index 30c10b3..888c14fc 100644 --- a/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.h +++ b/chrome/browser/ash/drive/fileapi/drivefs_async_file_util.h
@@ -12,8 +12,7 @@ class Profile; -namespace drive { -namespace internal { +namespace drive::internal { // The implementation of storage::AsyncFileUtil for DriveFS File System. This // forwards to a AsyncFileUtil for native files by default. @@ -45,7 +44,6 @@ base::WeakPtrFactory<DriveFsAsyncFileUtil> weak_factory_{this}; }; -} // namespace internal -} // namespace drive +} // namespace drive::internal #endif // CHROME_BROWSER_ASH_DRIVE_FILEAPI_DRIVEFS_ASYNC_FILE_UTIL_H_
diff --git a/chrome/browser/ash/extensions/file_manager/event_router.cc b/chrome/browser/ash/extensions/file_manager/event_router.cc index bdedc56..8521c027 100644 --- a/chrome/browser/ash/extensions/file_manager/event_router.cc +++ b/chrome/browser/ash/extensions/file_manager/event_router.cc
@@ -152,6 +152,8 @@ return file_manager_private::IO_TASK_STATE_SCANNING; case file_manager::io_task::State::kInProgress: return file_manager_private::IO_TASK_STATE_IN_PROGRESS; + case file_manager::io_task::State::kPaused: + return file_manager_private::IO_TASK_STATE_PAUSED; case file_manager::io_task::State::kSuccess: return file_manager_private::IO_TASK_STATE_SUCCESS; case file_manager::io_task::State::kError:
diff --git a/chrome/browser/ash/file_manager/copy_or_move_io_task_impl.cc b/chrome/browser/ash/file_manager/copy_or_move_io_task_impl.cc index 423417a..df3f941 100644 --- a/chrome/browser/ash/file_manager/copy_or_move_io_task_impl.cc +++ b/chrome/browser/ash/file_manager/copy_or_move_io_task_impl.cc
@@ -229,6 +229,7 @@ const base::FilePath& destination = progress_.destination_folder.path(); constexpr auto metadata_fields = + storage::FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY | storage::FileSystemOperation::GET_METADATA_FIELD_SIZE | storage::FileSystemOperation::GET_METADATA_FIELD_TOTAL_SIZE; @@ -288,6 +289,7 @@ progress_.total_bytes += file_info.size; source_sizes_[idx] = file_info.size; + progress_.sources[idx].is_directory = file_info.is_directory; // Return early if we didn't yet get the file size for all files. DCHECK_LT(files_preprocessed_, progress_.sources.size());
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc index ecc3bf9..59b09d6 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -5,18 +5,19 @@ #include <stddef.h> #include <memory> -#include "ash/constants/ash_switches.h" #include "ash/public/cpp/keyboard/keyboard_switches.h" #include "base/files/file_path.h" #include "base/functional/bind.h" +#include "base/immediate_crash.h" #include "base/run_loop.h" -#include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/test/metrics/histogram_tester.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/ash/file_manager/copy_or_move_io_task_scanning_impl.h" #include "chrome/browser/ash/file_manager/file_manager_browsertest_base.h" #include "chrome/browser/ash/file_manager/path_util.h" +#include "chrome/browser/ash/login/test/device_state_mixin.h" +#include "chrome/browser/ash/login/test/logged_in_user_mixin.h" #include "chrome/browser/ash/policy/dlp/dlp_files_controller.h" #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h" #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h" @@ -32,8 +33,10 @@ #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" +#include "chrome/test/base/fake_gaia_mixin.h" #include "chromeos/dbus/dlp/dlp_client.h" #include "chromeos/dbus/dlp/dlp_service.pb.h" +#include "components/account_id/account_id.h" #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" #include "components/prefs/pref_service.h" #include "components/session_manager/core/session_manager.h" @@ -196,6 +199,16 @@ return *this; } + TestCase& SetDeviceMode(DeviceMode device_mode) { + options.device_mode = device_mode; + return *this; + } + + TestCase& SetTestAccountType(TestAccountType test_account_type) { + options.test_account_type = test_account_type; + return *this; + } + std::string GetFullName() const { std::string full_name = name; @@ -249,6 +262,30 @@ full_name += "_GoogleOneOfferFilesBanner"; } + switch (options.device_mode) { + case DEVICE_MODE_NOT_SET: + break; + case CONSUMER_OWNED: + full_name += "_DeviceModeConsumerOwned"; + break; + case ENROLLED: + full_name += "_DeviceModeEnrolled"; + } + + switch (options.test_account_type) { + case TEST_ACCOUNT_TYPE_NOT_SET: + break; + case ENTERPRISE: + full_name += "_AccountTypeEnterprise"; + break; + case CHILD: + full_name += "_AccountTypeChild"; + break; + case NON_MANAGED: + full_name += "_AccountTypeNonManaged"; + break; + } + return full_name; } @@ -297,6 +334,96 @@ StartTest(); } +// `FilesAppBrowserTest` with `LoggedInUserMixin` and `DeviceStateMixin`. This +// test provides additional two options from `FilesAppBrowserTest`. Both options +// must be explicitly set for this test. +// +// - test_account_type: Account type used for a test. +// - device_mode: Status of a device, e.g. a device is enrolled. +class LoggedInUserFilesAppBrowserTest : public FilesAppBrowserTest { + public: + LoggedInUserFilesAppBrowserTest() { + // ChromeOS user will be set by `LoggedInUserMixin`. + set_chromeos_user_ = false; + + device_state_mixin_ = std::make_unique<ash::DeviceStateMixin>( + &mixin_host_, DeviceStateFor(GetOptions().device_mode)); + + logged_in_user_mixin_ = std::make_unique<ash::LoggedInUserMixin>( + &mixin_host_, LogInTypeFor(GetOptions().test_account_type), + embedded_test_server(), this, /*should_launch_browser=*/false, + AccountIdFor(GetOptions().test_account_type)); + } + + void SetUpOnMainThread() override { + logged_in_user_mixin_->LogInUser(); + FilesAppBrowserTest::SetUpOnMainThread(); + } + + AccountId GetAccountId() override { + return logged_in_user_mixin_->GetAccountId(); + } + + private: + ash::DeviceStateMixin::State DeviceStateFor(DeviceMode device_mode) { + switch (device_mode) { + case DEVICE_MODE_NOT_SET: + CHECK(false) << "device_mode option must be set for " + "LoggedInUserFilesAppBrowserTest"; + // `base::ImmediateCrash` is necessary for https://crbug.com/1061742. + base::ImmediateCrash(); + case CONSUMER_OWNED: + return ash::DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED; + case ENROLLED: + return ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED; + } + } + + ash::LoggedInUserMixin::LogInType LogInTypeFor( + TestAccountType test_account_type) { + switch (test_account_type) { + case TEST_ACCOUNT_TYPE_NOT_SET: + CHECK(false) << "test_account_type option must be set for " + "LoggedInUserFilesAppBrowserTest"; + // `base::ImmediateCrash` is necessary for https://crbug.com/1061742. + base::ImmediateCrash(); + case ENTERPRISE: + return ash::LoggedInUserMixin::LogInType::kRegular; + case CHILD: + return ash::LoggedInUserMixin::LogInType::kChild; + case NON_MANAGED: + return ash::LoggedInUserMixin::LogInType::kRegular; + } + } + + absl::optional<AccountId> AccountIdFor(TestAccountType test_account_type) { + switch (test_account_type) { + case TEST_ACCOUNT_TYPE_NOT_SET: + CHECK(false) << "test_account_type option must be set for " + "LoggedInUserFilesAppBrowserTest"; + // `base::ImmediateCrash` is necessary for https://crbug.com/1061742. + base::ImmediateCrash(); + case ENTERPRISE: + return AccountId::FromUserEmailGaiaId( + FakeGaiaMixin::kEnterpriseUser1, + FakeGaiaMixin::kEnterpriseUser1GaiaId); + case CHILD: + // Use the default account provided by `LoggedInUserMixin`. + return absl::nullopt; + case NON_MANAGED: + // Use the default account provided by `LoggedInUserMixin`. + return absl::nullopt; + } + } + + std::unique_ptr<ash::LoggedInUserMixin> logged_in_user_mixin_; + std::unique_ptr<ash::DeviceStateMixin> device_state_mixin_; +}; + +IN_PROC_BROWSER_TEST_P(LoggedInUserFilesAppBrowserTest, Test) { + StartTest(); +} + // A version of the FilesAppBrowserTest that supports spanning browser restart // to allow testing prefs and other things. class ExtendedFilesAppBrowserTest : public FilesAppBrowserTest { @@ -488,8 +615,8 @@ return false; } - // Invokes `callback` with the previously constructed `response`. Note that the - // result doesn't depend on the value of `request`. + // Invokes `callback` with the previously constructed `response`. Note that + // the result doesn't depend on the value of `request`. void GetFilesSourcesMock( const dlp::GetFilesSourcesResponse response, const dlp::GetFilesSourcesRequest request, @@ -1329,13 +1456,7 @@ TestCase("driveOfflineInfoBanner"), TestCase("driveDeleteDialogDoesntMentionPermanentDelete"), TestCase("driveInlineSyncStatusSingleFile").EnableInlineStatusSync(), - TestCase("driveInlineSyncStatusParentFolder").EnableInlineStatusSync(), - TestCase("driveGoogleOneOfferBannerEnabled") - .EnableGoogleOneOfferFilesBanner(), - // Google One offer banner is disabled by default. - TestCase("driveGoogleOneOfferBannerDisabled"), - TestCase("driveGoogleOneOfferBannerDismiss") - .EnableGoogleOneOfferFilesBanner() + TestCase("driveInlineSyncStatusParentFolder").EnableInlineStatusSync() // TODO(b/189173190): Enable // TestCase("driveEnableDocsOfflineDialog"), // TODO(b/189173190): Enable @@ -1423,6 +1544,40 @@ TestCase("openDlpRestrictedFile").EnableDlp(), TestCase("openFolderDlpRestricted").EnableDlp())); +WRAPPED_INSTANTIATE_TEST_SUITE_P( + DriveSpecific, /* drive_specific.js */ + LoggedInUserFilesAppBrowserTest, + ::testing::Values( + // Google One offer banner checks device state. Device state is NOT set + // to `policy::DeviceMode::DEVICE_MODE_CONSUMER` in + // `FilesAppBrowserTest`. + TestCase("driveGoogleOneOfferBannerEnabled") + .SetDeviceMode(DeviceMode::CONSUMER_OWNED) + .SetTestAccountType(TestAccountType::NON_MANAGED) + .EnableGoogleOneOfferFilesBanner(), + // Google One offer banner is disabled by default. + TestCase("driveGoogleOneOfferBannerDisabled") + .SetDeviceMode(DeviceMode::CONSUMER_OWNED) + .SetTestAccountType(TestAccountType::NON_MANAGED), + TestCase("driveGoogleOneOfferBannerDismiss") + .SetDeviceMode(DeviceMode::CONSUMER_OWNED) + .SetTestAccountType(TestAccountType::NON_MANAGED) + .EnableGoogleOneOfferFilesBanner(), + TestCase("driveGoogleOneOfferBannerDisabled") + .EnableGoogleOneOfferFilesBanner() + .SetDeviceMode(DeviceMode::CONSUMER_OWNED) + .SetTestAccountType(TestAccountType::ENTERPRISE), + TestCase("driveGoogleOneOfferBannerDisabled") + .EnableGoogleOneOfferFilesBanner() + .SetDeviceMode(DeviceMode::CONSUMER_OWNED) + .SetTestAccountType(TestAccountType::CHILD), + // Google One offer is for a device. The banner will not + // be shown for an enrolled device. + TestCase("driveGoogleOneOfferBannerDisabled") + .EnableGoogleOneOfferFilesBanner() + .SetDeviceMode(DeviceMode::ENROLLED) + .SetTestAccountType(TestAccountType::NON_MANAGED))); + #define FILE_TRANSFER_TEST_CASE(name) \ TestCase(name).EnableFileTransferConnector()
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 8482423..f9a1b00 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -86,6 +86,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/enterprise/connectors/connectors_service.h" +#include "chrome/browser/extensions/mixin_based_extension_apitest.h" #include "chrome/browser/notifications/notification_display_service_tester.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/sync_file_system/mock_remote_file_sync_service.h" @@ -113,6 +114,7 @@ #include "chromeos/ash/components/smbfs/smbfs_host.h" #include "chromeos/ash/components/smbfs/smbfs_mounter.h" #include "chromeos/dbus/constants/dbus_switches.h" +#include "components/account_id/account_id.h" #include "components/drive/drive_pref_names.h" #include "components/prefs/pref_service.h" #include "components/services/app_service/public/cpp/app_launch_util.h" @@ -1866,7 +1868,8 @@ void FileManagerBrowserTestBase::SetUp() { net::NetworkChangeNotifier::SetTestNotificationsOnly(true); - extensions::ExtensionApiTest::SetUp(); + + extensions::MixinBasedExtensionApiTest::SetUp(); } void FileManagerBrowserTestBase::SetUpCommandLine( @@ -2009,18 +2012,25 @@ feature_list_ = std::make_unique<base::test::ScopedFeatureList>(); feature_list_->InitWithFeatures(enabled_features, disabled_features); - extensions::ExtensionApiTest::SetUpCommandLine(command_line); + extensions::MixinBasedExtensionApiTest::SetUpCommandLine(command_line); } bool FileManagerBrowserTestBase::SetUpUserDataDirectory() { if (GetOptions().guest_mode == IN_GUEST_MODE) return true; - return drive::SetUpUserDataDirectoryForDriveFsTest(); + return extensions::MixinBasedExtensionApiTest::SetUpUserDataDirectory() && + drive::SetUpUserDataDirectoryForDriveFsTest(GetAccountId()); +} + +AccountId FileManagerBrowserTestBase::GetAccountId() { + return AccountId::FromUserEmailGaiaId( + drive::FakeDriveFsHelper::kDefaultUserEmail, + drive::FakeDriveFsHelper::kDefaultGaiaId); } void FileManagerBrowserTestBase::SetUpInProcessBrowserTestFixture() { - extensions::ExtensionApiTest::SetUpInProcessBrowserTestFixture(); + extensions::MixinBasedExtensionApiTest::SetUpInProcessBrowserTestFixture(); local_volume_ = std::make_unique<DownloadsTestVolume>(); @@ -2046,7 +2056,8 @@ std::make_unique<::testing::NiceMock< sync_file_system::MockRemoteFileSyncService>>()); - extensions::ExtensionApiTest::SetUpOnMainThread(); + extensions::MixinBasedExtensionApiTest::SetUpOnMainThread(); + CHECK(profile()); CHECK_EQ(!!browser(), options.browser); @@ -2057,8 +2068,15 @@ } if (options.guest_mode != IN_GUEST_MODE) { - // Start the embedded test server to serve the mocked CWS widget container. - CHECK(embedded_test_server()->Start()); + // `LoggedInUserFilesAppBrowserTest` starts `embedded_test_server` via + // `LoggedInUserMixin`. Starting the server again can cause a CHECK + // failure. + if (!embedded_test_server()->Started()) { + // Start the embedded test server to serve the mocked CWS widget + // container. + CHECK(embedded_test_server()->Start()); + } + drive_volume_ = drive_volumes_[profile()->GetOriginalProfile()].get(); if (options.mount_volumes) { test_util::WaitUntilDriveMountPointIsAdded(profile()); @@ -2184,7 +2202,7 @@ } void FileManagerBrowserTestBase::TearDown() { - extensions::ExtensionApiTest::TearDown(); + extensions::MixinBasedExtensionApiTest::TearDown(); feature_list_.reset(); }
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 a9a3f32..5c1870f1 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h +++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -16,7 +16,7 @@ #include "base/test/scoped_feature_list.h" #include "chrome/browser/ash/crostini/fake_crostini_features.h" #include "chrome/browser/ash/drive/drive_integration_service.h" -#include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/extensions/mixin_based_extension_apitest.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/web_app_id.h" #include "chrome/test/base/devtools_listener.h" @@ -40,6 +40,13 @@ namespace file_manager { enum GuestMode { NOT_IN_GUEST_MODE, IN_GUEST_MODE, IN_INCOGNITO }; +enum TestAccountType { + TEST_ACCOUNT_TYPE_NOT_SET, + ENTERPRISE, + CHILD, + NON_MANAGED +}; +enum DeviceMode { DEVICE_MODE_NOT_SET, CONSUMER_OWNED, ENROLLED }; class DriveFsTestVolume; class FakeTestVolume; @@ -53,8 +60,9 @@ class HiddenTestVolume; class GuestOsTestVolume; -class FileManagerBrowserTestBase : public content::DevToolsAgentHostObserver, - public extensions::ExtensionApiTest { +class FileManagerBrowserTestBase + : public content::DevToolsAgentHostObserver, + public extensions::MixinBasedExtensionApiTest { public: struct Options { Options(); @@ -63,6 +71,16 @@ // Should test run in Guest or Incognito mode? GuestMode guest_mode = NOT_IN_GUEST_MODE; + // Account type used to log-in for a test session. This option is valid only + // for `LoggedInUserFilesAppBrowserTest`. This won't work with `guest_mode` + // option. + TestAccountType test_account_type = TEST_ACCOUNT_TYPE_NOT_SET; + + // Device mode used for a test session. This option is valid only for + // `LoggedInUserFilesAppBrowserTest`. This might not work with `guest_mode` + // option. + DeviceMode device_mode = DEVICE_MODE_NOT_SET; + // Whether test runs in tablet mode. bool tablet_mode = false; @@ -175,6 +193,10 @@ virtual std::string GetFullTestCaseName() const = 0; virtual const char* GetTestExtensionManifestName() const = 0; + // Returns an account id used for a test. The base class provides a default + // implementation. + virtual AccountId GetAccountId(); + // Launches the test extension from GetTestExtensionManifestName() and uses // it to drive the testing the actual FileManager component extension under // test by calling RunTestMessageLoop().
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc index 9811c64..85e193495 100644 --- a/chrome/browser/ash/file_manager/file_manager_string_util.cc +++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -22,13 +22,18 @@ #include "chrome/browser/ash/login/demo_mode/demo_session.h" #include "chrome/browser/ash/plugin_vm/plugin_vm_features.h" #include "chrome/browser/ash/plugin_vm/plugin_vm_util.h" +#include "chrome/browser/ash/policy/core/user_cloud_policy_manager_ash.h" +#include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h" #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_features.h" #include "chrome/grit/generated_resources.h" +#include "chromeos/ash/components/install_attributes/install_attributes.h" +#include "components/policy/core/common/cloud/cloud_policy_constants.h" #include "components/strings/grit/components_strings.h" +#include "components/user_manager/user_manager.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/webui/web_ui_util.h" #include "ui/chromeos/strings/grit/ui_chromeos_strings.h" @@ -1039,6 +1044,46 @@ #undef SET_STRING +bool IsEligibleAndEnabledGoogleOneOfferFilesBanner() { + user_manager::UserManager* user_manager = user_manager::UserManager::Get(); + if (!user_manager) { + return false; + } + + user_manager::User* user = user_manager->GetActiveUser(); + if (!user) { + return false; + } + + Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user); + if (!profile) { + return false; + } + + // `GetUserCloudPolicyManagerAsh` returns non-nullptr if a profile is a + // managed account, e.g. enterprise account, child account. + // This approach is taken in + // `UserTypeByDeviceTypeMetricsProvider::GetUserSegment`. + if (profile->GetUserCloudPolicyManagerAsh()) { + return false; + } + + ash::InstallAttributes* install_attributes = ash::InstallAttributes::Get(); + if (!install_attributes) { + return false; + } + + // Google One offer is for a device. Do not show a banner if a device is not + // `policy::DeviceMode::DEVICE_MODE_CONSUMER`. + if (install_attributes->GetMode() != + policy::DeviceMode::DEVICE_MODE_CONSUMER) { + return false; + } + + return base::FeatureList::IsEnabled( + ash::features::kGoogleOneOfferFilesBanner); +} + } // namespace base::Value::Dict GetFileManagerStrings() { @@ -1166,7 +1211,8 @@ dict->Set("UI_LOCALE", locale); dict->Set("WEEK_START_FROM", GetLocaleBasedWeekStart()); - dict->Set( - "GOOGLE_ONE_OFFER_FILES_BANNER", - base::FeatureList::IsEnabled(ash::features::kGoogleOneOfferFilesBanner)); + // ELIGIBLE_AND_ENABLED_GOOGLE_ONE_OFFER_FILES_BANNER does additional checks + // in addition to a feature flag check. + dict->Set("ELIGIBLE_AND_ENABLED_GOOGLE_ONE_OFFER_FILES_BANNER", + IsEligibleAndEnabledGoogleOneOfferFilesBanner()); }
diff --git a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc index 45e640fa..29714db2 100644 --- a/chrome/browser/ash/file_manager/file_tasks_browsertest.cc +++ b/chrome/browser/ash/file_manager/file_tasks_browsertest.cc
@@ -21,6 +21,9 @@ #include "base/test/scoped_feature_list.h" #include "build/branding_buildflags.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" +#include "chrome/browser/apps/app_service/publishers/app_publisher.h" #include "chrome/browser/ash/drive/drivefs_test_support.h" #include "chrome/browser/ash/file_manager/app_id.h" #include "chrome/browser/ash/file_manager/file_manager_test_util.h" @@ -81,6 +84,8 @@ const char* blockedUrl = "https://blocked.com"; +static const char kOneDriveSampleUrl[] = "https://1drv.ms/123"; + // A list of file extensions (`/` delimited) representing a selection of files // and the app expected to be the default to open these files. // A null app_id indicates there is no preferred default. @@ -1049,28 +1054,16 @@ class FakeProvidedFileSystemOneDrive : public ash::file_system_provider::FakeProvidedFileSystem { public: - FakeProvidedFileSystemOneDrive( - const ash::file_system_provider::ProvidedFileSystemInfo& file_system_info, - base::OnceClosure callback) - : FakeProvidedFileSystem(file_system_info), - callback_(std::move(callback)) {} - - ash::file_system_provider::AbortCallback ExecuteAction( + explicit FakeProvidedFileSystemOneDrive( + const ash::file_system_provider::ProvidedFileSystemInfo& file_system_info) + : FakeProvidedFileSystem(file_system_info) {} + ash::file_system_provider::AbortCallback GetActions( const std::vector<base::FilePath>& entry_paths, - const std::string& action_id, - storage::AsyncFileUtil::StatusCallback callback) override { - // When the "OPEN_WEB" action is observed, notify the - // `OneDriveTest` via the `callback_`. - if (action_id == file_manager::file_tasks::kActionIdOpenWeb) { - std::move(callback_).Run(); - } - return FakeProvidedFileSystem::ExecuteAction(entry_paths, action_id, - std::move(callback)); + GetActionsCallback callback) override { + std::move(callback).Run({{"HIDDEN_ONEDRIVE_URL", kOneDriveSampleUrl}}, + base::File::FILE_OK); + return ash::file_system_provider::AbortCallback(); } - - protected: - // OneDriveTest::OpenWebAction. - base::OnceClosure callback_; }; // TODO(cassycc): move this class to a more appropriate spot @@ -1083,13 +1076,12 @@ static std::unique_ptr<ProviderInterface> Create( const extensions::ExtensionId& extension_id, const base::FilePath relative_test_file_path, - std::string test_file_name, - base::OnceClosure callback) { + std::string test_file_name) { ash::file_system_provider::Capabilities default_capabilities( false, false, false, extensions::SOURCE_NETWORK); return std::unique_ptr<ProviderInterface>(new FakeExtensionProviderOneDrive( extension_id, default_capabilities, relative_test_file_path, - test_file_name, std::move(callback))); + test_file_name)); } std::unique_ptr<ash::file_system_provider::ProvidedFileSystemInterface> @@ -1099,8 +1091,7 @@ override { DCHECK(profile); std::unique_ptr<FakeProvidedFileSystemOneDrive> fake_provided_file_system = - std::make_unique<FakeProvidedFileSystemOneDrive>(file_system_info, - std::move(callback_)); + std::make_unique<FakeProvidedFileSystemOneDrive>(file_system_info); // Add test file. fake_provided_file_system->AddEntry( relative_test_file_path_, false, test_file_name_, 0, base::Time::Now(), @@ -1115,19 +1106,77 @@ const extensions::ExtensionId& extension_id, const ash::file_system_provider::Capabilities& capabilities, const base::FilePath relative_test_file_path, - std::string test_file_name, - base::OnceClosure callback) + std::string test_file_name) : FakeExtensionProvider(extension_id, capabilities), - callback_(std::move(callback)), relative_test_file_path_(relative_test_file_path), test_file_name_(test_file_name) {} - // OneDriveTest::OpenWebAction. - base::OnceClosure callback_; const base::FilePath relative_test_file_path_; std::string test_file_name_; }; +// Fake app service web app publisher to test when an app is launched. +class FakeWebAppPublisher : public apps::AppPublisher { + public: + struct LaunchEvent { + std::string app_id; + std::string intent_url; + }; + explicit FakeWebAppPublisher(Profile* profile) + : AppPublisher(apps::AppServiceProxyFactory::GetForProfile(profile)) { + RegisterPublisher(apps::AppType::kWeb); + + std::vector<apps::AppPtr> apps; + apps.push_back(std::make_unique<apps::App>(apps::AppType::kWeb, + web_app::kMicrosoftOfficeAppId)); + Publish(std::move(apps), apps::AppType::kWeb, + /*should_notify_initialized=*/true); + } + + void LoadIcon(const std::string& app_id, + const apps::IconKey& icon_key, + apps::IconType icon_type, + int32_t size_hint_in_dip, + bool allow_placeholder_icon, + apps::LoadIconCallback callback) override { + // Never called in these tests. + NOTREACHED(); + } + + void Launch(const std::string& app_id, + int32_t event_flags, + apps::LaunchSource launch_source, + apps::WindowInfoPtr window_info) override { + // Never called in these tests. + NOTREACHED(); + } + + void LaunchAppWithIntent(const std::string& app_id, + int32_t event_flags, + apps::IntentPtr intent, + apps::LaunchSource launch_source, + apps::WindowInfoPtr window_info, + apps::LaunchCallback callback) override { + launches_.push_back({ + .app_id = app_id, + .intent_url = (intent && intent->url) ? intent->url->spec() : "", + }); + } + + void LaunchAppWithParams(apps::AppLaunchParams&& params, + apps::LaunchCallback callback) override { + // Never called in these tests. + NOTREACHED(); + } + + void ClearPastLaunches() { launches_.clear(); } + + std::vector<LaunchEvent> GetLaunches() { return launches_; } + + private: + std::vector<LaunchEvent> launches_; +}; + // TODO(cassycc or petermarshall) share this class with other test files for // testing with a fake ODFS. // Tests the office fallback flow that occurs when a @@ -1149,10 +1198,6 @@ storage::ExternalMountPoints::GetSystemInstance()->RevokeAllFileSystems(); } - // Callback for when the `FakeProvidedFileSystemOneDrive` observes that a file - // in the ODFS was opened. - void OpenWebAction() { file_opened_ = true; } - // Creates and mounts fake provided file system for OneDrive with a test file // added. Installs QuickOffice for the check in GetUserFallbackChoice() before // the dialog can launched. @@ -1166,8 +1211,7 @@ // `FakeProvidedFileSystemOneDrive`. The use of `base::Unretained()` is safe // because the class will exist for the duration of the test. service_->RegisterProvider(FakeExtensionProviderOneDrive::Create( - kODFSExtensionId, relative_test_file_path_, test_file_name_, - base::BindOnce(&OneDriveTest::OpenWebAction, base::Unretained(this)))); + kODFSExtensionId, relative_test_file_path_, test_file_name_)); provider_id_ = ash::file_system_provider::ProviderId::CreateFromExtensionId( kODFSExtensionId); ash::file_system_provider::MountOptions options(file_system_id_, "ODFS"); @@ -1179,6 +1223,8 @@ profile(), file_manager::util::GetFileManagerFileSystemContext(profile()), observed_one_drive_path()); + + web_app_publisher_ = std::make_unique<FakeWebAppPublisher>(profile()); } Profile* profile() { return browser()->profile(); } @@ -1209,8 +1255,8 @@ } protected: - bool file_opened_; FileSystemURL one_drive_test_file_url_; + std::unique_ptr<FakeWebAppPublisher> web_app_publisher_; private: base::test::ScopedFeatureList feature_list_; @@ -1244,9 +1290,7 @@ expected_dialog_URL); navigation_observer_dialog.StartWatchingNewWebContents(); - // This boolean only becomes `True` if the fake provided ODFS - // observes the test file being opened. - file_opened_ = false; + web_app_publisher_->ClearPastLaunches(); // Fails as system is offline and thus will open office fallback dialog. ExecuteFileTask( @@ -1259,7 +1303,7 @@ navigation_observer_dialog.Wait(); ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded()); - ASSERT_FALSE(file_opened_); + CHECK_EQ(0u, web_app_publisher_->GetLaunches().size()); SetConnectionOnline(); @@ -1268,7 +1312,10 @@ OnDialogChoiceReceived(profile(), open_in_office_task, file_urls, ash::office_fallback::kDialogChoiceTryAgain); - ASSERT_TRUE(file_opened_); + auto launches = web_app_publisher_->GetLaunches(); + ASSERT_EQ(1u, launches.size()); + CHECK_EQ(launches[0].app_id, web_app::kMicrosoftOfficeAppId); + CHECK_EQ(launches[0].intent_url, kOneDriveSampleUrl); } // Test to check that the test file fails to open when the system is offline and @@ -1291,9 +1338,7 @@ expected_dialog_URL); navigation_observer_dialog.StartWatchingNewWebContents(); - // This boolean only becomes `True` if the fake provided ODFS - // observes the test file being opened. - file_opened_ = false; + web_app_publisher_->ClearPastLaunches(); // Fails as system is offline and thus will open office fallback dialog. ExecuteFileTask( @@ -1306,7 +1351,7 @@ navigation_observer_dialog.Wait(); ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded()); - ASSERT_FALSE(file_opened_); + ASSERT_EQ(0u, web_app_publisher_->GetLaunches().size()); SetConnectionOnline(); @@ -1315,7 +1360,7 @@ OnDialogChoiceReceived(profile(), open_in_office_task, file_urls, ash::office_fallback::kDialogChoiceCancel); - ASSERT_FALSE(file_opened_); + ASSERT_EQ(0u, web_app_publisher_->GetLaunches().size()); } #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) @@ -1327,14 +1372,15 @@ std::vector<storage::FileSystemURL> file_urls{one_drive_test_file_url_}; - // This boolean only becomes `True` if the fake provided ODFS - // observes the test file being opened. - file_opened_ = false; + web_app_publisher_->ClearPastLaunches(); ash::cloud_upload::OpenOrMoveFiles( profile(), file_urls, ash::cloud_upload::CloudProvider::kOneDrive); - ASSERT_TRUE(file_opened_); + auto launches = web_app_publisher_->GetLaunches(); + ASSERT_EQ(1u, launches.size()); + CHECK_EQ(launches[0].app_id, web_app::kMicrosoftOfficeAppId); + CHECK_EQ(launches[0].intent_url, kOneDriveSampleUrl); } // Test that OpenOrMoveFiles() will open the Move Confirmation dialog when the
diff --git a/chrome/browser/ash/file_manager/guest_os_file_tasks_unittest.cc b/chrome/browser/ash/file_manager/guest_os_file_tasks_unittest.cc index 1bc27d0..e500821 100644 --- a/chrome/browser/ash/file_manager/guest_os_file_tasks_unittest.cc +++ b/chrome/browser/ash/file_manager/guest_os_file_tasks_unittest.cc
@@ -61,21 +61,21 @@ ScopedDictPrefUpdate update(profile_.GetPrefs(), guest_os::prefs::kGuestOsRegistry); base::Value::Dict& registry = update.Get(); - base::Value app(base::Value::Type::DICTIONARY); - app.SetKey("container_name", base::Value("penguin")); - base::Value mime_list(base::Value::Type::LIST); + base::Value::Dict app; + app.Set("container_name", "penguin"); + base::Value::List mime_list; for (const auto& mime : mimes) mime_list.Append(mime); - app.SetKey("mime_types", std::move(mime_list)); - base::Value extension_list(base::Value::Type::LIST); + app.Set("mime_types", std::move(mime_list)); + base::Value::List extension_list; for (const auto& extension : extensions) extension_list.Append(extension); - app.SetKey("extensions", std::move(extension_list)); - base::Value name_dict(base::Value::Type::DICTIONARY); - name_dict.SetKey("", base::Value(name)); - app.SetKey("name", std::move(name_dict)); - app.SetKey("vm_name", base::Value("termina")); - app.SetIntKey("vm_type", static_cast<int>(vm_type)); + app.Set("extensions", std::move(extension_list)); + base::Value::Dict name_dict; + name_dict.Set("", name); + app.Set("name", std::move(name_dict)); + app.Set("vm_name", "termina"); + app.Set("vm_type", static_cast<int>(vm_type)); registry.Set(id, std::move(app)); }
diff --git a/chrome/browser/ash/file_manager/io_task.h b/chrome/browser/ash/file_manager/io_task.h index db935bd..acdb0bb 100644 --- a/chrome/browser/ash/file_manager/io_task.h +++ b/chrome/browser/ash/file_manager/io_task.h
@@ -27,6 +27,9 @@ // Task is currently running. kInProgress, + // Task is currently paused. + kPaused, + // Task has been successfully completed. kSuccess, @@ -77,6 +80,9 @@ // May be empty if the entry has not been fully processed yet. absl::optional<base::File::Error> error; + + // True if entry is a directory when its metadata is processed. + bool is_directory = false; }; // Represents the current progress of an I/O task.
diff --git a/chrome/browser/ash/file_system_provider/registry.cc b/chrome/browser/ash/file_system_provider/registry.cc index 760f96b5..bdf087a8 100644 --- a/chrome/browser/ash/file_system_provider/registry.cc +++ b/chrome/browser/ash/file_system_provider/registry.cc
@@ -51,30 +51,26 @@ void Registry::RememberFileSystem( const ProvidedFileSystemInfo& file_system_info, const Watchers& watchers) { - base::Value file_system(base::Value::Type::DICTIONARY); - file_system.SetKey(kPrefKeyFileSystemId, - base::Value(file_system_info.file_system_id())); - file_system.SetKey(kPrefKeyDisplayName, - base::Value(file_system_info.display_name())); - file_system.SetKey(kPrefKeyWritable, - base::Value(file_system_info.writable())); - file_system.SetKey(kPrefKeySupportsNotifyTag, - base::Value(file_system_info.supports_notify_tag())); - file_system.SetKey(kPrefKeyOpenedFilesLimit, - base::Value(file_system_info.opened_files_limit())); + base::Value::Dict file_system; + file_system.Set(kPrefKeyFileSystemId, file_system_info.file_system_id()); + file_system.Set(kPrefKeyDisplayName, file_system_info.display_name()); + file_system.Set(kPrefKeyWritable, file_system_info.writable()); + file_system.Set(kPrefKeySupportsNotifyTag, + file_system_info.supports_notify_tag()); + file_system.Set(kPrefKeyOpenedFilesLimit, + file_system_info.opened_files_limit()); // We don't need to write and read "persistent" field (in MountOptions) to // and from preference because all filesystems which are remembered must be // persistent. - base::Value watchers_value(base::Value::Type::DICTIONARY); + base::Value::Dict watchers_dict; for (const auto& it : watchers) { - base::Value watcher(base::Value::Type::DICTIONARY); - watcher.SetKey(kPrefKeyWatcherEntryPath, - base::Value(it.second.entry_path.value())); - watcher.SetKey(kPrefKeyWatcherRecursive, base::Value(it.second.recursive)); - watcher.SetKey(kPrefKeyWatcherLastTag, base::Value(it.second.last_tag)); - base::Value persistent_origins_value(base::Value::Type::LIST); + base::Value::Dict watcher; + watcher.Set(kPrefKeyWatcherEntryPath, it.second.entry_path.value()); + watcher.Set(kPrefKeyWatcherRecursive, it.second.recursive); + watcher.Set(kPrefKeyWatcherLastTag, it.second.last_tag); + base::Value::List persistent_origins_value; for (const auto& subscriber_it : it.second.subscribers) { // Only persistent subscribers should be stored in persistent storage. // Other ones should not be restired after a restart. @@ -82,11 +78,11 @@ persistent_origins_value.Append(subscriber_it.first.spec()); } } - watcher.SetKey(kPrefKeyWatcherPersistentOrigins, - std::move(persistent_origins_value)); - watchers_value.SetKey(it.second.entry_path.value(), std::move(watcher)); + watcher.Set(kPrefKeyWatcherPersistentOrigins, + std::move(persistent_origins_value)); + watchers_dict.Set(it.second.entry_path.value(), std::move(watcher)); } - file_system.SetKey(kPrefKeyWatchers, std::move(watchers_value)); + file_system.Set(kPrefKeyWatchers, std::move(watchers_dict)); PrefService* const pref_service = profile_->GetPrefs(); DCHECK(pref_service);
diff --git a/chrome/browser/ash/file_system_provider/registry_unittest.cc b/chrome/browser/ash/file_system_provider/registry_unittest.cc index d0c319049..efe8462 100644 --- a/chrome/browser/ash/file_system_provider/registry_unittest.cc +++ b/chrome/browser/ash/file_system_provider/registry_unittest.cc
@@ -58,37 +58,35 @@ profile->GetTestingPrefService(); ASSERT_TRUE(pref_service); - base::Value extensions{base::Value::Type::DICTIONARY}; - base::Value file_system{base::Value::Type::DICTIONARY}; - file_system.SetKey(kPrefKeyFileSystemId, base::Value(kFileSystemId)); - file_system.SetKey(kPrefKeyDisplayName, base::Value(kDisplayName)); - file_system.SetKey(kPrefKeyWritable, base::Value(writable)); - file_system.SetKey(kPrefKeySupportsNotifyTag, - base::Value(supports_notify_tag)); - file_system.SetKey(kPrefKeyOpenedFilesLimit, base::Value(opened_files_limit)); + base::Value::Dict extensions; + base::Value::Dict file_system; + file_system.Set(kPrefKeyFileSystemId, kFileSystemId); + file_system.Set(kPrefKeyDisplayName, kDisplayName); + file_system.Set(kPrefKeyWritable, writable); + file_system.Set(kPrefKeySupportsNotifyTag, supports_notify_tag); + file_system.Set(kPrefKeyOpenedFilesLimit, opened_files_limit); // Remember watchers. - base::Value watcher_value{base::Value::Type::DICTIONARY}; - watcher_value.SetKey(kPrefKeyWatcherEntryPath, - base::Value(watcher.entry_path.value())); - watcher_value.SetKey(kPrefKeyWatcherRecursive, - base::Value(watcher.recursive)); - watcher_value.SetKey(kPrefKeyWatcherLastTag, base::Value(watcher.last_tag)); - base::Value persistent_origins_value{base::Value::Type::LIST}; + base::Value::Dict watcher_value; + watcher_value.Set(kPrefKeyWatcherEntryPath, watcher.entry_path.value()); + watcher_value.Set(kPrefKeyWatcherRecursive, watcher.recursive); + watcher_value.Set(kPrefKeyWatcherLastTag, watcher.last_tag); + base::Value::List persistent_origins_value; for (const auto& subscriber_it : watcher.subscribers) { if (subscriber_it.second.persistent) persistent_origins_value.Append(subscriber_it.first.spec()); } - watcher_value.SetKey(kPrefKeyWatcherPersistentOrigins, - std::move(persistent_origins_value)); - base::Value watchers{base::Value::Type::DICTIONARY}; - watchers.SetKey(watcher.entry_path.value(), std::move(watcher_value)); - file_system.SetKey(kPrefKeyWatchers, std::move(watchers)); - base::Value file_systems{base::Value::Type::DICTIONARY}; - file_systems.SetKey(kFileSystemId, std::move(file_system)); - extensions.SetKey(kProviderId.ToString(), std::move(file_systems)); - pref_service->Set(prefs::kFileSystemProviderMounted, std::move(extensions)); + watcher_value.Set(kPrefKeyWatcherPersistentOrigins, + std::move(persistent_origins_value)); + base::Value::Dict watchers; + watchers.Set(watcher.entry_path.value(), std::move(watcher_value)); + file_system.Set(kPrefKeyWatchers, std::move(watchers)); + base::Value::Dict file_systems; + file_systems.Set(kFileSystemId, std::move(file_system)); + extensions.Set(kProviderId.ToString(), std::move(file_systems)); + pref_service->SetDict(prefs::kFileSystemProviderMounted, + std::move(extensions)); } } // namespace @@ -208,12 +206,12 @@ EXPECT_TRUE(opened_files_limit.has_value()); EXPECT_EQ(kOpenedFilesLimit, opened_files_limit.value()); - const base::Value::Dict* watchers_value = + const base::Value::Dict* watchers_dict = file_system->FindDict(kPrefKeyWatchers); - ASSERT_TRUE(watchers_value); + ASSERT_TRUE(watchers_dict); const base::Value::Dict* watcher = - watchers_value->FindDict(fake_watcher_.entry_path.value()); + watchers_dict->FindDict(fake_watcher_.entry_path.value()); ASSERT_TRUE(watcher); const std::string* entry_path = watcher->FindString(kPrefKeyWatcherEntryPath); @@ -296,12 +294,12 @@ const base::Value::Dict* file_system = file_systems->FindDict(kFileSystemId); ASSERT_TRUE(file_system); - const base::Value::Dict* watchers_value = + const base::Value::Dict* watchers_dict = file_system->FindDict(kPrefKeyWatchers); - ASSERT_TRUE(watchers_value); + ASSERT_TRUE(watchers_dict); const base::Value::Dict* watcher = - watchers_value->FindDict(fake_watcher_.entry_path.value()); + watchers_dict->FindDict(fake_watcher_.entry_path.value()); ASSERT_TRUE(watcher); const std::string* last_tag = watcher->FindString(kPrefKeyWatcherLastTag);
diff --git a/chrome/browser/ash/login/saml/security_token_saml_test.cc b/chrome/browser/ash/login/saml/security_token_saml_test.cc index 389aa68..caff13c 100644 --- a/chrome/browser/ash/login/saml/security_token_saml_test.cc +++ b/chrome/browser/ash/login/saml/security_token_saml_test.cc
@@ -184,14 +184,17 @@ policy_map.GetMutable(policy::key::kAutoSelectCertificateForUrls); if (existing_entry) { // Append to the existing policy. - existing_entry->value(base::Value::Type::LIST)->Append(policy_item_value); + existing_entry->value(base::Value::Type::LIST) + ->GetList() + .Append(policy_item_value); } else { // Set the new policy value. - base::Value policy_value(base::Value::Type::LIST); + base::Value::List policy_value; policy_value.Append(policy_item_value); policy_map.Set(policy::key::kAutoSelectCertificateForUrls, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE, - policy::POLICY_SOURCE_CLOUD, std::move(policy_value), + policy::POLICY_SOURCE_CLOUD, + base::Value(std::move(policy_value)), /*external_data_fetcher=*/nullptr); } policy_provider_.UpdateChromePolicy(policy_map);
diff --git a/chrome/browser/ash/login/screens/app_downloading_screen_browsertest.cc b/chrome/browser/ash/login/screens/app_downloading_screen_browsertest.cc index abc7f998..e209957 100644 --- a/chrome/browser/ash/login/screens/app_downloading_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/app_downloading_screen_browsertest.cc
@@ -113,10 +113,10 @@ ->defer_oobe_flow_finished_for_tests = true; Login(); - base::Value apps(base::Value::Type::LIST); + base::Value::List apps; apps.Append("app.test.package.1"); - ProfileManager::GetActiveUserProfile()->GetPrefs()->Set( + ProfileManager::GetActiveUserProfile()->GetPrefs()->SetList( arc::prefs::kArcFastAppReinstallPackages, std::move(apps)); ShowAppDownloadingScreen(); @@ -136,11 +136,11 @@ ->defer_oobe_flow_finished_for_tests = true; Login(); - base::Value apps(base::Value::Type::LIST); + base::Value::List apps; apps.Append("app.test.package.1"); apps.Append("app.test.package.2"); - ProfileManager::GetActiveUserProfile()->GetPrefs()->Set( + ProfileManager::GetActiveUserProfile()->GetPrefs()->SetList( arc::prefs::kArcFastAppReinstallPackages, std::move(apps)); ShowAppDownloadingScreen();
diff --git a/chrome/browser/ash/login/screens/recommend_apps/fake_recommend_apps_fetcher.cc b/chrome/browser/ash/login/screens/recommend_apps/fake_recommend_apps_fetcher.cc index c5be662..6a5b4d9 100644 --- a/chrome/browser/ash/login/screens/recommend_apps/fake_recommend_apps_fetcher.cc +++ b/chrome/browser/ash/login/screens/recommend_apps/fake_recommend_apps_fetcher.cc
@@ -26,16 +26,16 @@ FakeRecommendAppsFetcher::~FakeRecommendAppsFetcher() = default; void FakeRecommendAppsFetcher::OnTimer() { - base::Value apps(base::Value::Type::LIST); + base::Value::List apps; for (int i = 0; i < base::clamp(fake_apps_count_, 0, kMaxAppCount); i++) { - base::Value app(base::Value::Type::DICTIONARY); - app.SetKey("name", base::Value(base::StringPrintf("Fake App %d", (i + 1)))); - app.SetKey("package_name", base::Value(base::StringPrintf( - "com.example.fake.app%d", (i + 1)))); + base::Value::Dict app; + app.Set("name", base::StringPrintf("Fake App %d", (i + 1))); + app.Set("package_name", + base::StringPrintf("com.example.fake.app%d", (i + 1))); apps.Append(std::move(app)); } - delegate_->OnLoadSuccess(std::move(apps)); + delegate_->OnLoadSuccess(base::Value(std::move(apps))); } void FakeRecommendAppsFetcher::Start() {
diff --git a/chrome/browser/ash/login/signin_partition_manager.cc b/chrome/browser/ash/login/signin_partition_manager.cc index 5c0aa78..f7d31f2 100644 --- a/chrome/browser/ash/login/signin_partition_manager.cc +++ b/chrome/browser/ash/login/signin_partition_manager.cc
@@ -113,11 +113,8 @@ std::move(partition_data_cleared).Run(); return; } - clear_storage_partition_task_.Run( - current_storage_partition_, - base::BindOnce(&SigninPartitionManager::OnStoragePartitionCleared, - weak_ptr_factory_.GetWeakPtr(), current_storage_partition_, - std::move(partition_data_cleared))); + clear_storage_partition_task_.Run(current_storage_partition_, + std::move(partition_data_cleared)); current_storage_partition_ = nullptr; current_storage_partition_name_.clear(); } @@ -158,31 +155,6 @@ return IsInSigninSession() && storage_partition == current_storage_partition_; } -void SigninPartitionManager::DisposeOldStoragePartitions() { - if (pending_removal_partitions_.empty()) - return; - - // Disposes all but the last storage partition. The last storage partition - // represents the last gaia load and there might still be references to it, - // e.g. fast gaia reload in All/SshWarningTest.VisibilityOnEnrollment/0 test. - - content::StoragePartition* last = pending_removal_partitions_.back(); - pending_removal_partitions_.pop_back(); - - for (auto* partition : pending_removal_partitions_) - browser_context_->DisposeStoragePartition(partition); - - pending_removal_partitions_.clear(); - pending_removal_partitions_.push_back(last); -} - -void SigninPartitionManager::OnStoragePartitionCleared( - content::StoragePartition* storage_partition, - base::OnceClosure partition_data_cleared) { - pending_removal_partitions_.push_back(storage_partition); - std::move(partition_data_cleared).Run(); -} - SigninPartitionManager::Factory::Factory() : ProfileKeyedServiceFactory( "SigninPartitionManager",
diff --git a/chrome/browser/ash/login/signin_partition_manager.h b/chrome/browser/ash/login/signin_partition_manager.h index cc406a46..ddf8404 100644 --- a/chrome/browser/ash/login/signin_partition_manager.h +++ b/chrome/browser/ash/login/signin_partition_manager.h
@@ -6,11 +6,9 @@ #define CHROME_BROWSER_ASH_LOGIN_SIGNIN_PARTITION_MANAGER_H_ #include <string> -#include <vector> #include "base/functional/callback.h" #include "base/memory/singleton.h" -#include "base/memory/weak_ptr.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" #include "components/keyed_service/core/keyed_service.h" @@ -88,10 +86,6 @@ bool IsCurrentSigninStoragePartition( const content::StoragePartition* storage_partition) const; - // Disposes old storage partitions. Note that callers need to be sure that - // old partitions will not be referenced again. - void DisposeOldStoragePartitions(); - void SetClearStoragePartitionTaskForTesting( ClearStoragePartitionTask clear_storage_partition_task); void SetGetSystemNetworkContextForTesting( @@ -121,10 +115,6 @@ }; private: - // Invoked after `storage_partition` is cleared. - void OnStoragePartitionCleared(content::StoragePartition* storage_partition, - base::OnceClosure partition_data_cleared); - content::BrowserContext* const browser_context_; ClearStoragePartitionTask clear_storage_partition_task_; @@ -140,17 +130,6 @@ // The StoragePartition identified by `storage_partition_domain_` and // `current_storage_partition_name_`. content::StoragePartition* current_storage_partition_ = nullptr; - - // Storage partitions that should be disposed. Storage partitions for previous - // gaia loads are added here. It if only safe to remove them when there are no - // outstanding references. The current assumption is that all references are - // gone after the gaia loading webview is fully navigated away. The vector - // here is maintained in the time order of gaia loads and the last element - // is used as a barrier to indicate all previous ones could be safely - // disposed. - std::vector<content::StoragePartition*> pending_removal_partitions_; - - base::WeakPtrFactory<SigninPartitionManager> weak_ptr_factory_{this}; }; } // namespace login
diff --git a/chrome/browser/ash/login/test/session_flags_manager.cc b/chrome/browser/ash/login/test/session_flags_manager.cc index adb3b92..30041c338 100644 --- a/chrome/browser/ash/login/test/session_flags_manager.cc +++ b/chrome/browser/ash/login/test/session_flags_manager.cc
@@ -232,15 +232,15 @@ base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM); cmd_line.InitFromArgv(argv); - base::Value flag_list(base::Value::Type::LIST); + base::Value::List flag_list; for (const auto& flag : cmd_line.GetSwitches()) { - base::Value flag_value(base::Value::Type::DICTIONARY); - flag_value.SetKey(kFlagNameKey, base::Value(flag.first)); - flag_value.SetKey(kFlagValueKey, base::Value(flag.second)); + base::Value::Dict flag_value; + flag_value.Set(kFlagNameKey, flag.first); + flag_value.Set(kFlagValueKey, flag.second); flag_list.Append(std::move(flag_value)); } - return flag_list; + return base::Value(std::move(flag_list)); } } // namespace test
diff --git a/chrome/browser/ash/net/network_diagnostics/dns_resolver_present_routine_unittest.cc b/chrome/browser/ash/net/network_diagnostics/dns_resolver_present_routine_unittest.cc index 829dc8a..e5164d3b 100644 --- a/chrome/browser/ash/net/network_diagnostics/dns_resolver_present_routine_unittest.cc +++ b/chrome/browser/ash/net/network_diagnostics/dns_resolver_present_routine_unittest.cc
@@ -73,15 +73,14 @@ // Set up the IP config base::Value::Dict ip_config_properties; ip_config_properties.Set(shill::kMethodProperty, type); - ip_config_properties.Set(shill::kNameServersProperty, - base::Value(dns_servers.Clone())); - helper()->ip_config_test()->AddIPConfig( - kIPConfigPath, base::Value(ip_config_properties.Clone())); + ip_config_properties.Set(shill::kNameServersProperty, dns_servers.Clone()); + helper()->ip_config_test()->AddIPConfig(kIPConfigPath, + ip_config_properties.Clone()); std::string wifi_device_path = helper()->device_test()->GetDevicePathForType(shill::kTypeWifi); helper()->device_test()->SetDeviceProperty( wifi_device_path, shill::kIPConfigsProperty, - base::Value(ip_config_properties.Clone()), + base::Value(std::move(ip_config_properties)), /*notify_changed=*/true); SetServiceProperty(wifi_path(), shill::kIPConfigProperty, base::Value(kIPConfigPath));
diff --git a/chrome/browser/ash/net/network_diagnostics/network_diagnostics_unittest.cc b/chrome/browser/ash/net/network_diagnostics/network_diagnostics_unittest.cc index af9c4715..9b6f88a 100644 --- a/chrome/browser/ash/net/network_diagnostics/network_diagnostics_unittest.cc +++ b/chrome/browser/ash/net/network_diagnostics/network_diagnostics_unittest.cc
@@ -105,9 +105,9 @@ // Set up the IP v4 config base::Value::Dict ip_config_v4_properties; ip_config_v4_properties.Set(shill::kNameServersProperty, - base::Value(dns_servers.Clone())); - helper()->ip_config_test()->AddIPConfig( - kIPv4ConfigPath, base::Value(ip_config_v4_properties.Clone())); + std::move(dns_servers)); + helper()->ip_config_test()->AddIPConfig(kIPv4ConfigPath, + ip_config_v4_properties.Clone()); std::string wifi_device_path = helper()->device_test()->GetDevicePathForType(shill::kTypeWifi); helper()->device_test()->SetDeviceProperty(
diff --git a/chrome/browser/ash/net/rollback_network_config/rollback_network_config.cc b/chrome/browser/ash/net/rollback_network_config/rollback_network_config.cc index bae86d0..3d1ba3a 100644 --- a/chrome/browser/ash/net/rollback_network_config/rollback_network_config.cc +++ b/chrome/browser/ash/net/rollback_network_config/rollback_network_config.cc
@@ -298,13 +298,13 @@ } std::string RollbackNetworkConfig::Exporter::SerializeNetworkConfigs() const { - base::Value network_config_list(base::Value::Type::LIST); + base::Value::List network_config_list; for (const auto& network_config : network_configs_) { network_config_list.Append(network_config.Clone()); } - base::Value complete_network_configuration(base::Value::Type::DICTIONARY); - complete_network_configuration.SetKey( + base::Value::Dict complete_network_configuration; + complete_network_configuration.Set( onc::toplevel_config::kNetworkConfigurations, std::move(network_config_list)); std::string serialized_config;
diff --git a/chrome/browser/ash/ownership/owner_settings_service_ash.cc b/chrome/browser/ash/ownership/owner_settings_service_ash.cc index fec87e8d..b1057188 100644 --- a/chrome/browser/ash/ownership/owner_settings_service_ash.cc +++ b/chrome/browser/ash/ownership/owner_settings_service_ash.cc
@@ -325,15 +325,16 @@ bool OwnerSettingsServiceAsh::AppendToList(const std::string& setting, const base::Value& value) { DCHECK(thread_checker_.CalledOnValidThread()); - const base::Value* old_value = CrosSettings::Get()->GetPref(setting); - if (old_value && !old_value->is_list()) + const base::Value::List* old_value; + if (!CrosSettings::Get()->GetList(setting, &old_value)) { return false; + } - base::Value new_value = - old_value ? old_value->Clone() : base::Value(base::Value::Type::LIST); + base::Value::List new_value = + old_value ? old_value->Clone() : base::Value::List(); new_value.Append(value.Clone()); - return Set(setting, new_value); + return Set(setting, base::Value(std::move(new_value))); } bool OwnerSettingsServiceAsh::RemoveFromList(const std::string& setting,
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_telemetry_sampler_unittest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_telemetry_sampler_unittest.cc index 1b32183..d6769a6 100644 --- a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_telemetry_sampler_unittest.cc +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_telemetry_sampler_unittest.cc
@@ -140,8 +140,8 @@ ip_config_properties.Set(shill::kGatewayProperty, network_data.gateway); const std::string kIPConfigPath = base::StrCat({"test_ip_config", network_data.guid}); - ip_config_client->AddIPConfig( - kIPConfigPath, base::Value(std::move(ip_config_properties))); + ip_config_client->AddIPConfig(kIPConfigPath, + std::move(ip_config_properties)); service_client->SetServiceProperty(service_path, shill::kIPConfigProperty, base::Value(kIPConfigPath)); if (network_data.type == shill::kTypeCellular) {
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc index 01173f6..c0c18e85 100644 --- a/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc +++ b/chrome/browser/ash/policy/status_collector/device_status_collector_browsertest.cc
@@ -3945,8 +3945,8 @@ ip_config_properties.Set(shill::kAddressProperty, fake_network.address); ip_config_properties.Set(shill::kGatewayProperty, fake_network.gateway); const std::string kIPConfigPath = "test_ip_config"; - ip_config_client->AddIPConfig( - kIPConfigPath, base::Value(std::move(ip_config_properties))); + ip_config_client->AddIPConfig(kIPConfigPath, + std::move(ip_config_properties)); service_client->SetServiceProperty(fake_network.name, shill::kIPConfigProperty, base::Value(kIPConfigPath));
diff --git a/chrome/browser/ash/printing/calculators_policies_binder_unittest.cc b/chrome/browser/ash/printing/calculators_policies_binder_unittest.cc index a97eda2c6..e1cb1d9e 100644 --- a/chrome/browser/ash/printing/calculators_policies_binder_unittest.cc +++ b/chrome/browser/ash/printing/calculators_policies_binder_unittest.cc
@@ -92,16 +92,16 @@ ])json"; template <class Container> -std::unique_ptr<base::Value> StringsToList(Container container) { +base::Value StringsToList(Container container) { auto first = container.begin(); auto last = container.end(); - auto list = std::make_unique<base::Value>(base::Value::Type::LIST); + base::Value::List list; while (first != last) { - list->Append(*first); + list.Append(*first); first++; } - return list; + return base::Value(std::move(list)); } class CalculatorsPoliciesBinderTest : public testing::Test { @@ -146,9 +146,9 @@ auto calculator = UserCalculator(); // Set prefs to complete computation - prefs_.SetManagedPref(prefs::kRecommendedPrintersAccessMode, - std::make_unique<base::Value>( - BulkPrintersCalculator::AccessMode::ALL_ACCESS)); + prefs_.SetManagedPref( + prefs::kRecommendedPrintersAccessMode, + base::Value(BulkPrintersCalculator::AccessMode::ALL_ACCESS)); env_.RunUntilIdle(); EXPECT_TRUE(calculator->IsComplete()); @@ -161,8 +161,7 @@ // Set prefs to complete computation prefs_.SetManagedPref( prefs::kRecommendedPrintersAccessMode, - std::make_unique<base::Value>( - BulkPrintersCalculator::AccessMode::ALLOWLIST_ONLY)); + base::Value(BulkPrintersCalculator::AccessMode::ALLOWLIST_ONLY)); prefs_.SetManagedPref(prefs::kRecommendedPrintersAllowlist, StringsToList(kAllowlistIds)); @@ -177,8 +176,7 @@ // Set prefs to complete computation prefs_.SetManagedPref( prefs::kRecommendedPrintersAccessMode, - std::make_unique<base::Value>( - BulkPrintersCalculator::AccessMode::BLOCKLIST_ONLY)); + base::Value(BulkPrintersCalculator::AccessMode::BLOCKLIST_ONLY)); prefs_.SetManagedPref(prefs::kRecommendedPrintersBlocklist, StringsToList(kBlocklistIds)); @@ -192,8 +190,7 @@ // calculator is still properly populated. prefs_.SetManagedPref( prefs::kRecommendedPrintersAccessMode, - std::make_unique<base::Value>( - BulkPrintersCalculator::AccessMode::ALLOWLIST_ONLY)); + base::Value(BulkPrintersCalculator::AccessMode::ALLOWLIST_ONLY)); prefs_.SetManagedPref(prefs::kRecommendedPrintersAllowlist, StringsToList(kAllowlistIds)); @@ -221,7 +218,7 @@ SetDeviceSetting( kDevicePrintersAccessMode, base::Value(BulkPrintersCalculator::AccessMode::ALLOWLIST_ONLY)); - SetDeviceSetting(kDevicePrintersAllowlist, *StringsToList(kAllowlistIds)); + SetDeviceSetting(kDevicePrintersAllowlist, StringsToList(kAllowlistIds)); env_.RunUntilIdle(); EXPECT_TRUE(calculator->IsComplete()); @@ -234,7 +231,7 @@ SetDeviceSetting( kDevicePrintersAccessMode, base::Value(BulkPrintersCalculator::AccessMode::BLOCKLIST_ONLY)); - SetDeviceSetting(kDevicePrintersBlocklist, *StringsToList(kBlocklistIds)); + SetDeviceSetting(kDevicePrintersBlocklist, StringsToList(kBlocklistIds)); env_.RunUntilIdle(); EXPECT_TRUE(calculator->IsComplete());
diff --git a/chrome/browser/ash/printing/cups_printer_status_creator.cc b/chrome/browser/ash/printing/cups_printer_status_creator.cc index d9f35d89..56789065 100644 --- a/chrome/browser/ash/printing/cups_printer_status_creator.cc +++ b/chrome/browser/ash/printing/cups_printer_status_creator.cc
@@ -19,8 +19,7 @@ CupsPrinterStatus PrinterStatusToCupsPrinterStatus( const std::string& printer_id, const printing::PrinterStatus& printer_status, - const chromeos::PrinterAuthenticationInfo& auth_info, - bool client_info_supported) { + const chromeos::PrinterAuthenticationInfo& auth_info) { CupsPrinterStatus cups_printer_status(printer_id); for (const auto& reason : printer_status.reasons) { @@ -32,10 +31,7 @@ PrinterReasonToCupsReason(reason.reason), PrinterSeverityToCupsSeverity(reason.severity)); } - cups_printer_status.SetAuthenticationInfo(auth_info); - cups_printer_status.SetClientInfoSupported(client_info_supported); - return cups_printer_status; }
diff --git a/chrome/browser/ash/printing/cups_printer_status_creator.h b/chrome/browser/ash/printing/cups_printer_status_creator.h index 6c27bad6..6e1482d 100644 --- a/chrome/browser/ash/printing/cups_printer_status_creator.h +++ b/chrome/browser/ash/printing/cups_printer_status_creator.h
@@ -19,8 +19,7 @@ chromeos::CupsPrinterStatus PrinterStatusToCupsPrinterStatus( const std::string& printer_id, const printing::PrinterStatus& printer_status, - const chromeos::PrinterAuthenticationInfo& auth_info, - bool client_info_supported); + const chromeos::PrinterAuthenticationInfo& auth_info); chromeos::CupsPrinterStatus::CupsPrinterStatusReason::Reason PrinterReasonToCupsReason(
diff --git a/chrome/browser/ash/printing/cups_printer_status_creator_unittest.cc b/chrome/browser/ash/printing/cups_printer_status_creator_unittest.cc index e455fd7..35cecf7 100644 --- a/chrome/browser/ash/printing/cups_printer_status_creator_unittest.cc +++ b/chrome/browser/ash/printing/cups_printer_status_creator_unittest.cc
@@ -34,11 +34,8 @@ std::string printer_id = "id"; chromeos::PrinterAuthenticationInfo auth_info{.oauth_server = "a", .oauth_scope = "b"}; - - bool client_info_supported = true; - - CupsPrinterStatus cups_printer_status = PrinterStatusToCupsPrinterStatus( - printer_id, printer_status, auth_info, client_info_supported); + CupsPrinterStatus cups_printer_status = + PrinterStatusToCupsPrinterStatus(printer_id, printer_status, auth_info); EXPECT_EQ("id", cups_printer_status.GetPrinterId()); EXPECT_EQ(2u, cups_printer_status.GetStatusReasons().size()); @@ -52,7 +49,6 @@ EXPECT_EQ(cups_printer_status.GetAuthenticationInfo().oauth_server, "a"); EXPECT_EQ(cups_printer_status.GetAuthenticationInfo().oauth_scope, "b"); - EXPECT_EQ(cups_printer_status.IsClientInfoSupported(), client_info_supported); } TEST(CupsPrinterStatusCreatorTest, PrinterSeverityToCupsSeverity) {
diff --git a/chrome/browser/ash/printing/cups_printers_manager.cc b/chrome/browser/ash/printing/cups_printers_manager.cc index 40412c0..b83e054 100644 --- a/chrome/browser/ash/printing/cups_printers_manager.cc +++ b/chrome/browser/ash/printing/cups_printers_manager.cc
@@ -420,18 +420,16 @@ const std::string& make_and_model, const std::vector<std::string>& document_formats, bool ipp_everywhere, - const chromeos::PrinterAuthenticationInfo& auth_info, - bool client_info_supported) { + const chromeos::PrinterAuthenticationInfo& auth_info) { SendPrinterStatus(printer_id, std::move(cb), result, printer_status, - auth_info, client_info_supported); + auth_info); } void SendPrinterStatus(const std::string& printer_id, PrinterStatusCallback cb, PrinterQueryResult result, const ::printing::PrinterStatus& printer_status, - const chromeos::PrinterAuthenticationInfo& auth_info, - bool client_info_supported) { + const chromeos::PrinterAuthenticationInfo& auth_info) { base::UmaHistogramEnumeration("Printing.CUPS.PrinterStatusQueryResult", result); switch (result) { @@ -471,7 +469,7 @@ // Convert printing::PrinterStatus to printing::CupsPrinterStatus CupsPrinterStatus cups_printers_status = PrinterStatusToCupsPrinterStatus(printer_id, printer_status, - auth_info, client_info_supported); + auth_info); // Save the PrinterStatus so it can be attached along side future // Printer retrievals.
diff --git a/chrome/browser/ash/printing/printer_info.h b/chrome/browser/ash/printing/printer_info.h index dc32685..ef9dc58 100644 --- a/chrome/browser/ash/printing/printer_info.h +++ b/chrome/browser/ash/printing/printer_info.h
@@ -26,16 +26,14 @@ // the raw printer-make-and-model value from the printer. |autoconf| indicates // if we think we can compute the printer capabilities without a PPD. // |auth_info| holds the information about authentication required by the -// printer. |client_info_supported| indicates whether the printer supports all -// members of the 'client-info' IPP attribute. +// printer. using PrinterInfoCallback = base::OnceCallback<void( ::printing::PrinterQueryResult result, const ::printing::PrinterStatus& status, const std::string& make_and_model, const std::vector<std::string>& document_formats, bool autoconf, - const chromeos::PrinterAuthenticationInfo& auth_info, - bool client_info_supported)>; + const chromeos::PrinterAuthenticationInfo& auth_info)>; // Dispatch an IPP request to |host| on |port| for |path| to obtain // basic printer information.
diff --git a/chrome/browser/ash/printing/printer_info_cups.cc b/chrome/browser/ash/printing/printer_info_cups.cc index 87d9512..c3d932a 100644 --- a/chrome/browser/ash/printing/printer_info_cups.cc +++ b/chrome/browser/ash/printing/printer_info_cups.cc
@@ -7,7 +7,6 @@ #include <array> #include <string> -#include "base/containers/contains.h" #include "base/functional/bind.h" #include "base/logging.h" #include "base/metrics/histogram_functions.h" @@ -16,7 +15,6 @@ #include "base/task/thread_pool.h" #include "base/version.h" #include "chromeos/printing/cups_printer_status.h" -#include "printing/backend/cups_ipp_constants.h" #include "printing/backend/cups_jobs.h" #include "printing/printer_status.h" @@ -104,18 +102,6 @@ SupportsRequiredPDLS(info.document_formats)); } -// Returns true if all sub-attributes of 'client-info' are in -// |client_info_supported|. -bool IsClientInfoFullySupported( - const std::vector<std::string>& client_info_supported) { - return base::Contains(client_info_supported, printing::kIppClientName) && - base::Contains(client_info_supported, printing::kIppClientPatches) && - base::Contains(client_info_supported, - printing::kIppClientStringVersion) && - base::Contains(client_info_supported, printing::kIppClientType) && - base::Contains(client_info_supported, printing::kIppClientVersion); -} - // Dispatches an IPP request to |host| to retrieve printer information. Returns // a nullptr if the request fails. QueryResult QueryPrinterImpl(const std::string& host, @@ -145,8 +131,7 @@ std::move(callback).Run(result, ::printing::PrinterStatus(), /*make_and_model=*/std::string(), /*document_formats=*/{}, /*ipp_everywhere=*/false, - chromeos::PrinterAuthenticationInfo{}, - /*client_info_supported=*/false); + chromeos::PrinterAuthenticationInfo{}); return; } @@ -157,12 +142,11 @@ ToIppVersion(*std::max_element(printer_info.ipp_versions.begin(), printer_info.ipp_versions.end()))); - std::move(callback).Run( - result, printer_status, printer_info.make_and_model, - printer_info.document_formats, IsAutoconf(printer_info), - {.oauth_server = printer_info.oauth_server, - .oauth_scope = printer_info.oauth_scope}, - IsClientInfoFullySupported(printer_info.client_info_supported)); + std::move(callback).Run(result, printer_status, printer_info.make_and_model, + printer_info.document_formats, + IsAutoconf(printer_info), + {.oauth_server = printer_info.oauth_server, + .oauth_scope = printer_info.oauth_scope}); } } // namespace
diff --git a/chrome/browser/ash/printing/printer_info_stub.cc b/chrome/browser/ash/printing/printer_info_stub.cc index af2a129..f1ef7b5b 100644 --- a/chrome/browser/ash/printing/printer_info_stub.cc +++ b/chrome/browser/ash/printing/printer_info_stub.cc
@@ -25,8 +25,7 @@ std::move(callback), printing::PrinterQueryResult::kUnknownFailure, printing::PrinterStatus(), /*make_and_model=*/"Foo Bar", /*document_formats=*/std::vector<std::string>{}, - /*ipp_everywhere=*/false, chromeos::PrinterAuthenticationInfo{}, - /*client_info_supported=*/false)); + /*ipp_everywhere=*/false, chromeos::PrinterAuthenticationInfo{})); } } // namespace ash
diff --git a/chrome/browser/ash/system_logs/traffic_counters_log_source.cc b/chrome/browser/ash/system_logs/traffic_counters_log_source.cc index 52a8e5f..5370570 100644 --- a/chrome/browser/ash/system_logs/traffic_counters_log_source.cc +++ b/chrome/browser/ash/system_logs/traffic_counters_log_source.cc
@@ -38,17 +38,15 @@ return ss.str(); } -base::Value ParseTrafficCounters( +base::Value::List ParseTrafficCounters( const std::vector<chromeos::network_config::mojom::TrafficCounterPtr>& traffic_counters) { - auto traffic_counters_list = base::Value(base::Value::Type::LIST); + base::Value::List traffic_counters_list; for (const auto& tc : traffic_counters) { - auto traffic_counter = base::Value(base::Value::Type::DICTIONARY); - traffic_counter.SetKey(kSource, base::Value(GetSourceString(tc->source))); - traffic_counter.SetKey(kRxBytes, - base::Value(static_cast<double>(tc->rx_bytes))); - traffic_counter.SetKey(kTxBytes, - base::Value(static_cast<double>(tc->tx_bytes))); + base::Value::Dict traffic_counter; + traffic_counter.Set(kSource, GetSourceString(tc->source)); + traffic_counter.Set(kRxBytes, static_cast<double>(tc->rx_bytes)); + traffic_counter.Set(kTxBytes, static_cast<double>(tc->tx_bytes)); traffic_counters_list.Append(std::move(traffic_counter)); } return traffic_counters_list; @@ -70,7 +68,7 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!callback.is_null()); callback_ = std::move(callback); - traffic_counters_ = base::Value(base::Value::Type::DICTIONARY); + traffic_counters_.clear(); network_health_service_->GetRecentlyActiveNetworks( base::BindOnce(&TrafficCountersLogSource::OnGetRecentlyActiveNetworks, weak_factory_.GetWeakPtr())); @@ -102,18 +100,18 @@ std::vector<chromeos::network_config::mojom::TrafficCounterPtr> traffic_counters, chromeos::network_config::mojom::ManagedPropertiesPtr managed_properties) { - auto tc_dict = base::Value(base::Value::Type::DICTIONARY); - tc_dict.SetKey(kTrafficCountersKey, ParseTrafficCounters(traffic_counters)); + base::Value::Dict tc_dict; + tc_dict.Set(kTrafficCountersKey, ParseTrafficCounters(traffic_counters)); if (managed_properties && managed_properties->traffic_counter_properties && managed_properties->traffic_counter_properties->friendly_date .has_value()) { - tc_dict.SetKey(kLastResetTimeKey, - base::Value(managed_properties->traffic_counter_properties - ->friendly_date.value())); + tc_dict.Set( + kLastResetTimeKey, + managed_properties->traffic_counter_properties->friendly_date.value()); } else { - tc_dict.SetKey(kLastResetTimeKey, base::Value(kNotAvailable)); + tc_dict.Set(kLastResetTimeKey, kNotAvailable); } - traffic_counters_.SetKey(guid, tc_dict.Clone()); + traffic_counters_.Set(guid, std::move(tc_dict)); SendResponseIfDone(); }
diff --git a/chrome/browser/ash/system_logs/traffic_counters_log_source.h b/chrome/browser/ash/system_logs/traffic_counters_log_source.h index cae1ce5..cb4bf4e13 100644 --- a/chrome/browser/ash/system_logs/traffic_counters_log_source.h +++ b/chrome/browser/ash/system_logs/traffic_counters_log_source.h
@@ -53,7 +53,7 @@ remote_cros_network_config_; int total_guids_ = 0; - base::Value traffic_counters_; + base::Value::Dict traffic_counters_; base::WeakPtrFactory<TrafficCountersLogSource> weak_factory_{this}; };
diff --git a/chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc b/chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc index 6d5584b6..37d57e3 100644 --- a/chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc +++ b/chrome/browser/ash/wallpaper_handlers/wallpaper_handlers.cc
@@ -757,11 +757,15 @@ const auto* num_photos_string = response_album.FindString("numPhotos"); const auto* cover_photo_url = response_album.FindString("coverItemServingUrl"); + const auto* timestamp_string = + response_album.FindString("latestModificationTimestamp"); int64_t num_photos; + base::Time timestamp; if (!album_id || !title || !num_photos_string || !base::StringToInt64(*num_photos_string, &num_photos) || - num_photos < 1 || !cover_photo_url) { + num_photos < 1 || !cover_photo_url || !timestamp_string || + !base::Time::FromUTCString(timestamp_string->c_str(), ×tamp)) { LOG(ERROR) << "Failed to parse item in Google Photos albums response."; continue; } @@ -769,7 +773,7 @@ parsed_response->albums->push_back( ash::personalization_app::mojom::GooglePhotosAlbum::New( *album_id, *title, base::saturated_cast<int>(num_photos), - GURL(*cover_photo_url))); + GURL(*cover_photo_url), timestamp)); } return parsed_response; } @@ -828,8 +832,12 @@ const auto* title = response_album.FindString("name"); const auto* cover_photo_url = response_album.FindString("coverItemServingUrl"); + const auto* timestamp_string = + response_album.FindString("latestModificationTimestamp"); - if (!album_id || !title || !cover_photo_url) { + base::Time timestamp; + if (!album_id || !title || !cover_photo_url || !timestamp_string || + !base::Time::FromUTCString(timestamp_string->c_str(), ×tamp)) { LOG(ERROR) << "Failed to parse item in Google Photos albums response."; continue; } @@ -837,7 +845,8 @@ // `num_image` is always 0 for shared albums. parsed_response->albums->push_back( ash::personalization_app::mojom::GooglePhotosAlbum::New( - *album_id, *title, /*num_image=*/0, GURL(*cover_photo_url))); + *album_id, *title, /*num_image=*/0, GURL(*cover_photo_url), + timestamp)); } return parsed_response; }
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc index d0ca715..ff8a338 100644 --- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc +++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
@@ -76,7 +76,8 @@ " }," " \"coverItemServingUrl\": \"https://www.google.com/\"," " \"name\": \"title\"," - " \"numPhotos\": \"1\"" + " \"numPhotos\": \"1\"," + " \"latestModificationTimestamp\": \"2021-12-31T07:07:07.000Z\"" " } ]," " \"resumeToken\": \"token\"" "}"; @@ -775,8 +776,11 @@ // Parse a response with a valid album and a resume token. auto response = JsonToDict(kGooglePhotosAlbumsFullResponse); auto valid_albums_vector = std::vector<GooglePhotosAlbumPtr>(); + base::Time timestamp; + EXPECT_TRUE( + base::Time::FromUTCString("2021-12-31T07:07:07.000Z", ×tamp)); valid_albums_vector.push_back(GooglePhotosAlbum::New( - "albumId", "title", 1, GURL("https://www.google.com/"))); + "albumId", "title", 1, GURL("https://www.google.com/"), timestamp)); auto result = FetchGooglePhotosAlbumsResponse::New( mojo::Clone(valid_albums_vector), kResumeToken); EXPECT_EQ(google_photos_albums_fetcher->ParseResponse(&response), result);
diff --git a/chrome/browser/ash/web_applications/projector_app/untrusted_projector_ui_config.cc b/chrome/browser/ash/web_applications/projector_app/untrusted_projector_ui_config.cc index 9afc3c1..74e6ff8 100644 --- a/chrome/browser/ash/web_applications/projector_app/untrusted_projector_ui_config.cc +++ b/chrome/browser/ash/web_applications/projector_app/untrusted_projector_ui_config.cc
@@ -57,6 +57,9 @@ source->AddBoolean( "isInternalServerSideSpeechRecognitionEnabled", ash::features::IsInternalServerSideSpeechRecognitionEnabled()); + source->AddBoolean( + "isFoldShortGapIntoPreviousTranscriptEnabled", + ash::features::IsProjectorFoldShortGapIntoPreviousTranscriptEnabled()); source->AddString("appLocale", g_browser_process->GetApplicationLocale()); }
diff --git a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc index f89e7a4..9a71f93 100644 --- a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc +++ b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/autofill/captured_sites_test_utils.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/autofill/chrome_autofill_client.h" +#include "chrome/browser/ui/autofill/payments/test_card_unmask_prompt_waiter.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/translate/translate_bubble_test_utils.h" #include "chrome/common/chrome_features.h" @@ -39,6 +40,7 @@ #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_util.h" #include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/user_prefs/user_prefs.h" #include "components/variations/variations_switches.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_renderer_host.h" @@ -54,7 +56,9 @@ namespace { -const base::TimeDelta autofill_wait_for_action_interval = base::Seconds(5); +constexpr base::TimeDelta kAutofillWaitForActionInterval = base::Seconds(5); +constexpr base::TimeDelta kAutofillWaitForFormToFillWithCvcInterval = + base::Seconds(30); base::FilePath GetReplayFilesRootDirectory() { base::FilePath src_dir; @@ -81,10 +85,12 @@ public ::testing::WithParamInterface<CapturedSiteParams> { public: // TestRecipeReplayChromeFeatureActionExecutor - bool AutofillForm(const std::string& focus_element_css_selector, - const std::vector<std::string>& iframe_path, - const int attempts, - content::RenderFrameHost* frame) override { + bool AutofillForm( + const std::string& focus_element_css_selector, + const std::vector<std::string>& iframe_path, + const int attempts, + content::RenderFrameHost* frame, + absl::optional<ServerFieldType> triggered_field_type) override { content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(frame); auto* autofill_manager = static_cast<BrowserAutofillManager*>( @@ -115,7 +121,7 @@ // Press the down key to highlight the first choice in the autofill // suggestion drop down. test_delegate()->SetExpectations({ObservedUiEvents::kPreviewFormData}, - autofill_wait_for_action_interval); + kAutofillWaitForActionInterval); SendKeyToPopup(frame, ui::DomKey::ARROW_DOWN); if (!test_delegate()->Wait()) { LOG(WARNING) << "Failed to select an option from the " @@ -123,10 +129,36 @@ continue; } + absl::optional<std::u16string> cvc = profile_controller_->cvc(); + // If CVC is available in the Action Recorder receipts and this is a + // payment form, this means it's running the test with a server card. So + // the "Enter CVC" dialog will pop up for card autofill. + bool is_credit_card_field = + triggered_field_type.has_value() && + AutofillType(triggered_field_type.value()).group() == + FieldTypeGroup::kCreditCard; + bool should_cvc_dialog_pop_up = is_credit_card_field && cvc; + // Press the enter key to invoke autofill using the first suggestion. - test_delegate()->SetExpectations({ObservedUiEvents::kFormDataFilled}, - autofill_wait_for_action_interval); + test_delegate()->SetExpectations( + {ObservedUiEvents::kFormDataFilled}, + should_cvc_dialog_pop_up ? kAutofillWaitForFormToFillWithCvcInterval + : kAutofillWaitForActionInterval); + TestCardUnmaskPromptWaiter test_card_unmask_prompt_waiter( + web_contents, + user_prefs::UserPrefs::Get(web_contents->GetBrowserContext())); SendKeyToPopup(frame, ui::DomKey::ENTER); + + if (should_cvc_dialog_pop_up) { + if (!test_card_unmask_prompt_waiter.Wait()) { + LOG(WARNING) << "\"Enter CVC\" dialog did not pop up."; + } else { + VLOG(1) << "CVC to be filled is: " << *cvc; + if (test_card_unmask_prompt_waiter.EnterAndAcceptCvcDialog(*cvc)) { + VLOG(1) << "\"Enter CVC\" dialog popped up and closed."; + } + } + } if (!test_delegate()->Wait()) { LOG(WARNING) << "Failed to fill the form."; continue; @@ -243,7 +275,7 @@ // Doing so ensures that Chrome scrolls the element into view if the // element is off the page. test_delegate()->SetExpectations({ObservedUiEvents::kSuggestionShown}, - autofill_wait_for_action_interval); + kAutofillWaitForActionInterval); if (!captured_sites_test_utils::TestRecipeReplayer::PlaceFocusOnElement( target_element_xpath, iframe_path, frame)) { return false; @@ -257,7 +289,7 @@ } test_delegate()->SetExpectations({ObservedUiEvents::kSuggestionShown}, - autofill_wait_for_action_interval); + kAutofillWaitForActionInterval); if (!captured_sites_test_utils::TestRecipeReplayer:: SimulateLeftMouseClickAt(rect.CenterPoint(), frame)) return false;
diff --git a/chrome/browser/autofill/captured_sites_test_utils.cc b/chrome/browser/autofill/captured_sites_test_utils.cc index 3dc25a5f..60921e1 100644 --- a/chrome/browser/autofill/captured_sites_test_utils.cc +++ b/chrome/browser/autofill/captured_sites_test_utils.cc
@@ -128,6 +128,30 @@ command_file_path.AsUTF8Unsafe().c_str()); } +absl::optional<autofill::ServerFieldType> StringToFieldType( + const std::string& str) { + static auto map = []() { + std::map<std::string, autofill::ServerFieldType> map; + for (size_t i = autofill::NO_SERVER_DATA; + i < autofill::MAX_VALID_FIELD_TYPE; ++i) { + auto field_type = static_cast<autofill::ServerFieldType>(i); + map[autofill::AutofillType(field_type).ToString()] = field_type; + } + for (size_t i = static_cast<size_t>(autofill::HtmlFieldType::kUnspecified); + i <= static_cast<size_t>(autofill::HtmlFieldType::kMaxValue); ++i) { + autofill::AutofillType field_type(static_cast<autofill::HtmlFieldType>(i), + autofill::HtmlFieldMode::kNone); + map[field_type.ToString()] = field_type.GetStorableType(); + } + return map; + }(); + auto it = map.find(str); + if (it == map.end()) { + return absl::nullopt; + } + return it->second; +} + // Command types to control and debug execution. // * The |kAbsoluteLimit| and |kRelativeLimit| commands indicate that // execution shall not proceed if the next action's position is >= |param| @@ -802,6 +826,9 @@ base::CompareCase::INSENSITIVE_ASCII) || base::StartsWith(field_type, "CREDIT_CARD_", base::CompareCase::INSENSITIVE_ASCII)) { + if (type == autofill::CREDIT_CARD_VERIFICATION_CODE) { + cvc_ = base::UTF8ToUTF16(field_value); + } if (type == autofill::CREDIT_CARD_NAME_FIRST || type == autofill::CREDIT_CARD_NAME_LAST) { card_.SetRawInfo(autofill::CREDIT_CARD_NAME_FULL, u""); @@ -814,15 +841,6 @@ return true; } -absl::optional<autofill::ServerFieldType> -ProfileDataController::StringToFieldType(const std::string& str) const { - auto it = string_to_field_type_map_.find(str); - if (it == string_to_field_type_map_.end()) { - return absl::nullopt; - } - return it->second; -} - // TestRecipeReplayer --------------------------------------------------------- TestRecipeReplayer::TestRecipeReplayer( Browser* browser, @@ -1269,9 +1287,21 @@ return false; } + std::string autofill_triggered_field_type; + if (GetElementProperty(frame, xpath, + "return target.getAttribute('autofill-prediction');", + &autofill_triggered_field_type)) { + VLOG(1) << "The field's Chrome Autofill annotation: " + << autofill_triggered_field_type << " during autofill form step."; + } else { + VLOG(1) << "Failed to obtain the field's Chrome Autofill annotation during " + "autofill form step!"; + } if (!feature_action_executor()->AutofillForm( - xpath, frame_path, kAutofillActionNumRetries, frame)) + xpath, frame_path, kAutofillActionNumRetries, frame, + StringToFieldType(autofill_triggered_field_type))) { return false; + } WaitTillPageIsIdle(kAutofillActionWaitForVisualUpdateTimeout); return true; } @@ -2366,7 +2396,8 @@ const std::string& focus_element_css_selector, const std::vector<std::string>& iframe_path, const int attempts, - content::RenderFrameHost* frame) { + content::RenderFrameHost* frame, + absl::optional<autofill::ServerFieldType> triggered_field_type) { ADD_FAILURE() << "TestRecipeReplayChromeFeatureActionExecutor::AutofillForm " "is not implemented!"; return false;
diff --git a/chrome/browser/autofill/captured_sites_test_utils.h b/chrome/browser/autofill/captured_sites_test_utils.h index 1a13e66..6a24bb8 100644 --- a/chrome/browser/autofill/captured_sites_test_utils.h +++ b/chrome/browser/autofill/captured_sites_test_utils.h
@@ -181,14 +181,16 @@ const autofill::CreditCard& credit_card() const { return card_; } const autofill::AutofillProfile& profile() { return profile_; } - bool AddAutofillProfileInfo(const std::string& field_type, const std::string& field_value); + absl::optional<std::u16string> cvc() const { return cvc_; } private: - absl::optional<autofill::ServerFieldType> StringToFieldType( - const std::string& str) const; - + // If a CVC is available in the Action Recorder receipt, this test uses a + // server card to autofill the payment form. So the "Enter CVC" dialog will + // pop up for card autofill. Otherwise, this test uses a local card to + // autofill the payment form. + absl::optional<std::u16string> cvc_; autofill::AutofillProfile profile_; autofill::CreditCard card_; std::map<std::string, autofill::ServerFieldType> string_to_field_type_map_; @@ -215,10 +217,12 @@ // Chrome Autofill feature methods. // Triggers Chrome Autofill in the specified input element on the specified // document. - virtual bool AutofillForm(const std::string& focus_element_css_selector, - const std::vector<std::string>& iframe_path, - const int attempts, - content::RenderFrameHost* frame); + virtual bool AutofillForm( + const std::string& focus_element_css_selector, + const std::vector<std::string>& iframe_path, + const int attempts, + content::RenderFrameHost* frame, + absl::optional<autofill::ServerFieldType> triggered_field_type); virtual bool AddAutofillProfileInfo(const std::string& field_type, const std::string& field_value); virtual bool SetupAutofillProfile();
diff --git a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java index 0660d8a..2af0d0a 100644 --- a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java +++ b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -125,7 +125,6 @@ */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@Features.EnableFeatures(ChromeFeatureList.ENABLE_IPH) public class AppBannerManagerTest { @Rule public ChromeTabbedActivityTestRule mTabbedActivityTestRule = @@ -1100,7 +1099,6 @@ + ChromeFeatureList.INSTALLABLE_AMBIENT_BADGE_INFOBAR, "disable-features=" + ChromeFeatureList.ADD_TO_HOMESCREEN_IPH + "," + ChromeFeatureList.INSTALLABLE_AMBIENT_BADGE_MESSAGE}) - @Features.DisableFeatures(ChromeFeatureList.SNOOZABLE_IPH) public void testInProductHelp() throws Exception { // Visit a site that is a PWA. The ambient badge should show. @@ -1140,7 +1138,6 @@ + ChromeFeatureList.INSTALLABLE_AMBIENT_BADGE_MESSAGE, "disable-features=" + ChromeFeatureList.ADD_TO_HOMESCREEN_IPH + "," + ChromeFeatureList.INSTALLABLE_AMBIENT_BADGE_INFOBAR}) - @Features.DisableFeatures(ChromeFeatureList.SNOOZABLE_IPH) public void testInProductHelp_Message() throws Exception { // Visit a site that is a PWA. The ambient badge should show.
diff --git a/chrome/browser/cart/OWNERS b/chrome/browser/cart/OWNERS index 74bc7e5..bd6eb29 100644 --- a/chrome/browser/cart/OWNERS +++ b/chrome/browser/cart/OWNERS
@@ -3,3 +3,6 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS + +meiliang@chromium.org +yuezhanggg@chromium.org
diff --git a/chrome/browser/cart/cart_discount_fetcher_unittest.cc b/chrome/browser/cart/cart_discount_fetcher_unittest.cc index 21a41c3..72c4e27 100644 --- a/chrome/browser/cart/cart_discount_fetcher_unittest.cc +++ b/chrome/browser/cart/cart_discount_fetcher_unittest.cc
@@ -7,7 +7,7 @@ #include "base/test/scoped_feature_list.h" #include "chrome/browser/cart/fetch_discount_worker.h" #include "components/commerce/core/commerce_feature_list.h" -#include "components/endpoint_fetcher/endpoint_fetcher.h" +#include "components/endpoint_fetcher/mock_endpoint_fetcher.h" #include "components/search/ntp_features.h" #include "components/session_proto_db/session_proto_db.h" #include "content/public/test/browser_task_environment.h" @@ -83,19 +83,6 @@ } // namespace -class MockEndpointFetcher : public EndpointFetcher { - public: - explicit MockEndpointFetcher( - const net::NetworkTrafficAnnotationTag& annotation_tag) - : EndpointFetcher(annotation_tag) {} - - MOCK_METHOD(void, - PerformRequest, - (EndpointFetcherCallback endpoint_fetcher_callback, - const char* key), - (override)); -}; - class CartDiscountFetcherTest { public: static std::string generatePostData( @@ -160,7 +147,7 @@ TEST(CartDiscountFetcherTest, TestOnDiscountsAvailableParsing) { std::unique_ptr<EndpointFetcher> mock_endpoint_fetcher = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + std::make_unique<MockEndpointFetcher>(); base::MockCallback<CartDiscountFetcher::CartDiscountFetcherCallback> mock_callback; @@ -178,7 +165,7 @@ TEST(CartDiscountFetcherTest, TestHighestDiscounts) { std::unique_ptr<EndpointFetcher> mock_endpoint_fetcher = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + std::make_unique<MockEndpointFetcher>(); base::MockCallback<CartDiscountFetcher::CartDiscountFetcherCallback> mock_callback; @@ -202,7 +189,7 @@ TEST(CartDiscountFetcherTest, TestRawMaerchantOffersIsOptional) { std::unique_ptr<EndpointFetcher> mock_endpoint_fetcher = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + std::make_unique<MockEndpointFetcher>(); base::MockCallback<CartDiscountFetcher::CartDiscountFetcherCallback> mock_callback; @@ -248,7 +235,7 @@ TEST(CartDiscountFetcherTest, TestExternalTesterDiscount) { std::unique_ptr<EndpointFetcher> mock_endpoint_fetcher = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + std::make_unique<MockEndpointFetcher>(); base::MockCallback<CartDiscountFetcher::CartDiscountFetcherCallback> mock_callback; @@ -296,7 +283,7 @@ TEST(CartDiscountFetcherTest, TestNoRuleDiscounts) { std::unique_ptr<EndpointFetcher> mock_endpoint_fetcher = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + std::make_unique<MockEndpointFetcher>(); base::MockCallback<CartDiscountFetcher::CartDiscountFetcherCallback> mock_callback; @@ -330,7 +317,7 @@ TEST(CartDiscountFetcherTest, TestOverallDiscountText) { std::unique_ptr<EndpointFetcher> mock_endpoint_fetcher = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + std::make_unique<MockEndpointFetcher>(); base::MockCallback<CartDiscountFetcher::CartDiscountFetcherCallback> mock_callback; @@ -367,7 +354,7 @@ TEST(CartDiscountFetcherTest, TestOverallDiscountTextWithRuleDiscounts) { std::unique_ptr<EndpointFetcher> mock_endpoint_fetcher = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + std::make_unique<MockEndpointFetcher>(); base::MockCallback<CartDiscountFetcher::CartDiscountFetcherCallback> mock_callback; @@ -420,7 +407,7 @@ {}); std::unique_ptr<EndpointFetcher> mock_endpoint_fetcher = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + std::make_unique<MockEndpointFetcher>(); base::MockCallback<CartDiscountFetcher::CartDiscountFetcherCallback> mock_callback;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 5f064723..e2a31ffde 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -39,7 +39,6 @@ #include "chrome/browser/accessibility/accessibility_labels_service.h" #include "chrome/browser/accessibility/accessibility_labels_service_factory.h" #include "chrome/browser/after_startup_task_utils.h" -#include "chrome/browser/ash/crosapi/browser_util.h" #include "chrome/browser/bluetooth/chrome_bluetooth_delegate_impl_client.h" #include "chrome/browser/browser_about_handler.h" #include "chrome/browser/browser_features.h" @@ -2672,10 +2671,6 @@ if (!login_profile.empty()) command_line->AppendSwitchASCII(ash::switches::kLoginProfile, login_profile); - - if (!crosapi::browser_util::IsAshWebBrowserEnabled()) { - command_line->AppendSwitch(switches::kAshWebBrowserDisabled); - } #endif MaybeCopyDisableWebRtcEncryptionSwitch(command_line, browser_command_line,
diff --git a/chrome/browser/creator/android/java/res/layout/creator_profile.xml b/chrome/browser/creator/android/java/res/layout/creator_profile.xml index 424e115..264fa518 100644 --- a/chrome/browser/creator/android/java/res/layout/creator_profile.xml +++ b/chrome/browser/creator/android/java/res/layout/creator_profile.xml
@@ -16,7 +16,7 @@ android:orientation="vertical" android:layout_weight="1" android:layout_width="@dimen/creator_profile_container_width" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:layout_marginStart="@dimen/creator_profile_container_margin" > <TextView android:id="@+id/creator_name" @@ -35,7 +35,8 @@ </LinearLayout> <FrameLayout android:layout_width="wrap_content" - android:layout_height="wrap_content" > + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" > <org.chromium.ui.widget.ButtonCompat android:id="@+id/creator_follow_button" android:layout_width="wrap_content"
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.cc b/chrome/browser/devtools/device/devtools_android_bridge.cc index 35454ca..b4f4aa14 100644 --- a/chrome/browser/devtools/device/devtools_android_bridge.cc +++ b/chrome/browser/devtools/device/devtools_android_bridge.cc
@@ -165,11 +165,12 @@ prefs::kDevToolsDiscoverTCPTargetsEnabled, base::BindRepeating(&DevToolsAndroidBridge::CreateDeviceProviders, base::Unretained(this))); - base::Value target_discovery(base::Value::Type::LIST); + base::Value::List target_discovery; target_discovery.Append(kChromeDiscoveryURL); target_discovery.Append(kNodeDiscoveryURL); - profile->GetPrefs()->SetDefaultPrefValue(prefs::kDevToolsTCPDiscoveryConfig, - std::move(target_discovery)); + profile->GetPrefs()->SetDefaultPrefValue( + prefs::kDevToolsTCPDiscoveryConfig, + base::Value(std::move(target_discovery))); CreateDeviceProviders(); }
diff --git a/chrome/browser/devtools/devtools_targets_ui.cc b/chrome/browser/devtools/devtools_targets_ui.cc index ee6de02..3d86fc9 100644 --- a/chrome/browser/devtools/devtools_targets_ui.cc +++ b/chrome/browser/devtools/devtools_targets_ui.cc
@@ -141,8 +141,8 @@ continue; targets_[host->GetId()] = host; - hosts.push_back( - {host->GetId(), host->GetParentId(), Serialize(host.get())}); + hosts.push_back({host->GetId(), host->GetParentId(), + base::Value(Serialize(host.get()))}); } SendSerializedTargets( @@ -224,57 +224,56 @@ if (!android_bridge_) return; - base::Value device_list(base::Value::Type::LIST); + base::Value::List device_list; for (const auto& device_ptr : devices) { DevToolsAndroidBridge::RemoteDevice* device = device_ptr.get(); - base::Value device_data(base::Value::Type::DICTIONARY); - device_data.SetStringKey(kAdbModelField, device->model()); - device_data.SetStringKey(kAdbSerialField, device->serial()); - device_data.SetBoolKey(kAdbConnectedField, device->is_connected()); + base::Value::Dict device_data; + device_data.Set(kAdbModelField, device->model()); + device_data.Set(kAdbSerialField, device->serial()); + device_data.Set(kAdbConnectedField, device->is_connected()); std::string device_id = base::StringPrintf( kAdbDeviceIdFormat, device->serial().c_str()); - device_data.SetStringKey(kTargetIdField, device_id); - base::Value browser_list(base::Value::Type::LIST); + device_data.Set(kTargetIdField, device_id); + base::Value::List browser_list; DevToolsAndroidBridge::RemoteBrowsers& browsers = device->browsers(); for (const auto& browser_ptr : browsers) { DevToolsAndroidBridge::RemoteBrowser* browser = browser_ptr.get(); - base::Value browser_data(base::Value::Type::DICTIONARY); - browser_data.SetStringKey(kAdbBrowserNameField, browser->display_name()); - browser_data.SetStringKey(kAdbBrowserUserField, browser->user()); - browser_data.SetStringKey(kAdbBrowserVersionField, browser->version()); + base::Value::Dict browser_data; + browser_data.Set(kAdbBrowserNameField, browser->display_name()); + browser_data.Set(kAdbBrowserUserField, browser->user()); + browser_data.Set(kAdbBrowserVersionField, browser->version()); DevToolsAndroidBridge::RemoteBrowser::ParsedVersion parsed = browser->GetParsedVersion(); - browser_data.SetIntKey( - kAdbBrowserChromeVersionField, - browser->IsChrome() && !parsed.empty() ? parsed[0] : 0); + browser_data.Set(kAdbBrowserChromeVersionField, + browser->IsChrome() && !parsed.empty() ? parsed[0] : 0); std::string browser_id = browser->GetId(); - browser_data.SetStringKey(kTargetIdField, browser_id); - browser_data.SetStringKey(kTargetSourceField, source_id()); + browser_data.Set(kTargetIdField, browser_id); + browser_data.Set(kTargetSourceField, source_id()); - base::Value page_list(base::Value::Type::LIST); + base::Value::List page_list; remote_browsers_[browser_id] = browser; for (const auto& page : browser->pages()) { scoped_refptr<DevToolsAgentHost> host = page->CreateTarget(); - base::Value target_data = Serialize(host.get()); + base::Value::Dict target_data = Serialize(host.get()); // Pass the screen size in the target object to make sure that // the caching logic does not prevent the target item from updating // when the screen size changes. gfx::Size screen_size = device->screen_size(); - target_data.SetIntKey(kAdbScreenWidthField, screen_size.width()); - target_data.SetIntKey(kAdbScreenHeightField, screen_size.height()); + target_data.Set(kAdbScreenWidthField, screen_size.width()); + target_data.Set(kAdbScreenHeightField, screen_size.height()); targets_[host->GetId()] = host; page_list.Append(std::move(target_data)); } - browser_data.SetKey(kAdbPagesList, std::move(page_list)); + browser_data.Set(kAdbPagesList, std::move(page_list)); browser_list.Append(std::move(browser_data)); } - device_data.SetKey(kAdbBrowsersList, std::move(browser_list)); + device_data.Set(kAdbBrowsersList, std::move(browser_list)); device_list.Append(std::move(device_data)); } - SendSerializedTargets(device_list); + SendSerializedTargets(base::Value(std::move(device_list))); } } // namespace @@ -322,16 +321,16 @@ return nullptr; } -base::Value DevToolsTargetsUIHandler::Serialize(DevToolsAgentHost* host) { - base::Value target_data(base::Value::Type::DICTIONARY); - target_data.SetStringKey(kTargetSourceField, source_id_); - target_data.SetStringKey(kTargetIdField, host->GetId()); - target_data.SetStringKey(kTargetTypeField, host->GetType()); - target_data.SetBoolKey(kAttachedField, host->IsAttached()); - target_data.SetStringKey(kUrlField, host->GetURL().spec()); - target_data.SetStringKey(kNameField, host->GetTitle()); - target_data.SetStringKey(kFaviconUrlField, host->GetFaviconURL().spec()); - target_data.SetStringKey(kDescriptionField, host->GetDescription()); +base::Value::Dict DevToolsTargetsUIHandler::Serialize(DevToolsAgentHost* host) { + base::Value::Dict target_data; + target_data.Set(kTargetSourceField, source_id_); + target_data.Set(kTargetIdField, host->GetId()); + target_data.Set(kTargetTypeField, host->GetType()); + target_data.Set(kAttachedField, host->IsAttached()); + target_data.Set(kUrlField, host->GetURL().spec()); + target_data.Set(kNameField, host->GetTitle()); + target_data.Set(kFaviconUrlField, host->GetFaviconURL().spec()); + target_data.Set(kDescriptionField, host->GetDescription()); return target_data; } @@ -363,23 +362,22 @@ void PortForwardingStatusSerializer::PortStatusChanged( const ForwardingStatus& status) { - base::Value result(base::Value::Type::DICTIONARY); + base::Value::Dict result; for (const auto& status_pair : status) { - base::Value port_status_dict(base::Value::Type::DICTIONARY); + base::Value::Dict port_status_dict; const PortStatusMap& port_status_map = status_pair.second; for (const auto& p : port_status_map) { - port_status_dict.SetIntKey(base::NumberToString(p.first), p.second); + port_status_dict.Set(base::NumberToString(p.first), p.second); } - base::Value device_status_dict(base::Value::Type::DICTIONARY); - device_status_dict.SetKey(kPortForwardingPorts, - std::move(port_status_dict)); - device_status_dict.SetStringKey(kPortForwardingBrowserId, - status_pair.first->GetId()); + base::Value::Dict device_status_dict; + device_status_dict.Set(kPortForwardingPorts, std::move(port_status_dict)); + device_status_dict.Set(kPortForwardingBrowserId, + status_pair.first->GetId()); std::string device_id = base::StringPrintf( kAdbDeviceIdFormat, status_pair.first->serial().c_str()); - result.SetKey(device_id, std::move(device_status_dict)); + result.Set(device_id, std::move(device_status_dict)); } - callback_.Run(std::move(result)); + callback_.Run(base::Value(std::move(result))); }
diff --git a/chrome/browser/devtools/devtools_targets_ui.h b/chrome/browser/devtools/devtools_targets_ui.h index a5f7109a..de2a08f 100644 --- a/chrome/browser/devtools/devtools_targets_ui.h +++ b/chrome/browser/devtools/devtools_targets_ui.h
@@ -10,12 +10,9 @@ #include <string> #include "base/functional/callback.h" +#include "base/values.h" #include "chrome/browser/devtools/device/devtools_android_bridge.h" -namespace base { -class Value; -} - class Profile; class DevToolsTargetsUIHandler { @@ -51,7 +48,7 @@ virtual void ForceUpdate(); protected: - base::Value Serialize(content::DevToolsAgentHost* host); + base::Value::Dict Serialize(content::DevToolsAgentHost* host); void SendSerializedTargets(const base::Value& list); using TargetMap =
diff --git a/chrome/browser/devtools/protocol/form_devtools_issues_browsertest.cc b/chrome/browser/devtools/protocol/form_devtools_issues_browsertest.cc index 6307799..b3bc390 100644 --- a/chrome/browser/devtools/protocol/form_devtools_issues_browsertest.cc +++ b/chrome/browser/devtools/protocol/form_devtools_issues_browsertest.cc
@@ -5,22 +5,27 @@ #include <memory> #include <tuple> +#include "base/test/scoped_feature_list.h" #include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/autofill/core/common/autofill_features.h" #include "content/public/test/browser_test.h" #include "content/public/test/content_browser_test_utils.h" -namespace content { +namespace autofill { namespace { class AutofillFormDevtoolsProtocolTest : public DevToolsProtocolTestBase { public: - AutofillFormDevtoolsProtocolTest() = default; + AutofillFormDevtoolsProtocolTest() { + scoped_features_.InitAndEnableFeature( + features::kAutofillEnableDevtoolsIssues); + } void NavigateToFormPageAndEnableAudits() { - GURL test_url = - GetTestUrl("autofill", "autofill_form_devtools_issues_test.html"); + GURL test_url = content::GetTestUrl( + "autofill", "autofill_form_devtools_issues_test.html"); EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url)); EXPECT_TRUE(content::WaitForLoadStop(web_contents())); @@ -44,6 +49,9 @@ return notification; } + + private: + base::test::ScopedFeatureList scoped_features_; }; } // namespace @@ -80,4 +88,4 @@ .has_value()); } -} // namespace content +} // namespace autofill
diff --git a/chrome/browser/download/save_package_file_picker.cc b/chrome/browser/download/save_package_file_picker.cc index e27a1ec2..fa00671 100644 --- a/chrome/browser/download/save_package_file_picker.cc +++ b/chrome/browser/download/save_package_file_picker.cc
@@ -9,7 +9,6 @@ #include <memory> #include "base/command_line.h" -#include "base/feature_list.h" #include "base/functional/bind.h" #include "base/i18n/file_util_icu.h" #include "base/metrics/histogram_macros.h" @@ -21,7 +20,6 @@ #include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/chrome_select_file_policy.h" -#include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "chrome/grit/generated_resources.h" #include "components/prefs/pref_member.h" @@ -32,7 +30,6 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/save_page_type.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/content_features.h" #include "ui/base/l10n/l10n_util.h" using content::RenderProcessHost; @@ -75,16 +72,6 @@ FILE_PATH_LITERAL("mhtml")}); } -// Adds "Webpage, Single File (Web Bundle)" type to FileTypeInfo. -void AddWebBundleFileFileTypeInfo( - ui::SelectFileDialog::FileTypeInfo* file_type_info) { - file_type_info->extension_description_overrides.push_back( - l10n_util::GetStringUTF16(IDS_SAVE_PAGE_DESC_WEB_BUNDLE_FILE)); - file_type_info->extensions.emplace_back( - std::initializer_list<base::FilePath::StringType>{ - FILE_PATH_LITERAL("wbn")}); -} - // Chrome OS doesn't support HTML-Complete. crbug.com/154823 #if !BUILDFLAG(IS_CHROMEOS_ASH) // Adds "Webpage, Complete" type to FileTypeInfo. @@ -180,11 +167,6 @@ if (can_save_as_complete_) { AddSingleFileFileTypeInfo(&file_type_info); save_types_.push_back(content::SAVE_PAGE_TYPE_AS_MHTML); - - if (base::FeatureList::IsEnabled(features::kSavePageAsWebBundle)) { - AddWebBundleFileFileTypeInfo(&file_type_info); - save_types_.push_back(content::SAVE_PAGE_TYPE_AS_WEB_BUNDLE); - } } #if !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc b/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc index f8860073..76f01e3 100644 --- a/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc +++ b/chrome/browser/enterprise/connectors/device_trust/device_trust_browsertest.cc
@@ -30,6 +30,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/device_signals/test/signals_contract.h" +#include "components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h" #include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h" #include "components/enterprise/browser/enterprise_switches.h" #include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h" @@ -70,6 +71,8 @@ namespace enterprise_connectors { +using KeyRotationResult = DeviceTrustKeyManager::KeyRotationResult; + namespace { constexpr char kRedirectPath[] = @@ -135,6 +138,7 @@ "Enterprise.DeviceTrust.Attestation.ResponseLatency.Failure"; #if BUILDFLAG(IS_WIN) +constexpr char kFakeNonce[] = "fake nonce"; constexpr int kSuccessCode = 200; constexpr int kHardFailureCode = 400; #endif // BUILDFLAG(IS_WIN) @@ -710,6 +714,54 @@ VerifyAttestationFlowSuccessful(/*failed_attempts=*/2); ASSERT_TRUE(device_trust_test_environment_win_->KeyExists()); } + +IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTest, + RemoteCommandKeyRotationSuccess) { + // Create Key before remote command. + device_trust_test_environment_win_->SetUpExistingKey(); + + // Make sure key presents and stores its current value. + std::vector<uint8_t> current_key_pair = + device_trust_test_environment_win_->GetWrappedKey(); + + auto* key_manager = g_browser_process->browser_policy_connector() + ->chrome_browser_cloud_management_controller() + ->GetDeviceTrustKeyManager(); + + base::test::TestFuture<KeyRotationResult> future_result; + key_manager->RotateKey(kFakeNonce, future_result.GetCallback()); + ASSERT_EQ(future_result.Get(), KeyRotationResult::SUCCESS); + + // Check that key still exists & is replaced with new value. + ASSERT_TRUE(device_trust_test_environment_win_->KeyExists()); + EXPECT_NE(device_trust_test_environment_win_->GetWrappedKey(), + current_key_pair); +} + +IN_PROC_BROWSER_TEST_F(DeviceTrustBrowserTest, + RemoteCommandKeyRotationFailure) { + // Create Key before remote command. + device_trust_test_environment_win_->SetUpExistingKey(); + // Make sure key presents and stores its current value. + std::vector<uint8_t> current_key_pair = + device_trust_test_environment_win_->GetWrappedKey(); + + // Force key upload to fail, in turn failing the key rotation + device_trust_test_environment_win_->SetUploadResult(kHardFailureCode); + + auto* key_manager = g_browser_process->browser_policy_connector() + ->chrome_browser_cloud_management_controller() + ->GetDeviceTrustKeyManager(); + + base::test::TestFuture<KeyRotationResult> future_result; + key_manager->RotateKey(kFakeNonce, future_result.GetCallback()); + ASSERT_EQ(future_result.Get(), KeyRotationResult::FAILURE); + + // Check that key still exists & has the same value since rotation failed. + ASSERT_TRUE(device_trust_test_environment_win_->KeyExists()); + EXPECT_EQ(device_trust_test_environment_win_->GetWrappedKey(), + current_key_pair); +} #endif } // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment.h b/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment.h index 28047be..dec6d80 100644 --- a/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment.h +++ b/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment.h
@@ -28,6 +28,10 @@ // key already exists on the device. virtual void SetUpExistingKey() = 0; + // Set up an existing device trust key on the device, to test the case where a + // key already exists on the device. + virtual std::vector<uint8_t> GetWrappedKey() = 0; + // Set the result of key upload to test different behaviours of // KeyNetworkDelegate. void SetUploadResult(HttpResponseCode upload_response_code);
diff --git a/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.cc b/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.cc index a1f295e..1436174 100644 --- a/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.cc +++ b/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.cc
@@ -116,4 +116,8 @@ trust_level, key_pair->key()->GetWrappedKey())); } +std::vector<uint8_t> DeviceTrustTestEnvironmentWin::GetWrappedKey() { + return key_persistence_delegate_->LoadKeyPair()->key()->GetWrappedKey(); +} + } // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.h b/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.h index 113ab81..71d9986 100644 --- a/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.h +++ b/chrome/browser/enterprise/connectors/device_trust/test/device_trust_test_environment_win.h
@@ -29,6 +29,9 @@ // DeviceTrustTestEnvironment: void SetUpExistingKey() override; + // DeviceTrustTestEnvironment: + std::vector<uint8_t> GetWrappedKey() override; + private: // RegistryOverrideManager for testing with registry registry_util::RegistryOverrideManager registry_override_manager_;
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 4cd9198a..9cf822e 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -196,6 +196,8 @@ "api/identity/identity_token_cache.h", "api/identity/web_auth_flow.cc", "api/identity/web_auth_flow.h", + "api/identity/web_auth_flow_info_bar_delegate.cc", + "api/identity/web_auth_flow_info_bar_delegate.h", "api/idltest/idltest_api.cc", "api/idltest/idltest_api.h", "api/image_writer_private/destroy_partitions_operation.cc",
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc index a46c2c1..14af307 100644 --- a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc +++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc
@@ -127,7 +127,11 @@ DeclarativeContentCssConditionTracker::DeclarativeContentCssConditionTracker( Delegate* delegate) - : delegate_(delegate) {} + : delegate_(delegate) { + registrar_.Add(this, + content::NOTIFICATION_RENDERER_PROCESS_CREATED, + content::NotificationService::AllBrowserContextsAndSources()); +} DeclarativeContentCssConditionTracker:: ~DeclarativeContentCssConditionTracker() = default; @@ -238,9 +242,16 @@ return true; } -void DeclarativeContentCssConditionTracker::OnRenderProcessHostCreated( - content::RenderProcessHost* host) { - InstructRenderProcessIfManagingBrowserContext(host, GetWatchedCssSelectors()); +void DeclarativeContentCssConditionTracker::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_CREATED, type); + + content::RenderProcessHost* process = + content::Source<content::RenderProcessHost>(source).ptr(); + InstructRenderProcessIfManagingBrowserContext(process, + GetWatchedCssSelectors()); } void DeclarativeContentCssConditionTracker::
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h index deea11e..2c8faf6e 100644 --- a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h +++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h
@@ -15,7 +15,8 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "chrome/browser/extensions/api/declarative_content/content_predicate_evaluator.h" -#include "content/public/browser/render_process_host_creation_observer.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_observer.h" namespace base { @@ -61,7 +62,7 @@ // context, and querying for the matching CSS selectors for a context. class DeclarativeContentCssConditionTracker : public ContentPredicateEvaluator, - public content::RenderProcessHostCreationObserver { + public content::NotificationObserver { public: explicit DeclarativeContentCssConditionTracker(Delegate* delegate); @@ -130,8 +131,10 @@ std::unordered_set<std::string> matching_css_selectors_; }; - // content::RenderProcessHostCreationObserver implementation. - void OnRenderProcessHostCreated(content::RenderProcessHost* host) override; + // content::NotificationObserver implementation. + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override; // Informs renderer processes of a new set of watched CSS selectors. void UpdateRenderersWatchedCssSelectors( @@ -163,6 +166,9 @@ // Maps WebContents to the tracker for that WebContents state. std::map<content::WebContents*, std::unique_ptr<PerWebContentsTracker>> per_web_contents_tracker_; + + // Manages our notification registrations. + content::NotificationRegistrar registrar_; }; } // namespace extensions
diff --git a/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc b/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc index 38c843c..18ccee6 100644 --- a/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc +++ b/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc
@@ -97,14 +97,14 @@ base::Value::Dict ipconfig_v4_dictionary; ipconfig_v4_dictionary.Set(shill::kAddressProperty, kIpv4Address); ipconfig_v4_dictionary.Set(shill::kMethodProperty, shill::kTypeIPv4); - shill_ipconfig_client->AddIPConfig( - kWifiIPConfigV4Path, base::Value(std::move(ipconfig_v4_dictionary))); + shill_ipconfig_client->AddIPConfig(kWifiIPConfigV4Path, + std::move(ipconfig_v4_dictionary)); base::Value::Dict ipconfig_v6_dictionary; ipconfig_v6_dictionary.Set(shill::kAddressProperty, kIpv6Address); ipconfig_v6_dictionary.Set(shill::kMethodProperty, shill::kTypeIPv6); - shill_ipconfig_client->AddIPConfig( - kWifiIPConfigV6Path, base::Value(std::move(ipconfig_v6_dictionary))); + shill_ipconfig_client->AddIPConfig(kWifiIPConfigV6Path, + std::move(ipconfig_v6_dictionary)); base::Value::List ip_configs; ip_configs.Append(kWifiIPConfigV4Path);
diff --git a/chrome/browser/extensions/api/file_handlers/OWNERS b/chrome/browser/extensions/api/file_handlers/OWNERS index 64f6677..ab35d48 100644 --- a/chrome/browser/extensions/api/file_handlers/OWNERS +++ b/chrome/browser/extensions/api/file_handlers/OWNERS
@@ -1,2 +1,2 @@ -benwells@chromium.org +file://ui/file_manager/OWNERS sammc@chromium.org
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc index cdf195e..3a15bde 100644 --- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc +++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
@@ -52,11 +52,13 @@ Delegate* delegate, Profile* profile, const ExtensionTokenKey& token_key, - const RemoteConsentResolutionData& resolution_data) + const RemoteConsentResolutionData& resolution_data, + const std::string& extension_name) : delegate_(delegate), profile_(profile), account_id_(token_key.account_info.account_id), resolution_data_(resolution_data), + extension_name_(extension_name), web_flow_started_(false) {} GaiaRemoteConsentFlow::~GaiaRemoteConsentFlow() { @@ -67,7 +69,7 @@ if (!web_flow_) { web_flow_ = std::make_unique<WebAuthFlow>( this, profile_, resolution_data_.url, WebAuthFlow::INTERACTIVE, - WebAuthFlow::GET_AUTH_TOKEN); + WebAuthFlow::GET_AUTH_TOKEN, extension_name_); #if BUILDFLAG(IS_CHROMEOS_LACROS) // `profile_` may be nullptr in tests. if (profile_) {
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h index c10861f2..dbbe0db 100644 --- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h +++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
@@ -53,7 +53,8 @@ GaiaRemoteConsentFlow(Delegate* delegate, Profile* profile, const ExtensionTokenKey& token_key, - const RemoteConsentResolutionData& resolution_data); + const RemoteConsentResolutionData& resolution_data, + const std::string& extension_name); ~GaiaRemoteConsentFlow() override; GaiaRemoteConsentFlow(const GaiaRemoteConsentFlow& other) = delete; @@ -98,6 +99,7 @@ raw_ptr<Profile> profile_; CoreAccountId account_id_; RemoteConsentResolutionData resolution_data_; + const std::string extension_name_; std::unique_ptr<WebAuthFlow> web_flow_; bool web_flow_started_;
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc index d6510fc..4fb52e8 100644 --- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc +++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc
@@ -137,8 +137,8 @@ RemoteConsentResolutionData resolution_data; resolution_data.url = fake_gaia_test_server()->GetURL("/title1.html"); - flow_ = std::make_unique<GaiaRemoteConsentFlow>(&mock(), profile(), - token_key, resolution_data); + flow_ = std::make_unique<GaiaRemoteConsentFlow>( + &mock(), profile(), token_key, resolution_data, "extension_name"); content::TestNavigationObserver navigation_observer(resolution_data.url); navigation_observer.StartWatchingNewWebContents();
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc index 3e88611..bf545a85 100644 --- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc +++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
@@ -31,7 +31,8 @@ nullptr, GURL(), WebAuthFlow::INTERACTIVE, - WebAuthFlow::GET_AUTH_TOKEN), + WebAuthFlow::GET_AUTH_TOKEN, + "extension_name"), fake_window_key_(window_key) {} ~FakeWebAuthFlowWithWindowKey() override = default; @@ -52,7 +53,11 @@ const ExtensionTokenKey& token_key, const RemoteConsentResolutionData& resolution_data, const std::string& window_key) - : GaiaRemoteConsentFlow(delegate, nullptr, token_key, resolution_data), + : GaiaRemoteConsentFlow(delegate, + nullptr, + token_key, + resolution_data, + "extension_name"), window_key_(window_key) { SetWebAuthFlowForTesting( std::make_unique<FakeWebAuthFlowWithWindowKey>(this, window_key_));
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc index 120ed70a..04a1506 100644 --- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc +++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -888,7 +888,7 @@ void IdentityGetAuthTokenFunction::ShowRemoteConsentDialog( const RemoteConsentResolutionData& resolution_data) { gaia_remote_consent_flow_ = std::make_unique<GaiaRemoteConsentFlow>( - this, GetProfile(), token_key_, resolution_data); + this, GetProfile(), token_key_, resolution_data, extension()->name()); gaia_remote_consent_flow_->Start(); }
diff --git a/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc b/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc index e5b9b15..4a6fa3c 100644 --- a/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc +++ b/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc
@@ -50,7 +50,8 @@ AddRef(); // Balanced in OnAuthFlowSuccess/Failure. auth_flow_ = std::make_unique<WebAuthFlow>(this, profile, auth_url, mode, - WebAuthFlow::LAUNCH_WEB_AUTH_FLOW); + WebAuthFlow::LAUNCH_WEB_AUTH_FLOW, + extension()->name()); auth_flow_->Start(); return RespondLater(); }
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.cc b/chrome/browser/extensions/api/identity/web_auth_flow.cc index 946ed3a..9ba2602 100644 --- a/chrome/browser/extensions/api/identity/web_auth_flow.cc +++ b/chrome/browser/extensions/api/identity/web_auth_flow.cc
@@ -15,6 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/trace_event/trace_event.h" +#include "chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" @@ -98,12 +99,14 @@ Profile* profile, const GURL& provider_url, Mode mode, - Partition partition) + Partition partition, + const std::string& extension_name) : delegate_(delegate), profile_(profile), provider_url_(provider_url), mode_(mode), - partition_(partition) { + partition_(partition), + extension_name_(extension_name) { TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("identity", "WebAuthFlow", this); } @@ -114,6 +117,8 @@ web_contents()->Close(); } + CloseInfoBar(); + // Stop listening to notifications first since some of the code // below may generate notifications. WebContentsObserver::Observe(nullptr); @@ -244,6 +249,20 @@ (embedded_window_created_ || using_auth_with_browser_tab_); } +void WebAuthFlow::DisplayInfoBar() { + DCHECK(web_contents()); + DCHECK(using_auth_with_browser_tab_); + + info_bar_delegate_ = + WebAuthFlowInfoBarDelegate::Create(web_contents(), extension_name_); +} + +void WebAuthFlow::CloseInfoBar() { + if (info_bar_delegate_) { + info_bar_delegate_->CloseInfoBar(); + } +} + void WebAuthFlow::BeforeUrlLoaded(const GURL& url) { if (delegate_ && IsObservingProviderWebContents()) delegate_->OnAuthFlowURLChange(url); @@ -263,6 +282,8 @@ NavigateParams params(browser_displayer.browser(), std::move(web_contents_)); Navigate(¶ms); + + DisplayInfoBar(); } } @@ -306,22 +327,26 @@ content::NavigationHandle* navigation_handle) { // If web_contents_ is nullptr, then the auth page tab is opened. // If the navigation is initiated by the user, the tab will exit the auth - // flow screen, this should result in a declined authentication. + // flow screen, this should result in a declined authentication and deleting + // the flow. if (using_auth_with_browser_tab_ && !web_contents_ && !navigation_handle->IsRendererInitiated()) { // Stop observing the web contents since it is not part of the flow anymore. WebContentsObserver::Observe(nullptr); delegate_->OnAuthFlowFailure(Failure::USER_NAVIGATED_AWAY); + return; } - if (navigation_handle->IsInPrimaryMainFrame()) + if (navigation_handle->IsInPrimaryMainFrame()) { BeforeUrlLoaded(navigation_handle->GetURL()); + } } void WebAuthFlow::DidRedirectNavigation( content::NavigationHandle* navigation_handle) { - if (navigation_handle->IsInPrimaryMainFrame()) + if (navigation_handle->IsInPrimaryMainFrame()) { BeforeUrlLoaded(navigation_handle->GetURL()); + } } void WebAuthFlow::DidFinishNavigation( @@ -373,8 +398,14 @@ navigation_handle->GetResponseHeaders()->response_code()); } - if (failed && delegate_) + if (failed && delegate_) { delegate_->OnAuthFlowFailure(LOAD_FAILED); + } +} + +base::WeakPtr<WebAuthFlowInfoBarDelegate> +WebAuthFlow::GetInfoBarDelegateForTesting() { + return info_bar_delegate_; } } // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.h b/chrome/browser/extensions/api/identity/web_auth_flow.h index ca50a91..554e142 100644 --- a/chrome/browser/extensions/api/identity/web_auth_flow.h +++ b/chrome/browser/extensions/api/identity/web_auth_flow.h
@@ -9,6 +9,7 @@ #include "base/feature_list.h" #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "content/public/browser/storage_partition_config.h" #include "content/public/browser/web_contents_observer.h" #include "extensions/browser/app_window/app_window_registry.h" @@ -24,6 +25,8 @@ namespace extensions { +class WebAuthFlowInfoBarDelegate; + // When enabled, cookies in the `launchWebAuthFlow()` partition are persisted // across browser restarts. BASE_DECLARE_FEATURE(kPersistentStorageForWebAuthFlow); @@ -86,7 +89,8 @@ Profile* profile, const GURL& provider_url, Mode mode, - Partition partition); + Partition partition, + const std::string& extension_name); WebAuthFlow(const WebAuthFlow&) = delete; WebAuthFlow& operator=(const WebAuthFlow&) = delete; @@ -112,6 +116,9 @@ Partition partition, content::BrowserContext* browser_context); + // Returns nullptr if the InfoBar is not displayed. + base::WeakPtr<WebAuthFlowInfoBarDelegate> GetInfoBarDelegateForTesting(); + private: friend class ::WebAuthFlowTest; @@ -139,6 +146,9 @@ bool IsObservingProviderWebContents() const; + void DisplayInfoBar(); + void CloseInfoBar(); + raw_ptr<Delegate> delegate_ = nullptr; const raw_ptr<Profile> profile_; const GURL provider_url_; @@ -159,6 +169,10 @@ // `this`. When this value becomes nullptr, this means that the browser tab // has taken ownership and the interactive tab was opened. std::unique_ptr<content::WebContents> web_contents_; + const std::string extension_name_; + // WeakPtr to the info bar delegate attached to the auth tab when opened. Used + // to close the info bar when closing the flow if still valid. + base::WeakPtr<WebAuthFlowInfoBarDelegate> info_bar_delegate_ = nullptr; }; } // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc b/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc index 6bd3acb..9a7b388 100644 --- a/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc +++ b/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
@@ -5,8 +5,10 @@ #include "chrome/browser/extensions/api/identity/web_auth_flow.h" #include "base/strings/strcat.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_future.h" +#include "chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h" #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h" #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h" #include "chrome/browser/ui/browser.h" @@ -26,6 +28,8 @@ namespace extensions { +const char kExtensionName[] = "extension_name"; + class MockWebAuthFlowDelegate : public WebAuthFlow::Delegate { public: MOCK_METHOD(void, OnAuthFlowURLChange, (const GURL&), (override)); @@ -38,12 +42,25 @@ void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); ASSERT_TRUE(embedded_test_server()->Start()); + + // Delete the flow early if OnAuthFlowFailure is called. Simulates real + // usages. + ON_CALL(mock(), OnAuthFlowFailure(testing::_)) + .WillByDefault( + [this](WebAuthFlow::Failure failure) { DeleteWebAuthFlow(); }); } - void TearDownOnMainThread() override { + void DeleteWebAuthFlow() { + DCHECK(web_auth_flow_); // Delete the web auth flow (uses DeleteSoon). web_auth_flow_.release()->DetachDelegateAndDelete(); base::RunLoop().RunUntilIdle(); + } + + void TearDownOnMainThread() override { + if (web_auth_flow_) { + DeleteWebAuthFlow(); + } InProcessBrowserTest::TearDownOnMainThread(); } @@ -55,15 +72,18 @@ if (!profile) profile = browser()->profile(); - web_auth_flow_ = std::make_unique<WebAuthFlow>( - &mock_web_auth_flow_delegate_, profile, url, mode, partition); + web_auth_flow_ = + std::make_unique<WebAuthFlow>(&mock_web_auth_flow_delegate_, profile, + url, mode, partition, kExtensionName); web_auth_flow_->Start(); } WebAuthFlow* web_auth_flow() { return web_auth_flow_.get(); } content::WebContents* web_contents() { - DCHECK(web_auth_flow_); + if (!web_auth_flow_) { + return nullptr; + } return web_auth_flow_->web_contents(); } @@ -353,6 +373,16 @@ EXPECT_EQ(tabs->count(), initial_tab_count + 1); EXPECT_EQ(tabs->GetActiveWebContents()->GetLastCommittedURL(), auth_url); + // Check info bar exists and displays proper message with extension name. + base::WeakPtr<WebAuthFlowInfoBarDelegate> infobar_delegate = + web_auth_flow()->GetInfoBarDelegateForTesting(); + EXPECT_TRUE(infobar_delegate); + EXPECT_EQ( + infobar_delegate->GetIdentifier(), + infobars::InfoBarDelegate::EXTENSIONS_WEB_AUTH_FLOW_INFOBAR_DELEGATE); + EXPECT_TRUE(infobar_delegate->GetMessageText().find( + base::UTF8ToUTF16(std::string(kExtensionName)))); + //--------------------------------------------------------------------- // Part of the test that closes the tab, simulating declining the consent. //--------------------------------------------------------------------- @@ -382,6 +412,10 @@ //--------------------------------------------------------------------- testing::Mock::VerifyAndClearExpectations(&mock()); + // Keeping a reference to the info bar delegate to check later. + base::WeakPtr<WebAuthFlowInfoBarDelegate> auth_info_bar = + web_auth_flow()->GetInfoBarDelegateForTesting(); + GURL new_url = embedded_test_server()->GetURL("a.com", "/new.html"); EXPECT_CALL(mock(), OnAuthFlowFailure(WebAuthFlow::Failure::USER_NAVIGATED_AWAY)); @@ -392,11 +426,13 @@ web_contents()->GetController().LoadURLWithParams(load_params); web_contents_observer.Wait(); - // New tab is not execpted to be closed, it is now used for navigation and not + // New tab is not expected to be closed, it is now used for navigation and not // part of the flow anymore. EXPECT_EQ(web_contents(), nullptr); EXPECT_EQ(tabs->count(), initial_tab_count + 1); EXPECT_EQ(tabs->GetActiveWebContents()->GetLastCommittedURL(), new_url); + // Infobar should be closed on navigation. + EXPECT_FALSE(auth_info_bar); } IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.cc b/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.cc new file mode 100644 index 0000000..02f4025f --- /dev/null +++ b/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.cc
@@ -0,0 +1,67 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h" + +#include <string> + +#include "base/memory/weak_ptr.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/infobars/confirm_infobar_creator.h" +#include "components/infobars/content/content_infobar_manager.h" +#include "components/infobars/core/infobar.h" + +namespace extensions { + +base::WeakPtr<WebAuthFlowInfoBarDelegate> WebAuthFlowInfoBarDelegate::Create( + content::WebContents* web_contents, + const std::string& extension_name) { + std::unique_ptr<WebAuthFlowInfoBarDelegate> delegate = + base::WrapUnique(new WebAuthFlowInfoBarDelegate(extension_name)); + base::WeakPtr<WebAuthFlowInfoBarDelegate> weak_ptr = + delegate->weak_factory_.GetWeakPtr(); + + infobars::ContentInfoBarManager::FromWebContents(web_contents) + ->AddInfoBar(CreateConfirmInfoBar(std::move(delegate))); + + return weak_ptr; +} + +WebAuthFlowInfoBarDelegate::WebAuthFlowInfoBarDelegate( + const std::string& extension_name) + : extension_name_(extension_name) {} + +WebAuthFlowInfoBarDelegate::~WebAuthFlowInfoBarDelegate() = default; + +infobars::InfoBarDelegate::InfoBarIdentifier +WebAuthFlowInfoBarDelegate::GetIdentifier() const { + return InfoBarIdentifier::EXTENSIONS_WEB_AUTH_FLOW_INFOBAR_DELEGATE; +} + +std::u16string WebAuthFlowInfoBarDelegate::GetMessageText() const { + // TODO(https://crbug.com/1408402): The below hardcoded string is temporary. + // Once the string to display is ready, replace the hardcoded string with a + // translation string. + return base::UTF8ToUTF16("Tab opened from extension -- " + extension_name_ + + " -- for authentication"); +} + +bool WebAuthFlowInfoBarDelegate::ShouldExpire( + const NavigationDetails& details) const { + // Infobar should not be closed as long as the auth flow is active. + // Flows themselves should take care of closing the infobar when needed using + // `WebAuthFlowInfoBarDelegate::CloseInfoBar()` and keeping a WeakPtr on + // creation using static `WebAuthFlowInfoBarDelegate::Create()`. + return false; +} + +int WebAuthFlowInfoBarDelegate::GetButtons() const { + return BUTTON_NONE; +} + +void WebAuthFlowInfoBarDelegate::CloseInfoBar() { + infobar()->RemoveSelf(); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h b/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h new file mode 100644 index 0000000..da9e7a7 --- /dev/null +++ b/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h
@@ -0,0 +1,54 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_WEB_AUTH_FLOW_INFO_BAR_DELEGATE_H_ +#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_WEB_AUTH_FLOW_INFO_BAR_DELEGATE_H_ + +#include "components/infobars/core/confirm_infobar_delegate.h" + +#include "base/memory/weak_ptr.h" + +namespace content { +class WebContents; +} // namespace content + +namespace extensions { + +// Infobar used by extension auth flows when authentication is done through a +// Browser Tab. A browser tab is opened when needing action from the user in +// those flows. +// This infobar displays information to the user to clarify why this tab was +// opened, mentioning the extension name as part of the text. +// Auth flows should take care of managing when to close the bar if not manually +// closed by the user, otherwise it should live as long as the flow is alive. +class WebAuthFlowInfoBarDelegate : public ConfirmInfoBarDelegate { + public: + static base::WeakPtr<WebAuthFlowInfoBarDelegate> Create( + content::WebContents* web_contents, + const std::string& extension_name); + + ~WebAuthFlowInfoBarDelegate() override; + + // infobars::InfoBarDelegate: + InfoBarIdentifier GetIdentifier() const override; + bool ShouldExpire(const NavigationDetails& details) const override; + + // ConfirmInfoBarDelegate: + std::u16string GetMessageText() const override; + int GetButtons() const override; + + // Closes the info bar this delegate is associated with. + void CloseInfoBar(); + + private: + explicit WebAuthFlowInfoBarDelegate(const std::string& extension_name); + + const std::string extension_name_; + + base::WeakPtrFactory<WebAuthFlowInfoBarDelegate> weak_factory_{this}; +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_WEB_AUTH_FLOW_INFO_BAR_DELEGATE_H_
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc index 2d22c3c5..e09a600b 100644 --- a/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc +++ b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
@@ -165,7 +165,7 @@ if (!fail_) { result.Append(::onc::network_config::kEthernet); } - std::move(callback).Run(std::make_unique<base::Value>(std::move(result))); + std::move(callback).Run(std::move(result)); } void GetDeviceStateList(DeviceStateListCallback callback) override {
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc index 31e61d2..f576474 100644 --- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc +++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -141,7 +141,7 @@ ipconfig.Set(shill::kGatewayProperty, "0.0.0.1"); ipconfig.Set(shill::kPrefixlenProperty, 0); ipconfig.Set(shill::kMethodProperty, shill::kTypeIPv4); - AddIPConfig(kIPConfigPath, base::Value(std::move(ipconfig))); + AddIPConfig(kIPConfigPath, std::move(ipconfig)); // Add Devices AddDevice(kEthernetDevicePath, shill::kTypeEthernet, @@ -296,7 +296,7 @@ const std::string& service_path) = 0; virtual std::string GetSharedProfilePath() = 0; virtual void AddIPConfig(const std::string& ip_config_path, - const base::Value& properties) = 0; + base::Value::Dict properties) = 0; }; #if BUILDFLAG(IS_CHROMEOS_ASH) @@ -479,9 +479,9 @@ } void AddIPConfig(const std::string& ip_config_path, - const base::Value& properties) override { - network_handler_test_helper_->ip_config_test()->AddIPConfig(ip_config_path, - properties); + base::Value::Dict properties) override { + network_handler_test_helper_->ip_config_test()->AddIPConfig( + ip_config_path, std::move(properties)); } void AddProfile(const std::string& profile_path, @@ -600,9 +600,9 @@ } void AddIPConfig(const std::string& ip_config_path, - const base::Value& properties) override { + base::Value::Dict properties) override { ShillClientTestInterfaceAsyncWaiter(shill_test_.get()) - .AddIPConfig(ip_config_path, properties.Clone()); + .AddIPConfig(ip_config_path, base::Value(std::move(properties))); } void AddProfile(const std::string& profile_path,
diff --git a/chrome/browser/extensions/component_extensions_allowlist/EXTENSION_ALLOWLIST_OWNERS b/chrome/browser/extensions/component_extensions_allowlist/EXTENSION_ALLOWLIST_OWNERS index d5a5a98..193dd01 100644 --- a/chrome/browser/extensions/component_extensions_allowlist/EXTENSION_ALLOWLIST_OWNERS +++ b/chrome/browser/extensions/component_extensions_allowlist/EXTENSION_ALLOWLIST_OWNERS
@@ -2,4 +2,4 @@ rdevlin.cronin@chromium.org # For Component Apps -benwells@chromium.org +dominickn@chromium.org
diff --git a/chrome/browser/extensions/extension_assets_manager.cc b/chrome/browser/extensions/extension_assets_manager.cc index 201a0c3..47bde2c 100644 --- a/chrome/browser/extensions/extension_assets_manager.cc +++ b/chrome/browser/extensions/extension_assets_manager.cc
@@ -41,7 +41,7 @@ } void UninstallExtension(const std::string& id, - Profile* profile, + const std::string& profile_user_name, const base::FilePath& local_install_dir, const base::FilePath& extension_root) override { file_util::UninstallExtension(local_install_dir, id);
diff --git a/chrome/browser/extensions/extension_assets_manager.h b/chrome/browser/extensions/extension_assets_manager.h index 0d961c79c..42d0bf0f 100644 --- a/chrome/browser/extensions/extension_assets_manager.h +++ b/chrome/browser/extensions/extension_assets_manager.h
@@ -42,7 +42,7 @@ // Remove extension assets if it is not used by anyone else. virtual void UninstallExtension(const std::string& id, - Profile* profile, + const std::string& profile_user_name, const base::FilePath& local_install_dir, const base::FilePath& extension_root) = 0;
diff --git a/chrome/browser/extensions/extension_assets_manager_chromeos.cc b/chrome/browser/extensions/extension_assets_manager_chromeos.cc index 0ce1166..7d9e69b 100644 --- a/chrome/browser/extensions/extension_assets_manager_chromeos.cc +++ b/chrome/browser/extensions/extension_assets_manager_chromeos.cc
@@ -172,7 +172,7 @@ void ExtensionAssetsManagerChromeOS::UninstallExtension( const std::string& id, - Profile* profile, + const std::string& profile_user_name, const base::FilePath& local_install_dir, const base::FilePath& extension_root) { if (local_install_dir.IsParent(extension_root)) { @@ -187,7 +187,7 @@ FROM_HERE, base::BindOnce( &ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused, id, - profile)); + profile_user_name)); } } @@ -422,7 +422,7 @@ // static void ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused( const std::string& id, - Profile* profile) { + const std::string& profile_user_name) { DCHECK_CURRENTLY_ON(BrowserThread::UI); PrefService* local_state = g_browser_process->local_state(); @@ -440,7 +440,7 @@ versions.push_back(kv.first); } - base::Value user_name(profile->GetProfileUserName()); + base::Value user_name(profile_user_name); for (std::vector<std::string>::const_iterator it = versions.begin(); it != versions.end(); it++) { base::Value::Dict* version_info = extension_info->FindDict(*it);
diff --git a/chrome/browser/extensions/extension_assets_manager_chromeos.h b/chrome/browser/extensions/extension_assets_manager_chromeos.h index d4438db..310b557 100644 --- a/chrome/browser/extensions/extension_assets_manager_chromeos.h +++ b/chrome/browser/extensions/extension_assets_manager_chromeos.h
@@ -50,7 +50,7 @@ InstallExtensionCallback callback, bool updates_from_webstore_or_empty_update_url) override; void UninstallExtension(const std::string& id, - Profile* profile, + const std::string& profile_user_name, const base::FilePath& local_install_dir, const base::FilePath& extension_root) override; @@ -114,7 +114,7 @@ // Called on UI thread to mark that shared version is not used. static void MarkSharedExtensionUnused(const std::string& id, - Profile* profile); + const std::string& profile_user_name); // Called on task runner thread to remove shared version. static void DeleteSharedVersion(const base::FilePath& shared_version_dir);
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 82adadf..5d6b1ba 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -817,11 +817,11 @@ if (!GetExtensionFileTaskRunner()->PostTaskAndReply( FROM_HERE, base::BindOnce(&ExtensionService::UninstallExtensionOnFileThread, - extension->id(), - base::UnsafeDanglingUntriaged(profile_), + extension->id(), profile_->GetProfileUserName(), install_directory_, extension->path()), - subtask_done_callback)) + subtask_done_callback)) { NOTREACHED(); + } } DataDeleter::StartDeleting(profile_, extension.get(), subtask_done_callback); @@ -842,12 +842,13 @@ // static void ExtensionService::UninstallExtensionOnFileThread( const std::string& id, - Profile* profile, + const std::string& profile_user_name, const base::FilePath& install_dir, const base::FilePath& extension_path) { ExtensionAssetsManager* assets_manager = ExtensionAssetsManager::GetInstance(); - assets_manager->UninstallExtension(id, profile, install_dir, extension_path); + assets_manager->UninstallExtension(id, profile_user_name, install_dir, + extension_path); } bool ExtensionService::IsExtensionEnabled(
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index ccbf89e7..40dc12c4 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h
@@ -618,7 +618,7 @@ // Called on file task runner thread to uninstall extension. static void UninstallExtensionOnFileThread( const std::string& id, - Profile* profile, + const std::string& profile_user_name, const base::FilePath& install_dir, const base::FilePath& extension_path);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java index abee933..3a5ac5e 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStream.java
@@ -397,8 +397,6 @@ String url = productSpecificDataMap.get(XSURFACE_CARD_URL); - Map<String, String> feedContext = convertNameFormat(productSpecificDataMap); - // We want to hide the bottom sheet before sending feedback so the snapshot doesn't show // the menu covering the article. However the menu is animating down, we need to wait // for the animation to finish. We post a task to wait for the duration of the @@ -409,8 +407,8 @@ // matching an allow list rule. PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT, () - -> mHelpAndFeedbackLauncher.showFeedback( - mActivity, profile, url, FEEDBACK_REPORT_TYPE, feedContext), + -> mHelpAndFeedbackLauncher.showFeedback(mActivity, profile, url, + FEEDBACK_REPORT_TYPE, productSpecificDataMap), MENU_DISMISS_TASK_DELAY); } @@ -539,37 +537,6 @@ mNativeFeedStream, FeedStream.this, feedKindToInvalidate); } } - - // Since the XSurface client strings are slightly different than the Feed strings, convert - // the name from the XSurface format to the format that can be handled by the feedback - // system. Any new strings that are added on the XSurface side will need a code change - // here, and adding the PSD to the allow list. - private Map<String, String> convertNameFormat(Map<String, String> xSurfaceMap) { - Map<String, String> feedbackNameConversionMap = new HashMap<>(); - feedbackNameConversionMap.put("Card URL", "CardUrl"); - feedbackNameConversionMap.put("Card Title", "CardTitle"); - feedbackNameConversionMap.put("Card Snippet", "CardSnippet"); - feedbackNameConversionMap.put("Card category", "CardCategory"); - feedbackNameConversionMap.put("Doc Creation Date", "DocCreationDate"); - - // For each <name, value> entry in the input map, convert the name to the new name, and - // write the new <name, value> pair into the output map. - Map<String, String> feedbackMap = new HashMap<>(); - for (Map.Entry<String, String> entry : xSurfaceMap.entrySet()) { - String newName = feedbackNameConversionMap.get(entry.getKey()); - if (newName != null) { - feedbackMap.put(newName, entry.getValue()); - } else { - Log.v(TAG, "Found an entry with no conversion available."); - // We will put the entry into the map if untranslatable. It will be discarded - // unless it matches an allow list on the server, though. This way we can choose - // to allow it on the server if desired. - feedbackMap.put(entry.getKey(), entry.getValue()); - } - } - - return feedbackMap; - } } private class RotationObserver implements DisplayAndroid.DisplayAndroidObserver {
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewTest.java index 5956def0..1aee127 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewTest.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewTest.java
@@ -71,7 +71,6 @@ private void setFeatureOverridesForIPH() { FeatureList.TestValues testValues = new FeatureList.TestValues(); testValues.addFeatureFlagOverride(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); - testValues.addFeatureFlagOverride(ChromeFeatureList.ENABLE_IPH, true); testValues.addFeatureFlagOverride(ChromeFeatureList.WEB_FEED, true); testValues.addFeatureFlagOverride(ChromeFeatureList.WEB_FEED_ONBOARDING, true); testValues.addFieldTrialParamOverride(
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java index 1dbe809..a52d173bb 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java
@@ -227,8 +227,6 @@ public void meetsShowingRequirements_showsIntro_IPH() { mBaseTestValues.addFieldTrialParamOverride( ChromeFeatureList.WEB_FEED, "intro_style", "IPH"); - mBaseTestValues.addFeatureFlagOverride(ChromeFeatureList.SNOOZABLE_IPH, false); - mBaseTestValues.addFeatureFlagOverride(ChromeFeatureList.ENABLE_IPH, true); mBaseTestValues.addFeatureFlagOverride( ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); FeatureList.setTestValues(mBaseTestValues); @@ -258,8 +256,6 @@ public void sameWebFeedIsNotShownMoreThan3Times() { mBaseTestValues.addFieldTrialParamOverride( ChromeFeatureList.WEB_FEED, "intro_style", "IPH"); - mBaseTestValues.addFeatureFlagOverride(ChromeFeatureList.SNOOZABLE_IPH, false); - mBaseTestValues.addFeatureFlagOverride(ChromeFeatureList.ENABLE_IPH, true); mBaseTestValues.addFeatureFlagOverride( ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); FeatureList.setTestValues(mBaseTestValues);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroViewTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroViewTest.java index 1aadef7a..770aaaf 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroViewTest.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroViewTest.java
@@ -89,7 +89,6 @@ FeatureList.TestValues baseTestValues = new FeatureList.TestValues(); baseTestValues.addFeatureFlagOverride( ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); - baseTestValues.addFeatureFlagOverride(ChromeFeatureList.ENABLE_IPH, true); FeatureList.setTestValues(baseTestValues); mWebFeedFollowIntroView.showIPH(mHelper, () -> {}, () -> {});
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 2a92e8f..954396ae 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -438,6 +438,11 @@ "expiry_milestone": 113 }, { + "name": "autofill-account-profiles-union-view", + "owners": [ "vidhanj", "koerber" ], + "expiry_milestone": 120 + }, + { "name": "autofill-address-verification-in-save-prompt", "owners": [ "mamir", "koerber" ], "expiry_milestone": 106 @@ -703,7 +708,7 @@ { "name": "block-insecure-private-network-requests", "owners": [ "titouan", "chrome-security-owp-team@google.com" ], - "expiry_milestone": 111 + "expiry_milestone": 114 }, { "name": "bluetooth-coredump", @@ -3785,7 +3790,7 @@ { "name": "files-inline-sync-status", "owners": [ "simmonsjosh@google.com", "benhartney@google.com", "msalomao" ], - "expiry_milestone": 111 + "expiry_milestone": 115 }, { "name": "files-search-v2", @@ -4776,6 +4781,11 @@ "expiry_milestone": 84 }, { + "name": "multi-zone-rgb-keyboard", + "owners": [ "jasontt", "assistive-eng@google.com"], + "expiry_milestone": 120 + }, + { "name": "multiline-fade-truncating-label", "owners": [ "christianxu", "stkhapugin", "bling-flags@google.com"], "expiry_milestone": 120 @@ -4806,11 +4816,6 @@ "expiry_milestone": 115 }, { - "name": "nearby-sharing-wifilan", - "owners": [ "nohle@google.com", "chromeos-cross-device-eng@google.com" ], - "expiry_milestone": 105 - }, - { "name": "network-service-in-process", "owners": [ "yhirano", "network-service-dev" ], "expiry_milestone": 120 @@ -4860,9 +4865,14 @@ "expiry_milestone": 115 }, { + "name": "notification-permission-rationale-bottom-sheet", + "owners": ["shaktisahu", "salg"], + "expiry_milestone": 114 + }, + { "name": "notification-permission-rationale-dialog", "owners": ["shaktisahu", "salg"], - "expiry_milestone": 110 + "expiry_milestone": 114 }, { "name": "notification-scheduler",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 3ca344a..c50adac 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1061,11 +1061,6 @@ const char kEnableGpuServiceLoggingDescription[] = "Enable printing the actual GL driver calls."; -const char kEnableIphName[] = "Enable IPH"; -const char kEnableIphDescription[] = - "Enables the ability to show IPH. When disabled, IPHs are disabled system " - "wide."; - const char kEnableIsolatedWebAppsName[] = "Enable Isolated Web Apps"; const char kEnableIsolatedWebAppsDescription[] = "Enables experimental support for isolated web apps. " @@ -3755,6 +3750,13 @@ "Configure the dialog shown before requesting notification permission. " "Only works with builds targeting Android T."; +const char kNotificationPermissionRationaleBottomSheetName[] = + "Notification Permission Rationale Bottom Sheet UI"; +const char kNotificationPermissionRationaleBottomSheetDescription[] = + "Enable the alternative bottom sheet UI for the notification permission " + "flow. " + "Only works with builds targeting Android T+."; + const char kOfflinePagesLivePageSharingName[] = "Enables live page sharing of offline pages"; const char kOfflinePagesLivePageSharingDescription[] = @@ -5128,11 +5130,6 @@ "Turns off DNS proxying and SecureDNS for ChromeOS (only). Does not impact " "Chrome browser."; -const char kEnableDnsProxyName[] = "Enable DNS proxy service"; -const char kEnableDnsProxyDescription[] = - "When enabled, standard DNS queries will be proxied through the system " - "service"; - const char kEnableEdidBasedDisplayIdsName[] = "Enable EDID-based display IDs"; const char kEnableEdidBasedDisplayIdsDescription[] = "When enabled, a display's ID will be produced by hashing certain values " @@ -5141,12 +5138,6 @@ "physical port they were connected to, and load user display layouts more " "accurately."; -const char kDnsProxyEnableDOHName[] = - "Enable DNS-over-HTTPS in the DNS proxy service"; -const char kDnsProxyEnableDOHDescription[] = - "When enabled, the DNS proxy will perform DNS-over-HTTPS in accordance " - "with the ChromeOS SecureDNS settings."; - const char kEnableExternalKeyboardsInDiagnosticsAppName[] = "Enable external keyboards in the Diagnostics App"; const char kEnableExternalKeyboardsInDiagnosticsAppDescription[] = @@ -5672,6 +5663,11 @@ "flag does not affect the toggle functionality, it only affects how the " "System UI handles the mute toggle state."; +const char kMultiZoneRgbKeyboardName[] = + "Enable multi-zone RGB keyboard customization"; +const char kMultiZoneRgbKeyboardDescription[] = + "Enable multi-zone RGB keyboard customization on supported devices."; + const char kMultilingualTypingName[] = "Multilingual typing on CrOS"; const char kMultilingualTypingDescription[] = "Enables support for multilingual assistive typing on ChromeOS."; @@ -5692,10 +5688,6 @@ "Enables UI features for Self Share to allow seamless sharing between a " "user's own devices."; -const char kNearbySharingWifiLanName[] = "Nearby Sharing WifiLan"; -const char kNearbySharingWifiLanDescription[] = - "Enables WifiLan as a Nearby Share transfer medium."; - const char kOobeHidDetectionRevampName[] = "OOBE HID Detection Revamp"; const char kOobeHidDetectionRevampDescription[] = "Enables the ChromeOS HID Detection Revamp, which updates OOBE HID "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index d1d146ed..230d1941 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -671,9 +671,6 @@ extern const char kEnableGamepadButtonAxisEventsName[]; extern const char kEnableGamepadButtonAxisEventsDescription[]; -extern const char kEnableIphName[]; -extern const char kEnableIphDescription[]; - extern const char kEnableIsolatedWebAppsName[]; extern const char kEnableIsolatedWebAppsDescription[]; @@ -2153,6 +2150,9 @@ extern const char kNotificationPermissionRationaleName[]; extern const char kNotificationPermissionRationaleDescription[]; +extern const char kNotificationPermissionRationaleBottomSheetName[]; +extern const char kNotificationPermissionRationaleBottomSheetDescription[]; + extern const char kOfflinePagesLivePageSharingName[]; extern const char kOfflinePagesLivePageSharingDescription[]; @@ -2937,15 +2937,9 @@ extern const char kDisableDnsProxyName[]; extern const char kDisableDnsProxyDescription[]; -extern const char kEnableDnsProxyName[]; -extern const char kEnableDnsProxyDescription[]; - extern const char kEnableEdidBasedDisplayIdsName[]; extern const char kEnableEdidBasedDisplayIdsDescription[]; -extern const char kDnsProxyEnableDOHName[]; -extern const char kDnsProxyEnableDOHDescription[]; - extern const char kEnableExternalKeyboardsInDiagnosticsAppName[]; extern const char kEnableExternalKeyboardsInDiagnosticsAppDescription[]; @@ -3254,6 +3248,9 @@ extern const char kMicrophoneMuteSwitchDeviceName[]; extern const char kMicrophoneMuteSwitchDeviceDescription[]; +extern const char kMultiZoneRgbKeyboardName[]; +extern const char kMultiZoneRgbKeyboardDescription[]; + extern const char kMultilingualTypingName[]; extern const char kMultilingualTypingDescription[]; @@ -3266,9 +3263,6 @@ extern const char kNearbySharingSelfShareUIName[]; extern const char kNearbySharingSelfShareUIDescription[]; -extern const char kNearbySharingWifiLanName[]; -extern const char kNearbySharingWifiLanDescription[]; - extern const char kOobeHidDetectionRevampName[]; extern const char kOobeHidDetectionRevampDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 7f6d06b..d5d54bf 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -129,9 +129,7 @@ &features::kWebNfc, &features::kIncognitoDownloadsWarning, &features::kIncognitoNtpRevamp, - &feature_engagement::kEnableIPH, &feature_engagement::kIPHNewTabPageHomeButtonFeature, - &feature_engagement::kIPHSnooze, &feature_engagement::kIPHTabSwitcherButtonFeature, &feature_engagement::kUseClientConfigIPH, &feature_guide::features::kFeatureNotificationGuide, @@ -236,6 +234,7 @@ &kLensCameraAssistedSearch, &kLensOnQuickActionSearchWidget, &kNotificationPermissionVariant, + &kNotificationPermissionBottomSheet, &kPageAnnotationsService, &kBookmarksImprovedSaveFlow, &kBookmarksRefresh, @@ -286,7 +285,6 @@ &kTestDefaultDisabled, &kTestDefaultEnabled, &kToolbarMicIphAndroid, - &kToolbarPhoneOptimizations, &kToolbarScrollAblationAndroid, &kTrustedWebActivityPostMessage, &kTrustedWebActivityQualityEnforcement, @@ -727,6 +725,10 @@ "NotificationPermissionVariant", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kNotificationPermissionBottomSheet, + "NotificationPermissionBottomSheet", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kInstanceSwitcher, "InstanceSwitcher", base::FEATURE_ENABLED_BY_DEFAULT); @@ -923,10 +925,6 @@ "ToolbarMicIphAndroid", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kToolbarPhoneOptimizations, - "ToolbarPhoneOptimizations", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kToolbarScrollAblationAndroid, "ToolbarScrollAblationAndroid", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index bf8fb75..9efca7d7 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -101,6 +101,7 @@ BASE_DECLARE_FEATURE(kLensOnQuickActionSearchWidget); BASE_DECLARE_FEATURE(kLocationBarModelOptimizations); BASE_DECLARE_FEATURE(kNotificationPermissionVariant); +BASE_DECLARE_FEATURE(kNotificationPermissionBottomSheet); BASE_DECLARE_FEATURE(kOmahaMinSdkVersionAndroid); BASE_DECLARE_FEATURE(kOmniboxModernizeVisualUpdate); BASE_DECLARE_FEATURE(kOptimizeGeolocationHeaderGeneration); @@ -152,7 +153,6 @@ BASE_DECLARE_FEATURE(kTestDefaultDisabled); BASE_DECLARE_FEATURE(kTestDefaultEnabled); BASE_DECLARE_FEATURE(kToolbarMicIphAndroid); -BASE_DECLARE_FEATURE(kToolbarPhoneOptimizations); BASE_DECLARE_FEATURE(kToolbarScrollAblationAndroid); BASE_DECLARE_FEATURE(kToolbarUseHardwareBitmapDraw); BASE_DECLARE_FEATURE(kTrustedWebActivityPostMessage);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index ccbff72..f2ae3e7 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -365,6 +365,8 @@ public static final String METRICS_SETTINGS_ANDROID = "MetricsSettingsAndroid"; public static final String MODAL_PERMISSION_DIALOG_VIEW = "ModalPermissionDialogView"; public static final String NOTIFICATION_PERMISSION_VARIANT = "NotificationPermissionVariant"; + public static final String NOTIFICATION_PERMISSION_BOTTOM_SHEET = + "NotificationPermissionBottomSheet"; public static final String OFFLINE_PAGES_DESCRIPTIVE_FAIL_STATUS = "OfflinePagesDescriptiveFailStatus"; public static final String OFFLINE_PAGES_DESCRIPTIVE_PENDING_STATUS = @@ -468,10 +470,9 @@ "SkipServiceWorkerForInstallPromot"; public static final String SMART_SUGGESTION_FOR_LARGE_DOWNLOADS = "SmartSuggestionForLargeDownloads"; - public static final String SNOOZABLE_IPH = "IPH_Snooze"; + public static final String SPLIT_COMPOSITOR_TASK = "SplitCompositorTask"; public static final String SPLIT_CACHE_BY_NETWORK_ISOLATION_KEY = "SplitCacheByNetworkIsolationKey"; - public static final String SPLIT_COMPOSITOR_TASK = "SplitCompositorTask"; public static final String START_SURFACE_ANDROID = "StartSurfaceAndroid"; public static final String START_SURFACE_DISABLED_FEED_IMPROVEMENT = "StartSurfaceDisabledFeedImprovement"; @@ -500,7 +501,6 @@ public static final String TEST_DEFAULT_DISABLED = "TestDefaultDisabled"; public static final String TEST_DEFAULT_ENABLED = "TestDefaultEnabled"; public static final String TOOLBAR_MIC_IPH_ANDROID = "ToolbarMicIphAndroid"; - public static final String TOOLBAR_PHONE_OPTIMIZATIONS = "ToolbarPhoneOptimizations"; public static final String TOOLBAR_SCROLL_ABLATION_ANDROID = "ToolbarScrollAblationAndroid"; public static final String TOOLBAR_USE_HARDWARE_BITMAP_DRAW = "ToolbarUseHardwareBitmapDraw"; public static final String TRANSLATE_ASSIST_CONTENT = "TranslateAssistContent";
diff --git a/chrome/browser/headless/headless_mode_browsertest.cc b/chrome/browser/headless/headless_mode_browsertest.cc index aca825a..67c0bca 100644 --- a/chrome/browser/headless/headless_mode_browsertest.cc +++ b/chrome/browser/headless/headless_mode_browsertest.cc
@@ -37,6 +37,12 @@ #include "testing/multiprocess_func_list.h" #include "ui/gfx/switches.h" +namespace switches { +// This switch runs tests in headful mode, intended for experiments only because +// not all tests are expected to pass in headful mode. +static const char kHeadfulMode[] = "headful-mode"; +} // namespace switches + namespace { const int kErrorResultCode = -1; } // namespace @@ -51,14 +57,18 @@ base::CommandLine* command_line) { InProcessBrowserTest::SetUpCommandLine(command_line); - command_line->AppendSwitchASCII(switches::kHeadless, kHeadlessSwitchValue); - headless::SetUpCommandLine(command_line); + if (command_line->HasSwitch(switches::kHeadfulMode)) { + headful_mode_ = true; + } else { + command_line->AppendSwitchASCII(switches::kHeadless, kHeadlessSwitchValue); + headless::SetUpCommandLine(command_line); + } } void HeadlessModeBrowserTest::SetUpOnMainThread() { InProcessBrowserTest::SetUpOnMainThread(); - ASSERT_TRUE(headless::IsHeadlessMode()); + ASSERT_TRUE(headless::IsHeadlessMode() || headful_mode_); } void HeadlessModeBrowserTestWithStartWindowMode::SetUpCommandLine(
diff --git a/chrome/browser/headless/headless_mode_browsertest.h b/chrome/browser/headless/headless_mode_browsertest.h index 233a6202..1cb2bf0 100644 --- a/chrome/browser/headless/headless_mode_browsertest.h +++ b/chrome/browser/headless/headless_mode_browsertest.h
@@ -23,6 +23,9 @@ void SetUpCommandLine(base::CommandLine* command_line) override; void SetUpOnMainThread() override; + + protected: + bool headful_mode_ = false; }; enum StartWindowMode {
diff --git a/chrome/browser/icon_loader_browsertest.cc b/chrome/browser/icon_loader_browsertest.cc index 1bfb226d1..4e09d38e 100644 --- a/chrome/browser/icon_loader_browsertest.cc +++ b/chrome/browser/icon_loader_browsertest.cc
@@ -59,14 +59,15 @@ base::OnceClosure quit_closure_; }; +// Under GTK, the icon providing functions do not return icons. #if !((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \ defined(MEMORY_SANITIZER)) -const base::FilePath::CharType kGroupOnlyFilename[] = - FILE_PATH_LITERAL("unlikely-to-exist-file.txt"); -// Under GTK, the icon providing functions do not return icons. -IN_PROC_BROWSER_TEST_F(IconLoaderBrowserTest, DISABLED_LoadGroup) { +IN_PROC_BROWSER_TEST_F(IconLoaderBrowserTest, LoadGroup) { float scale = 1.0; + constexpr base::FilePath::CharType kGroupOnlyFilename[] = + FILE_PATH_LITERAL("unlikely-to-exist-file.txt"); + #if BUILDFLAG(IS_WIN) scale = display::win::GetDPIScale(); #endif @@ -81,6 +82,7 @@ runner.Run(); EXPECT_TRUE(test_loader.load_succeeded()); } + #endif // !((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && // defined(MEMORY_SANITIZER))
diff --git a/chrome/browser/icon_loader_mac.mm b/chrome/browser/icon_loader_mac.mm index 535c113a..ec9c7f75 100644 --- a/chrome/browser/icon_loader_mac.mm +++ b/chrome/browser/icon_loader_mac.mm
@@ -5,11 +5,13 @@ #include "chrome/browser/icon_loader.h" #import <AppKit/AppKit.h> -#include <UniformTypeIdentifiers/UniformTypeIdentifiers.h> +#import <CoreServices/CoreServices.h> // pre-macOS 11 +#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h> // macOS 11 #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/mac/foundation_util.h" +#include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" #include "base/task/thread_pool.h" #include "base/threading/thread.h" @@ -19,23 +21,59 @@ // static IconLoader::IconGroup IconLoader::GroupForFilepath( const base::FilePath& file_path) { - NSURL* file_url = base::mac::FilePathToNSURL(file_path); + // The best option is to get the type directly from the file. The next best + // option is to pull the extension from the file and get the type from that. + // The last and worst option is to fall back to `public.content` which will + // give a generic file icon. + if (@available(macOS 11, *)) { UTType* type; - if (![file_url getResourceValue:&type - forKey:NSURLContentTypeKey - error:nil]) { - return {}; + NSURL* file_url = base::mac::FilePathToNSURL(file_path); + if (file_url && [file_url getResourceValue:&type + forKey:NSURLContentTypeKey + error:nil]) { + return base::SysNSStringToUTF8(type.identifier); } - return base::SysNSStringToUTF8(type.identifier); + + std::string extension_string = file_path.FinalExtension(); + if (!extension_string.empty()) { + // Remove the leading dot. + extension_string.erase(extension_string.begin()); + + type = [UTType + typeWithFilenameExtension:base::SysUTF8ToNSString(extension_string)]; + if (type) { + return base::SysNSStringToUTF8(type.identifier); + } + } + + return base::SysNSStringToUTF8(UTTypeContent.identifier); } else { NSString* type; - if (![file_url getResourceValue:&type - forKey:NSURLTypeIdentifierKey - error:nil]) { - return {}; + NSURL* file_url = base::mac::FilePathToNSURL(file_path); + if (file_url && [file_url getResourceValue:&type + forKey:NSURLTypeIdentifierKey + error:nil]) { + return base::SysNSStringToUTF8(type); } - return base::SysNSStringToUTF8(type); + + std::string extension_string = file_path.FinalExtension(); + if (!extension_string.empty()) { + // Remove the leading dot. + extension_string.erase(extension_string.begin()); + + base::ScopedCFTypeRef<CFStringRef> extension_cf = + base::SysUTF8ToCFStringRef(extension_string); + base::ScopedCFTypeRef<CFStringRef> cftype( + UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, + extension_cf, + /*inConformingToUTI=*/nullptr)); + if (cftype) { + return base::SysCFStringRefToUTF8(cftype); + } + } + + return base::SysCFStringRefToUTF8(kUTTypeContent); } } @@ -46,40 +84,36 @@ } void IconLoader::ReadIcon() { - gfx::Image image; + NSImage* icon; + if (@available(macOS 11, *)) { + UTType* type = [UTType typeWithIdentifier:base::SysUTF8ToNSString(group_)]; + icon = [NSWorkspace.sharedWorkspace iconForContentType:type]; + } else { + NSString* type = base::SysUTF8ToNSString(group_); + icon = [NSWorkspace.sharedWorkspace iconForFileType:type]; + } - if (!group_.empty()) { - NSImage* icon; - if (@available(macOS 11, *)) { - UTType* type = - [UTType typeWithIdentifier:base::SysUTF8ToNSString(group_)]; - icon = [NSWorkspace.sharedWorkspace iconForContentType:type]; - } else { - NSString* type = base::SysUTF8ToNSString(group_); - icon = [NSWorkspace.sharedWorkspace iconForFileType:type]; + gfx::Image image; + if (icon_size_ == ALL) { + // The NSImage already has all sizes. + image = gfx::Image(icon); + } else { + NSSize size = NSZeroSize; + switch (icon_size_) { + case IconLoader::SMALL: + size = NSMakeSize(16, 16); + break; + case IconLoader::NORMAL: + size = NSMakeSize(32, 32); + break; + default: + NOTREACHED(); } - if (icon_size_ == ALL) { - // The NSImage already has all sizes. - image = gfx::Image(icon); - } else { - NSSize size = NSZeroSize; - switch (icon_size_) { - case IconLoader::SMALL: - size = NSMakeSize(16, 16); - break; - case IconLoader::NORMAL: - size = NSMakeSize(32, 32); - break; - default: - NOTREACHED(); - } - - gfx::ImageSkia image_skia = gfx::ImageSkiaFromResizedNSImage(icon, size); - if (!image_skia.isNull()) { - image_skia.MakeThreadSafe(); - image = gfx::Image(image_skia); - } + gfx::ImageSkia image_skia = gfx::ImageSkiaFromResizedNSImage(icon, size); + if (!image_skia.isNull()) { + image_skia.MakeThreadSafe(); + image = gfx::Image(image_skia); } }
diff --git a/chrome/browser/login_detection/password_store_sites_browsertest.cc b/chrome/browser/login_detection/password_store_sites_browsertest.cc index ab434d3..7f028a16 100644 --- a/chrome/browser/login_detection/password_store_sites_browsertest.cc +++ b/chrome/browser/login_detection/password_store_sites_browsertest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/password_store_interface.h" #include "components/password_manager/core/browser/test_password_store.h"
diff --git a/chrome/browser/navigation_predictor/anchor_element_preloader.cc b/chrome/browser/navigation_predictor/anchor_element_preloader.cc index cadaff7..3badf2be 100644 --- a/chrome/browser/navigation_predictor/anchor_element_preloader.cc +++ b/chrome/browser/navigation_predictor/anchor_element_preloader.cc
@@ -51,10 +51,10 @@ // likely compute the confidence by looking at different factors (e.g. anchor // element dimensions, last time since scroll, etc.). preloading_data->AddPreloadingPrediction( - ToPreloadingPredictor(ChromePreloadingPredictor::kPointerDownOnAnchor), + chrome_preloading_predictor::kPointerDownOnAnchor, /*confidence=*/100, match_callback); content::PreloadingAttempt* attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor(ChromePreloadingPredictor::kPointerDownOnAnchor), + chrome_preloading_predictor::kPointerDownOnAnchor, content::PreloadingType::kPreconnect, match_callback); if (content::PreloadingEligibility eligibility =
diff --git a/chrome/browser/navigation_predictor/anchor_element_preloader_browsertest.cc b/chrome/browser/navigation_predictor/anchor_element_preloader_browsertest.cc index 78ce006..bbadcc6 100644 --- a/chrome/browser/navigation_predictor/anchor_element_preloader_browsertest.cc +++ b/chrome/browser/navigation_predictor/anchor_element_preloader_browsertest.cc
@@ -71,8 +71,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); ukm_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kPointerDownOnAnchor)); + chrome_preloading_predictor::kPointerDownOnAnchor); test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>(); ASSERT_TRUE(loading_predictor); loading_predictor->preconnect_manager()->SetObserverForTesting(this);
diff --git a/chrome/browser/notifications/BUILD.gn b/chrome/browser/notifications/BUILD.gn index 0547b71..1c7e4f7 100644 --- a/chrome/browser/notifications/BUILD.gn +++ b/chrome/browser/notifications/BUILD.gn
@@ -59,6 +59,7 @@ "android/java/src/org/chromium/chrome/browser/notifications/channels/SiteChannelsManager.java", "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionChangeReceiver.java", "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java", + "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheet.java", "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogController.java", ] @@ -70,6 +71,7 @@ "//chrome/browser/offline_pages/android:java", "//chrome/browser/preferences:java", "//chrome/browser/profiles/android:java", + "//components/browser_ui/bottomsheet/android:java", "//components/browser_ui/notifications/android:java", "//components/browser_ui/settings/android:java", "//components/browser_ui/site_settings/android:java", @@ -112,6 +114,7 @@ "android/java/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitionsTest.java", "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionChangeReceiverTest.java", "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionControllerTest.java", + "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheetTest.java", "android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogControllerTest.java", "android/java/src/org/chromium/chrome/browser/notifications/permissions/TestRationaleDelegate.java", ] @@ -124,6 +127,7 @@ "//chrome/browser/flags:java", "//chrome/browser/preferences:java", "//chrome/test/android:chrome_java_unit_test_support", + "//components/browser_ui/bottomsheet/android:java", "//components/browser_ui/notifications/android:java", "//components/embedder_support/android:junit_test_support", "//components/url_formatter/android:url_formatter_java", @@ -175,6 +179,7 @@ sources = [ "android/java/res/drawable-ldrtl/notification_permission_rationale_dialog_header.xml", "android/java/res/drawable/notification_permission_rationale_dialog_header.xml", + "android/java/res/layout/notification_permission_rationale_bottom_sheet.xml", "android/java/res/layout/notification_permission_rationale_dialog.xml", "android/java/res/values-night/colors.xml", "android/java/res/values/colors.xml",
diff --git a/chrome/browser/notifications/android/java/res/layout/notification_permission_rationale_bottom_sheet.xml b/chrome/browser/notifications/android/java/res/layout/notification_permission_rationale_bottom_sheet.xml new file mode 100644 index 0000000..70fb7b5 --- /dev/null +++ b/chrome/browser/notifications/android/java/res/layout/notification_permission_rationale_bottom_sheet.xml
@@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:orientation="vertical"> + + <ImageView + android:layout_width="250dp" + android:layout_height="0dp" + android:layout_weight="1" + android:layout_marginVertical="24dp" + android:layout_gravity="center_horizontal" + android:importantForAccessibility="no" + android:src="@drawable/notification_permission_rationale_dialog_header" + app:srcCompat="@drawable/notification_permission_rationale_dialog_header" /> + + <TextView + android:id="@+id/notification_permission_rationale_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginHorizontal="16dp" + android:text="@string/notification_permission_rationale_dialog_title" + android:textAppearance="@style/TextAppearance.Headline.Primary" /> + + <TextView + android:id="@+id/notification_permission_rationale_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="12dp" + android:layout_marginHorizontal="16dp" + android:text="@string/notification_permission_rationale_dialog_message" + android:textAppearance="@style/TextAppearance.TextMedium.Primary" /> + + <org.chromium.ui.widget.ButtonCompat + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/notification_permission_rationale_positive_button" + android:layout_marginTop="28dp" + android:layout_marginHorizontal="16dp" + style="@style/FilledButton.Flat" + android:text="@string/notification_permission_rationale_accept_button_text"/> + + <org.chromium.ui.widget.ButtonCompat + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/notification_permission_rationale_negative_button" + android:layout_marginHorizontal="16dp" + style="@style/TextButton" + android:text="@string/notification_permission_rationale_reject_button_text"/> + +</LinearLayout> \ No newline at end of file
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java index 5b323a5..94627dd 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -194,6 +194,13 @@ NotificationRationaleResult.NAVIGATE_BACK_OR_TOUCH_OUTSIDE, NotificationRationaleResult.NOT_ATTACHED_TO_WINDOW, NotificationRationaleResult.ACTIVITY_DESTROYED, + NotificationRationaleResult.BOTTOM_SHEET_BACK_PRESS, + NotificationRationaleResult.BOTTOM_SHEET_SWIPE, + NotificationRationaleResult.BOTTOM_SHEET_TAP_SCRIM, + NotificationRationaleResult.BOTTOM_SHEET_FAILED_TO_OPEN, + NotificationRationaleResult.BOTTOM_SHEET_DESTROYED, + NotificationRationaleResult.BOTTOM_SHEET_CLOSED_UNKNOWN, + NotificationRationaleResult.BOTTOM_SHEET_NEVER_OPENED, NotificationRationaleResult.NUM_ENTRIES}) @Retention(RetentionPolicy.SOURCE) public @interface NotificationRationaleResult { @@ -202,8 +209,15 @@ int NAVIGATE_BACK_OR_TOUCH_OUTSIDE = 2; int ACTIVITY_DESTROYED = 3; int NOT_ATTACHED_TO_WINDOW = 4; + int BOTTOM_SHEET_BACK_PRESS = 5; + int BOTTOM_SHEET_SWIPE = 6; + int BOTTOM_SHEET_TAP_SCRIM = 7; + int BOTTOM_SHEET_FAILED_TO_OPEN = 8; + int BOTTOM_SHEET_DESTROYED = 9; + int BOTTOM_SHEET_CLOSED_UNKNOWN = 10; + int BOTTOM_SHEET_NEVER_OPENED = 11; - int NUM_ENTRIES = 5; + int NUM_ENTRIES = 12; } /**
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java index 99fdc70a..efe8907 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionController.java
@@ -51,6 +51,14 @@ public static final String FIELD_TRIAL_PERMISSION_REQUEST_MAX_COUNT = "permission_request_max_count"; + /** + * Returns whether the bottom sheet rationale UI should be used. + * @return true if the bottom sheet UI should be used, false if the dialog UI should be used. + */ + public static boolean shouldUseBottomSheetRationaleUi() { + return ChromeFeatureList.isEnabled(ChromeFeatureList.NOTIFICATION_PERMISSION_BOTTOM_SHEET); + } + /** Refers to what type of permission UI should be shown. */ @IntDef({PermissionRequestMode.DO_NOT_REQUEST, PermissionRequestMode.REQUEST_ANDROID_PERMISSION, PermissionRequestMode.REQUEST_PERMISSION_WITH_RATIONALE}) @@ -69,13 +77,27 @@ int REQUEST_PERMISSION_WITH_RATIONALE = 2; } + /** + * Refers to the result of trying to show the rationale UI. + */ + @IntDef({RationaleUiResult.ACCEPTED, RationaleUiResult.REJECTED, RationaleUiResult.NOT_SHOWN}) + public @interface RationaleUiResult { + /** Rationale UI was shown and user accepted. */ + int ACCEPTED = 0; + /** Rationale UI was shown and user rejected or dismissed. */ + int REJECTED = 1; + /** Rationale UI couldn't be shown. */ + int NOT_SHOWN = 2; + } + /** A delegate to show an in-app UI demonstrating rationale behind the permission request. */ - interface RationaleDelegate { + public interface RationaleDelegate { /** * Called to show the in-app UI. * @param callback The callback to be invoked as part of the user action on the dialog UI. + * Its argument is a value from {@code RationaleUiResult}. */ - void showRationaleUi(Callback<Boolean> callback); + void showRationaleUi(Callback<Integer> callback); } private static final UnownedUserDataKey<NotificationPermissionController> KEY = @@ -153,18 +175,15 @@ int requestMode = shouldRequestPermission(); if (requestMode == PermissionRequestMode.DO_NOT_REQUEST) return false; - SharedPreferencesManager.getInstance().incrementInt( - ChromePreferenceKeys.NOTIFICATION_PERMISSION_REQUEST_COUNT); - NotificationUmaTracker.getInstance().onNotificationPermissionRequested(); - if (requestMode == PermissionRequestMode.REQUEST_ANDROID_PERMISSION) { requestAndroidPermission(); + recordOsPromptShown(); } else if (requestMode == PermissionRequestMode.REQUEST_PERMISSION_WITH_RATIONALE) { - SharedPreferencesManager.getInstance().writeLong( - ChromePreferenceKeys.NOTIFICATION_PERMISSION_RATIONALE_TIMESTAMP_KEY, - System.currentTimeMillis()); - mRationaleDelegate.showRationaleUi(accept -> { - if (accept) { + mRationaleDelegate.showRationaleUi(rationaleResult -> { + if (rationaleResult != RationaleUiResult.NOT_SHOWN) { + recordRationaleUiShown(); + } + if (rationaleResult == RationaleUiResult.ACCEPTED) { requestAndroidPermission(); } }); @@ -172,6 +191,21 @@ return true; } + private void recordOsPromptShown() { + SharedPreferencesManager.getInstance().incrementInt( + ChromePreferenceKeys.NOTIFICATION_PERMISSION_REQUEST_COUNT); + NotificationUmaTracker.getInstance().onNotificationPermissionRequested(); + } + + private void recordRationaleUiShown() { + SharedPreferencesManager.getInstance().incrementInt( + ChromePreferenceKeys.NOTIFICATION_PERMISSION_REQUEST_COUNT); + NotificationUmaTracker.getInstance().onNotificationPermissionRequested(); + SharedPreferencesManager.getInstance().writeLong( + ChromePreferenceKeys.NOTIFICATION_PERMISSION_RATIONALE_TIMESTAMP_KEY, + System.currentTimeMillis()); + } + @PermissionRequestMode int shouldRequestPermission() { // Notifications only require permission starting at Android T. And apps targeting < T can't
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheet.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheet.java new file mode 100644 index 0000000..e3d8b0d --- /dev/null +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheet.java
@@ -0,0 +1,228 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.notifications.permissions; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.widget.Button; + +import org.chromium.base.Callback; +import org.chromium.chrome.browser.notifications.NotificationUmaTracker; +import org.chromium.chrome.browser.notifications.NotificationUmaTracker.NotificationRationaleResult; +import org.chromium.chrome.browser.notifications.R; +import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleDelegate; +import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleUiResult; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver; +import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver; + +/** + * Bottom sheet to explain the advantages of Chrome notifications. + */ +public class NotificationPermissionRationaleBottomSheet + implements RationaleDelegate, BottomSheetContent { + private final BottomSheetController mBottomSheetController; + private final Context mContext; + private Callback<Integer> mResponseCallback; + private final BottomSheetObserver mBottomSheetObserver; + private View mContentView; + private boolean mWasSheetOpened; + + public NotificationPermissionRationaleBottomSheet( + Context context, BottomSheetController bottomSheetController) { + mBottomSheetController = bottomSheetController; + mContext = context; + + mBottomSheetObserver = new EmptyBottomSheetObserver() { + @Override + public void onSheetClosed(@StateChangeReason int reason) { + // If the callback was already invoked then the user must have explicitly clicked + // one of the buttons. + if (mResponseCallback == null) return; + + switch (reason) { + case StateChangeReason.BACK_PRESS: + executeResponseCallback(RationaleUiResult.REJECTED, + NotificationRationaleResult.BOTTOM_SHEET_BACK_PRESS); + break; + case StateChangeReason.SWIPE: + executeResponseCallback(RationaleUiResult.REJECTED, + NotificationRationaleResult.BOTTOM_SHEET_SWIPE); + break; + case StateChangeReason.TAP_SCRIM: + executeResponseCallback(RationaleUiResult.REJECTED, + NotificationRationaleResult.BOTTOM_SHEET_TAP_SCRIM); + break; + default: + executeResponseCallback(RationaleUiResult.REJECTED, + NotificationRationaleResult.BOTTOM_SHEET_CLOSED_UNKNOWN); + break; + } + } + + @Override + public void onSheetOpened(int reason) { + if (mBottomSheetController.getCurrentSheetContent() + == NotificationPermissionRationaleBottomSheet.this) { + mWasSheetOpened = true; + } + } + + @Override + public void onSheetContentChanged(BottomSheetContent newContent) { + // Destroy the content view when no longer needed, we do it here instead of on + // destroy() because getContentView() is called after it. + if (newContent == null + || newContent != NotificationPermissionRationaleBottomSheet.this) { + destroyContentView(); + } + } + }; + } + + private void initializeContentView() { + if (mContentView != null) return; + + mContentView = LayoutInflater.from(mContext).inflate( + R.layout.notification_permission_rationale_bottom_sheet, null); + // This view will be displayed inside a FrameLayout, if its LayoutParams are not set before + // then FrameLayout will set a default value, which is LayoutParams.MATCH_PARENT for height + // and width. + mContentView.setLayoutParams( + new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + + Button positiveButton = + mContentView.findViewById(R.id.notification_permission_rationale_positive_button); + Button negativeButton = + mContentView.findViewById(R.id.notification_permission_rationale_negative_button); + + positiveButton.setOnClickListener((v) -> { + mBottomSheetController.hideContent(this, /* animate= */ true, + BottomSheetController.StateChangeReason.INTERACTION_COMPLETE); + executeResponseCallback(RationaleUiResult.ACCEPTED, + NotificationRationaleResult.POSITIVE_BUTTON_CLICKED); + }); + negativeButton.setOnClickListener((view -> { + mBottomSheetController.hideContent(this, /* animate= */ true, + BottomSheetController.StateChangeReason.INTERACTION_COMPLETE); + executeResponseCallback(RationaleUiResult.REJECTED, + NotificationRationaleResult.NEGATIVE_BUTTON_CLICKED); + })); + } + + private void executeResponseCallback(@RationaleUiResult int callbackResult, + @NotificationRationaleResult int detailedResultForMetrics) { + NotificationUmaTracker.getInstance().onNotificationPermissionRationaleResult( + detailedResultForMetrics); + + mResponseCallback.onResult(callbackResult); + mResponseCallback = null; + } + + /* RationaleDelegate implementation. */ + @Override + public void showRationaleUi(Callback<Integer> callback) { + assert mResponseCallback == null; + assert !mBottomSheetController.isSheetOpen(); + + initializeContentView(); + + mResponseCallback = callback; + mBottomSheetController.addObserver(mBottomSheetObserver); + if (!mBottomSheetController.requestShowContent(this, /* animate= */ true)) { + executeResponseCallback(RationaleUiResult.NOT_SHOWN, + NotificationRationaleResult.BOTTOM_SHEET_FAILED_TO_OPEN); + destroy(); + } + } + + private void destroyContentView() { + mBottomSheetController.removeObserver(mBottomSheetObserver); + mContentView = null; + } + + /* BottomSheetContent implementation. */ + @Override + public View getContentView() { + return mContentView; + } + + @Override + public View getToolbarView() { + return null; + } + + @Override + public int getVerticalScrollOffset() { + return 0; + } + + @Override + public void destroy() { + if (mResponseCallback != null) { + if (!mWasSheetOpened) { + // Some startup cases may destroy the action sheet before it's shown. + executeResponseCallback(RationaleUiResult.NOT_SHOWN, + NotificationRationaleResult.BOTTOM_SHEET_NEVER_OPENED); + // If the content view was never shown then destroy it here, otherwise wait until it + // has been replaced (see onSheetContentChanged). + } else { + executeResponseCallback(RationaleUiResult.REJECTED, + NotificationRationaleResult.BOTTOM_SHEET_DESTROYED); + } + } + } + + @Override + public int getPriority() { + return ContentPriority.HIGH; + } + + @Override + public int getPeekHeight() { + return HeightMode.DISABLED; + } + + @Override + public float getHalfHeightRatio() { + return HeightMode.DISABLED; + } + + @Override + public float getFullHeightRatio() { + return HeightMode.WRAP_CONTENT; + } + + @Override + public boolean swipeToDismissEnabled() { + return false; + } + + @Override + public int getSheetContentDescriptionStringId() { + return R.string.notification_permission_rationale_content_description; + } + + @Override + public int getSheetHalfHeightAccessibilityStringId() { + // Half-height is disabled so no need for an accessibility string. + assert false : "This method should not be called"; + return 0; + } + + @Override + public int getSheetFullHeightAccessibilityStringId() { + return R.string.notification_permission_rationale_opened_full; + } + + @Override + public int getSheetClosedAccessibilityStringId() { + return R.string.notification_permission_rationale_closed_description; + } +}
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheetTest.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheetTest.java new file mode 100644 index 0000000..0590a93 --- /dev/null +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleBottomSheetTest.java
@@ -0,0 +1,239 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.notifications.permissions; + +import static androidx.test.espresso.matcher.ViewMatchers.assertThat; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.view.View; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import org.chromium.base.Callback; +import org.chromium.base.metrics.RecordHistogram; +import org.chromium.base.metrics.UmaRecorderHolder; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.notifications.NotificationUmaTracker.NotificationRationaleResult; +import org.chromium.chrome.browser.notifications.R; +import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleUiResult; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver; + +/** + * Tests for {@link NotificationPermissionRationaleBottomSheet}. + */ +@RunWith(BaseRobolectricTestRunner.class) +public class NotificationPermissionRationaleBottomSheetTest { + private BottomSheetController mBottomSheetController; + private Context mContext; + + @Captor + ArgumentCaptor<BottomSheetObserver> mBottomSheetObserverCaptor; + + @Mock + Callback<Integer> mMockCallback; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + UmaRecorderHolder.resetForTesting(); + mBottomSheetController = Mockito.mock(BottomSheetController.class); + when(mBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true); + + mContext = ApplicationProvider.getApplicationContext(); + } + + @Test + public void testShowBottomSheet() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + + // Show the bottom sheet, we don't dismiss it so the callback shouldn't be called. + bottomSheet.showRationaleUi(mMockCallback); + + verify(mBottomSheetController).requestShowContent(bottomSheet, true); + verify(mBottomSheetController).addObserver(any()); + + View bottomSheetContentView = bottomSheet.getContentView(); + + assertNotNull(bottomSheetContentView); + + View bottomSheetTitle = + bottomSheetContentView.findViewById(R.id.notification_permission_rationale_title); + View bottomSheetMessage = + bottomSheetContentView.findViewById(R.id.notification_permission_rationale_message); + + verify(mMockCallback, never()).onResult(anyInt()); + // Check that the custom view contains the expected title and message. + assertThat(bottomSheetTitle, + withText(R.string.notification_permission_rationale_dialog_title)); + assertThat(bottomSheetMessage, + withText(R.string.notification_permission_rationale_dialog_message)); + } + + @Test + public void testRejectBottomSheet() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + + bottomSheet.showRationaleUi(mMockCallback); + + View bottomSheetContentView = bottomSheet.getContentView(); + View bottomSheetNegativeButton = bottomSheetContentView.findViewById( + R.id.notification_permission_rationale_negative_button); + bottomSheetNegativeButton.performClick(); + + verify(mMockCallback).onResult(RationaleUiResult.REJECTED); + assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "Mobile.SystemNotification.Permission.RationaleResult", + NotificationRationaleResult.NEGATIVE_BUTTON_CLICKED)); + } + + @Test + public void testDismissBottomSheet_BackPress() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + + bottomSheet.showRationaleUi(mMockCallback); + + verify(mBottomSheetController).addObserver(mBottomSheetObserverCaptor.capture()); + + mBottomSheetObserverCaptor.getValue().onSheetClosed(StateChangeReason.BACK_PRESS); + + verify(mMockCallback).onResult(RationaleUiResult.REJECTED); + assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "Mobile.SystemNotification.Permission.RationaleResult", + NotificationRationaleResult.BOTTOM_SHEET_BACK_PRESS)); + } + + @Test + public void testDismissBottomSheet_SwipeAway() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + + bottomSheet.showRationaleUi(mMockCallback); + + verify(mBottomSheetController).addObserver(mBottomSheetObserverCaptor.capture()); + + mBottomSheetObserverCaptor.getValue().onSheetClosed(StateChangeReason.SWIPE); + + verify(mMockCallback).onResult(RationaleUiResult.REJECTED); + assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "Mobile.SystemNotification.Permission.RationaleResult", + NotificationRationaleResult.BOTTOM_SHEET_SWIPE)); + } + + @Test + public void testDismissBottomSheet_TapOutside() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + + bottomSheet.showRationaleUi(mMockCallback); + + verify(mBottomSheetController).addObserver(mBottomSheetObserverCaptor.capture()); + + mBottomSheetObserverCaptor.getValue().onSheetClosed(StateChangeReason.TAP_SCRIM); + + verify(mMockCallback).onResult(RationaleUiResult.REJECTED); + assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "Mobile.SystemNotification.Permission.RationaleResult", + NotificationRationaleResult.BOTTOM_SHEET_TAP_SCRIM)); + } + + @Test + public void testAcceptBottomSheet() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + + bottomSheet.showRationaleUi(mMockCallback); + + View bottomSheetContentView = bottomSheet.getContentView(); + View bottomSheetPositiveButton = bottomSheetContentView.findViewById( + R.id.notification_permission_rationale_positive_button); + bottomSheetPositiveButton.performClick(); + + verify(mMockCallback).onResult(RationaleUiResult.ACCEPTED); + assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "Mobile.SystemNotification.Permission.RationaleResult", + NotificationRationaleResult.POSITIVE_BUTTON_CLICKED)); + } + + @Test + public void testResultBottomSheetDestroyed_AfterOpened() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + when(mBottomSheetController.getCurrentSheetContent()).thenReturn(bottomSheet); + + bottomSheet.showRationaleUi(mMockCallback); + + verify(mBottomSheetController).addObserver(mBottomSheetObserverCaptor.capture()); + mBottomSheetObserverCaptor.getValue().onSheetOpened(StateChangeReason.NONE); + + bottomSheet.destroy(); + + verify(mMockCallback).onResult(RationaleUiResult.REJECTED); + assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "Mobile.SystemNotification.Permission.RationaleResult", + NotificationRationaleResult.BOTTOM_SHEET_DESTROYED)); + } + + @Test + public void testResultBottomSheetDestroyed_WithoutOpening() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + + bottomSheet.showRationaleUi(mMockCallback); + + bottomSheet.destroy(); + + verify(mMockCallback).onResult(RationaleUiResult.NOT_SHOWN); + assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "Mobile.SystemNotification.Permission.RationaleResult", + NotificationRationaleResult.BOTTOM_SHEET_NEVER_OPENED)); + } + + @Test + public void testResultBottomSheetFailedToOpen() { + NotificationPermissionRationaleBottomSheet bottomSheet = + new NotificationPermissionRationaleBottomSheet(mContext, mBottomSheetController); + Mockito.when(mBottomSheetController.requestShowContent(any(), anyBoolean())) + .thenReturn(false); + + bottomSheet.showRationaleUi(mMockCallback); + + verify(mMockCallback).onResult(RationaleUiResult.NOT_SHOWN); + assertEquals(1, + RecordHistogram.getHistogramValueCountForTesting( + "Mobile.SystemNotification.Permission.RationaleResult", + NotificationRationaleResult.BOTTOM_SHEET_FAILED_TO_OPEN)); + } +} \ No newline at end of file
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogController.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogController.java index 50a3fc1..19d5bb4 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogController.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogController.java
@@ -8,14 +8,13 @@ import android.content.res.Resources; import android.view.LayoutInflater; import android.view.View; -import android.widget.TextView; import org.chromium.base.Callback; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; import org.chromium.chrome.browser.notifications.NotificationUmaTracker.NotificationRationaleResult; import org.chromium.chrome.browser.notifications.R; import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleDelegate; +import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleUiResult; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType; @@ -28,8 +27,6 @@ * Dialog to explain the advantages of Chrome notifications. */ public class NotificationPermissionRationaleDialogController implements RationaleDelegate { - public static final String DIALOG_TEXT_VARIANT_2 = - "notification_permission_dialog_text_variant_2"; private final ModalDialogManager mModalDialogManager; private final Context mContext; @@ -50,23 +47,12 @@ * notifications. */ @Override - public void showRationaleUi(Callback<Boolean> rationaleCallback) { + public void showRationaleUi(Callback<Integer> rationaleCallback) { LayoutInflater inflater = LayoutInflater.from(mContext); Resources resources = mContext.getResources(); View dialogView = inflater.inflate(R.layout.notification_permission_rationale_dialog, /* root= */ null); - TextView titleView = dialogView.findViewById(R.id.notification_permission_rationale_title); - TextView descriptionView = - dialogView.findViewById(R.id.notification_permission_rationale_message); - boolean shouldShowVariant2 = ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( - ChromeFeatureList.NOTIFICATION_PERMISSION_VARIANT, DIALOG_TEXT_VARIANT_2, false); - titleView.setText(shouldShowVariant2 - ? R.string.notification_permission_rationale_dialog_title_variation_2 - : R.string.notification_permission_rationale_dialog_title); - descriptionView.setText(shouldShowVariant2 - ? R.string.notification_permission_rationale_dialog_message_variation_2 - : R.string.notification_permission_rationale_dialog_message); PropertyModel.Builder dialogModelBuilder = new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS) @@ -87,7 +73,7 @@ mModalDialogManager.showDialog(dialogModel, ModalDialogType.APP); } - private Callback<Integer> wrapDialogDismissalCallback(Callback<Boolean> rationaleCallback) { + private Callback<Integer> wrapDialogDismissalCallback(Callback<Integer> rationaleCallback) { return result -> { @NotificationRationaleResult int resultEnumValue; @@ -112,7 +98,9 @@ NotificationUmaTracker.getInstance().onNotificationPermissionRationaleResult( resultEnumValue); - rationaleCallback.onResult(result == DialogDismissalCause.POSITIVE_BUTTON_CLICKED); + rationaleCallback.onResult(result == DialogDismissalCause.POSITIVE_BUTTON_CLICKED + ? RationaleUiResult.ACCEPTED + : RationaleUiResult.REJECTED); }; } }
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogControllerTest.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogControllerTest.java index 2a08243..0042478f 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogControllerTest.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/NotificationPermissionRationaleDialogControllerTest.java
@@ -24,15 +24,12 @@ import org.mockito.Mockito; import org.chromium.base.Callback; -import org.chromium.base.FeatureList; -import org.chromium.base.FeatureList.TestValues; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.UmaRecorderHolder; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.notifications.NotificationUmaTracker.NotificationRationaleResult; import org.chromium.chrome.browser.notifications.R; -import org.chromium.chrome.test.util.browser.Features; +import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleUiResult; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogProperties; @@ -43,7 +40,6 @@ * Tests for {@link NotificationPermissionRationaleDialogController}. */ @RunWith(BaseRobolectricTestRunner.class) -@Features.DisableFeatures(ChromeFeatureList.NOTIFICATION_PERMISSION_VARIANT) public class NotificationPermissionRationaleDialogControllerTest { private ModalDialogManager mModalDialogManager; private Context mContext; @@ -54,11 +50,6 @@ mModalDialogManager = new ModalDialogManager(Mockito.mock(ModalDialogManager.Presenter.class), 0); mContext = ApplicationProvider.getApplicationContext(); - FeatureList.TestValues testValues = new TestValues(); - testValues.addFieldTrialParamOverride(ChromeFeatureList.NOTIFICATION_PERMISSION_VARIANT, - NotificationPermissionRationaleDialogController.DIALOG_TEXT_VARIANT_2, - Boolean.toString(false)); - FeatureList.setTestValues(testValues); } @Test @@ -99,14 +90,14 @@ NotificationPermissionRationaleDialogController dialog = new NotificationPermissionRationaleDialogController(mContext, mModalDialogManager); - Callback<Boolean> mockCallback = Mockito.mock(Callback.class); + Callback<Integer> mockCallback = Mockito.mock(Callback.class); dialog.showRationaleUi(mockCallback); PropertyModel dialogModel = mModalDialogManager.getCurrentDialogForTest(); mModalDialogManager.dismissDialog( dialogModel, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED); - verify(mockCallback).onResult(false); + verify(mockCallback).onResult(RationaleUiResult.REJECTED); assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "Mobile.SystemNotification.Permission.RationaleResult", @@ -118,14 +109,14 @@ NotificationPermissionRationaleDialogController dialog = new NotificationPermissionRationaleDialogController(mContext, mModalDialogManager); - Callback<Boolean> mockCallback = Mockito.mock(Callback.class); + Callback<Integer> mockCallback = Mockito.mock(Callback.class); dialog.showRationaleUi(mockCallback); PropertyModel dialogModel = mModalDialogManager.getCurrentDialogForTest(); mModalDialogManager.dismissDialog( dialogModel, DialogDismissalCause.NAVIGATE_BACK_OR_TOUCH_OUTSIDE); - verify(mockCallback).onResult(false); + verify(mockCallback).onResult(RationaleUiResult.REJECTED); assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "Mobile.SystemNotification.Permission.RationaleResult", @@ -137,14 +128,14 @@ NotificationPermissionRationaleDialogController dialog = new NotificationPermissionRationaleDialogController(mContext, mModalDialogManager); - Callback<Boolean> mockCallback = Mockito.mock(Callback.class); + Callback<Integer> mockCallback = Mockito.mock(Callback.class); dialog.showRationaleUi(mockCallback); PropertyModel dialogModel = mModalDialogManager.getCurrentDialogForTest(); mModalDialogManager.dismissDialog( dialogModel, DialogDismissalCause.POSITIVE_BUTTON_CLICKED); - verify(mockCallback).onResult(true); + verify(mockCallback).onResult(RationaleUiResult.ACCEPTED); assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "Mobile.SystemNotification.Permission.RationaleResult", @@ -156,13 +147,13 @@ NotificationPermissionRationaleDialogController dialog = new NotificationPermissionRationaleDialogController(mContext, mModalDialogManager); - Callback<Boolean> mockCallback = Mockito.mock(Callback.class); + Callback<Integer> mockCallback = Mockito.mock(Callback.class); dialog.showRationaleUi(mockCallback); PropertyModel dialogModel = mModalDialogManager.getCurrentDialogForTest(); mModalDialogManager.dismissDialog(dialogModel, DialogDismissalCause.ACTIVITY_DESTROYED); - verify(mockCallback).onResult(false); + verify(mockCallback).onResult(RationaleUiResult.REJECTED); assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "Mobile.SystemNotification.Permission.RationaleResult", @@ -174,13 +165,13 @@ NotificationPermissionRationaleDialogController dialog = new NotificationPermissionRationaleDialogController(mContext, mModalDialogManager); - Callback<Boolean> mockCallback = Mockito.mock(Callback.class); + Callback<Integer> mockCallback = Mockito.mock(Callback.class); dialog.showRationaleUi(mockCallback); PropertyModel dialogModel = mModalDialogManager.getCurrentDialogForTest(); mModalDialogManager.dismissDialog(dialogModel, DialogDismissalCause.NOT_ATTACHED_TO_WINDOW); - verify(mockCallback).onResult(false); + verify(mockCallback).onResult(RationaleUiResult.REJECTED); assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( "Mobile.SystemNotification.Permission.RationaleResult",
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/TestRationaleDelegate.java b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/TestRationaleDelegate.java index 329a6c6..3764c35 100644 --- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/TestRationaleDelegate.java +++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/permissions/TestRationaleDelegate.java
@@ -6,6 +6,7 @@ import org.chromium.base.Callback; import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleDelegate; +import org.chromium.chrome.browser.notifications.permissions.NotificationPermissionController.RationaleUiResult; import org.chromium.ui.modaldialog.DialogDismissalCause; /** @@ -16,13 +17,13 @@ private int mCallCount; @Override - public void showRationaleUi(Callback<Boolean> callback) { + public void showRationaleUi(Callback<Integer> callback) { assert mDialogAction != null; mCallCount++; if (mDialogAction == DialogDismissalCause.POSITIVE_BUTTON_CLICKED) { - callback.onResult(true); + callback.onResult(RationaleUiResult.ACCEPTED); } else { - callback.onResult(false); + callback.onResult(RationaleUiResult.REJECTED); } }
diff --git a/chrome/browser/performance_manager/browser_child_process_watcher.cc b/chrome/browser/performance_manager/browser_child_process_watcher.cc index d5a2304..56658986 100644 --- a/chrome/browser/performance_manager/browser_child_process_watcher.cc +++ b/chrome/browser/performance_manager/browser_child_process_watcher.cc
@@ -59,7 +59,8 @@ data.process_type == content::PROCESS_TYPE_UTILITY) { std::unique_ptr<ProcessNodeImpl> process_node = PerformanceManagerImpl::CreateProcessNode( - static_cast<content::ProcessType>(data.process_type)); + static_cast<content::ProcessType>(data.process_type), + BrowserChildProcessHostProxy(BrowserChildProcessHostId(data.id))); OnProcessLaunched(data.GetProcess(), data.metrics_name, process_node.get()); tracked_process_nodes_[data.id] = std::move(process_node); }
diff --git a/chrome/browser/predictors/autocomplete_action_predictor.cc b/chrome/browser/predictors/autocomplete_action_predictor.cc index f888eff..5911aecb 100644 --- a/chrome/browser/predictors/autocomplete_action_predictor.cc +++ b/chrome/browser/predictors/autocomplete_action_predictor.cc
@@ -212,8 +212,7 @@ // this prerendering attempt for Prerender. content::PreloadingAttempt* preloading_attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput), + chrome_preloading_predictor::kOmniboxDirectURLInput, content::PreloadingType::kPrerender, std::move(same_url_matcher)); PrerenderManager::CreateForWebContents(&web_contents); @@ -227,8 +226,7 @@ // this preloading attempt for NoStatePrefetch. content::PreloadingAttempt* preloading_attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput), + chrome_preloading_predictor::kOmniboxDirectURLInput, content::PreloadingType::kNoStatePrefetch, std::move(same_url_matcher)); @@ -318,8 +316,7 @@ // We multiply confidence by 100 to pass the percentage and cast it into int // for logs. preloading_data->AddPreloadingPrediction( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput), + chrome_preloading_predictor::kOmniboxDirectURLInput, static_cast<int64_t>(confidence * 100), std::move(same_url_matcher)); }
diff --git a/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc b/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc index 7b6711d..0879424 100644 --- a/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc +++ b/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc
@@ -123,8 +123,7 @@ profile_.get(), nullptr); ukm_entry_builder_ = std::make_unique<content::test::PreloadingPredictionUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput)); + chrome_preloading_predictor::kOmniboxDirectURLInput); test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>();
diff --git a/chrome/browser/preloading/chrome_preloading.cc b/chrome/browser/preloading/chrome_preloading.cc index f4262c0..e2cffc3 100644 --- a/chrome/browser/preloading/chrome_preloading.cc +++ b/chrome/browser/preloading/chrome_preloading.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/preloading/chrome_preloading.h" + #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "components/search_engines/template_url.h" @@ -10,8 +11,6 @@ #include "content/public/browser/browser_context.h" #include "url/gurl.h" -using content::PreloadingPredictor; - namespace { bool IsSideSearch(content::BrowserContext* browser_context, const GURL& url) { @@ -31,11 +30,6 @@ } // namespace -content::PreloadingPredictor ToPreloadingPredictor( - ChromePreloadingPredictor predictor) { - return static_cast<content::PreloadingPredictor>(predictor); -} - content::PreloadingEligibility ToPreloadingEligibility( ChromePreloadingEligibility eligibility) { return static_cast<content::PreloadingEligibility>(eligibility);
diff --git a/chrome/browser/preloading/chrome_preloading.h b/chrome/browser/preloading/chrome_preloading.h index c80387f..23202b22 100644 --- a/chrome/browser/preloading/chrome_preloading.h +++ b/chrome/browser/preloading/chrome_preloading.h
@@ -13,63 +13,66 @@ #include "url/gurl.h" class TemplateURLService; -using content::PreloadingPredictor; -// If you change any of the following emums, please follow the process in -// go/preloading-dashboard-updates to update the mapping reflected in -// dashboard, or if you are not a Googler, please file an FYI bug on -// https://crbug.new with component Internals>Preload. +// If you change any of the following enums or static variables, please follow +// the process in go/preloading-dashboard-updates to update the mapping +// reflected in dashboard, or if you are not a Googler, please file an FYI bug +// on https://crbug.new with component Internals>Preload. // Defines various embedder triggering mechanisms which triggers different // preloading operations mentioned in //content/public/browser/preloading.h. // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. -enum class ChromePreloadingPredictor { - // Numbering starts from `kPreloadingPredictorContentEnd` defined in - // //content/browser/public/preloading.h . Advance numbering by +1 when adding - // a new element. +// +// Advance numbering by +1 when adding a new element. +// +// Please make sure Chrome `PreloadingPredictor` are defined after 100 +// (inclusive) as 99 and below are reserved for content-public and +// content-internal definitions. Both the value and the name should be unique +// across all the namespaces. +namespace chrome_preloading_predictor { +// When the preloading URL is predicted from the Omnibox Direct URL Input +// (DUI). This is used to perform various preloading operations like prefetch +// and prerender to load Omnibox predicted URLs faster. +static constexpr content::PreloadingPredictor kOmniboxDirectURLInput( + 100, + "OmniboxDirectURLInput"); - // When the preloading URL is predicted from the Omnibox Direct URL Input - // (DUI). This is used to perform various preloading operations like prefetch - // and prerender to load Omnibox predicted URLs faster. - kOmniboxDirectURLInput = - static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd), +// When a pointerdown (e.g. mousedown or touchstart) event happens on an +// anchor element with an href value pointing to an HTTP(S) origin, we may +// attempt to preload the link. +static constexpr content::PreloadingPredictor kPointerDownOnAnchor( + 101, + "PointerDownOnAnchor"); - // When a pointerdown (e.g. mousedown or touchstart) event happens on an - // anchor element with an href value pointing to an HTTP(S) origin, we may - // attempt to preload the link. - kPointerDownOnAnchor = - static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd) + 1, +// When the preloading URL is predicted from the default search suggest +// service for faster search page loads. +static constexpr content::PreloadingPredictor kDefaultSearchEngine( + 102, + "DefaultSearchEngine"); - // When the preloading URL is predicted from the default search suggest - // service for faster search page loads. - kDefaultSearchEngine = - static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd) + 2, +// When the preloading URL is predicted from the default search suggest due to +// change in Omnibox selection. +static constexpr content::PreloadingPredictor kOmniboxSearchPredictor( + 103, + "OmniboxSearchPredictor"); - // When the preloading URL is predicted from the default search suggest due to - // change in Omnibox selection. - kOmniboxSearchPredictor = - static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd) + 3, +// When the preloading URL is predicted from the default search suggest due to +// mouse being pressed down on a Omnibox Search suggestion. +static constexpr content::PreloadingPredictor kOmniboxMousePredictor( + 104, + "OmniboxMousePredictor"); - // When the preloading URL is predicted from the default search suggest due to - // mouse being pressed down on a Omnibox Search suggestion. - kOmniboxMousePredictor = - static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd) + 4, +// When the default match in omnibox has the search prefetch or prerender +// hint. +static constexpr content::PreloadingPredictor kOmniboxSearchSuggestDefaultMatch( + 105, + "OmniboxSearchSuggestDefaultMatch"); - // When the default match in omnibox has the search prefetch or prerender - // hint. - kOmniboxSearchSuggestDefaultMatch = - static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd) + 5, - - // TODO(crbug.com/1309934): Integrate more Preloading predictors with - // Preloading logging APIs. -}; - -// Helper method to convert ChromePreloadingPredictor to -// content::PreloadingPredictor to avoid casting. -content::PreloadingPredictor ToPreloadingPredictor( - ChromePreloadingPredictor predictor); +// TODO(crbug.com/1309934): Integrate more Preloading predictors with +// Preloading logging APIs. +} // namespace chrome_preloading_predictor // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused.
diff --git a/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc index 2ece4a6..8097cab 100644 --- a/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc +++ b/chrome/browser/preloading/prefetch/no_state_prefetch/prerender_nostate_prefetch_browsertest.cc
@@ -305,11 +305,10 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); omnibox_attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput)); + chrome_preloading_predictor::kOmniboxDirectURLInput); link_rel_attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - content::PreloadingPredictor::kLinkRel); + content::preloading_predictor::kLinkRel); test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>(); host_resolver()->AddRule("*", "127.0.0.1"); }
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc index fd07c11..3a8543e 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_browser_test_base.cc
@@ -10,6 +10,7 @@ #include "base/task/single_thread_task_runner.h" #include "chrome/browser/devtools/devtools_window.h" #include "chrome/browser/devtools/devtools_window_testing.h" +#include "chrome/browser/preloading/chrome_preloading.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_request.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h"
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc index fcff469..92b86fa 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.cc
@@ -197,14 +197,14 @@ const GURL& url, content::WebContents* web_contents) { return MaybePrefetchURL(url, /*navigation_prefetch=*/false, web_contents, - ChromePreloadingPredictor::kDefaultSearchEngine); + chrome_preloading_predictor::kDefaultSearchEngine); } bool SearchPrefetchService::MaybePrefetchURL( const GURL& url, bool navigation_prefetch, content::WebContents* web_contents, - ChromePreloadingPredictor predictor) { + content::PreloadingPredictor predictor) { if (!SearchPrefetchServicePrefetchingIsEnabled()) return false; @@ -242,8 +242,7 @@ // this DefaultSearchEngine or OmniboxSearchPredictor prefetch attempt when // |navigation_prefetch| is true. attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor(predictor), content::PreloadingType::kPrefetch, - same_url_matcher); + predictor, content::PreloadingType::kPrefetch, same_url_matcher); if (!search_with_terms) { recorder.reason_ = @@ -648,8 +647,8 @@ // Create PreloadingPrediction for this match. preloading_data->AddPreloadingPrediction( - ToPreloadingPredictor(ChromePreloadingPredictor::kDefaultSearchEngine), - confidence, std::move(same_url_matcher)); + chrome_preloading_predictor::kDefaultSearchEngine, confidence, + std::move(same_url_matcher)); // Record a prediction for default match prefetch suggest predictions. if (result.default_match() == &match) { @@ -662,8 +661,7 @@ // Create PreloadingPrediction for this match. preloading_data->AddPreloadingPrediction( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxSearchSuggestDefaultMatch), + chrome_preloading_predictor::kOmniboxSearchSuggestDefaultMatch, confidence, std::move(same_url_matcher)); } else if (OnlyAllowDefaultMatchPreloading()) { // Only prefetch default match when in the experiment. @@ -781,17 +779,17 @@ [](NavigationPredictor navigation_predictor) { switch (navigation_predictor) { case NavigationPredictor::kMouseDown: - return ChromePreloadingPredictor::kOmniboxMousePredictor; + return chrome_preloading_predictor::kOmniboxMousePredictor; case NavigationPredictor::kUpOrDownArrowButton: - return ChromePreloadingPredictor::kOmniboxSearchPredictor; + return chrome_preloading_predictor::kOmniboxSearchPredictor; } }; auto predictor = navigation_likely_event_to_predictor(navigation_predictor); // Create PreloadingPrediction for this match. We set the confidence to 100 as // when the user changed the selected match, we always trigger prefetch. - preloading_data->AddPreloadingPrediction(ToPreloadingPredictor(predictor), - 100, std::move(same_url_matcher)); + preloading_data->AddPreloadingPrediction(predictor, 100, + std::move(same_url_matcher)); MaybePrefetchURL(preload_url, /*navigation_prefetch=*/true, web_contents, predictor); } @@ -998,8 +996,7 @@ content::PreloadingData::GetOrCreateForWebContents(web_contents); content::PreloadingAttempt* preloading_attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine), + chrome_preloading_predictor::kDefaultSearchEngine, content::PreloadingType::kPrerender, same_url_matcher); auto prefetch_request_iter = prefetches_.find(canonical_search_url);
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h index 04550b0..ec05044 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h
@@ -15,7 +15,6 @@ #include "base/scoped_observation.h" #include "base/time/time.h" #include "base/timer/timer.h" -#include "chrome/browser/preloading/chrome_preloading.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_request.h" #include "components/keyed_service/core/keyed_service.h" #include "components/omnibox/browser/autocomplete_match.h" @@ -23,6 +22,7 @@ #include "components/search_engines/template_url_data.h" #include "components/search_engines/template_url_service.h" #include "components/search_engines/template_url_service_observer.h" +#include "content/public/browser/preloading.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" @@ -211,7 +211,7 @@ bool MaybePrefetchURL(const GURL& url, bool navigation_prefetch, content::WebContents* web_contents, - ChromePreloadingPredictor predictor); + content::PreloadingPredictor predictor); // Adds |this| as an observer of |template_url_service| if not added already. void ObserveTemplateURLService(TemplateURLService* template_url_service);
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc index b281b21..553e093 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
@@ -36,6 +36,7 @@ #include "components/omnibox/browser/omnibox_view.h" #include "components/prefs/pref_service.h" #include "components/search_engines/template_url_service.h" +#include "content/public/browser/preloading.h" #include "content/public/browser/service_worker_context.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/content_client.h" @@ -266,8 +267,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine)); + chrome_preloading_predictor::kDefaultSearchEngine); } ukm::TestAutoSetUkmRecorder* test_ukm_recorder() { @@ -331,8 +331,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine)); + chrome_preloading_predictor::kDefaultSearchEngine); scoped_test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>(); } @@ -436,8 +435,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine)); + chrome_preloading_predictor::kDefaultSearchEngine); scoped_test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>(); } @@ -3510,15 +3508,15 @@ } std::unique_ptr<content::test::PreloadingAttemptUkmEntryBuilder> - attempt_entry_builder(ChromePreloadingPredictor predictor) { + attempt_entry_builder(content::PreloadingPredictor predictor) { return std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor(predictor)); + predictor); } std::unique_ptr<content::test::PreloadingPredictionUkmEntryBuilder> - prediction_entry_builder(ChromePreloadingPredictor predictor) { + prediction_entry_builder(content::PreloadingPredictor predictor) { return std::make_unique<content::test::PreloadingPredictionUkmEntryBuilder>( - ToPreloadingPredictor(predictor)); + predictor); } ukm::TestAutoSetUkmRecorder* test_ukm_recorder() { @@ -3587,12 +3585,13 @@ // Check that PreloadingAttempt is successful and accurately triggered. std::vector<UkmEntry> expected_prediction_entries = { prediction_entry_builder( - ChromePreloadingPredictor::kOmniboxMousePredictor) + chrome_preloading_predictor::kOmniboxMousePredictor) ->BuildEntry(ukm_source_id, /*confidence=*/100, /*accurate_prediction=*/true)}; std::vector<UkmEntry> expected_attempt_entries = { - attempt_entry_builder(ChromePreloadingPredictor::kOmniboxMousePredictor) + attempt_entry_builder( + chrome_preloading_predictor::kOmniboxMousePredictor) ->BuildEntry(ukm_source_id, content::PreloadingType::kPrefetch, content::PreloadingEligibility::kEligible, content::PreloadingHoldbackStatus::kAllowed, @@ -3668,13 +3667,13 @@ // Check that PreloadingAttempt is successful and accurately triggered. std::vector<UkmEntry> expected_prediction_entries = { prediction_entry_builder( - ChromePreloadingPredictor::kOmniboxSearchPredictor) + chrome_preloading_predictor::kOmniboxSearchPredictor) ->BuildEntry(ukm_source_id, /*confidence=*/100, /*accurate_prediction=*/true)}; std::vector<UkmEntry> expected_attempt_entries = { attempt_entry_builder( - ChromePreloadingPredictor::kOmniboxSearchPredictor) + chrome_preloading_predictor::kOmniboxSearchPredictor) ->BuildEntry(ukm_source_id, content::PreloadingType::kPrefetch, content::PreloadingEligibility::kEligible, content::PreloadingHoldbackStatus::kAllowed, @@ -3870,8 +3869,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxSearchPredictor)); + chrome_preloading_predictor::kOmniboxSearchPredictor); scoped_test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>(); } @@ -3966,8 +3964,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxSearchPredictor)); + chrome_preloading_predictor::kOmniboxSearchPredictor); } ukm::TestAutoSetUkmRecorder* test_ukm_recorder() {
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc index d93ecec..2d96638 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc
@@ -150,12 +150,10 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine)); + chrome_preloading_predictor::kDefaultSearchEngine); prediction_entry_builder_ = std::make_unique<content::test::PreloadingPredictionUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine)); + chrome_preloading_predictor::kDefaultSearchEngine); scoped_test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>(); }
diff --git a/chrome/browser/preloading/prerender/omnibox_prerender_browsertest.cc b/chrome/browser/preloading/prerender/omnibox_prerender_browsertest.cc index 19be709..62887c8e 100644 --- a/chrome/browser/preloading/prerender/omnibox_prerender_browsertest.cc +++ b/chrome/browser/preloading/prerender/omnibox_prerender_browsertest.cc
@@ -77,8 +77,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); ukm_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput)); + chrome_preloading_predictor::kOmniboxDirectURLInput); test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>(); ASSERT_TRUE(embedded_test_server()->Start()); }
diff --git a/chrome/browser/preloading/prerender/prerender_manager.cc b/chrome/browser/preloading/prerender/prerender_manager.cc index 50b7fd9d..e7edeb95 100644 --- a/chrome/browser/preloading/prerender/prerender_manager.cc +++ b/chrome/browser/preloading/prerender/prerender_manager.cc
@@ -389,8 +389,7 @@ // this prerendering attempt. content::PreloadingAttempt* preloading_attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine), + chrome_preloading_predictor::kDefaultSearchEngine, content::PreloadingType::kPrerender, same_url_matcher); // If the caller does not want to prerender a new result, this does not need
diff --git a/chrome/browser/preloading/prerender/prerender_manager_unittest.cc b/chrome/browser/preloading/prerender/prerender_manager_unittest.cc index 3fb9187..343b4585 100644 --- a/chrome/browser/preloading/prerender/prerender_manager_unittest.cc +++ b/chrome/browser/preloading/prerender/prerender_manager_unittest.cc
@@ -198,8 +198,7 @@ content::PreloadingData::GetSameURLMatcher(prerendering_url); content::PreloadingAttempt* preloading_attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput), + chrome_preloading_predictor::kOmniboxDirectURLInput, content::PreloadingType::kPrerender, same_url_matcher); prerender_manager()->StartPrerenderDirectUrlInput(prerendering_url, @@ -222,8 +221,7 @@ content::PreloadingData::GetSameURLMatcher(prerendering_url); content::PreloadingAttempt* preloading_attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput), + chrome_preloading_predictor::kOmniboxDirectURLInput, content::PreloadingType::kPrerender, same_url_matcher); prerender_manager()->StartPrerenderDirectUrlInput(prerendering_url, @@ -238,8 +236,7 @@ content::PreloadingData::GetSameURLMatcher(prerendering_url); content::PreloadingAttempt* preloading_attempt2 = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput), + chrome_preloading_predictor::kOmniboxDirectURLInput, content::PreloadingType::kPrerender, same_url_matcher); prerender_manager()->StartPrerenderDirectUrlInput(prerendering_url2, *preloading_attempt2);
diff --git a/chrome/browser/preloading/prerender/prerender_omnibox_ui_browsertest.cc b/chrome/browser/preloading/prerender/prerender_omnibox_ui_browsertest.cc index 4c22000..763f914 100644 --- a/chrome/browser/preloading/prerender/prerender_omnibox_ui_browsertest.cc +++ b/chrome/browser/preloading/prerender/prerender_omnibox_ui_browsertest.cc
@@ -126,8 +126,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); ukm_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kOmniboxDirectURLInput)); + chrome_preloading_predictor::kOmniboxDirectURLInput); ASSERT_TRUE(embedded_test_server()->Start()); scoped_test_timer_ = @@ -701,12 +700,10 @@ // This test suite only tests for Default Search Engine prerendering. attempt_entry_builder_ = std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine)); + chrome_preloading_predictor::kDefaultSearchEngine); prediction_entry_builder_ = std::make_unique<content::test::PreloadingPredictionUkmEntryBuilder>( - ToPreloadingPredictor( - ChromePreloadingPredictor::kDefaultSearchEngine)); + chrome_preloading_predictor::kDefaultSearchEngine); scoped_test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>(); }
diff --git a/chrome/browser/printing/print_backend_service_manager.cc b/chrome/browser/printing/print_backend_service_manager.cc index fbef4b3..1bb7f06 100644 --- a/chrome/browser/printing/print_backend_service_manager.cc +++ b/chrome/browser/printing/print_backend_service_manager.cc
@@ -116,21 +116,23 @@ print_backend->GetPrinterDriverInfo(printer_name)); } -uint32_t PrintBackendServiceManager::RegisterQueryClient() { +PrintBackendServiceManager::ClientId +PrintBackendServiceManager::RegisterQueryClient() { return *RegisterClient(ClientType::kQuery, kEmptyPrinterName); } -absl::optional<uint32_t> +absl::optional<PrintBackendServiceManager::ClientId> PrintBackendServiceManager::RegisterQueryWithUiClient() { return RegisterClient(ClientType::kQueryWithUi, kEmptyPrinterName); } -uint32_t PrintBackendServiceManager::RegisterPrintDocumentClient( +PrintBackendServiceManager::ClientId +PrintBackendServiceManager::RegisterPrintDocumentClient( const std::string& printer_name) { DCHECK_NE(printer_name, kEmptyPrinterName); return *RegisterClient(ClientType::kPrintDocument, printer_name); } -void PrintBackendServiceManager::UnregisterClient(uint32_t id) { +void PrintBackendServiceManager::UnregisterClient(ClientId id) { // Determine which client type has this ID, and remove it once found. absl::optional<ClientType> client_type; RemoteId remote_id = GetRemoteIdForPrinterName(kEmptyPrinterName); @@ -519,10 +521,10 @@ return RemoteId(1); } -absl::optional<uint32_t> PrintBackendServiceManager::RegisterClient( - ClientType client_type, - const std::string& printer_name) { - uint32_t client_id = ++last_client_id_; +absl::optional<PrintBackendServiceManager::ClientId> +PrintBackendServiceManager::RegisterClient(ClientType client_type, + const std::string& printer_name) { + ClientId client_id = ClientId(++last_client_id_); RemoteId remote_id = GetRemoteIdForPrinterName(printer_name); VLOG(1) << "Registering a client with ID " << client_id
diff --git a/chrome/browser/printing/print_backend_service_manager.h b/chrome/browser/printing/print_backend_service_manager.h index 7cc0f35..7dd0d66 100644 --- a/chrome/browser/printing/print_backend_service_manager.h +++ b/chrome/browser/printing/print_backend_service_manager.h
@@ -45,9 +45,10 @@ class PrintBackendServiceManager { public: using RemoteId = base::StrongAlias<class RemoteIdTag, uint32_t>; + using ClientId = base::StrongAlias<class ClientIdTag, uint32_t>; // Contains set of client IDs. - using ClientsSet = base::flat_set<uint32_t>; + using ClientsSet = base::flat_set<ClientId>; // Mapping of clients to each remote ID that is for printing. using PrintClientsMap = base::flat_map<RemoteId, ClientsSet>; @@ -68,21 +69,21 @@ // completed their printing activity. // Register as a client of PrintBackendServiceManager for print queries. - uint32_t RegisterQueryClient(); + ClientId RegisterQueryClient(); // Register as a client of PrintBackendServiceManager for print queries which // require a system print dialog UI. If a platform cannot support concurrent // queries of this type then this will return `absl::nullopt` if another // client is already registered. - absl::optional<uint32_t> RegisterQueryWithUiClient(); + absl::optional<ClientId> RegisterQueryWithUiClient(); // Register as a client of PrintBackendServiceManager for printing a document // to a specific printer. - uint32_t RegisterPrintDocumentClient(const std::string& printer_name); + ClientId RegisterPrintDocumentClient(const std::string& printer_name); // Notify the manager that this client is no longer needing print backend // services. This signal might alter the manager's internal optimizations. - void UnregisterClient(uint32_t id); + void UnregisterClient(ClientId id); // Wrappers around mojom::PrintBackendService call. void EnumeratePrinters( @@ -281,7 +282,7 @@ RemoteId GetRemoteIdForPrinterName(const std::string& printer_name); // Common helper for registering clients. - absl::optional<uint32_t> RegisterClient(ClientType client_type, + absl::optional<ClientId> RegisterClient(ClientType client_type, const std::string& printer_name); // Get the total number of clients registered. @@ -484,6 +485,9 @@ // Map of remote ID to the set of clients printing documents to it. PrintClientsMap print_document_clients_; + // Simple counter for incrementing ClientId. All ClientId objects are used + // only within the browser process, so need for this to be a more complicated + // token. uint32_t last_client_id_ = 0; // Track the saved callbacks for each remote.
diff --git a/chrome/browser/printing/print_backend_service_manager_unittest.cc b/chrome/browser/printing/print_backend_service_manager_unittest.cc index 5602f141a..1723343c 100644 --- a/chrome/browser/printing/print_backend_service_manager_unittest.cc +++ b/chrome/browser/printing/print_backend_service_manager_unittest.cc
@@ -15,6 +15,7 @@ namespace printing { +using ClientId = PrintBackendServiceManager::ClientId; using ClientsSet = PrintBackendServiceManager::ClientsSet; using PrintClientsMap = PrintBackendServiceManager::PrintClientsMap; using RemoteId = PrintBackendServiceManager::RemoteId; @@ -24,26 +25,38 @@ const RemoteId kRemoteIdEmpty{1}; const RemoteId kRemoteIdTestPrinter{2}; +// ClientId values should not repeat for different types. +const ClientId kClientIdQuery1{1}; +const ClientId kClientIdQuery2{2}; +const ClientId kClientIdQueryWithUi1{5}; +#if BUILDFLAG(IS_LINUX) +const ClientId kClientIdQueryWithUi2{6}; +#endif +const ClientId kClientIdPrintDocument1{10}; +const ClientId kClientIdPrintDocument2{11}; +const ClientId kClientIdPrintDocument3{20}; + const ClientsSet kTestQueryNoClients; -const ClientsSet kTestQueryWithOneClient{1}; -const ClientsSet kTestQueryWithTwoClients{1, 2}; +const ClientsSet kTestQueryWithOneClient{kClientIdQuery1}; +const ClientsSet kTestQueryWithTwoClients{kClientIdQuery1, kClientIdQuery2}; const ClientsSet kTestQueryWithUiNoClients; -const ClientsSet kTestQueryWithUiOneClient{5}; +const ClientsSet kTestQueryWithUiOneClient{kClientIdQueryWithUi1}; #if BUILDFLAG(IS_LINUX) -const ClientsSet kTestQueryWithUiTwoClients{5, 6}; +const ClientsSet kTestQueryWithUiTwoClients{kClientIdQueryWithUi1, + kClientIdQueryWithUi2}; #endif const PrintClientsMap kTestPrintDocumentNoClients; const PrintClientsMap kTestPrintDocumentOnePrinterWithOneClient{ - {kRemoteIdEmpty, {10}}, + {kRemoteIdEmpty, {kClientIdPrintDocument1}}, }; const PrintClientsMap kTestPrintDocumentOnePrinterWithTwoClients{ - {kRemoteIdEmpty, {10, 11}}, + {kRemoteIdEmpty, {kClientIdPrintDocument1, kClientIdPrintDocument2}}, }; const PrintClientsMap kTestPrintDocumentTwoPrintersWithOneClientEach{ - {kRemoteIdEmpty, {10}}, - {kRemoteIdTestPrinter, {20}}, + {kRemoteIdEmpty, {kClientIdPrintDocument1}}, + {kRemoteIdTestPrinter, {kClientIdPrintDocument3}}, }; constexpr absl::optional<base::TimeDelta> kNoNewTimeoutNeeded;
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc index 061aed4..c170426 100644 --- a/chrome/browser/printing/print_browsertest.cc +++ b/chrome/browser/printing/print_browsertest.cc
@@ -48,6 +48,7 @@ #include "components/printing/browser/print_manager_utils.h" #include "components/printing/common/print.mojom-test-utils.h" #include "components/printing/common/print.mojom.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/browser_message_filter.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -119,8 +120,7 @@ base::RepeatingCallback<void(mojom::ResultCode result)>; #endif using OnDidStartPrintingCallback = - base::RepeatingCallback<void(mojom::ResultCode result, - PrintJob* print_job)>; + base::RepeatingCallback<void(mojom::ResultCode result)>; #if BUILDFLAG(IS_WIN) using OnDidRenderPrintedPageCallback = base::RepeatingCallback<void(uint32_t page_number, @@ -519,6 +519,62 @@ mojo::AssociatedReceiver<mojom::PrintRenderFrame> receiver_{this}; }; +class PrintPreviewDoneObserver + : public mojom::PrintRenderFrameInterceptorForTesting { + public: + PrintPreviewDoneObserver(content::RenderFrameHost* render_frame_host, + mojom::PrintRenderFrame* print_render_frame) + : render_frame_host_(render_frame_host), + print_render_frame_(print_render_frame) { + OverrideBinderForTesting(); + } + ~PrintPreviewDoneObserver() override { + render_frame_host_->GetRemoteAssociatedInterfaces() + ->OverrideBinderForTesting(mojom::PrintRenderFrame::Name_, + base::NullCallback()); + } + + void WaitForPrintPreviewDialogClosed() { run_loop_.Run(); } + + // mojom::PrintRenderFrameInterceptorForTesting: + mojom::PrintRenderFrame* GetForwardingInterface() override { + return print_render_frame_; + } + void OnPrintPreviewDialogClosed() override { + GetForwardingInterface()->OnPrintPreviewDialogClosed(); + run_loop_.Quit(); + } + + private: + void OverrideBinderForTesting() { + // Safe to use base::Unretained() below because: + // 1) Normally, Bind() will unregister the override after it gets called. + // 2) If Bind() does not get called, the dtor will unregister the override. + render_frame_host_->GetRemoteAssociatedInterfaces() + ->OverrideBinderForTesting( + mojom::PrintRenderFrame::Name_, + base::BindRepeating(&PrintPreviewDoneObserver::Bind, + base::Unretained(this))); + } + + void Bind(mojo::ScopedInterfaceEndpointHandle handle) { + receiver_.Bind(mojo::PendingAssociatedReceiver<mojom::PrintRenderFrame>( + std::move(handle))); + + // After the initial binding, reset the binder override. Otherwise, + // PrintPreviewDoneObserver will also try to bind the remote passed by + // SetPrintPreviewUI(), which will fail since `receiver_` is already bound. + render_frame_host_->GetRemoteAssociatedInterfaces() + ->OverrideBinderForTesting(mojom::PrintRenderFrame::Name_, + base::NullCallback()); + } + + raw_ptr<content::RenderFrameHost> const render_frame_host_; + raw_ptr<mojom::PrintRenderFrame> const print_render_frame_; + mojo::AssociatedReceiver<mojom::PrintRenderFrame> receiver_{this}; + base::RunLoop run_loop_; +}; + } // namespace class TestPrintViewManager : public PrintViewManager { @@ -2054,6 +2110,39 @@ print_preview_observer.WaitUntilPreviewIsReady(); } +IN_PROC_BROWSER_TEST_F(PrintBrowserTest, + WindowDotPrintTriggersBeforeAfterEvents) { + // Load test page and check the initial state. + const GURL kUrl( + embedded_test_server()->GetURL("/printing/on_before_after_events.html")); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kUrl)); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::RenderFrameHost* rfh = web_contents->GetPrimaryMainFrame(); + EXPECT_EQ(false, content::EvalJs(rfh, "firedBeforePrint")); + EXPECT_EQ(false, content::EvalJs(rfh, "firedAfterPrint")); + + // Set up the PrintPreviewDoneObserver early, as it needs to intercept Mojo + // IPCs before they start. + PrintPreviewDoneObserver done_observer(rfh, GetPrintRenderFrame(rfh).get()); + + // Load Print Preview and make sure the beforeprint event fired. + PrintPreviewObserver print_preview_observer(/*wait_for_loaded=*/false); + content::ExecuteScriptAsync(rfh, "window.print();"); + print_preview_observer.WaitUntilPreviewIsReady(); + EXPECT_EQ(true, content::EvalJs(rfh, "firedBeforePrint")); + EXPECT_EQ(false, content::EvalJs(rfh, "firedAfterPrint")); + + // Close the Print Preview dialog and make sure the afterprint event fired. + auto* web_contents_modal_dialog_manager = + web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); + ASSERT_TRUE(web_contents_modal_dialog_manager); + web_contents_modal_dialog_manager->CloseAllDialogs(); + done_observer.WaitForPrintPreviewDialogClosed(); + EXPECT_EQ(true, content::EvalJs(rfh, "firedBeforePrint")); + EXPECT_EQ(true, content::EvalJs(rfh, "firedAfterPrint")); +} + class PrintPrerenderBrowserTest : public PrintBrowserTest { public: PrintPrerenderBrowserTest() @@ -2325,7 +2414,7 @@ DVLOG(1) << "Observed: start printing of document"; callbacks_->error_check_callback.Run(result); PrintJobWorkerOop::OnDidStartPrinting(result); - callbacks_->did_start_printing_callback.Run(result, print_job()); + callbacks_->did_start_printing_callback.Run(result); } #if BUILDFLAG(IS_WIN) @@ -2768,9 +2857,8 @@ } #endif - void OnDidStartPrinting(mojom::ResultCode result, PrintJob* print_job) { + void OnDidStartPrinting(mojom::ResultCode result) { start_printing_result_ = result; - print_job_ = print_job; CheckForQuit(); } @@ -2832,7 +2920,6 @@ mojo::Remote<mojom::PrintBackendService> test_remote_; std::unique_ptr<PrintBackendServiceTestImpl> print_backend_service_; #endif // BUILDFLAG(ENABLE_OOP_PRINTING) - raw_ptr<PrintJob, DanglingUntriaged> print_job_ = nullptr; bool reset_errors_after_check_ = true; int did_print_document_count_ = 0; mojom::ResultCode use_default_settings_result_ = mojom::ResultCode::kFailed; @@ -3687,7 +3774,7 @@ TestPrintViewManager::CreateForWebContents(web_contents); // Pretend that a window has started a system print. - absl::optional<uint32_t> client_id = + absl::optional<PrintBackendServiceManager::ClientId> client_id = PrintBackendServiceManager::GetInstance().RegisterQueryWithUiClient(); ASSERT_TRUE(client_id.has_value());
diff --git a/chrome/browser/printing/print_job_worker_oop.h b/chrome/browser/printing/print_job_worker_oop.h index 282291d..8a87b527 100644 --- a/chrome/browser/printing/print_job_worker_oop.h +++ b/chrome/browser/printing/print_job_worker_oop.h
@@ -9,6 +9,7 @@ #include "base/memory/weak_ptr.h" #include "build/build_config.h" +#include "chrome/browser/printing/print_backend_service_manager.h" #include "chrome/browser/printing/print_job_worker.h" #include "chrome/services/printing/public/mojom/print_backend_service.mojom.h" #include "printing/buildflags/buildflags.h" @@ -97,7 +98,8 @@ // Client ID with the print backend service manager for this print job. // Used only from UI thread. - absl::optional<uint32_t> service_manager_client_id_; + absl::optional<PrintBackendServiceManager::ClientId> + service_manager_client_id_; // The device name used when printing via a service. Used only from the UI // thread.
diff --git a/chrome/browser/printing/print_view_manager_base.h b/chrome/browser/printing/print_view_manager_base.h index e2823c4..1fe06e1 100644 --- a/chrome/browser/printing/print_view_manager_base.h +++ b/chrome/browser/printing/print_view_manager_base.h
@@ -25,6 +25,10 @@ #include "components/services/print_compositor/public/mojom/print_compositor.mojom.h" #include "printing/buildflags/buildflags.h" +#if BUILDFLAG(ENABLE_OOP_PRINTING) +#include "chrome/browser/printing/print_backend_service_manager.h" +#endif + #if BUILDFLAG(ENABLE_PRINT_CONTENT_ANALYSIS) #include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h" #endif // BUILDFLAG(ENABLE_PRINT_CONTENT_ANALYSIS) @@ -352,7 +356,8 @@ #if BUILDFLAG(ENABLE_OOP_PRINTING) // Client ID with the print backend service manager for this print job. - absl::optional<uint32_t> service_manager_client_id_; + absl::optional<PrintBackendServiceManager::ClientId> + service_manager_client_id_; #endif #if BUILDFLAG(ENABLE_PRINT_CONTENT_ANALYSIS)
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index d3b6cfd..bfb2186 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -12,7 +12,6 @@ #include "chrome/browser/accessibility/page_colors_factory.h" #include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h" #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" -#include "chrome/browser/autocomplete/autocomplete_scoring_model_service_factory.h" #include "chrome/browser/autocomplete/in_memory_url_index_factory.h" #include "chrome/browser/autocomplete/shortcuts_backend_factory.h" #include "chrome/browser/autofill/autofill_image_fetcher_factory.h" @@ -253,6 +252,7 @@ #endif #if BUILDFLAG(BUILD_WITH_TFLITE_LIB) +#include "chrome/browser/autocomplete/autocomplete_scoring_model_service_factory.h" #include "chrome/browser/permissions/prediction_model_handler_provider_factory.h" #endif @@ -328,7 +328,9 @@ apps::SupportedLinksInfoBarPrefsServiceFactory::GetInstance(); #endif AutocompleteClassifierFactory::GetInstance(); +#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) AutocompleteScoringModelServiceFactory::GetInstance(); +#endif autofill::AutofillImageFetcherFactory::GetInstance(); autofill::PersonalDataManagerFactory::GetInstance(); autofill::AutofillOfferManagerFactory::GetInstance();
diff --git a/chrome/browser/resources/app_home/app_home.html b/chrome/browser/resources/app_home/app_home.html index e1503ce..b25f4198 100644 --- a/chrome/browser/resources/app_home/app_home.html +++ b/chrome/browser/resources/app_home/app_home.html
@@ -11,7 +11,7 @@ <meta name="color-scheme" content="light dark"> <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> <base href="chrome://apps"> - <title>app home</title> + <title>$i18n{appHomeTitle}</title> <script type="module" src="app_list.js"></script> </head> <style>
diff --git a/chrome/browser/resources/app_home/app_list.html b/chrome/browser/resources/app_home/app_list.html index b0b9ad0b..23b4004 100644 --- a/chrome/browser/resources/app_home/app_list.html +++ b/chrome/browser/resources/app_home/app_list.html
@@ -43,38 +43,38 @@ on-click="onOpenInWindowItemClick_" hidden="[[isOpenInWindowHidden_(selectedActionMenuModel_)]]"> <div class="dropdown-item-label"> - Open in window + $i18n{appWindowOpenLabel} </div> <cr-checkbox checked="{{selectedActionMenuModel_.appInfo.openInWindow}}" on-click="onOpenInWindowItemClick_"> - Enable opening app in window + $i18n{appWindowOpenCheckboxLabel} </cr-checkbox> </div> <div id="launch-on-startup" tabindex="0" class="dropdown-item" on-click="onLaunchOnStartupItemClick_" hidden="[[isLaunchOnStartupHidden_(selectedActionMenuModel_)]]"> <div class="dropdown-item-label"> - Launch on startup + $i18n{appLaunchAtStartupLabel} </div> <cr-checkbox checked="[[isLaunchOnStartUp_(selectedActionMenuModel_)]]" disabled= "[[isLaunchOnStartupDisabled_(selectedActionMenuModel_)]]" on-click="onLaunchOnStartupItemClick_"> - Enable launching app on startup + $i18n{appLaunchAtStartupCheckboxLabel} </cr-checkbox> </div> <button id="create-shortcut" class="dropdown-item" on-click="onCreateShortcutItemClick_"> - Create a shortcut + $i18n{createShortcutForAppLabel} </button> <hr> <button id="uninstall" class="dropdown-item" on-click="onUninstallItemClick_"> - Uninstall + $i18n{uninstallAppLabel} </button> <button id="app-settings" class="dropdown-item" on-click="onAppSettingsItemClick_"> - App settings + $i18n{appSettingsLabel} </button> </cr-action-menu>
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index 68384ef..5dea13cf 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -119,6 +119,7 @@ "background/range_automation_handler.js", "background/smart_sticky_mode.js", "background/tts_background.js", + "background/tts_interface.js", "background/user_action_monitor.js", "common/background_bridge.js", "common/braille/braille_command_data.js", @@ -148,7 +149,6 @@ "common/role_type.js", "common/spannable.js", "common/tree_dumper.js", - "common/tts_interface.js", "common/tts_types.js", "learn_mode/learn_mode.js", "log_page/log.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/abstract_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/abstract_tts.js index 57da251..f3fd400 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/abstract_tts.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/abstract_tts.js
@@ -9,9 +9,10 @@ import {LocalStorage} from '../../common/local_storage.js'; import {Msgs} from '../common/msgs.js'; -import {TtsInterface} from '../common/tts_interface.js'; import * as ttsTypes from '../common/tts_types.js'; +import {TtsInterface} from './tts_interface.js'; + /** * @typedef {{ * pitch: number,
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox.js index db082154e..f68fcbd0 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox.js
@@ -6,10 +6,10 @@ * @fileoverview Defines a global object that holds references to the three * different output engines. */ -import {TtsInterface} from '../common/tts_interface.js'; import {AbstractEarcons} from './abstract_earcons.js'; import {BrailleInterface} from './braille/braille_interface.js'; +import {TtsInterface} from './tts_interface.js'; export const ChromeVox = { /** @type {BrailleInterface} */
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 9a02e1d..52121a4 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
@@ -44,6 +44,7 @@ import {TypingEcho} from './editing/editable_text_base.js'; import {EventSource} from './event_source.js'; import {GestureInterface} from './gesture_interface.js'; +import {BackgroundKeyboardHandler} from './keyboard_handler.js'; import {LogStore} from './logging/log_store.js'; import {Output} from './output/output.js'; import {OutputCustomEvent} from './output/output_types.js'; @@ -120,8 +121,7 @@ SmartStickyMode.instance.toggle(); return false; case Command.PASS_THROUGH_MODE: - ChromeVox.passThroughMode = true; - ChromeVox.tts.speak(Msgs.getMsg('pass_through_key'), QueueMode.QUEUE); + BackgroundKeyboardHandler.enablePassThroughMode(); return true; case Command.SHOW_LEARN_MODE_PAGE: this.showLearnModePage_();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/composite_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/composite_tts.js index c5401f8..7545c45 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/composite_tts.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/composite_tts.js
@@ -5,11 +5,11 @@ /** * @fileoverview A composite TTS allows ChromeVox to use multiple TTS engines at * the same time. - * */ -import {TtsInterface} from '../common/tts_interface.js'; import {QueueMode, TtsSpeechProperties} from '../common/tts_types.js'; +import {TtsInterface} from './tts_interface.js'; + /** * A Composite Tts * @implements {TtsInterface}
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js index 084414d..69a38fd 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/console_tts.js
@@ -6,11 +6,11 @@ * @fileoverview A TTS engine that writes to globalThis.console. */ import {SpeechLog} from '../common/log_types.js'; -import {TtsInterface} from '../common/tts_interface.js'; import {QueueMode, TtsCategory} from '../common/tts_types.js'; import {LogStore} from './logging/log_store.js'; import {ChromeVoxPrefs} from './prefs.js'; +import {TtsInterface} from './tts_interface.js'; /** @implements {TtsInterface} */ export class ConsoleTts {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base.js index e5d52bc..304d47c 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base.js
@@ -15,9 +15,9 @@ */ import {LocalStorage} from '../../../common/local_storage.js'; import {Msgs} from '../../common/msgs.js'; -import {TtsInterface} from '../../common/tts_interface.js'; import {Personality, QueueMode, TtsCategory, TtsSpeechProperties} from '../../common/tts_types.js'; import {ChromeVoxState} from '../chromevox_state.js'; +import {TtsInterface} from '../tts_interface.js'; /** * A class containing the information needed to speak
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler.js index 771b85b..2ddb384 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler.js
@@ -8,6 +8,7 @@ import {KeyCode} from '../../common/key_code.js'; import {EventSourceType} from '../common/event_source_type.js'; import {ChromeVoxKbHandler} from '../common/keyboard_handler.js'; +import {Msgs} from '../common/msgs.js'; import {QueueMode} from '../common/tts_types.js'; import {ChromeVox} from './chromevox.js'; @@ -40,12 +41,15 @@ export class BackgroundKeyboardHandler { /** @private */ constructor() { + /** @private {Set} */ + this.eatenKeyDowns_ = new Set(); + + /** @private {boolean} */ + this.passThroughModeEnabled_ = false; + /** @private {!KeyboardPassThroughState_} */ this.passThroughState_ = KeyboardPassThroughState_.NO_PASS_THROUGH; - /** @type {Set} @private */ - this.eatenKeyDowns_ = new Set(); - /** @private {Set} */ this.passedThroughKeyDowns_ = new Set(); @@ -64,6 +68,11 @@ BackgroundKeyboardHandler.instance = new BackgroundKeyboardHandler(); } + static enablePassThroughMode() { + ChromeVox.tts.speak(Msgs.getMsg('pass_through_key'), QueueMode.QUEUE); + BackgroundKeyboardHandler.instance.passThroughModeEnabled_ = true; + } + /** * Handles key down events. * @param {Event} evt The key down event to process. @@ -82,7 +91,7 @@ this.passedThroughKeyDowns_.clear(); } - if (ChromeVox.passThroughMode) { + if (this.passThroughModeEnabled_) { this.passedThroughKeyDowns_.add(evt.keyCode); return false; } @@ -94,7 +103,7 @@ if (!this.callOnKeyDownHandlers_(evt) || this.shouldConsumeSearchKey_(evt)) { - if (ChromeVox.passThroughMode) { + if (this.passThroughModeEnabled_) { this.passThroughState_ = KeyboardPassThroughState_.PENDING_PASS_THROUGH_SHORTCUT_KEYUPS; } @@ -155,7 +164,7 @@ this.eatenKeyDowns_.delete(evt.keyCode); } - if (ChromeVox.passThroughMode) { + if (this.passThroughModeEnabled_) { this.passedThroughKeyDowns_.delete(evt.keyCode); if (this.passThroughState_ === KeyboardPassThroughState_.PENDING_PASS_THROUGH_SHORTCUT_KEYUPS && @@ -170,7 +179,7 @@ this.passedThroughKeyDowns_.size === 0) { // All keys of the passed through shortcut have been released. Ready to // go back to normal processing (aka no pass through). - ChromeVox.passThroughMode = false; + this.passThroughModeEnabled_ = false; this.passThroughState_ = KeyboardPassThroughState_.NO_PASS_THROUGH; } }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler_test.js index f36d078..9d44532 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/keyboard_handler_test.js
@@ -23,7 +23,7 @@ '/chromevox/background/keyboard_handler.js'); await importModule('KeyCode', '/common/key_code.js'); - globalThis.keyboardHandler = new BackgroundKeyboardHandler(); + globalThis.keyboardHandler = BackgroundKeyboardHandler.instance; } }; @@ -54,7 +54,7 @@ 'ChromeVoxBackgroundKeyboardHandlerTest', 'PassThroughMode', async function() { await this.runWithLoadedTree('<p>test</p>'); - assertUndefined(ChromeVox.passThroughMode); + assertFalse(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); assertEquals('no_pass_through', keyboardHandler.passThroughState_); assertEquals(0, keyboardHandler.eatenKeyDowns_.size); assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); @@ -66,7 +66,7 @@ assertEquals(1, keyboardHandler.eatenKeyDowns_.size); assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); assertEquals('no_pass_through', keyboardHandler.passThroughState_); - assertUndefined(ChromeVox.passThroughMode); + assertFalse(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); const searchShift = TestUtils.createMockKeyEvent( KeyCode.SHIFT, {metaKey: true, shiftKey: true}); @@ -74,7 +74,7 @@ assertEquals(2, keyboardHandler.eatenKeyDowns_.size); assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); assertEquals('no_pass_through', keyboardHandler.passThroughState_); - assertUndefined(ChromeVox.passThroughMode); + assertFalse(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); const searchShiftEsc = TestUtils.createMockKeyEvent( KeyCode.ESCAPE, {metaKey: true, shiftKey: true}); @@ -83,28 +83,28 @@ assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_pass_through_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); keyboardHandler.onKeyUp(searchShiftEsc); assertEquals(2, keyboardHandler.eatenKeyDowns_.size); assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_pass_through_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); keyboardHandler.onKeyUp(searchShift); assertEquals(1, keyboardHandler.eatenKeyDowns_.size); assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_pass_through_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); keyboardHandler.onKeyUp(search); assertEquals(0, keyboardHandler.eatenKeyDowns_.size); assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_shortcut_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); // Now, the next series of key downs should be passed through. // Try Search+Ctrl+M. @@ -113,7 +113,7 @@ assertEquals(1, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_shortcut_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); const searchCtrl = TestUtils.createMockKeyEvent( KeyCode.CONTROL, {metaKey: true, ctrlKey: true}); @@ -122,7 +122,7 @@ assertEquals(2, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_shortcut_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); const searchCtrlM = TestUtils.createMockKeyEvent( KeyCode.M, {metaKey: true, ctrlKey: true}); @@ -131,27 +131,27 @@ assertEquals(3, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_shortcut_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); keyboardHandler.onKeyUp(searchCtrlM); assertEquals(0, keyboardHandler.eatenKeyDowns_.size); assertEquals(2, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_shortcut_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); keyboardHandler.onKeyUp(searchCtrl); assertEquals(0, keyboardHandler.eatenKeyDowns_.size); assertEquals(1, keyboardHandler.passedThroughKeyDowns_.size); assertEquals( 'pending_shortcut_keyups', keyboardHandler.passThroughState_); - assertTrue(ChromeVox.passThroughMode); + assertTrue(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); keyboardHandler.onKeyUp(search); assertEquals(0, keyboardHandler.eatenKeyDowns_.size); assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); assertEquals('no_pass_through', keyboardHandler.passThroughState_); - assertFalse(ChromeVox.passThroughMode); + assertFalse(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); }); AX_TEST_F( @@ -159,7 +159,7 @@ async function() { await this.runWithLoadedTree('<p>test</p>'); function assertNoPassThrough() { - assertUndefined(ChromeVox.passThroughMode); + assertFalse(BackgroundKeyboardHandler.instance.passThroughModeEnabled_); assertEquals('no_pass_through', keyboardHandler.passThroughState_); assertEquals(0, keyboardHandler.passedThroughKeyDowns_.size); } @@ -239,7 +239,7 @@ 'UnexpectedKeyDownUpPairsPassThrough', async function() { await this.runWithLoadedTree('<p>test</p>'); // Force pass through mode. - ChromeVox.passThroughMode = true; + BackgroundKeyboardHandler.instance.passThroughModeEnabled_ = true; // Send a few key downs (which are passed through). const search =
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js index b9c3f4a..638fd5a 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js
@@ -7,10 +7,10 @@ */ import {AsyncUtil} from '../../common/async_util.js'; import {LocalStorage} from '../../common/local_storage.js'; -import {TtsCapturingEventListener} from '../common/tts_interface.js'; import {BaseAutomationHandler} from './base_automation_handler.js'; import {ChromeVox} from './chromevox.js'; +import {TtsCapturingEventListener} from './tts_interface.js'; const AutomationEvent = chrome.automation.AutomationEvent; const AutomationNode = chrome.automation.AutomationNode;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js index dc626705..8ba5f453 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
@@ -874,19 +874,16 @@ rule.populateOutput(this.formatOptions_.braille); if (eventBlock[rule.role][formatName]) { if (this.formatOptions_.braille) { - buff = []; + buff = /** @type {!Array<Spannable>} */ ([]); formatLog.bufferClear(); } excludeRoles.add(formatNode.role); formatLog.writeRule(rule.specifier); - const enterFormat = rule.output ? - eventBlock[rule.role][formatName][rule.output] : - eventBlock[rule.role][formatName]; this.formattedAncestors_.add(formatNode); OutputFormatter.format(this, { node: formatNode, - outputFormat: enterFormat, + outputFormat: rule.enterFormat, outputBuffer: buff, outputFormatLogger: formatLog, opt_prevNode: prevNode,
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_formatter.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_formatter.js index ab6d09d2..def9d27 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_formatter.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_formatter.js
@@ -63,14 +63,26 @@ return true; } - if (token === 'value') { - this.formatValue_(this.params_, token, options); - } else if (token === 'name') { - this.formatName_(this.params_, token, options); + if (token === 'cellIndexText') { + this.formatCellIndexText_(this.params_, token, options); + } else if (token === 'checked') { + this.formatChecked_(this.params_, token); + } else if (token === 'descendants') { + this.formatDescendants_(this.params_, token); } else if (token === 'description') { this.formatDescription_(this.params_, token, options); - } else if (token === 'urlFilename') { - this.formatUrlFilename_(this.params_, token, options); + } else if (token === 'find') { + this.formatFind_(this.params_, token, tree); + } else if (token === 'inputType') { + this.formatInputType_(this.params_, token, options); + } else if (token === 'indexInParent') { + this.formatIndexInParent_(this.params_, token, tree, options); + } else if (token === 'joinedDescendants') { + this.formatJoinedDescendants_(this.params_, token, options); + } else if (token === 'listNestedLevel') { + this.formatListNestedLevel_(this.params_); + } else if (token === 'name') { + this.formatName_(this.params_, token, options); } else if (token === 'nameFromNode') { this.formatNameFromNode_(this.params_, token, options); } else if (token === 'nameOrDescendants') { @@ -79,22 +91,18 @@ // override the descendants text if |node| has only static text // children. this.formatNameOrDescendants_(this.params_, token, options); - } else if (token === 'indexInParent') { - this.formatIndexInParent_(this.params_, token, tree, options); - } else if (token === 'restriction') { - this.formatRestriction_(this.params_, token); - } else if (token === 'checked') { - this.formatChecked_(this.params_, token); + } else if (token === 'nameOrTextContent' || token === 'textContent') { + this.formatTextContent_(this.params_, token, options); + } else if (token === 'node') { + this.formatNode_(this.params_, token, tree, options); + } else if (token === 'phoneticReading') { + this.formatPhoneticReading_(this.params_); + } else if (token === 'precedingBullet') { + this.formatPrecedingBullet_(this.params_); } else if (token === 'pressed') { this.formatPressed_(this.params_, token); - } else if (token === 'state') { - this.formatState_(this.params_, token); - } else if (token === 'find') { - this.formatFind_(this.params_, token, tree); - } else if (token === 'descendants') { - this.formatDescendants_(this.params_, token); - } else if (token === 'joinedDescendants') { - this.formatJoinedDescendants_(this.params_, token, options); + } else if (token === 'restriction') { + this.formatRestriction_(this.params_, token); } else if (token === 'role') { if (LocalStorage.get('useVerboseMode') === false) { return true; @@ -105,27 +113,19 @@ } this.formatRole_(this.params_, token, options); - } else if (token === 'inputType') { - this.formatInputType_(this.params_, token, options); + } else if (token === 'state') { + this.formatState_(this.params_, token); } else if ( token === 'tableCellRowIndex' || token === 'tableCellColumnIndex') { this.formatTableCellIndex_(this.params_, token, options); - } else if (token === 'cellIndexText') { - this.formatCellIndexText_(this.params_, token, options); - } else if (token === 'node') { - this.formatNode_(this.params_, token, tree, options); - } else if (token === 'nameOrTextContent' || token === 'textContent') { - this.formatTextContent_(this.params_, token, options); + } else if (token === 'urlFilename') { + this.formatUrlFilename_(this.params_, token, options); + } else if (token === 'value') { + this.formatValue_(this.params_, token, options); } else if (this.params_.node[token] !== undefined) { this.formatAsFieldAccessor_(this.params_, token, options); } else if (outputTypes.OUTPUT_STATE_INFO[token]) { this.formatAsStateValue_(this.params_, token, options); - } else if (token === 'phoneticReading') { - this.formatPhoneticReading_(this.params_); - } else if (token === 'listNestedLevel') { - this.formatListNestedLevel_(this.params_); - } else if (token === 'precedingBullet') { - this.formatPrecedingBullet_(this.params_); } else if (tree.firstChild) { this.formatCustomFunction_(this.params_, token, tree, options); }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_rules.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_rules.js index 75c8e1a..e37fb69d 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_rules.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_rules.js
@@ -141,6 +141,15 @@ this.output_ = OutputFormatType.BRAILLE; } } + + /** @return {string} */ + get enterFormat() { + const rule = OutputRule.RULES[this.event_][this.role_][this.formatName_]; + if (this.output_) { + return rule[this.output_]; + } + return rule || ''; + } } /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/primary_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/primary_tts.js index e1b5e38a..3258c1c 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/primary_tts.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/primary_tts.js
@@ -9,12 +9,12 @@ import {LocalStorage} from '../../common/local_storage.js'; import {Msgs} from '../common/msgs.js'; import {PanelCommand, PanelCommandType} from '../common/panel_command.js'; -import {TtsCapturingEventListener, TtsInterface} from '../common/tts_interface.js'; import * as ttsTypes from '../common/tts_types.js'; import {AbstractTts} from './abstract_tts.js'; import {ChromeVox} from './chromevox.js'; import {PhoneticData} from './phonetic_data.js'; +import {TtsCapturingEventListener, TtsInterface} from './tts_interface.js'; const Utterance = class { /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js index 755417c..58fa58c 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js
@@ -11,7 +11,6 @@ import {BridgeConstants} from '../common/bridge_constants.js'; import {BridgeHelper} from '../common/bridge_helper.js'; import {Msgs} from '../common/msgs.js'; -import {TtsInterface} from '../common/tts_interface.js'; import {Personality, QueueMode, TtsSpeechProperties} from '../common/tts_types.js'; import {ChromeVox} from './chromevox.js';
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/tts_interface.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_interface.js similarity index 90% rename from chrome/browser/resources/chromeos/accessibility/chromevox/common/tts_interface.js rename to chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_interface.js index 2eaae0f..6955694 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/tts_interface.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_interface.js
@@ -4,9 +4,11 @@ /** * @fileoverview Defines a Tts interface. + * * All TTS engines in ChromeVox conform to the this interface. + * */ -import {QueueMode, TtsSpeechProperties} from './tts_types.js'; +import {QueueMode, TtsSpeechProperties} from '../common/tts_types.js'; /** * An interface for clients who want to get notified when an utterance @@ -14,13 +16,19 @@ * @interface */ export class TtsCapturingEventListener { - /** Called when any utterance starts. */ + /** + * Called when any utterance starts. + */ onTtsStart() {} - /** Called when any utterance ends. */ + /** + * Called when any utterance ends. + */ onTtsEnd() {} - /** Called when any utterance gets interrupted. */ + /** + * Called when any utterance gets interrupted. + */ onTtsInterrupted() {} }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/user_action_monitor_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/user_action_monitor_test.js index 5241da2f..c1de4e1 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/user_action_monitor_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/user_action_monitor_test.js
@@ -236,7 +236,7 @@ // since we don't directly call a UserActionMonitor function. AX_TEST_F('ChromeVoxUserActionMonitorTest', 'SingleKey', async function() { await this.runWithLoadedTree(this.simpleDoc); - const keyboardHandler = new BackgroundKeyboardHandler(); + const keyboardHandler = BackgroundKeyboardHandler.instance; let finished = false; const actions = [{type: 'key_sequence', value: {'keys': {'keyCode': [KeyCode.SPACE]}}}]; @@ -258,7 +258,7 @@ // since we don't directly call a UserActionMonitor function. AX_TEST_F('ChromeVoxUserActionMonitorTest', 'MultipleKeys', async function() { await this.runWithLoadedTree(this.simpleDoc); - const keyboardHandler = new BackgroundKeyboardHandler(); + const keyboardHandler = BackgroundKeyboardHandler.instance; let finished = false; const actions = [{ type: 'key_sequence', @@ -341,7 +341,7 @@ AX_TEST_F('ChromeVoxUserActionMonitorTest', 'BlockCommands', async function() { const mockFeedback = this.createMockFeedback(); await this.runWithLoadedTree(this.paragraphDoc); - const keyboardHandler = new BackgroundKeyboardHandler(); + const keyboardHandler = BackgroundKeyboardHandler.instance; let finished = false; const actions = [ { @@ -402,7 +402,7 @@ // is active. AX_TEST_F('ChromeVoxUserActionMonitorTest', 'CloseChromeVox', async function() { await this.runWithLoadedTree(this.simpleDoc); - const keyboardHandler = new BackgroundKeyboardHandler(); + const keyboardHandler = BackgroundKeyboardHandler.instance; let finished = false; let closed = false; const actions =
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_e2e_test_base.js b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_e2e_test_base.js index 82ad4a0..25d4ac2 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_e2e_test_base.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_e2e_test_base.js
@@ -146,6 +146,8 @@ await importModule( 'ChromeVoxState', '/chromevox/background/chromevox_state.js'); await importModule( + 'TtsInterface', '/chromevox/background/tts_interface.js'); + await importModule( 'CommandHandler', '/chromevox/background/command_handler.js'); await importModule( 'CommandHandlerInterface', @@ -159,7 +161,6 @@ 'OutputContextOrder', '/chromevox/background/output/output_types.js'); await importModule( 'NavBraille', '/chromevox/common/braille/nav_braille.js'); - await importModule('TtsInterface', '/chromevox/common/tts_interface.js'); await importModule('QueueMode', '/chromevox/common/tts_types.js'); // For tests, enable announcement of events we trigger via automation.
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access.js b/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access.js index 59b7d5f0..bd29edbf 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access.js
@@ -28,7 +28,7 @@ const desktop = await AsyncUtil.getDesktop(); const currentFocus = await AsyncUtil.getFocus(); - SwitchAccess.waitForFocus_(desktop, currentFocus); + await SwitchAccess.waitForFocus_(desktop, currentFocus); } /** @@ -36,32 +36,36 @@ * @param {AutomationNode} currentFocus * @private */ - static waitForFocus_(desktop, currentFocus) { - // Focus is available. Finish init without waiting for further events. - // Disallow web view nodes, which indicate a root web area is still - // loading and pending focus. - if (currentFocus && currentFocus.role !== RoleType.WEB_VIEW) { - SwitchAccess.finishInit_(desktop); - return; - } - - // Wait for the focus to be sent. If |currentFocus| was undefined, this is - // guaranteed. Otherwise, also set a timed callback to ensure we do - // eventually init. - let callbackId = 0; - const listener = maybeEvent => { - if (maybeEvent && maybeEvent.target.role === RoleType.WEB_VIEW) { + static async waitForFocus_(desktop, currentFocus) { + return new Promise(resolve => { + // Focus is available. Finish init without waiting for further events. + // Disallow web view nodes, which indicate a root web area is still + // loading and pending focus. + if (currentFocus && currentFocus.role !== RoleType.WEB_VIEW) { + SwitchAccess.finishInit_(desktop); + resolve(); return; } - desktop.removeEventListener(EventType.FOCUS, listener, false); - clearTimeout(callbackId); + // Wait for the focus to be sent. If |currentFocus| was undefined, this is + // guaranteed. Otherwise, also set a timed callback to ensure we do + // eventually init. + let callbackId = 0; + const listener = maybeEvent => { + if (maybeEvent && maybeEvent.target.role === RoleType.WEB_VIEW) { + return; + } - SwitchAccess.finishInit_(desktop); - }; + desktop.removeEventListener(EventType.FOCUS, listener, false); + clearTimeout(callbackId); - desktop.addEventListener(EventType.FOCUS, listener, false); - callbackId = setTimeout(listener, 5000); + SwitchAccess.finishInit_(desktop); + resolve(); + }; + + desktop.addEventListener(EventType.FOCUS, listener, false); + callbackId = setTimeout(listener, 5000); + }); } /** @private */
diff --git a/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.ts b/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.ts index 15a3fdf..6201ff1 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.ts +++ b/chrome/browser/resources/chromeos/cloud_upload/cloud_upload_dialog.ts
@@ -34,6 +34,12 @@ /** The modal dialog shown to confirm if the user wants to cancel setup. */ private cancelDialog: SetupCancelDialogElement; + /** + True if the setup flow is being run for the first time. False if the fixup + flow is being run. + */ + private firstTimeSetup: boolean = true; + /** The names of the files to upload. */ private fileNames: string[] = []; @@ -69,7 +75,8 @@ } const oneDriveUploadPage = new OneDriveUploadPageElement(); - oneDriveUploadPage.setFileNames(this.fileNames); + oneDriveUploadPage.setFileNamesAndFirstTimeSetup( + this.fileNames, this.firstTimeSetup); this.pages.push(oneDriveUploadPage); this.pages.forEach((page, index) => { @@ -110,6 +117,7 @@ try { const dialogArgs = await this.proxy.handler.getDialogArgs(); assert(dialogArgs.args); + this.firstTimeSetup = dialogArgs.args.firstTimeSetup; this.fileNames = dialogArgs.args.fileNames; } catch (e) { // TODO(b/243095484) Define expected behavior.
diff --git a/chrome/browser/resources/chromeos/cloud_upload/one_drive_upload_page.ts b/chrome/browser/resources/chromeos/cloud_upload/one_drive_upload_page.ts index b32ab7c..e7431c3 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/one_drive_upload_page.ts +++ b/chrome/browser/resources/chromeos/cloud_upload/one_drive_upload_page.ts
@@ -17,17 +17,26 @@ /** The names of the files to upload. */ private fileNames: string[] = []; + /** + True if the setup flow is being run for the first time. False if the fixup + flow is being run. + */ + private firstTimeSetup: boolean = true; + constructor() { super(); } /** * Sets the file name to be displayed by this dialog. Can be null if there is - * no file to upload. + * no file to upload. Sets whether the setup flow is running for the first + * time. * @param fileName Name of the file to be displayed. + * @param firstTimeSetup Whether the setup flow is running for the first time. */ - setFileNames(fileNames: string[]) { + setFileNamesAndFirstTimeSetup(fileNames: string[], firstTimeSetup: boolean) { this.fileNames = fileNames; + this.firstTimeSetup = firstTimeSetup; if (this.isConnected) { this.connectedCallback(); } @@ -48,8 +57,9 @@ const uploadButton = this.querySelector('.action-button')! as HTMLElement; const cancelButton = this.querySelector('.cancel-button') as HTMLElement; - this.proxy.handler.setOfficeAsDefaultHandler(); - + if (this.firstTimeSetup) { + this.proxy.handler.setOfficeAsDefaultHandler(); + } // TODO(b/251046341): Show multiple files. if (this.fileNames.length > 0) { fileContainerElement.hidden = false;
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html index c73dc3e..31c9d65 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html +++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
@@ -257,6 +257,7 @@ class="emoji-button" is="cr-auto-img" auto-src$="[[getUrl(item)]]]" + on-mouseenter="showTooltip" on-focus="showTooltip" alt$="[[item.base.name]]"> </template> </div> @@ -266,6 +267,7 @@ class="emoji-button" is="cr-auto-img" auto-src$="[[getUrl(item)]]" + on-mouseenter="showTooltip" on-focus="showTooltip" alt$="[[item.base.name]]"> </template> </div>
diff --git a/chrome/browser/resources/intro/browser_proxy.ts b/chrome/browser/resources/intro/browser_proxy.ts index 32fa2f4..e3508ce1 100644 --- a/chrome/browser/resources/intro/browser_proxy.ts +++ b/chrome/browser/resources/intro/browser_proxy.ts
@@ -13,6 +13,9 @@ // Called when the user clicks the "continue without account" button. continueWithoutAccount(): void; + + // Initializes the FRE intro main view. + initializeMainView(): void; } export class IntroBrowserProxyImpl implements IntroBrowserProxy { @@ -24,6 +27,10 @@ chrome.send('continueWithoutAccount'); } + initializeMainView() { + chrome.send('initializeMainView'); + } + static getInstance(): IntroBrowserProxy { return instance || (instance = new IntroBrowserProxyImpl()); }
diff --git a/chrome/browser/resources/intro/sign_in_promo.html b/chrome/browser/resources/intro/sign_in_promo.html index 37fe320..f400410b 100644 --- a/chrome/browser/resources/intro/sign_in_promo.html +++ b/chrome/browser/resources/intro/sign_in_promo.html
@@ -136,7 +136,11 @@ } .fade-in { - animation: fade-in-animation 500ms 1 ease-in-out; + animation: fade-in-animation 500ms ease-in-out; + } + + .fast-fade-in { + animation: fade-in-animation 300ms ease-in-out; } #contentArea { @@ -239,7 +243,6 @@ #left-background-image { animation-duration: 500ms; - animation-iteration-count: 1; animation-name: left-background-slide-animation, fade-in-animation; content: var(--left-background-image-url); left: 0; @@ -248,14 +251,13 @@ #right-background-image { animation-duration: 500ms; - animation-iteration-count: 1; animation-name: right-background-slide-animation, fade-in-animation; content: var(--right-background-image-url); right: 0; } #safeZone { - animation: safe-zone-transition-animation 500ms 1 ease-in-out; + animation: safe-zone-transition-animation 500ms ease-in-out; box-sizing: border-box; display: flex; height: calc(100% - var(--btn-container-height)); @@ -269,7 +271,7 @@ border-top: var(--cr-separator-line); } - #managed-device-disclaimer { + #managedDeviceDisclaimer { align-items: center; border: 1px solid var(--disclaimer-border-color); border-radius: 8px; @@ -283,7 +285,15 @@ padding-inline-end: 18px; } - #managed-device-disclaimer > p { + #managedDeviceDisclaimer.hidden { + display: none; + } + + #managedDeviceDisclaimer.temporarily-hidden { + visibility: hidden; + } + + #managedDeviceDisclaimer > p { flex-grow: 1; font-family: Roboto, Cantarell, Arial, sans-serif; margin-block: 0; @@ -324,25 +334,26 @@ </div> </template> </div> - <template is="dom-if" if="[[shouldDisplayManagedDisclaimer_]]"> - <div id="managed-device-disclaimer" class="fade-in"> - <div id="icon-container"> - <iron-icon icon="cr:domain"></iron-icon> - </div> - <p> - $i18n{managedDeviceDisclaimer} - </p> + <div class$="[[getDisclaimerVisibilityClass_(isDeviceManaged_, managedDeviceDisclaimer_)]]" + id="managedDeviceDisclaimer"> + <div id="icon-container"> + <iron-icon icon="cr:domain"></iron-icon> </div> - </template> + <p> + [[managedDeviceDisclaimer_]] + </p> + </div> </div> </div> <div class="fade-in" id="buttonRow"> <div id="buttonContainer"> <cr-button id="declineSignInButton" - on-click="onContinueWithoutAccountClick_">$i18n{declineSignInButtonTitle}</cr-button> - </cr-button> + disabled="[[areButtonsDisabled_(isDeviceManaged_, managedDeviceDisclaimer_)]]" + on-click="onContinueWithoutAccountClick_">$i18n{declineSignInButtonTitle}</cr-button> + </cr-button> <cr-button class="action-button" id="acceptSignInButton" + disabled="[[areButtonsDisabled_(isDeviceManaged_, managedDeviceDisclaimer_)]]" on-click="onContinueWithAccountClick_">$i18n{acceptSignInButtonTitle}</cr-button> </div> </div>
diff --git a/chrome/browser/resources/intro/sign_in_promo.ts b/chrome/browser/resources/intro/sign_in_promo.ts index d72857a..da1f871 100644 --- a/chrome/browser/resources/intro/sign_in_promo.ts +++ b/chrome/browser/resources/intro/sign_in_promo.ts
@@ -11,6 +11,7 @@ import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -23,6 +24,7 @@ buttonRow: HTMLElement, contentArea: HTMLElement, declineSignInButton: CrButtonElement, + managedDeviceDisclaimer: HTMLElement, safeZone: HTMLElement, }; } @@ -33,7 +35,7 @@ iconName: string; } -const SignInPromoElementBase = I18nMixin(PolymerElement); +const SignInPromoElementBase = WebUiListenerMixin(I18nMixin(PolymerElement)); export class SignInPromoElement extends SignInPromoElementBase { static get is() { @@ -74,11 +76,14 @@ type: Array, }, - shouldDisplayManagedDisclaimer_: { + managedDeviceDisclaimer_: { + type: String, + value: '', + }, + + isDeviceManaged_: { type: Boolean, - value() { - return loadTimeData.getString('managedDeviceDisclaimer').length > 0; - }, + value: loadTimeData.getBoolean('isDeviceManaged'), }, }; } @@ -87,11 +92,20 @@ IntroBrowserProxyImpl.getInstance(); private benefitCards_: BenefitCard[]; private divisionLineResizeObserver_: ResizeObserver|null = null; - private shouldDisplayManagedDisclaimer_: boolean; + private managedDeviceDisclaimer_: string; + private isDeviceManaged_: boolean; override connectedCallback() { super.connectedCallback(); + + this.browserProxy_.initializeMainView(); this.toggleDivisionLine_(); + + if (this.isDeviceManaged_) { + this.addWebUiListener( + 'managed-device-disclaimer-updated', + this.handleManagedDeviceDisclaimerUpdate_.bind(this)); + } } override disconnectedCallback() { @@ -101,11 +115,12 @@ override ready() { super.ready(); - this.addEventListener('view-enter-start', this.onViewEnterStart_); + this.addEventListener( + 'view-enter-start', this.onViewEnterStart_.bind(this)); } private onViewEnterStart_() { - this.setTranslationHeightToAlignLogoAndAnimation(); + this.setTranslationHeightToAlignLogoAndAnimation_(); } private toggleDivisionLine_() { @@ -118,11 +133,25 @@ this.divisionLineResizeObserver_.observe(safeZone); } + private handleManagedDeviceDisclaimerUpdate_(disclaimer: string) { + this.managedDeviceDisclaimer_ = disclaimer; + this.$.managedDeviceDisclaimer.classList.remove('temporarily-hidden'); + this.$.managedDeviceDisclaimer.classList.toggle('fast-fade-in'); + } + + /** + * Disable buttons if the device is managed until the management + * disclaimer is loaded. + */ + private areButtonsDisabled_() { + return this.isDeviceManaged_ && this.managedDeviceDisclaimer_.length === 0; + } + // At the start of the signInPromo animation, the product logo should be at // the same position as the splash view logo animation. To be able // to do that, we had to translate the safeZone vertically up by the value // calculated in the function below, after doing top:50%. - private setTranslationHeightToAlignLogoAndAnimation() { + private setTranslationHeightToAlignLogoAndAnimation_() { const contentAreaHeight = this.$.contentArea.clientHeight; const safeZoneHeight = this.$.safeZone.clientHeight; const productLogoMarginTop = parseInt( @@ -148,6 +177,17 @@ private onContinueWithoutAccountClick_() { this.browserProxy_.continueWithoutAccount(); } + + // To keep the layout stable during animations, for non-managed devices the + // disclaimer is omitted from the layout, and for managed devices it is + // invisible while we're fetching the text to display. + private getDisclaimerVisibilityClass_() { + if (!this.isDeviceManaged_) { + return 'hidden'; + } + return this.managedDeviceDisclaimer_.length === 0 ? 'temporarily-hidden' : + ''; + } } declare global {
diff --git a/chrome/browser/resources/nearby_share/shared/BUILD.gn b/chrome/browser/resources/nearby_share/shared/BUILD.gn index a6ea3a45..8948886d 100644 --- a/chrome/browser/resources/nearby_share/shared/BUILD.gn +++ b/chrome/browser/resources/nearby_share/shared/BUILD.gn
@@ -10,7 +10,7 @@ assert(is_chromeos, "Nearby Share is CrOS only") os_settings_dir = "$root_gen_dir/chrome/browser/resources/settings/chromeos" -preprocess_folder = "tsc/shared" +preprocessed_folder = "tsc_input/shared" preprocess_gen_v3_manifest = "preprocessed_gen_v3_manifest.json" preprocess_v3_manifest = "preprocessed_v3_manifest.json" @@ -54,10 +54,7 @@ generate_grd("build_v3_grdp") { grd_prefix = "nearby_share" out_grd = "$target_gen_dir/${grd_prefix}_resources_v3.grdp" - deps = [ - ":preprocess_gen_v3", - ":preprocess_v3", - ] + deps = [ ":preprocess" ] manifest_files = [ "$target_gen_dir/$preprocess_gen_v3_manifest", "$target_gen_dir/$preprocess_v3_manifest", @@ -65,17 +62,24 @@ resource_path_prefix = "shared" } +group("preprocess") { + public_deps = [ + ":preprocess_gen_v3", + ":preprocess_v3", + ] +} + preprocess_if_expr("preprocess_gen_v3") { deps = [ ":html_wrapper_files" ] in_folder = target_gen_dir in_files = html_wrapper_files - out_folder = "$os_settings_dir/$preprocess_folder" + out_folder = "$os_settings_dir/$preprocessed_folder" out_manifest = "$target_gen_dir/$preprocess_gen_v3_manifest" } preprocess_if_expr("preprocess_v3") { in_files = web_component_files + non_web_component_files - out_folder = "$os_settings_dir/$preprocess_folder" + out_folder = "$os_settings_dir/$preprocessed_folder" out_manifest = "$target_gen_dir/$preprocess_v3_manifest" }
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 0a96167e..cea6e62d 100644 --- a/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js +++ b/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.js
@@ -14,6 +14,7 @@ import 'chrome://resources/cr_elements/cr_shared_style.css.js'; import 'chrome://resources/cr_elements/cr_icons.css.js'; +import './nearby_contact_visibility.js'; import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
diff --git a/chrome/browser/resources/new_tab_page/OWNERS b/chrome/browser/resources/new_tab_page/OWNERS index 33d721a..827e01a 100644 --- a/chrome/browser/resources/new_tab_page/OWNERS +++ b/chrome/browser/resources/new_tab_page/OWNERS
@@ -1,5 +1,6 @@ mahmadi@chromium.org pauladedeji@google.com romanarora@chromium.org +rtatum@google.com tiborg@chromium.org tluk@chromium.org
diff --git a/chrome/browser/resources/new_tab_page/app.html b/chrome/browser/resources/new_tab_page/app.html index d96e6e2..b2f0ae42 100644 --- a/chrome/browser/resources/new_tab_page/app.html +++ b/chrome/browser/resources/new_tab_page/app.html
@@ -1,5 +1,6 @@ <style include="cr-shared-style"> :host { + --cr-focus-outline-color: var(--color-new-tab-page-focus-ring); --ntp-theme-text-shadow: none; --ntp-one-google-bar-height: 56px; --ntp-search-box-width: 337px;
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 f337439..d3c723c 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
@@ -94,6 +94,10 @@ right: 0; top: 2px; } + + .action-button:focus-visible { + outline: var(--color-new-tab-page-focus-ring) 1px auto; + } </style> <div id="consentCardContainer"> @@ -113,7 +117,7 @@ <template id="consentStepRepeat" is="dom-repeat" items="[[steps_]]" as="step"> <div class="step-container" id="[[step.id]]"> - <div class="content-container truncate" tabindex="0"> + <div class="content-container truncate"> <span class="content"> [[step.content]] </span>
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 20e00f56..57737d6 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/module.html +++ b/chrome/browser/resources/new_tab_page/modules/cart/module.html
@@ -18,6 +18,10 @@ } } + a:focus-visible { + outline: var(--color-new-tab-page-focus-ring); + } + #module:hover .side-scroll-button { visibility: visible; }
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.html b/chrome/browser/resources/new_tab_page/realbox/realbox.html index fba0165..1db2c26b 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox.html +++ b/chrome/browser/resources/new_tab_page/realbox/realbox.html
@@ -1,19 +1,20 @@ <style include="cr-icons"> :host { - --ntp-realbox-border-radius: calc(0.5 * var(--ntp-realbox-height)); - --ntp-realbox-height: 44px; - --ntp-realbox-shadow: 0 1px 6px 0 var(--color-realbox-shadow); + --cr-realbox-height: 44px; + --cr-realbox-shadow: 0 1px 6px 0 var(--color-realbox-shadow); + + --ntp-realbox-border-radius: calc(0.5 * var(--cr-realbox-height)); --ntp-realbox-icon-width: 26px; --ntp-realbox-inner-icon-margin: 8px; --ntp-realbox-voice-icon-offset: 16px; border-radius: var(--ntp-realbox-border-radius); - box-shadow: var(--ntp-realbox-shadow); + box-shadow: var(--cr-realbox-shadow); font-size: 16px; - height: var(--ntp-realbox-height); + height: var(--cr-realbox-height); } :host([is-dark]) { - --ntp-realbox-shadow: 0 2px 6px 0 var(--color-realbox-shadow); + --cr-realbox-shadow: 0 2px 6px 0 var(--color-realbox-shadow); } :host([realbox-lens-search-enabled_]) { @@ -36,7 +37,7 @@ :host([match-searchbox]:not([matches-are-visible]):hover) { border: 1px solid transparent; - box-shadow: var(--ntp-realbox-shadow); + box-shadow: var(--cr-realbox-shadow); } :host([match-searchbox]:not([is-dark]):not([matches-are-visible]):not(:hover)) { @@ -99,14 +100,14 @@ background-color: var(--color-realbox-background-hovered); } - ntp-realbox-icon { + cr-realbox-icon { height: 100%; left: 12px; position: absolute; top: 0; } - :host-context([dir='rtl']) ntp-realbox-icon { + :host-context([dir='rtl']) cr-realbox-icon { left: unset; right: 12px; } @@ -170,11 +171,11 @@ box-shadow: var(--ntp-focus-shadow); } - :-webkit-any(input, ntp-realbox-icon, .realbox-icon-button) { + :-webkit-any(input, cr-realbox-icon, .realbox-icon-button) { z-index: 100; } - ntp-realbox-dropdown { + cr-realbox-dropdown { left: 0; position: absolute; right: 0; @@ -191,9 +192,9 @@ on-cut="onInputCutCopy_" on-focus="onInputFocus_" on-input="onInputInput_" on-keydown="onInputKeydown_" on-keyup="onInputKeyup_" on-mousedown="onInputMouseDown_" on-paste="onInputPaste_"> - <ntp-realbox-icon id="icon" match="[[selectedMatch_]]" + <cr-realbox-icon id="icon" match="[[selectedMatch_]]" default-icon="[[realboxIcon_]]" in-searchbox> - </ntp-realbox-icon> + </cr-realbox-icon> <button id="voiceSearchButton" class="realbox-icon-button" on-click="onVoiceSearchClick_" title="$i18n{voiceSearchButtonLabel}"> </button> @@ -202,10 +203,10 @@ on-click="onLensSearchClick_" title="$i18n{lensSearchButtonLabel}"> </button> </template> - <ntp-realbox-dropdown id="matches" role="listbox" result="[[result_]]" + <cr-realbox-dropdown id="matches" role="listbox" result="[[result_]]" selected-match-index="{{selectedMatchIndex_}}" on-result-repaint="onResultRepaint_" on-match-focusin="onMatchFocusin_" on-match-click="onMatchClick_" on-match-remove="onMatchRemove_" on-header-focusin="onHeaderFocusin_" hidden$="[[!matchesAreVisible]]"> - </ntp-realbox-dropdown> -</div> \ No newline at end of file + </cr-realbox-dropdown> +</div>
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.ts b/chrome/browser/resources/new_tab_page/realbox/realbox.ts index d768901..eb4a19b 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox.ts +++ b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
@@ -181,7 +181,7 @@ /** * Index of the currently selected match, if any. - * Do not modify this. Use <ntp-realbox-dropdown> API to change selection. + * Do not modify this. Use <cr-realbox-dropdown> API to change selection. */ selectedMatchIndex_: { type: Number,
diff --git a/chrome/browser/resources/new_tab_page/shared_vars.css b/chrome/browser/resources/new_tab_page/shared_vars.css index cb1ee77e..69999e12 100644 --- a/chrome/browser/resources/new_tab_page/shared_vars.css +++ b/chrome/browser/resources/new_tab_page/shared_vars.css
@@ -14,6 +14,6 @@ --google-red-50: rgb(var(--google-red-50-rgb)); --google-red-800-rgb: 179, 20, 18; /* #b31412 */ --google-red-800: rgb(var(--google-red-800-rgb)); - --ntp-focus-shadow: 0 0 0 2px var(--color-new-tab-page-focus-shadow); + --ntp-focus-shadow: 0 0 0 2px var(--color-new-tab-page-focus-ring); --ntp-module-text-size: 13px; }
diff --git a/chrome/browser/resources/omnibox_popup/app.html b/chrome/browser/resources/omnibox_popup/app.html index 847b738..f28f933a 100644 --- a/chrome/browser/resources/omnibox_popup/app.html +++ b/chrome/browser/resources/omnibox_popup/app.html
@@ -3,6 +3,6 @@ font-size: 14.6px; /* closely resembles the omnibox input font size. */ } </style> -<ntp-realbox-dropdown id="matches" result="[[result_]]" +<cr-realbox-dropdown id="matches" result="[[result_]]" on-dom-change="onResultRepaint_"> -</ntp-realbox-dropdown> +</cr-realbox-dropdown>
diff --git a/chrome/browser/resources/print_preview/ui/OWNERS b/chrome/browser/resources/print_preview/ui/OWNERS new file mode 100644 index 0000000..076a1bf --- /dev/null +++ b/chrome/browser/resources/print_preview/ui/OWNERS
@@ -0,0 +1 @@ +per-file *_cros*=gavinwill@chromium.org
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn index 251381828..16e6d00 100644 --- a/chrome/browser/resources/settings/BUILD.gn +++ b/chrome/browser/resources/settings/BUILD.gn
@@ -256,9 +256,6 @@ if (is_win) { web_component_files += [ - "safety_check_page/safety_check_chrome_cleaner_child.ts", - "chrome_cleanup_page/chrome_cleanup_page.ts", - "chrome_cleanup_page/items_to_remove_list.ts", "incompatible_applications_page/incompatible_application_item.ts", "incompatible_applications_page/incompatible_applications_page.ts", ] @@ -370,10 +367,7 @@ } if (is_win) { - non_web_component_files += [ - "chrome_cleanup_page/chrome_cleanup_proxy.ts", - "incompatible_applications_page/incompatible_applications_browser_proxy.ts", - ] + non_web_component_files += [ "incompatible_applications_page/incompatible_applications_browser_proxy.ts" ] } if (is_win || is_mac) { non_web_component_files += [ "autofill_page/passkeys_browser_proxy.ts" ]
diff --git a/chrome/browser/resources/settings/autofill_page/iban_edit_dialog.ts b/chrome/browser/resources/settings/autofill_page/iban_edit_dialog.ts index bf1fe05ea..145bc941 100644 --- a/chrome/browser/resources/settings/autofill_page/iban_edit_dialog.ts +++ b/chrome/browser/resources/settings/autofill_page/iban_edit_dialog.ts
@@ -114,6 +114,7 @@ */ private onIbanSaveButtonClick_() { const iban = { + guid: this.iban?.guid, value: this.value_!.trim(), nickname: this.nickname_ ? this.nickname_.trim() : '', };
diff --git a/chrome/browser/resources/settings/autofill_page/iban_list_entry.html b/chrome/browser/resources/settings/autofill_page/iban_list_entry.html index ec09c995..d77f0a5f 100644 --- a/chrome/browser/resources/settings/autofill_page/iban_list_entry.html +++ b/chrome/browser/resources/settings/autofill_page/iban_list_entry.html
@@ -1,4 +1,11 @@ <style include="settings-shared passwords-shared"> + .second-column { + align-items: center; + display: flex; + flex: 1; + justify-content: flex-end; + } + .list-item { margin-bottom: 8px; margin-top: 8px; @@ -10,4 +17,10 @@ <div id="value" class="ellipses">[[iban.metadata.summaryLabel]]</div> <div id="nickname" class="ellipses sub-label">[[iban.nickname]]</div> </div> + <div role="cell" class="second-column"> + <cr-icon-button class="icon-more-vert" id="ibanMenu" + title="[[getMoreActionsTitle_(iban)]]" + on-click="onDotsMenuClick_"> + </cr-icon-button> + </div> </div>
diff --git a/chrome/browser/resources/settings/autofill_page/iban_list_entry.ts b/chrome/browser/resources/settings/autofill_page/iban_list_entry.ts index 56722541..8ebc35c 100644 --- a/chrome/browser/resources/settings/autofill_page/iban_list_entry.ts +++ b/chrome/browser/resources/settings/autofill_page/iban_list_entry.ts
@@ -12,11 +12,33 @@ import '../settings_shared.css.js'; import './passwords_shared.css.js'; +import {I18nMixin} from '//resources/cr_elements/i18n_mixin.js'; +import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './iban_list_entry.html.js'; -export class SettingsIbanListEntryElement extends PolymerElement { +export type DotsIbanMenuClickEvent = CustomEvent<{ + iban: chrome.autofillPrivate.IbanEntry, + anchorElement: HTMLElement, +}>; + +declare global { + interface HTMLElementEventMap { + 'dots-iban-menu-click': DotsIbanMenuClickEvent; + } +} + +export interface SettingsIbanListEntryElement { + $: { + ibanMenu: CrButtonElement, + }; +} + +const SettingsIbanListEntryElementBase = I18nMixin(PolymerElement); + +export class SettingsIbanListEntryElement extends + SettingsIbanListEntryElementBase { static get is() { return 'settings-iban-list-entry'; } @@ -33,6 +55,54 @@ } iban: chrome.autofillPrivate.IbanEntry; + + /** + * Opens the IBAN action menu. + */ + private onDotsMenuClick_() { + this.dispatchEvent(new CustomEvent('dots-iban-menu-click', { + bubbles: true, + composed: true, + detail: { + iban: this.iban, + anchorElement: this.$.ibanMenu, + }, + })); + } + + private onRemoteEditClick_() { + this.dispatchEvent(new CustomEvent('remote-iban-menu-click', { + bubbles: true, + composed: true, + })); + } + + /** + * @return the title for the More Actions button corresponding to the IBAN + * which is described by the nickname or last 4 digits of the IBAN's + * value. + */ + private getMoreActionsTitle_(iban: chrome.autofillPrivate.IbanEntry): string { + if (iban.nickname) { + return this.i18n('moreActionsForIban', iban.nickname); + } + + // Strip all whitespace and get the pure last four digits of the value. + const strippedSummaryLabel = + iban.metadata ? iban.metadata!.summaryLabel.replace(/\s/g, '') : ''; + const lastFourDigits = strippedSummaryLabel.substring( + Math.max(0, strippedSummaryLabel.length - 4)); + + return this.i18n( + 'moreActionsForIban', + this.i18n('moreActionsForIbanDescription', lastFourDigits)); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'settings-iban-list-entry': SettingsIbanListEntryElement; + } } customElements.define(
diff --git a/chrome/browser/resources/settings/autofill_page/payments_list.html b/chrome/browser/resources/settings/autofill_page/payments_list.html index bd3bb9d..8075a84 100644 --- a/chrome/browser/resources/settings/autofill_page/payments_list.html +++ b/chrome/browser/resources/settings/autofill_page/payments_list.html
@@ -31,15 +31,16 @@ </settings-credit-card-list-entry> </template> </div> + <div class="list-separator" hidden$="[[!showCreditCardIbanSeparator_]]"> + </div> <div class="vertical-list list-with-header" role="rowgroup"> <template is="dom-repeat" items="[[ibans]]"> <settings-iban-list-entry iban="[[item]]"> </settings-iban-list-entry> </template> </div> - <template is="dom-if" if="[[showCreditCardUpiSeparator_]]"> - <div class="list-separator"></div> - </template> + <div class="list-separator" hidden$="[[!showSeparatorBeforeUpiSection_]]"> + </div> <template is="dom-if" if="[[showUpiIds_(upiIds, enableUpiIds_)]]"> <div class="vertical-list list-with-header" role="rowgroup"> <template is="dom-repeat" items="[[upiIds]]">
diff --git a/chrome/browser/resources/settings/autofill_page/payments_list.ts b/chrome/browser/resources/settings/autofill_page/payments_list.ts index e7c6cecd..b4668e0 100644 --- a/chrome/browser/resources/settings/autofill_page/payments_list.ts +++ b/chrome/browser/resources/settings/autofill_page/payments_list.ts
@@ -79,13 +79,24 @@ }, /** - * True iff both credit cards and UPI IDs will be shown. + * True iff both credit cards and IBANs will be shown. */ - showCreditCardUpiSeparator_: { + showCreditCardIbanSeparator_: { type: Boolean, value: false, - computed: 'computeShowCreditCardUpiSeparator_(' + - 'creditCards, upiIds, enableUpiIds_)', + computed: 'computeShowCreditCardIbanSeparator_(' + + 'creditCards, ibans, enableIbans_)', + }, + + /** + * True if at least credit cards or IBANs will be shown before UPI IDs + * section. + */ + showSeparatorBeforeUpiSection_: { + type: Boolean, + value: false, + computed: 'computeShowSeparatorBeforeUpiSection_(' + + 'creditCards, ibans, enableIbans_, upiIds, enableUpiIds_)', }, /** @@ -106,7 +117,8 @@ private enableIbans_: boolean; private enableUpiIds_: boolean; private removeCardExpirationAndTypeTitlesEnabled_: boolean; - private showCreditCardUpiSeparator_: boolean; + private showCreditCardIbanSeparator_: boolean; + private showSeparatorBeforeUpiSection_: boolean; private showAnyPaymentMethods_: boolean; /** @@ -139,10 +151,18 @@ } /** - * @return true iff both credit cards and UPI IDs will be shown. + * @return true iff both credit cards and IBANs will be shown. */ - private computeShowCreditCardUpiSeparator_(): boolean { - return this.showCreditCards_() && this.showUpiIds_(); + private computeShowCreditCardIbanSeparator_(): boolean { + return this.showCreditCards_() && this.showIbans_(); + } + + /** + * @return true iff both credit cards and UPI IDs will be shown, or both IBANs + * and UPI IDs will be shown. + */ + private computeShowSeparatorBeforeUpiSection_(): boolean { + return (this.showCreditCards_() || this.showIbans_()) && this.showUpiIds_(); } /**
diff --git a/chrome/browser/resources/settings/autofill_page/payments_manager_proxy.ts b/chrome/browser/resources/settings/autofill_page/payments_manager_proxy.ts index 7662fafe..ba07592 100644 --- a/chrome/browser/resources/settings/autofill_page/payments_manager_proxy.ts +++ b/chrome/browser/resources/settings/autofill_page/payments_manager_proxy.ts
@@ -42,6 +42,9 @@ */ saveCreditCard(creditCard: chrome.autofillPrivate.CreditCardEntry): void; + /** @param guid The GUID of the IBAN to remove. */ + removeIban(guid: string): void; + /** * Saves the given IBAN. */ @@ -119,6 +122,10 @@ chrome.autofillPrivate.saveIban(iban); } + removeIban(guid: string) { + chrome.autofillPrivate.removeEntry(guid); + } + migrateCreditCards() { chrome.autofillPrivate.migrateCreditCards(); }
diff --git a/chrome/browser/resources/settings/autofill_page/payments_section.html b/chrome/browser/resources/settings/autofill_page/payments_section.html index c634d67..858955c1 100644 --- a/chrome/browser/resources/settings/autofill_page/payments_section.html +++ b/chrome/browser/resources/settings/autofill_page/payments_section.html
@@ -113,7 +113,8 @@ class$="list-frame [[computeCssClass_( removeCardExpirationAndTypeTitlesEnabled_, virtualCardMetadataEnabled_)]]" - credit-cards="[[creditCards]]" ibans="[[ibans]]" upi-ids="[[upiIds]]"> + credit-cards="[[creditCards]]" ibans="[[ibans]]" upi-ids="[[upiIds]]" + on-dots-iban-menu-click="onDotsIbanMenuClick_"> </settings-payments-list> <cr-action-menu id="creditCardSharedMenu" role-description="$i18n{menu}"> @@ -143,6 +144,21 @@ </button> </cr-action-menu> +<cr-lazy-render id="ibanSharedActionMenu"> + <template> + <cr-action-menu id="ibanSharedMenu" role-description="$i18n{menu}"> + <button id="menuEditIban" class="dropdown-item" + on-click="onMenuEditIbanClick_"> + $i18n{editIban} + </button> + <button id="menuRemoveIban" class="dropdown-item" + on-click="onMenuRemoveIbanClick_"> + $i18n{removeIban} + </button> + </cr-action-menu> + </template> +</cr-lazy-render> + <template is="dom-if" if="[[showCreditCardDialog_]]" restamp> <settings-credit-card-edit-dialog credit-card="[[activeCreditCard_]]" on-close="onCreditCardDialogClose_">
diff --git a/chrome/browser/resources/settings/autofill_page/payments_section.ts b/chrome/browser/resources/settings/autofill_page/payments_section.ts index 51d29b3..8d64a9d 100644 --- a/chrome/browser/resources/settings/autofill_page/payments_section.ts +++ b/chrome/browser/resources/settings/autofill_page/payments_section.ts
@@ -35,10 +35,10 @@ import {MetricsBrowserProxyImpl, PrivacyElementInteractions} from '../metrics_browser_proxy.js'; import {PersonalDataChangedListener} from './autofill_manager_proxy.js'; +import {DotsIbanMenuClickEvent} from './iban_list_entry.js'; import {PaymentsManagerImpl, PaymentsManagerProxy} from './payments_manager_proxy.js'; import {getTemplate} from './payments_section.html.js'; - type DotsCardMenuiClickEvent = CustomEvent<{ creditCard: chrome.autofillPrivate.CreditCardEntry, anchorElement: HTMLElement, @@ -55,6 +55,7 @@ autofillCreditCardToggle: SettingsToggleButtonElement, canMakePaymentToggle: SettingsToggleButtonElement, creditCardSharedMenu: CrActionMenuElement, + ibanSharedActionMenu: CrLazyRenderElement<CrActionMenuElement>, menuClearCreditCard: HTMLElement, menuEditCreditCard: HTMLElement, menuRemoveCreditCard: HTMLElement, @@ -223,6 +224,7 @@ override ready() { super.ready(); + // TODO(crbug.com/1409766): Add the listener declaratively for all above. this.addEventListener('save-credit-card', this.saveCreditCard_); this.addEventListener( 'dots-card-menu-click', this.onCreditCardDotsMenuClick_); @@ -336,6 +338,17 @@ } /** + * Opens the IBAN action menu. + */ + private onDotsIbanMenuClick_(e: DotsIbanMenuClickEvent) { + // Copy item so dialog won't update model on cancel. + this.activeIban_ = e.detail.iban; + this.activeDialogAnchor_ = e.detail.anchorElement; + + this.$.ibanSharedActionMenu.get().showAt(e.detail.anchorElement); + } + + /** * Handles clicking on the "Add credit card" button. */ private onAddCreditCardClick_(e: Event) { @@ -420,6 +433,27 @@ } /** + * Handles clicking on the "Edit" IBAN button. + */ + private onMenuEditIbanClick_(e: Event) { + e.preventDefault(); + this.showIbanDialog_ = true; + this.$.ibanSharedActionMenu.get().close(); + } + + /** + * Handles clicking on the "Remove" IBAN button. + */ + private onMenuRemoveIbanClick_() { + assert(this.activeIban_); + this.paymentsManager_.removeIban(this.activeIban_.guid!); + this.$.ibanSharedActionMenu.get().close(); + assert(this.activeDialogAnchor_); + focusWithoutInk(this.activeDialogAnchor_); + this.activeIban_ = null; + } + + /** * Handles clicking on the "Clear copy" button for cached credit cards. */ private onMenuClearCreditCardClick_() {
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html deleted file mode 100644 index 632c1061..0000000 --- a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html +++ /dev/null
@@ -1,79 +0,0 @@ - <style include="cr-shared-style settings-shared iron-flex"> - #status-title { - font-weight: 500; - } - - #waiting-spinner { - flex-shrink: 0; - height: 2.0em; - width: 2.0em; - } - - /* Apply a fixed height to the <svg> tag inside #powered-by-logo. - Used by |chromeCleanupPoweredByHTML|. */ - #powered-by-logo > svg { - height: 22px; - } - </style> - <div class="cr-row first"> - <div class="flex"> - <div id="status-title" role="status" inner-h-t-m-l="[[title_]]"></div> - <div hidden="[[!showExplanation_]]"> - <span class="secondary">[[explanation_]]</span> - </div> - </div> - <paper-spinner-lite id="waiting-spinner" - hidden="[[!isWaitingForResult_]]" active="[[isWaitingForResult_]]"> - </paper-spinner-lite> - <template is="dom-if" if="[[showActionButton_]]"> - <cr-policy-pref-indicator pref="[[prefs.software_reporter.enabled]]"> - </cr-policy-pref-indicator> - <div class="separator"></div> - <cr-button id="action-button" class="action-button" - disabled$="[[!cleanupEnabled_]]" on-click="proceed_"> - [[actionButtonLabel_]] - </cr-button> - </template> - </div> - <div class="cr-row continuation"> - <settings-checkbox hidden="[[!showLogsPermission_]]" - id="chromeCleanupLogsUploadControl" - sub-label="$i18n{chromeCleanupExplanationLogsPermissionPref}" - pref="{{prefs.software_reporter.reporting}}" - disabled$="[[!cleanupEnabled_]]"> - </settings-checkbox> - </div> - <cr-expand-button - aria-label="[[showItemsLinkLabel_]]" - class="cr-row" - expanded="{{itemsToRemoveSectionExpanded_}}" - hidden="[[!showItemsToRemove_]]" - id="show-items-button"> - [[showItemsLinkLabel_]] - </cr-expand-button> - <iron-collapse id="iron-collapse-items" - opened="[[itemsToRemoveSectionExpanded_]]"> - <items-to-remove-list - id="files-to-remove-list" - hidden="[[!hasFilesToShow_]]" - title="$i18n{chromeCleanupDetailsFilesAndPrograms}" - items-to-show="[[ - getListEntriesFromFilePaths_(scannerResults_.files)]]"> - </items-to-remove-list> - <items-to-remove-list - id="registry-keys-list" - hidden="[[!hasRegistryKeysToShow_]]" - title="$i18n{chromeCleanupDetailsRegistryEntries}" - items-to-show="[[ - getListEntriesFromStrings_(scannerResults_.registryKeys)]]"> - </items-to-remove-list> - <div class="cr-row continuation"> - <div class="secondary"> - $i18nRaw{chromeCleanupDetailsExplanation} - </div> - </div> - <div id="powered-by" class="cr-row continuation" - hidden="[[!isPoweredByPartner_]]"> - $i18nRaw{chromeCleanupPoweredByHtml} - </div> - </iron-collapse>
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.ts b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.ts deleted file mode 100644 index 20a1f6f5..0000000 --- a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.ts +++ /dev/null
@@ -1,744 +0,0 @@ -// Copyright 2015 The Chromium Authors -// 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_button/cr_button.js'; -import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js'; -import 'chrome://resources/cr_elements/policy/cr_policy_pref_indicator.js'; -import 'chrome://resources/cr_elements/cr_shared_style.css.js'; -import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; -import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; -import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; -import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; -import 'chrome://resources/polymer/v3_0/paper-styles/color.js'; -import '../controls/controlled_button.js'; -import '../controls/settings_checkbox.js'; -import '../prefs/prefs.js'; -import '../settings_shared.css.js'; - -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; -import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; -import {assert} from 'chrome://resources/js/assert_ts.js'; -import {sanitizeInnerHtml} from 'chrome://resources/js/parse_html_subset.js'; -import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {SettingsCheckboxElement} from '../controls/settings_checkbox.js'; - -import {getTemplate} from './chrome_cleanup_page.html.js'; -import {ChromeCleanupProxy, ChromeCleanupProxyImpl} from './chrome_cleanup_proxy.js'; -import {ChromeCleanupRemovalListItem} from './items_to_remove_list.js'; - -/** - * The reason why the controller is in state kIdle. - * Must be kept in sync with ChromeCleanerController::IdleReason. - */ -export enum ChromeCleanupIdleReason { - INITIAL = 'initial', - REPORTER_FOUND_NOTHING = 'reporter_found_nothing', - REPORTER_FAILED = 'reporter_failed', - SCANNING_FOUND_NOTHING = 'scanning_found_nothing', - SCANNING_FAILED = 'scanning_failed', - CONNECTION_LOST = 'connection_lost', - USER_DECLINED_CLEANUP = 'user_declined_cleanup', - CLEANING_FAILED = 'cleaning_failed', - CLEANING_SUCCEEDED = 'cleaning_succeeded', - CLEANER_DOWNLOAD_FAILED = 'cleaner_download_failed', -} - -/** - * The possible states for the cleanup card. - */ -enum ChromeCleanerCardState { - SCANNING_OFFERED = 'scanning_offered', - SCANNING = 'scanning', - CLEANUP_OFFERED = 'cleanup_offered', - CLEANING = 'cleaning', - REBOOT_REQUIRED = 'reboot_required', - SCANNING_FOUND_NOTHING = 'scanning_found_nothing', - SCANNING_FAILED = 'scanning_failed', - CLEANUP_SUCCEEDED = 'cleanup_succeeded', - CLEANING_FAILED = 'cleanup_failed', - CLEANER_DOWNLOAD_FAILED = 'cleaner_download_failed', -} - -/** - * Boolean properties for a cleanup card state. - */ -enum ChromeCleanupCardFlags { - NONE = 0, - SHOW_LOGS_PERMISSIONS = 1 << 0, - WAITING_FOR_RESULT = 1 << 1, - SHOW_ITEMS_TO_REMOVE = 1 << 2, -} - -/** - * Identifies an ongoing scanning/cleanup action. - */ -enum ChromeCleanupOngoingAction { - NONE = 0, - SCANNING = 1, - CLEANING = 2, -} - -interface ChromeCleanupCardActionButton { - label: string; - doAction: () => void; -} - -interface ChromeCleanupCardComponents { - title: string|null; - explanation: string|null; - actionButton: ChromeCleanupCardActionButton|null; - flags: number; -} - -/** - * Represents the file path structure of a base::FilePath. - * dirname ends with a separator. - */ -export interface ChromeCleanupFilePath { - dirname: string; - basename: string; -} - -export interface ChromeCleanerScannerResults { - files: ChromeCleanupFilePath[]; - registryKeys: string[]; -} - -/** - * @fileoverview - * 'settings-chrome-cleanup-page' is the settings page containing Chrome - * Cleanup settings. - * - * Example: - * - * <iron-animated-pages> - * <settings-chrome-cleanup-page></settings-chrome-cleanup-page> - * ... other pages ... - * </iron-animated-pages> - */ - -export interface SettingsChromeCleanupPageElement { - $: { - chromeCleanupLogsUploadControl: SettingsCheckboxElement, - chromeCleanupShowNotificationControl: SettingsCheckboxElement, - }; -} - -const SettingsChromeCleanupPageElementBase = - WebUiListenerMixin(I18nMixin(PolymerElement)); - -export class SettingsChromeCleanupPageElement extends - SettingsChromeCleanupPageElementBase { - static get is() { - return 'settings-chrome-cleanup-page'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /** - * Preferences state. - */ - prefs: { - type: Object, - notify: true, - }, - - title_: { - type: String, - value: '', - }, - - explanation_: { - type: String, - value: '', - }, - - isWaitingForResult_: { - type: Boolean, - value: '', - }, - - showActionButton_: { - type: Boolean, - value: false, - }, - - cleanupEnabled_: { - type: Boolean, - value: true, - }, - - actionButtonLabel_: { - type: String, - value: '', - }, - - showExplanation_: { - type: Boolean, - computed: 'computeShowExplanation_(explanation_)', - }, - - showLogsPermission_: { - type: Boolean, - value: false, - }, - - showItemsToRemove_: { - type: Boolean, - value: false, - }, - - itemsToRemoveSectionExpanded_: { - type: Boolean, - value: false, - observer: 'itemsToRemoveSectionExpandedChanged_', - }, - - showItemsLinkLabel_: { - type: String, - value: '', - }, - - showingAllFiles_: { - type: Boolean, - value: false, - }, - - scannerResults_: { - type: Object, - value() { - return {'files': [], 'registryKeys': []}; - }, - }, - - hasFilesToShow_: { - type: Boolean, - computed: 'computeHasFilesToShow_(scannerResults_)', - }, - - hasRegistryKeysToShow_: { - type: Boolean, - computed: 'computeHasRegistryKeysToShow_(scannerResults_)', - }, - - logsUploadPref_: { - type: Object, - value() { - return {}; - }, - }, - - isPoweredByPartner_: { - type: Boolean, - value: false, - }, - - /** - * Virtual pref that's attached to the notification checkbox. - */ - notificationEnabledPref_: { - type: Object, - value() { - return { - type: chrome.settingsPrivate.PrefType.BOOLEAN, - value: false, - }; - }, - }, - }; - } - - prefs: {software_reporter: {reporting: chrome.settingsPrivate.PrefObject}}; - private title_: TrustedHTML; - private explanation_: string; - private isWaitingForResult_: boolean; - private showActionButton_: boolean; - private cleanupEnabled_: boolean; - private actionButtonLabel_: string; - private showExplanation_: boolean; - private showLogsPermission_: boolean; - private showNotificationPermission_: boolean; - private showItemsToRemove_: boolean; - private itemsToRemoveSectionExpanded_: boolean; - private showItemsLinkLabel_: string; - private showingAllFiles_: boolean; - private scannerResults_: ChromeCleanerScannerResults; - private hasFilesToShow_: boolean; - private hasRegistryKeysToShow_: boolean; - private logsUploadPref_: chrome.settingsPrivate.PrefObject; - private isPoweredByPartner_: boolean; - private notificationEnabledPref_: chrome.settingsPrivate.PrefObject; - - private emptyChromeCleanerScannerResults_: - ChromeCleanerScannerResults = {files: [], registryKeys: []}; - private browserProxy_: ChromeCleanupProxy = - ChromeCleanupProxyImpl.getInstance(); - private doAction_: (() => void)|null = null; - private cardStateToComponentsMap_: - Map<ChromeCleanerCardState, ChromeCleanupCardComponents>|null = null; - private ongoingAction_: ChromeCleanupOngoingAction = - ChromeCleanupOngoingAction.NONE; - private renderScanOfferedByDefault_: boolean; - - constructor() { - super(); - - /** - * If true; the scan offered view is rendered on state idle, regardless of - * the idle reason received from the cleaner controller. The goal is to - * ignore previous interactions (such as completed cleanups) performed on - * other tabs or if this tab is reloaded. - * Set to false whenever there is a transition to a non-idle state while the - * current tab is open. - */ - this.renderScanOfferedByDefault_ = true; - } - - override connectedCallback() { - super.connectedCallback(); - - this.cardStateToComponentsMap_ = this.buildCardStateToComponentsMap_(); - - this.addWebUiListener( - 'chrome-cleanup-on-idle', - (idleReason: string) => this.onIdle_(idleReason)); - this.addWebUiListener( - 'chrome-cleanup-on-scanning', () => this.onScanning_()); - // Note: both reporter running and scanning share the same UI. - this.addWebUiListener( - 'chrome-cleanup-on-reporter-running', () => this.onScanning_()); - this.addWebUiListener( - 'chrome-cleanup-on-infected', - (isPoweredByPartner: boolean, - scannerResults: ChromeCleanerScannerResults) => - this.onInfected_(isPoweredByPartner, scannerResults)); - this.addWebUiListener( - 'chrome-cleanup-on-cleaning', - (isPoweredByPartner: boolean, - scannerResults: ChromeCleanerScannerResults) => - this.onCleaning_(isPoweredByPartner, scannerResults)); - this.addWebUiListener( - 'chrome-cleanup-on-reboot-required', () => this.onRebootRequired_()); - this.addWebUiListener( - 'chrome-cleanup-enabled-change', - (enabled: boolean) => this.onCleanupEnabledChange_(enabled)); - this.browserProxy_.registerChromeCleanerObserver(); - } - - /** - * Implements the action for the only visible button in the UI, which can be - * either to start an action such as a cleanup or to restart the computer. - */ - private proceed_() { - this.doAction_!(); - } - - /** - * Notifies Chrome that the details section was opened or closed. - */ - private itemsToRemoveSectionExpandedChanged_( - newVal: boolean, oldVal: boolean) { - if (!oldVal && newVal) { - this.browserProxy_.notifyShowDetails(this.itemsToRemoveSectionExpanded_); - } - } - - private computeShowExplanation_(explanation: string): boolean { - return explanation !== ''; - } - - /** - * @param scannerResults The cleanup items to be presented to the user. - * @return Whether there are files to show to the user. - */ - private computeHasFilesToShow_(scannerResults: ChromeCleanerScannerResults): - boolean { - return scannerResults.files.length > 0; - } - - /** - * @param scannerResults The cleanup items to be presented to the user. - * @return Whether user-initiated cleanups are enabled and there are registry - * keys to show to the user. - */ - private computeHasRegistryKeysToShow_( - scannerResults: ChromeCleanerScannerResults): boolean { - return scannerResults.registryKeys.length > 0; - } - - /** - * Listener of event 'chrome-cleanup-on-idle'. - */ - private onIdle_(idleReason: string) { - const lastAction = this.ongoingAction_; - this.ongoingAction_ = ChromeCleanupOngoingAction.NONE; - this.scannerResults_ = this.emptyChromeCleanerScannerResults_; - - // Ignore the idle reason and render the scan offered view if no - // interaction happened on this tab. - if (this.renderScanOfferedByDefault_) { - idleReason = ChromeCleanupIdleReason.INITIAL; - } - - switch (idleReason) { - case ChromeCleanupIdleReason.INITIAL: - this.renderCleanupCard_(ChromeCleanerCardState.SCANNING_OFFERED); - break; - - case ChromeCleanupIdleReason.SCANNING_FOUND_NOTHING: - case ChromeCleanupIdleReason.REPORTER_FOUND_NOTHING: - this.renderCleanupCard_(ChromeCleanerCardState.SCANNING_FOUND_NOTHING); - break; - - case ChromeCleanupIdleReason.SCANNING_FAILED: - case ChromeCleanupIdleReason.REPORTER_FAILED: - this.renderCleanupCard_(ChromeCleanerCardState.SCANNING_FAILED); - break; - - case ChromeCleanupIdleReason.CONNECTION_LOST: - if (lastAction === ChromeCleanupOngoingAction.SCANNING) { - this.renderCleanupCard_(ChromeCleanerCardState.SCANNING_FAILED); - } else { - assert(lastAction === ChromeCleanupOngoingAction.CLEANING); - this.renderCleanupCard_(ChromeCleanerCardState.CLEANING_FAILED); - } - break; - - case ChromeCleanupIdleReason.CLEANING_FAILED: - case ChromeCleanupIdleReason.USER_DECLINED_CLEANUP: - this.renderCleanupCard_(ChromeCleanerCardState.CLEANING_FAILED); - break; - - case ChromeCleanupIdleReason.CLEANING_SUCCEEDED: - this.renderCleanupCard_(ChromeCleanerCardState.CLEANUP_SUCCEEDED); - break; - - case ChromeCleanupIdleReason.CLEANER_DOWNLOAD_FAILED: - this.renderCleanupCard_(ChromeCleanerCardState.CLEANER_DOWNLOAD_FAILED); - break; - - default: - assert(false, `Unknown idle reason: ${idleReason}`); - } - } - - /** - * Listener of event 'chrome-cleanup-on-scanning'. - * No UI will be shown in the Settings page on that state, simply hide the - * card and cleanup this element's fields. - */ - private onScanning_() { - this.ongoingAction_ = ChromeCleanupOngoingAction.SCANNING; - this.scannerResults_ = this.emptyChromeCleanerScannerResults_; - this.renderScanOfferedByDefault_ = false; - this.renderCleanupCard_(ChromeCleanerCardState.SCANNING); - } - - /** - * Listener of event 'chrome-cleanup-on-infected'. - * Offers a cleanup to the user and enables presenting files to be removed. - * @param isPoweredByPartner If scanning results are provided by a partner's - * engine. - * @param scannerResults The cleanup items to be presented to the user. - */ - private onInfected_( - isPoweredByPartner: boolean, - scannerResults: ChromeCleanerScannerResults) { - this.isPoweredByPartner_ = isPoweredByPartner; - this.ongoingAction_ = ChromeCleanupOngoingAction.NONE; - this.renderScanOfferedByDefault_ = false; - this.scannerResults_ = scannerResults; - this.updateShowItemsLinklabel_(); - this.renderCleanupCard_(ChromeCleanerCardState.CLEANUP_OFFERED); - } - - /** - * Listener of event 'chrome-cleanup-on-cleaning'. - * Shows a spinner indicating that an on-going action and enables presenting - * files to be removed. - * @param isPoweredByPartner If scanning results are provided by a partner's - * engine. - * @param scannerResults The cleanup items to be presented to the user. - */ - private onCleaning_( - isPoweredByPartner: boolean, - scannerResults: ChromeCleanerScannerResults) { - this.isPoweredByPartner_ = isPoweredByPartner; - this.ongoingAction_ = ChromeCleanupOngoingAction.CLEANING; - this.renderScanOfferedByDefault_ = false; - this.scannerResults_ = scannerResults; - this.updateShowItemsLinklabel_(); - this.renderCleanupCard_(ChromeCleanerCardState.CLEANING); - } - - /** - * Listener of event 'chrome-cleanup-on-reboot-required'. - * No UI will be shown in the Settings page on that state, so we simply hide - * the card and cleanup this element's fields. - */ - private onRebootRequired_() { - this.ongoingAction_ = ChromeCleanupOngoingAction.NONE; - this.scannerResults_ = this.emptyChromeCleanerScannerResults_; - this.renderScanOfferedByDefault_ = false; - this.renderCleanupCard_(ChromeCleanerCardState.REBOOT_REQUIRED); - } - - /** - * Renders the cleanup card given the state and list of files. - * @param state The card state to be rendered. - */ - private renderCleanupCard_(state: ChromeCleanerCardState) { - const components = this.cardStateToComponentsMap_!.get(state); - assert(components); - - this.title_ = components.title === null ? - window.trustedTypes!.emptyHTML : - sanitizeInnerHtml(components.title); - this.explanation_ = components.explanation || ''; - this.updateActionButton_(components.actionButton); - this.updateCardFlags_(components.flags); - } - - /** - * Updates the action button on the cleanup card as the action expected for - * the current state. - * @param actionButton The button to render, or null if no button should be - * shown. - */ - private updateActionButton_(actionButton: ChromeCleanupCardActionButton| - null) { - if (!actionButton) { - this.showActionButton_ = false; - this.actionButtonLabel_ = ''; - this.doAction_ = null; - } else { - this.showActionButton_ = true; - this.actionButtonLabel_ = actionButton.label; - this.doAction_ = actionButton.doAction; - } - } - - /** - * Updates boolean flags corresponding to optional components to be rendered - * on the card. - * @param flags Flags indicating optional components to be rendered. - */ - private updateCardFlags_(flags: number) { - this.showLogsPermission_ = - (flags & ChromeCleanupCardFlags.SHOW_LOGS_PERMISSIONS) !== 0; - this.isWaitingForResult_ = - (flags & ChromeCleanupCardFlags.WAITING_FOR_RESULT) !== 0; - this.showItemsToRemove_ = - (flags & ChromeCleanupCardFlags.SHOW_ITEMS_TO_REMOVE) !== 0; - - // Files to remove list should only be expandable if details are being - // shown, otherwise it will add extra padding at the bottom of the card. - if (!this.showExplanation_ || !this.showItemsToRemove_) { - this.itemsToRemoveSectionExpanded_ = false; - } - } - - /** - * @param enabled Whether cleanup is enabled. - */ - private onCleanupEnabledChange_(enabled: boolean) { - this.cleanupEnabled_ = enabled; - } - - /** - * Sends an action to the browser proxy to start scanning. - */ - private startScanning_() { - this.browserProxy_.startScanning( - this.$.chromeCleanupLogsUploadControl.checked); - } - - /** - * Sends an action to the browser proxy to start the cleanup. - */ - private startCleanup_() { - this.browserProxy_.startCleanup( - this.$.chromeCleanupLogsUploadControl.checked); - } - - /** - * Sends an action to the browser proxy to restart the machine. - */ - private restartComputer_() { - this.browserProxy_.restartComputer(); - } - - /** - * Updates the label for the collapsed detailed view. If user-initiated - * cleanups are enabled, the string is obtained from the browser proxy, - * since it may require a plural version. Otherwise, use the default value - * for |chromeCleanupLinkShowItems|. - */ - private updateShowItemsLinklabel_() { - const setShowItemsLabel = (text: string) => this.showItemsLinkLabel_ = text; - this.browserProxy_ - .getItemsToRemovePluralString( - this.scannerResults_.files.length + - this.scannerResults_.registryKeys.length) - .then(setShowItemsLabel); - } - - /** - * @return The map of card states to components to be rendered. - */ - private buildCardStateToComponentsMap_(): - Map<ChromeCleanerCardState, ChromeCleanupCardComponents> { - /** - * The action buttons to show on the card. - * @enum {ChromeCleanupCardActionButton} - */ - const actionButtons = { - FIND: { - label: this.i18n('chromeCleanupFindButtonLabel'), - doAction: () => this.startScanning_(), - }, - - REMOVE: { - label: this.i18n('chromeCleanupRemoveButtonLabel'), - doAction: () => this.startCleanup_(), - }, - - RESTART_COMPUTER: { - label: this.i18n('chromeCleanupRestartButtonLabel'), - doAction: () => this.restartComputer_(), - }, - - TRY_SCAN_AGAIN: { - label: this.i18n('chromeCleanupTitleTryAgainButtonLabel'), - // TODO(crbug.com/776538): do not run the reporter component again. - // Try downloading the cleaner and scan with it instead. - doAction: () => this.startScanning_(), - }, - }; - - return new Map([ - [ - ChromeCleanerCardState.CLEANUP_OFFERED, - { - title: this.i18n('chromeCleanupTitleRemove'), - explanation: this.i18n('chromeCleanupExplanationRemove'), - actionButton: actionButtons.REMOVE, - flags: ChromeCleanupCardFlags.SHOW_LOGS_PERMISSIONS | - ChromeCleanupCardFlags.SHOW_ITEMS_TO_REMOVE, - }, - ], - [ - ChromeCleanerCardState.CLEANING, - { - title: this.i18n('chromeCleanupTitleRemoving'), - explanation: this.i18n('chromeCleanupExplanationRemoving'), - actionButton: null, - flags: ChromeCleanupCardFlags.WAITING_FOR_RESULT | - ChromeCleanupCardFlags.SHOW_ITEMS_TO_REMOVE, - }, - ], - [ - ChromeCleanerCardState.REBOOT_REQUIRED, - { - title: this.i18n('chromeCleanupTitleRestart'), - explanation: null, - actionButton: actionButtons.RESTART_COMPUTER, - flags: ChromeCleanupCardFlags.NONE, - }, - ], - [ - ChromeCleanerCardState.CLEANUP_SUCCEEDED, - { - title: this.i18nAdvanced('chromeCleanupTitleRemoved', {tags: ['a']}) - .toString(), - explanation: null, - actionButton: null, - flags: ChromeCleanupCardFlags.NONE, - }, - ], - [ - ChromeCleanerCardState.CLEANING_FAILED, - { - title: this.i18n('chromeCleanupTitleErrorCantRemove'), - explanation: this.i18n('chromeCleanupExplanationCleanupError'), - actionButton: null, - flags: ChromeCleanupCardFlags.NONE, - }, - ], - [ - ChromeCleanerCardState.SCANNING_OFFERED, - { - title: this.i18n('chromeCleanupTitleFindAndRemove'), - explanation: this.i18n('chromeCleanupExplanationFindAndRemove'), - actionButton: actionButtons.FIND, - flags: ChromeCleanupCardFlags.SHOW_LOGS_PERMISSIONS, - }, - ], - [ - ChromeCleanerCardState.SCANNING, - { - title: this.i18n('chromeCleanupTitleScanning'), - explanation: null, - actionButton: null, - flags: ChromeCleanupCardFlags.WAITING_FOR_RESULT, - }, - ], - [ - // TODO(crbug.com/776538): Could we offer to reset settings here? - ChromeCleanerCardState.SCANNING_FOUND_NOTHING, - { - title: this.i18n('chromeCleanupTitleNothingFound'), - explanation: null, - actionButton: null, - flags: ChromeCleanupCardFlags.NONE, - }, - ], - [ - ChromeCleanerCardState.SCANNING_FAILED, - { - title: this.i18n('chromeCleanupTitleScanningFailed'), - explanation: this.i18n('chromeCleanupExplanationScanError'), - actionButton: null, - flags: ChromeCleanupCardFlags.NONE, - }, - ], - [ - ChromeCleanerCardState.CLEANER_DOWNLOAD_FAILED, - { - // TODO(crbug.com/776538): distinguish between missing network - // connectivity and cleanups being disabled by the server. - title: this.i18n('chromeCleanupTitleCleanupUnavailable'), - explanation: this.i18n('chromeCleanupExplanationCleanupUnavailable'), - actionButton: actionButtons.TRY_SCAN_AGAIN, - flags: ChromeCleanupCardFlags.NONE, - }, - ], - ]); - } - - private getListEntriesFromStrings_(list: string[]): - ChromeCleanupRemovalListItem[] { - return list.map(entry => ({text: entry, highlightSuffix: null})); - } - - private getListEntriesFromFilePaths_(paths: ChromeCleanupFilePath[]): - ChromeCleanupRemovalListItem[] { - return paths.map( - path => ({text: path.dirname, highlightSuffix: path.basename})); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'settings-chrome-cleanup-page': SettingsChromeCleanupPageElement; - } -} - -customElements.define( - SettingsChromeCleanupPageElement.is, SettingsChromeCleanupPageElement);
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_proxy.ts b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_proxy.ts deleted file mode 100644 index 4956c34..0000000 --- a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_proxy.ts +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// clang-format off -import {sendWithPromise} from 'chrome://resources/js/cr.js'; -// clang-format on - -export interface ChromeCleanupProxy { - /** - * Registers the current ChromeCleanupHandler as an observer of - * ChromeCleanerController events. - */ - registerChromeCleanerObserver(): void; - - /** - * Starts scanning the user's computer. - */ - startScanning(logsUploadEnabled: boolean): void; - - /** - * Starts a cleanup on the user's computer. - */ - startCleanup(logsUploadEnabled: boolean): void; - - /** - * Restarts the user's computer. - */ - restartComputer(): void; - - /** - * Notifies Chrome that the state of the details section changed. - */ - notifyShowDetails(enabled: boolean): void; - - /** - * Notifies Chrome that the "learn more" link was clicked. - */ - notifyLearnMoreClicked(): void; - - /** - * Requests the plural string for the "show more" link in the detailed - * view for either files to delete or registry keys. - */ - getMoreItemsPluralString(numHiddenItems: number): Promise<string>; - - /** - * Requests the plural string for the "items to remove" link in the detailed - * view. - */ - getItemsToRemovePluralString(numItems: number): Promise<string>; -} - -export class ChromeCleanupProxyImpl implements ChromeCleanupProxy { - registerChromeCleanerObserver() { - chrome.send('registerChromeCleanerObserver'); - } - - startScanning(logsUploadEnabled: boolean) { - chrome.send('startScanning', [logsUploadEnabled]); - } - - startCleanup(logsUploadEnabled: boolean) { - chrome.send('startCleanup', [logsUploadEnabled]); - } - - restartComputer() { - chrome.send('restartComputer'); - } - - notifyShowDetails(enabled: boolean) { - chrome.send('notifyShowDetails', [enabled]); - } - - notifyLearnMoreClicked() { - chrome.send('notifyChromeCleanupLearnMoreClicked'); - } - - getMoreItemsPluralString(numHiddenItems: number) { - return sendWithPromise('getMoreItemsPluralString', numHiddenItems); - } - - getItemsToRemovePluralString(numItems: number) { - return sendWithPromise('getItemsToRemovePluralString', numItems); - } - - static getInstance(): ChromeCleanupProxy { - return instance || (instance = new ChromeCleanupProxyImpl()); - } - - static setInstance(obj: ChromeCleanupProxy) { - instance = obj; - } -} - -let instance: ChromeCleanupProxy|null = null;
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.html b/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.html deleted file mode 100644 index e2e4226b..0000000 --- a/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.html +++ /dev/null
@@ -1,55 +0,0 @@ - <style include="settings-shared"> - :host { - display: block; - margin: 0; - padding: 0 var(--cr-section-padding); - word-break: break-all; - } - - #more-items-link { - color: var(--cr-link-color); - cursor: pointer; - } - - #remaining-list :first-child { - margin-top: -1em; - } - - .highlight-suffix { - font-weight: bold; - } - - </style> - <div id="title" class="secondary">[[title]]</div> - <ul class="secondary"> - <template is="dom-repeat" items="[[initialItems_]]"> - <li class="visible-item"> - <span>[[item.text]]</span><!-- - --><span class="highlight-suffix" - hidden="[[!hasHighlightSuffix_(item)]]"><!-- - -->[[item.highlightSuffix]] - </span> - </li> - </template> - <li id="more-items-link" hidden="[[expanded_]]" on-click="expandList_"> - [[moreItemsLinkText_]] - </li> - </ul> - <!-- Remaining items are kept in a separate <ul> element so that screen - readers don't get confused when the list is expanded. If new items are - simply added to the first <ul> element, the first new item (which will - replace the "N more" link), will be skipped by the reader. As a - consequence, visual impaired users will only have a chance to inspect - that item if they move up on the list, which can't be considered an - expected action. --> - <ul id="remaining-list" hidden="[[!expanded_]]" class="secondary"> - <template is="dom-repeat" items="[[remainingItems_]]"> - <li class$="[[remainingItemsClass_(expanded_)]]"> - <span>[[item.text]]</span><!-- - --><span class="highlight-suffix" - hidden="[[!hasHighlightSuffix_(item)]]"><!-- - -->[[item.highlightSuffix]] - </span> - </li> - </template> - </ul>
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.ts b/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.ts deleted file mode 100644 index 2bd221b..0000000 --- a/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.ts +++ /dev/null
@@ -1,163 +0,0 @@ -// Copyright 2017 The Chromium Authors -// 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_shared_vars.css.js'; -import 'chrome://resources/polymer/v3_0/paper-styles/color.js'; -import '../settings_shared.css.js'; - -import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {ChromeCleanupProxyImpl} from './chrome_cleanup_proxy.js'; -import {getTemplate} from './items_to_remove_list.html.js'; - -/** - * For each line in the item list, the text field will be shown in normal - * style at front of the line. The highlightSuffix will be appended to the end - * of line and emphasized with bold font. - */ -export interface ChromeCleanupRemovalListItem { - text: string; - highlightSuffix: string|null; -} - -/** - * The default number of items to show for files, registry keys and extensions - * on the detailed view when user-initiated cleanups are enabled. - */ -export const CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW: number = 4; - -/** - * @fileoverview - * 'items-to-remove-list' represents a list of items to - * be removed or changed to be shown on the Chrome Cleanup page. - * TODO(crbug.com/776538): Update the strings to say that some items are only - * changed and not removed. - * - * Example: - * - * <!-- Items list initially shows |CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW| - * items. If there are more than - * |CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW| items on the list, then a "show - * more" link is shown; tapping on it expands the list. --> - * <items-to-remove-list - * title="Files and programs:" - * items-to-show="[[filesToShow]]"> - * </items-to-remove-list> - */ - -export class ItemsToRemoveListElement extends PolymerElement { - static get is() { - return 'items-to-remove-list'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - title: { - type: String, - value: '', - }, - - itemsToShow: { - type: Array, - observer: 'updateVisibleState_', - }, - - /** - * If true, all items from |itemsToShow| will be presented on the card, - * and the "show more" link will be omitted. - */ - expanded_: { - type: Boolean, - value: false, - }, - - /** - * The first |CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW| items of |itemsToShow| - * if the list is longer than |CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW|. - */ - initialItems_: Array, - - /** - * The remaining items to be presented that are not included in - * |initialItems_|. Items in this list are only shown to the user if - * |expanded_| is true. - */ - remainingItems_: Array, - - /** - * The text for the "show more" link available if not all files are - * visible in the card. - */ - moreItemsLinkText_: { - type: String, - value: '', - }, - }; - } - - override title: string; - itemsToShow: ChromeCleanupRemovalListItem[]; - private expanded_: boolean; - private initialItems_: ChromeCleanupRemovalListItem[]|null; - private remainingItems_: ChromeCleanupRemovalListItem[]|null; - private moreItemsLinkText_: string; - - private expandList_() { - this.expanded_ = true; - this.moreItemsLinkText_ = ''; - } - - /** - * Decides which elements will be visible in the card and if the "show more" - * link will be rendered. - * - * 1. If size(itemsToShow) < CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW, then all - * items will be visible. - * 2. Otherwise, exactly |CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW - 1| will be - * visible and the "show more" link will be rendered. The list presented - * to the user will contain exactly |CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW| - * elements, and the last one will be the "show more" link. - */ - private updateVisibleState_(itemsToShow: ChromeCleanupRemovalListItem[]) { - // Start expanded if there are less than - // |CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW| items to show. - this.expanded_ = itemsToShow.length <= CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW; - - if (this.expanded_) { - this.initialItems_ = itemsToShow; - this.remainingItems_ = []; - this.moreItemsLinkText_ = ''; - return; - } - - this.initialItems_ = - itemsToShow.slice(0, CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW - 1); - this.remainingItems_ = - itemsToShow.slice(CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW - 1); - - const browserProxy = ChromeCleanupProxyImpl.getInstance(); - browserProxy.getMoreItemsPluralString(this.remainingItems_.length) - .then(linkText => { - this.moreItemsLinkText_ = linkText; - }); - } - - /** - * Returns the class for the <li> elements that correspond to the items - * hidden in the default view. - */ - private remainingItemsClass_(expanded: boolean): string { - return expanded ? 'visible-item' : 'hidden-item'; - } - - private hasHighlightSuffix_(item: ChromeCleanupRemovalListItem): boolean { - return item.highlightSuffix !== null; - } -} - -customElements.define(ItemsToRemoveListElement.is, ItemsToRemoveListElement);
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index b7af3a2..91efda8 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -36,10 +36,7 @@ ] out_manifest = "$target_gen_dir/$build_manifest_v3" - deps = [ - ":build_ts", - "//chrome/browser/resources/nearby_share/shared:preprocess_v3", - ] + deps = [ ":build_ts" ] excludes = [ "chrome://resources/cr_components/app_management/app_management.mojom-webui.js", "chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js", @@ -84,11 +81,12 @@ ":generate_mojom_webui", ":preprocess", "//ash/webui/common/resources:generate_definitions", + "//chrome/browser/resources/nearby_share/shared:preprocess", ] definitions = ts_definition_files root_dir = tsc_input_dir - in_files = - src_ts_files + html_wrapper_files + css_wrapper_files + mojom_webui_files + in_files = src_ts_files + html_wrapper_files + css_wrapper_files + + mojom_webui_files + nearby_share_shared_files out_dir = tsc_output_dir }
diff --git a/chrome/browser/resources/settings/chromeos/assert_extras.ts b/chrome/browser/resources/settings/chromeos/assert_extras.ts index f3e0f3b..646a523 100644 --- a/chrome/browser/resources/settings/chromeos/assert_extras.ts +++ b/chrome/browser/resources/settings/chromeos/assert_extras.ts
@@ -14,10 +14,9 @@ * @throws If |arg| is undefined or null. */ export function assertExists<T>( - arg: T, message?: string): asserts arg is NonNullable<T> { - assert( - arg !== undefined && arg !== null, - message || `Expected ${arg} to be defined.`); + arg: T, message: string = `Expected ${arg} to be defined.`): + asserts arg is NonNullable<T> { + assert(arg !== undefined && arg !== null, message); } /**
diff --git a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_browser_proxy.ts b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_browser_proxy.ts index eba4560..8aac231 100644 --- a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_browser_proxy.ts +++ b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_browser_proxy.ts
@@ -295,6 +295,9 @@ */ setVmDeviceShared(id: GuestId, device: string, shared: boolean): Promise<boolean>; + + /** Show Bruschetta installer. */ + requestBruschettaInstallerView(): void; } let instance: CrostiniBrowserProxy|null = null; @@ -465,4 +468,8 @@ Promise<boolean> { return sendWithPromise('setVmDeviceShared', id, device, shared); } + + requestBruschettaInstallerView() { + chrome.send('requestBruschettaInstallerView'); + } }
diff --git a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_page.html b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_page.html index f4bea5f..a1dbc6c 100644 --- a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_page.html +++ b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_page.html
@@ -46,18 +46,33 @@ </template> </div> - <template is="dom-if" if="[[enableBruschetta_]]"> - <div id="bruschetta" class="settings-box first" - actionable + <template is="dom-if" if="[[showBruschetta_]]"> + <div id="bruschetta" class="settings-box two-line" + actionable$="[[isBruschettaInstalled_]]" on-click="onBruschettaSubpageTap_"> <div class="start"> $i18n{bruschettaPageLabel} + <div class="secondary" id="secondaryText"> + <localized-link + localized-string="[[i18nAdvanced('bruschettaSubtext')]]"> + </localized-link> + </div> </div> - <cr-icon-button class="subpage-arrow" - aria-label="$i18n{crostiniPageTitle}" - aria-describedby="secondaryText" - aria-roledescription="$i18n{subpageArrowRoleDescription}"> - </cr-icon-button> + <template is="dom-if" if="[[isBruschettaInstalled_]]"> + <cr-icon-button class="subpage-arrow" + aria-label="$i18n{bruschettaPageLabel}" + aria-describedby="secondaryText" + aria-roledescription="$i18n{subpageArrowRoleDescription}"> + </cr-icon-button> + </template> + <template is="dom-if" if="[[!isBruschettaInstalled_]]"> + <div class="separator"></div> + <cr-button id="enable" + on-click="onBruschettaEnableTap_" + aria-describedby="secondaryText"> + $i18n{bruschettaEnable} + </cr-button> + </template> </div> </template> </div>
diff --git a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_page.ts b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_page.ts index 30c6543..f4f65896 100644 --- a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_page.ts +++ b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_page.ts
@@ -121,16 +121,21 @@ value: () => new Set<Setting>([Setting.kSetUpCrostini]), }, - enableBruschetta_: { + showBruschetta_: { type: Boolean, - value: loadTimeData.getBoolean('enableBruschetta'), + value: loadTimeData.getBoolean('showBruschetta'), + }, + + isBruschettaInstalled_: { + type: Boolean, + value: loadTimeData.getBoolean('isBruschettaInstalled'), }, }; } private browserProxy_: CrostiniBrowserProxy; private disableCrostiniInstall_: boolean; - private enableBruschetta_: boolean; + private isBruschettaInstalled_: boolean; constructor() { super(); @@ -178,8 +183,15 @@ } } + private onBruschettaEnableTap_(event: Event) { + this.browserProxy_.requestBruschettaInstallerView(); + // Stop propagation so that onBruschettaSubpageTap_ isn't called. + event.stopPropagation(); + } + private onBruschettaSubpageTap_() { - if (this.enableBruschetta_) { + // This function is called on-click even if actionable=false. + if (this.isBruschettaInstalled_) { Router.getInstance().navigateTo(routes.BRUSCHETTA_DETAILS); } }
diff --git a/chrome/browser/resources/settings/chromeos/device_page/audio.html b/chrome/browser/resources/settings/chromeos/device_page/audio.html index 8414ef99..aab37a08 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/audio.html +++ b/chrome/browser/resources/settings/chromeos/device_page/audio.html
@@ -61,9 +61,8 @@ <!-- Output section --> <template is="dom-if" if="[[showAudioInfo]]"> - <!-- TODO(crbug.com/1092970): Output section should be hidden if there are no - output devices. --> - <div id="output"> + <div id="output" + hidden="[[getOutputHidden_(audioSystemProperties_.outputDevices)]]"> <h2 id="audioOutputTitle">$i18n{audioOutputTitle}</h2> <div id="audioOutputSubsection" class="subsection"> <div id="outputDeviceSubsection" class="settings-box"> @@ -106,8 +105,9 @@ </div> </div> <!--TODO(b/260277007): Replace placeholder text when localization strings - available. Add styling. --> - <div id="input"> + available. Add styling. --> + <div id="input" + hidden="[[getInputHidden_(audioSystemProperties_.inputDevices)]]"> <h2 id="audioInputTitle">Input</h2> <div id="audioInputSection" class="subsection"> <div id="audioInputDeviceSubsection" class="settings-box">
diff --git a/chrome/browser/resources/settings/chromeos/device_page/audio.ts b/chrome/browser/resources/settings/chromeos/device_page/audio.ts index 25cbae3..43107ae79 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/audio.ts +++ b/chrome/browser/resources/settings/chromeos/device_page/audio.ts
@@ -267,6 +267,22 @@ return SETTINGS_20PX_ICON_PREFIX + 'volume-up'; } + + /** + * Handles the case when there are no output devices. The output section + * should be hidden in this case. + */ + protected getOutputHidden_(): boolean { + return this.audioSystemProperties_.outputDevices.length === 0; + } + + /** + * Handles the case when there are no input devices. The input section should + * be hidden in this case. + */ + protected getInputHidden_(): boolean { + return this.audioSystemProperties_.inputDevices.length === 0; + } } declare global {
diff --git a/chrome/browser/resources/settings/chromeos/lazy_load.js b/chrome/browser/resources/settings/chromeos/lazy_load.js index 30d6633e..ad77a3c3 100644 --- a/chrome/browser/resources/settings/chromeos/lazy_load.js +++ b/chrome/browser/resources/settings/chromeos/lazy_load.js
@@ -86,8 +86,8 @@ export {TimeZoneAutoDetectMethod} from './date_time_page/date_time_types.js'; export {TimeZoneBrowserProxyImpl} from './date_time_page/timezone_browser_proxy.js'; export {CROSTINI_TYPE, GuestOsBrowserProxy, GuestOsBrowserProxyImpl, GuestOsSharedUsbDevice, PLUGIN_VM_TYPE} from './guest_os/guest_os_browser_proxy.js'; -export {LanguagesBrowserProxy, LanguagesBrowserProxyImpl} from './os_languages_page/languages_browser_proxy.js'; -export {InputsShortcutReminderState, LanguagesMetricsProxy, LanguagesMetricsProxyImpl, LanguagesPageInteraction} from './os_languages_page/languages_metrics_proxy.js'; +export {LanguagesBrowserProxyImpl} from './os_languages_page/languages_browser_proxy.js'; +export {InputsShortcutReminderState, LanguagesMetricsProxyImpl, LanguagesPageInteraction} from './os_languages_page/languages_metrics_proxy.js'; export {PrinterType} from './os_printing_page/cups_printer_types.js'; export {CupsPrintersBrowserProxy, CupsPrintersBrowserProxyImpl, PrinterSetupResult, PrintServerResult} from './os_printing_page/cups_printers_browser_proxy.js'; export {CupsPrintersEntryManager} from './os_printing_page/cups_printers_entry_manager.js';
diff --git a/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js b/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js index 89e86e9..20df7d1 100644 --- a/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js +++ b/chrome/browser/resources/settings/chromeos/nearby_share_page/nearby_share_contact_visibility_dialog.js
@@ -10,6 +10,7 @@ import 'chrome://resources/cr_elements/cr_button/cr_button.js'; import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import '../../shared/nearby_contact_visibility.js'; import '../../shared/nearby_onboarding_page.js'; import '../../shared/nearby_visibility_page.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html index 08c88d3..c3f7417 100644 --- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html +++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.html
@@ -35,7 +35,7 @@ id="bluetoothStateText" aria-live="polite" aria-label$="[[getDeviceStatusA11yLabel_(device_.*, pageState_)]]"> - [[getBluetoothStateTextLabel_(device_.*, pageState_)]] + [[getBluetoothStateTextLabel_(pageState_)]] </div> <template is="dom-if" if="[[shouldShowBatteryInfo_(device_.*, pageState_)]]" @@ -80,7 +80,7 @@ disabled$="[[isConnectDisconnectBtnDisabled(pageState_)]]" class="action-button" on-click="onConnectDisconnectBtnClick_"> - [[getBluetoothConnectDisconnectBtnLabel_(isDeviceConnected_)]] + [[getBluetoothConnectDisconnectBtnLabel_(isDeviceConnected_, pageState_)]] </cr-button> </template> </div>
diff --git a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.ts b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.ts index 987747d..b5cad6e 100644 --- a/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.ts +++ b/chrome/browser/resources/settings/chromeos/os_bluetooth_page/os_bluetooth_device_detail_subpage.ts
@@ -201,6 +201,10 @@ return this.i18n('bluetoothConnecting'); } + if (this.pageState_ === PageState.DISCONNECTING) { + return this.i18n('bluetoothDeviceDetailConnected'); + } + return this.pageState_ === PageState.CONNECTED ? this.i18n('bluetoothDeviceDetailConnected') : this.i18n('bluetoothDeviceDetailDisconnected'); @@ -473,15 +477,13 @@ private disconnectDevice_(): void { this.pageState_ = PageState.DISCONNECTING; - getBluetoothConfig().disconnect(this.deviceId_).then(response => { - this.handleDisconnectResult_(response.success); - }); - } - private handleDisconnectResult_(success: boolean): void { - if (success) { - this.pageState_ = PageState.DISCONNECTED; - } + // When disconnecting, disconnect() callback function could be called + // a few seconds before device connectionState is updated. This + // causes a situation where connectedState label is 'disconnected' + // while the color is green. `pageState_` would be updated in + // onDeviceChanged_(). + getBluetoothConfig().disconnect(this.deviceId_); } private isConnectDisconnectBtnDisabled(): boolean {
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.js b/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.ts similarity index 70% rename from chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.ts index 9a46227..f8b7df7 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.ts
@@ -18,14 +18,12 @@ import {LanguageHelper, LanguagesModel} from './languages_types.js'; // The IME ID for the Accessibility Common extension used by Dictation. -/** @type {string} */ -const ACCESSIBILITY_COMMON_IME_ID = +const ACCESSIBILITY_COMMON_IME_ID: string = '_ext_ime_egfdjlfmgnehecnclamagfafdccgfndpdictation'; -/** @polymer */ class OsSettingsAddInputMethodsDialogElement extends PolymerElement { static get is() { - return 'os-settings-add-input-methods-dialog'; + return 'os-settings-add-input-methods-dialog' as const; } static get template() { @@ -34,20 +32,19 @@ static get properties() { return { - /** @type {!LanguagesModel|undefined} */ languages: Object, - - /** @type {!LanguageHelper} */ languageHelper: Object, }; } + // Public API: Downwards data flow. + languages: LanguagesModel|undefined; + languageHelper: LanguageHelper; + /** * Get suggested input methods based on user's enabled languages and ARC IMEs - * @return {!Array<!chrome.languageSettingsPrivate.InputMethod>} - * @private */ - getSuggestedInputMethodIds_() { + private getSuggestedInputMethodIds_(): string[] { const languageCodes = [ ...this.languageHelper.getEnabledLanguageCodes(), this.languageHelper.getArcImeLanguageCode(), @@ -58,9 +55,10 @@ // methods to the top of the suggested list. // TODO(b/237492047): Remove this once 1P Vietnamese input methods are // suitable for widespread use. - const isVietnameseExtension = inputMethod => - (inputMethod.id.startsWith('_ext_ime_') && - inputMethod.languageCodes.includes('vi')); + const isVietnameseExtension = + (inputMethod: chrome.languageSettingsPrivate.InputMethod): boolean => + (inputMethod.id.startsWith('_ext_ime_') && + inputMethod.languageCodes.includes('vi')); inputMethods = inputMethods.filter(isVietnameseExtension) .concat(inputMethods.filter( inputMethod => !isVietnameseExtension(inputMethod))); @@ -68,11 +66,17 @@ } /** - * @return {!Array<!Item>} A list of possible input methods. - * @private + * @return A list of possible input methods. */ - getInputMethods_() { - return this.languages.inputMethods.supported + private getInputMethods_(): Item[] { + return this + // This assertion of `this.languages` is potentially unsafe and could + // fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + .languages! + // Safety: `LanguagesModel.inputMethods` is always defined on CrOS. + .inputMethods!.supported .filter(inputMethod => { // Don't show input methods which are already enabled. if (this.languageHelper.isInputMethodEnabled(inputMethod.id)) { @@ -95,10 +99,8 @@ /** * Add input methods. - * @param {!CustomEvent<!Set<string>>} e - * @private */ - onItemsAdded_(e) { + private onItemsAdded_(e: HTMLElementEventMap['items-added']): void { e.detail.forEach(id => { this.languageHelper.addInputMethod(id); }); @@ -109,3 +111,10 @@ customElements.define( OsSettingsAddInputMethodsDialogElement.is, OsSettingsAddInputMethodsDialogElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsAddInputMethodsDialogElement.is]: + OsSettingsAddInputMethodsDialogElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/add_items_dialog.js b/chrome/browser/resources/settings/chromeos/os_languages_page/add_items_dialog.js deleted file mode 100644 index 1a3bd1f0..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/add_items_dialog.js +++ /dev/null
@@ -1,347 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview 'os-settings-add-items-dialog' is a dialog for adding an - * unordered set of items at a time. The component supports suggested items, as - * well as items being disabled by policy. - */ -import 'chrome://resources/cr_elements/cr_button/cr_button.js'; -import 'chrome://resources/cr_elements/cr_search_field/cr_search_field.js'; -import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; -import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; -import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; -import './cr_checkbox_with_policy.js'; -import './shared_style.css.js'; -import '../../settings_shared.css.js'; - -import {CrScrollableBehavior, CrScrollableBehaviorInterface} from 'chrome://resources/ash/common/cr_scrollable_behavior.js'; -import {FindShortcutBehavior, FindShortcutBehaviorInterface} from '../find_shortcut_behavior.js'; -import {afterNextRender, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {getTemplate} from './add_items_dialog.html.js'; - -const ITEMS_ADDED_EVENT_NAME = 'items-added'; - -/** - * `id` must unique. - * `name` is the displayed name to the user. - * `searchTerms` are additional strings which will be matched when doing a text - * search. - * `disabledByPolicy` can be set to show that a given item is disabled by - * policy. These items will never appear as a suggestion. - * @typedef {{id: string, name: string, searchTerms: !Array<string>, - * disabledByPolicy: boolean}} - */ -export let Item; - -/** - * @constructor - * @extends {PolymerElement} - * @implements {CrScrollableBehaviorInterface} - * @implements {FindShortcutBehaviorInterface} - */ -const OsSettingsAddItemsDialogElementBase = mixinBehaviors( - [CrScrollableBehavior, FindShortcutBehavior], PolymerElement); - -/** @polymer */ -class OsSettingsAddItemsDialogElement extends - OsSettingsAddItemsDialogElementBase { - static get is() { - return 'os-settings-add-items-dialog'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /** @type {!Array<!Item>} */ - items: { - type: Array, - value: [], - }, - - /** - * Item IDs to show in the "Suggested" section of the dialog. - * Any items in this array which are disabled by policy, or IDs which do - * not appear in the items array will be filtered out automatically. - * @type {!Array<!string>} - */ - suggestedItemIds: { - type: Array, - value: [], - }, - - header: String, - - searchLabel: String, - - suggestedItemsLabel: String, - - allItemsLabel: String, - - policyTooltip: String, - - /** @private */ - lowercaseQueryString_: String, - - /** @private {!Array<!Item>} */ - filteredItems_: { - type: Array, - computed: 'getFilteredItems_(items.*, lowercaseQueryString_)', - value: [], - }, - - /** @private {!Set<string>} */ - itemIdsToAdd_: { - type: Object, - value() { - return new Set(); - }, - }, - - /** - * Mapping from item ID to item for use in computing `suggestedItems_`. - * @private {!Map<string, !Item>} - */ - itemIdsToItems_: { - type: Object, - computed: 'getItemIdsToItems_(items.*)', - value() { - return new Map(); - }, - }, - - /** - * All items are guaranteed to not be disabled by policy. - * @private {!Array<!Item>} - */ - suggestedItems_: { - type: Array, - computed: 'getSuggestedItems_(suggestedItemIds.*, itemIdsToItems_)', - value: [], - }, - - /** @private */ - showSuggestedList_: { - type: Boolean, - computed: `shouldShowSuggestedList_(suggestedItems_.length, - lowercaseQueryString_)`, - value: false, - }, - - /** @private */ - showFilteredList_: { - type: Boolean, - computed: 'shouldShowFilteredList_(filteredItems_.length)', - value: true, - }, - - disableActionButton_: { - type: Boolean, - computed: 'shouldDisableActionButton_(itemIdsToAdd_.size)', - value: true, - }, - }; - } - - static get observers() { - return [ - // The two observers below have all possible properties that could affect - // the scroll offset of the two lists as dependencies. - `updateSuggestedListScrollOffset_(showSuggestedList_, - suggestedItemsLabel)`, - `updateFilteredListScrollOffset_(showSuggestedList_, - suggestedItemsLabel, suggestedItems_.length, showFilteredList_)`, - ]; - } - - // Override FindShortcutBehavior methods. - handleFindShortcut(_modalContextOpen) { - // Assumes this is the only open modal. - const searchInput = this.$.search.getSearchInput(); - searchInput.scrollIntoView(); - if (!this.searchInputHasFocus()) { - searchInput.focus(); - } - return true; - } - - // Override FindShortcutBehavior methods. - searchInputHasFocus() { - return this.$.search.getSearchInput() === - this.$.search.shadowRoot.activeElement; - } - - /** - * @param {!CustomEvent<string>} e - * @private - */ - onSearchChanged_(e) { - this.lowercaseQueryString_ = e.detail.toLocaleLowerCase(); - } - - /** - * @param {{model: {item: !Item}, target: !Element}} e - * @private - */ - onCheckboxChange_(e) { - const id = e.model.item.id; - if (e.target.checked) { - this.itemIdsToAdd_.add(id); - } else { - this.itemIdsToAdd_.delete(id); - } - // Polymer doesn't notify changes to set size. - this.notifyPath('itemIdsToAdd_.size'); - } - - /** @private */ - onCancelButtonClick_() { - this.$.dialog.close(); - } - - /** - * @private - */ - onActionButtonClick_() { - const event = new CustomEvent(ITEMS_ADDED_EVENT_NAME, { - bubbles: true, - composed: true, - detail: this.itemIdsToAdd_, - }); - this.dispatchEvent(event); - this.$.dialog.close(); - } - - /** - * @param {!KeyboardEvent} e - * @private - */ - onKeydown_(e) { - // Close dialog if 'esc' is pressed and the search box is already empty. - if (e.key === 'Escape' && !this.$.search.getValue().trim()) { - this.$.dialog.close(); - } else if (e.key !== 'PageDown' && e.key !== 'PageUp') { - this.$.search.scrollIntoView(); - } - } - - /** - * True if the user has chosen to add this item (checked its checkbox). - * @param {string} id - * @return {boolean} - * @private - */ - willAdd_(id) { - return this.itemIdsToAdd_.has(id); - } - - /** - * @return {!Map<string, !Item>} - * @private - */ - getItemIdsToItems_() { - return new Map(this.items.map(item => [item.id, item])); - } - - /** - * Returns whether a string matches the current search query. - * @param {string} string - * @return {boolean} - * @private - */ - matchesSearchQuery_(string) { - return string.toLocaleLowerCase().includes(this.lowercaseQueryString_); - } - - /** - * @return {!Array<!Item>} - * @private - */ - getFilteredItems_() { - if (!this.lowercaseQueryString_) { - return this.items; - } - - return this.items.filter( - item => this.matchesSearchQuery_(item.name) || - item.searchTerms.some(term => this.matchesSearchQuery_(term))); - } - - /** - * @return {!Array<!Item>} - * @private - */ - getSuggestedItems_() { - return this.suggestedItemIds.map(id => this.itemIdsToItems_.get(id)) - .filter(item => item !== undefined) - .filter(item => !item.disabledByPolicy); - } - - /** - * @return {boolean} - * @private - */ - shouldShowSuggestedList_() { - return this.suggestedItems_.length > 0 && !this.lowercaseQueryString_; - } - - /** - * @return {boolean} - * @private - */ - shouldShowFilteredList_() { - return this.filteredItems_.length > 0; - } - - /** - * @return {boolean} - * @private - */ - shouldDisableActionButton_() { - return !this.itemIdsToAdd_.size; - } - - /** - * @private - */ - updateSuggestedListScrollOffset_() { - afterNextRender(this, () => { - if (!this.showSuggestedList_) { - return; - } - // Because #suggested-items-list is not statically created (as it is - // within a <template is="dom-if">), we can't use this.$ here. - const list = /** @type {!IronListElement|null} */ ( - this.shadowRoot.querySelector('#suggested-items-list')); - if (list === null) { - return; - } - list.scrollOffset = list.offsetTop; - }); - } - - /** - * @private - */ - updateFilteredListScrollOffset_() { - afterNextRender(this, () => { - if (!this.showFilteredList_) { - return; - } - const list = /** @type {!IronListElement|null} */ ( - this.shadowRoot.querySelector('#filtered-items-list')); - if (list === null) { - return; - } - list.scrollOffset = list.offsetTop; - }); - } -} - -customElements.define( - OsSettingsAddItemsDialogElement.is, OsSettingsAddItemsDialogElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/add_items_dialog.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/add_items_dialog.ts new file mode 100644 index 0000000..1486051 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/add_items_dialog.ts
@@ -0,0 +1,359 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'os-settings-add-items-dialog' is a dialog for adding an + * unordered set of items at a time. The component supports suggested items, as + * well as items being disabled by policy. + */ +import 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import 'chrome://resources/cr_elements/cr_search_field/cr_search_field.js'; +import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; +import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; +import './cr_checkbox_with_policy.js'; +import './shared_style.css.js'; +import '../../settings_shared.css.js'; + +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import {CrScrollableMixin} from 'chrome://resources/cr_elements/cr_scrollable_mixin.js'; +import {CrSearchFieldElement} from 'chrome://resources/cr_elements/cr_search_field/cr_search_field.js'; +import {FindShortcutMixin} from 'chrome://resources/cr_elements/find_shortcut_mixin.js'; +import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; +import {afterNextRender, DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {getTemplate} from './add_items_dialog.html.js'; + +const ITEMS_ADDED_EVENT_NAME = 'items-added' as const; + +/** + * `id` must unique. + * `name` is the displayed name to the user. + * `searchTerms` are additional strings which will be matched when doing a text + * search. + * `disabledByPolicy` can be set to show that a given item is disabled by + * policy. These items will never appear as a suggestion. + */ +export interface Item { + id: string; + name: string; + searchTerms: string[]; + disabledByPolicy: boolean; +} + +export interface OsSettingsAddItemsDialogElement { + $: { + dialog: CrDialogElement, + search: CrSearchFieldElement, + }; +} +const OsSettingsAddItemsDialogElementBase = + CrScrollableMixin(FindShortcutMixin(PolymerElement)); + +export class OsSettingsAddItemsDialogElement extends + OsSettingsAddItemsDialogElementBase { + static get is() { + return 'os-settings-add-items-dialog' as const; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + items: { + type: Array, + // This array is shared between all instances of the class: + // https://crrev.com/c/3897703/comment/fa845200_e10503c6/ + // TODO(b/265556004): Move this to the constructor to avoid this. + value: [], + }, + + /** + * Item IDs to show in the "Suggested" section of the dialog. + * Any items in this array which are disabled by policy, or IDs which do + * not appear in the items array will be filtered out automatically. + */ + suggestedItemIds: { + type: Array, + // This array is shared between all instances of the class: + // https://crrev.com/c/3897703/comment/fa845200_e10503c6/ + // TODO(b/265556004): Move this to the constructor to avoid this. + value: [], + }, + + header: String, + + searchLabel: String, + + suggestedItemsLabel: String, + + allItemsLabel: String, + + policyTooltip: String, + + lowercaseQueryString_: String, + + filteredItems_: { + type: Array, + computed: 'getFilteredItems_(items.*, lowercaseQueryString_)', + // This array is shared between all instances of the class: + // https://crrev.com/c/3897703/comment/fa845200_e10503c6/ + // TODO(b/265556004): Move this to the constructor to avoid this. + value: [], + }, + + itemIdsToAdd_: { + type: Object, + value() { + return new Set(); + }, + }, + + /** + * Mapping from item ID to item for use in computing `suggestedItems_`. + */ + itemIdsToItems_: { + type: Object, + computed: 'getItemIdsToItems_(items.*)', + value() { + return new Map(); + }, + }, + + /** + * All items in this array are guaranteed to not be disabled by policy. + */ + suggestedItems_: { + type: Array, + computed: 'getSuggestedItems_(suggestedItemIds.*, itemIdsToItems_)', + // This array is shared between all instances of the class: + // https://crrev.com/c/3897703/comment/fa845200_e10503c6/ + // TODO(b/265556004): Move this to the constructor to avoid this. + value: [], + }, + + showSuggestedList_: { + type: Boolean, + computed: `shouldShowSuggestedList_(suggestedItems_.length, + lowercaseQueryString_)`, + value: false, + }, + + showFilteredList_: { + type: Boolean, + computed: 'shouldShowFilteredList_(filteredItems_.length)', + value: true, + }, + + disableActionButton_: { + type: Boolean, + computed: 'shouldDisableActionButton_(itemIdsToAdd_.size)', + value: true, + }, + }; + } + + // Public API: Items to show in the dialog (downwards data flow). + items: Item[]; + /** + * Item IDs to show in the "Suggested" section of the dialog. + * Any items in this array which are disabled by policy, or IDs which do not + * appear in the items array will be filtered out automatically. + */ + suggestedItemIds: string[]; + + // Public API: Strings displayed to the user, in the order a user would see + // them (downwards data flow). + header: string; + searchLabel: string; + suggestedItemsLabel: string; + allItemsLabel: string; + policyTooltip: string; + + // Internal state. + private itemIdsToAdd_: Set<string>; + // This property does not have a default value in `static get properties()`. + // TODO(b/265556480): Update the initial value to be ''. + private lowercaseQueryString_: string; + + // Computed properties for suggested items. + /** Mapping from item ID to item for use in computing `suggestedItems_`. */ + private itemIdsToItems_: Map<string, Item>; + /** All items in this array are guaranteed to not be disabled by policy. */ + private suggestedItems_: Item[]; + /** Whether suggestedItems_ is non-empty. */ + private showSuggestedList_: boolean; + + // Computed properties for filtered items. + private filteredItems_: Item[]; + /** Whether filteredItems_ is non-empty. */ + private showFilteredList_: boolean; + + // Other computed properties. + private disableActionButton_: boolean; + + static get observers() { + return [ + // The two observers below have all possible properties that could affect + // the scroll offset of the two lists as dependencies. + `updateSuggestedListScrollOffset_(showSuggestedList_, + suggestedItemsLabel)`, + `updateFilteredListScrollOffset_(showSuggestedList_, + suggestedItemsLabel, suggestedItems_.length, showFilteredList_)`, + ]; + } + + override handleFindShortcut(_modalContextOpen: boolean): boolean { + // Assumes this is the only open modal. + const searchInput = this.$.search.getSearchInput(); + searchInput.scrollIntoView(); + if (!this.searchInputHasFocus()) { + searchInput.focus(); + } + return true; + } + + override searchInputHasFocus(): boolean { + return this.$.search.getSearchInput() === + this.$.search.shadowRoot!.activeElement; + } + + // 'search-changed' event listener on a <cr-search-field>. + private onSearchChanged_(e: CustomEvent<string>): void { + this.lowercaseQueryString_ = e.detail.toLocaleLowerCase(); + } + + // 'change' event listener on a <cr-checkbox>. + private onCheckboxChange_(e: DomRepeatEvent<Item, CustomEvent<boolean>>): + void { + const id = e.model.item.id; + // Safety: This method is only called from a 'change' event from a + // <cr-checkbox>, so the event target must be a <cr-checkbox>. + if ((e.target! as CrCheckboxElement).checked) { + this.itemIdsToAdd_.add(id); + } else { + this.itemIdsToAdd_.delete(id); + } + // Polymer doesn't notify changes to set size. + this.notifyPath('itemIdsToAdd_.size'); + } + + private onCancelButtonClick_(): void { + this.$.dialog.close(); + } + + private onActionButtonClick_(): void { + const event: HTMLElementEventMap[typeof ITEMS_ADDED_EVENT_NAME] = + new CustomEvent(ITEMS_ADDED_EVENT_NAME, { + bubbles: true, + composed: true, + detail: this.itemIdsToAdd_, + }); + this.dispatchEvent(event); + this.$.dialog.close(); + } + + private onKeydown_(e: KeyboardEvent): void { + // Close dialog if 'esc' is pressed and the search box is already empty. + if (e.key === 'Escape' && !this.$.search.getValue().trim()) { + this.$.dialog.close(); + } else if (e.key !== 'PageDown' && e.key !== 'PageUp') { + this.$.search.scrollIntoView(); + } + } + + /** + * True if the user has chosen to add this item (checked its checkbox). + */ + private willAdd_(id: string): boolean { + return this.itemIdsToAdd_.has(id); + } + + private getItemIdsToItems_(): Map<string, Item> { + return new Map(this.items.map(item => [item.id, item])); + } + + /** + * Returns whether a string matches the current search query. + */ + private matchesSearchQuery_(string: string): boolean { + return string.toLocaleLowerCase().includes(this.lowercaseQueryString_); + } + + private getFilteredItems_(): Item[] { + if (!this.lowercaseQueryString_) { + return this.items; + } + + return this.items.filter( + item => this.matchesSearchQuery_(item.name) || + item.searchTerms.some(term => this.matchesSearchQuery_(term))); + } + + private getSuggestedItems_(): Item[] { + return this.suggestedItemIds.map(id => this.itemIdsToItems_.get(id)) + .filter( + <T>(item: T): item is Exclude<T, undefined> => item !== undefined) + .filter(item => !item.disabledByPolicy); + } + + private shouldShowSuggestedList_(): boolean { + return this.suggestedItems_.length > 0 && !this.lowercaseQueryString_; + } + + private shouldShowFilteredList_(): boolean { + return this.filteredItems_.length > 0; + } + + private shouldDisableActionButton_(): boolean { + return !this.itemIdsToAdd_.size; + } + + private updateSuggestedListScrollOffset_(): void { + afterNextRender(this, () => { + if (!this.showSuggestedList_) { + return; + } + // Because #suggested-items-list is not statically created (as it is + // within a <template is="dom-if">), we can't use this.$ here. + const list = this.shadowRoot!.querySelector<IronListElement>( + '#suggested-items-list'); + if (list === null) { + return; + } + list.scrollOffset = list.offsetTop; + }); + } + + private updateFilteredListScrollOffset_(): void { + afterNextRender(this, () => { + if (!this.showFilteredList_) { + return; + } + // Because #filtered-items-list is not statically created (as it is + // within a <template is="dom-if">), we can't use this.$ here. + const list = this.shadowRoot!.querySelector<IronListElement>( + '#filtered-items-list'); + if (list === null) { + return; + } + list.scrollOffset = list.offsetTop; + }); + } +} + +customElements.define( + OsSettingsAddItemsDialogElement.is, OsSettingsAddItemsDialogElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsAddItemsDialogElement.is]: OsSettingsAddItemsDialogElement; + } + interface HTMLElementEventMap { + [ITEMS_ADDED_EVENT_NAME]: CustomEvent<Set<string>>; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/add_spellcheck_languages_dialog.js b/chrome/browser/resources/settings/chromeos/os_languages_page/add_spellcheck_languages_dialog.js deleted file mode 100644 index 4df0647..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/add_spellcheck_languages_dialog.js +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview 'os-settings-add-spellcheck-language-dialog' is a dialog for - * adding spell check languages. - */ - -import './add_items_dialog.js'; - -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {recordSettingChange} from '../metrics_recorder.js'; -import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js'; - -import {Item} from './add_items_dialog.js'; -import {getTemplate} from './add_spellcheck_languages_dialog.html.js'; -import {LanguageHelper, LanguagesModel} from './languages_types.js'; - -/** - * @constructor - * @extends {PolymerElement} - * @implements {PrefsBehaviorInterface} - */ -const OsSettingsAddSpellcheckLanguagesDialogElementBase = - mixinBehaviors([PrefsBehavior], PolymerElement); - -/** @polymer */ -class OsSettingsAddSpellcheckLanguagesDialogElement extends - OsSettingsAddSpellcheckLanguagesDialogElementBase { - static get is() { - return 'os-settings-add-spellcheck-languages-dialog'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /* Preferences state. */ - prefs: { - type: Object, - notify: true, - }, - - /** @type {!LanguagesModel|undefined} */ - languages: Object, - - /** @type {!LanguageHelper} */ - languageHelper: Object, - }; - } - - /** - * Get suggested languages based on enabled languages and input methods. - * @return {!Array<string>} - * @private - */ - getSuggestedLanguageCodes_() { - const languageCodes = new Set([ - ...this.languages.inputMethods.enabled.flatMap( - inputMethod => inputMethod.languageCodes), - ...this.languageHelper.getEnabledLanguageCodes(), - ]); - return this.languages.spellCheckOffLanguages - .map(spellCheckLang => spellCheckLang.language.code) - .filter(code => languageCodes.has(code)); - } - - /** - * Get the list of languages used for the "all languages" section, filtering - * based on the current search query. - * @return {!Array<!Item>} - * @private - */ - getAllLanguages_() { - return this.languages.spellCheckOffLanguages.map( - spellCheckLang => ({ - id: spellCheckLang.language.code, - name: this.getDisplayText_(spellCheckLang.language), - searchTerms: [ - spellCheckLang.language.displayName, - spellCheckLang.language.nativeDisplayName, - ], - disabledByPolicy: spellCheckLang.isManaged, - })); - } - - /** - * @param {!chrome.languageSettingsPrivate.Language} language - * @return {string} The text to be displayed. - * @private - */ - getDisplayText_(language) { - let displayText = language.displayName; - // If the native name is different, add it. - if (language.displayName !== language.nativeDisplayName) { - displayText += ' - ' + language.nativeDisplayName; - } - return displayText; - } - - /** - * Add spell check languages. - * @param {!CustomEvent<!Set<string>>} e - * @private - */ - onItemsAdded_(e) { - e.detail.forEach(code => { - this.languageHelper.toggleSpellCheck(code, true); - }); - recordSettingChange(); - } -} - -customElements.define( - OsSettingsAddSpellcheckLanguagesDialogElement.is, - OsSettingsAddSpellcheckLanguagesDialogElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/add_spellcheck_languages_dialog.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/add_spellcheck_languages_dialog.ts new file mode 100644 index 0000000..f363635b --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/add_spellcheck_languages_dialog.ts
@@ -0,0 +1,133 @@ +// Copyright 2021 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'os-settings-add-spellcheck-language-dialog' is a dialog for + * adding spell check languages. + */ + +import './add_items_dialog.js'; + +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {PrefsMixin} from '../../prefs/prefs_mixin.js'; +import {recordSettingChange} from '../metrics_recorder.js'; + +import {Item} from './add_items_dialog.js'; +import {getTemplate} from './add_spellcheck_languages_dialog.html.js'; +import {LanguageHelper, LanguagesModel} from './languages_types.js'; + +// TODO(b/265559727): Remove PrefsMixin as it is unused. +const OsSettingsAddSpellcheckLanguagesDialogElementBase = + PrefsMixin(PolymerElement); + +class OsSettingsAddSpellcheckLanguagesDialogElement extends + OsSettingsAddSpellcheckLanguagesDialogElementBase { + static get is() { + return 'os-settings-add-spellcheck-languages-dialog' as const; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in PrefsMixin. + /* Preferences state. */ + prefs: { + type: Object, + notify: true, + }, + + languages: Object, + + languageHelper: Object, + }; + } + + // Public API: Bidirectional data flow. + // override prefs: unknown; // From PrefsMixin. + + // Public API: Downwards data flow. + languages: LanguagesModel|undefined; + languageHelper: LanguageHelper; + + /** + * Get suggested languages based on enabled languages and input methods. + */ + private getSuggestedLanguageCodes_(): string[] { + const languageCodes = new Set([ + ...this + // This assertion of `this.languages` is potentially unsafe and could + // fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite + // this to avoid this assertion. + .languages! + // Safety: `LanguagesModel.inputMethods` is always defined on CrOS. + .inputMethods!.enabled.flatMap( + inputMethod => inputMethod.languageCodes), + ...this.languageHelper.getEnabledLanguageCodes(), + ]); + // Safety: We checked that `this.languages` is defined above. + return this.languages!.spellCheckOffLanguages + .map(spellCheckLang => spellCheckLang.language.code) + .filter(code => languageCodes.has(code)); + } + + /** + * Get the list of languages used for the "all languages" section, filtering + * based on the current search query. + */ + private getAllLanguages_(): Item[] { + // This assertion of `this.languages` is potentially unsafe and could fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. + return this.languages!.spellCheckOffLanguages.map( + spellCheckLang => ({ + id: spellCheckLang.language.code, + name: this.getDisplayText_(spellCheckLang.language), + searchTerms: [ + spellCheckLang.language.displayName, + spellCheckLang.language.nativeDisplayName, + ], + disabledByPolicy: spellCheckLang.isManaged, + })); + } + + /** + * @return The text to be displayed. + */ + private getDisplayText_(language: chrome.languageSettingsPrivate.Language): + string { + let displayText = language.displayName; + // If the native name is different, add it. + if (language.displayName !== language.nativeDisplayName) { + displayText += ' - ' + language.nativeDisplayName; + } + return displayText; + } + + /** + * Add spell check languages. + */ + private onItemsAdded_(e: HTMLElementEventMap['items-added']): void { + e.detail.forEach(code => { + this.languageHelper.toggleSpellCheck(code, true); + }); + recordSettingChange(); + } +} + +customElements.define( + OsSettingsAddSpellcheckLanguagesDialogElement.is, + OsSettingsAddSpellcheckLanguagesDialogElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsAddSpellcheckLanguagesDialogElement.is]: + OsSettingsAddSpellcheckLanguagesDialogElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.js b/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.ts similarity index 63% rename from chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.ts index b8ca487..b21d0edf8 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.ts
@@ -17,32 +17,34 @@ import './languages.js'; import '../../settings_shared.css.js'; -import {CrScrollableBehavior, CrScrollableBehaviorInterface} from 'chrome://resources/ash/common/cr_scrollable_behavior.js'; -import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import {CrScrollableMixin} from 'chrome://resources/cr_elements/cr_scrollable_mixin.js'; +import {CrSearchFieldElement} from 'chrome://resources/cr_elements/cr_search_field/cr_search_field.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {assert} from 'chrome://resources/js/assert_ts.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {LifetimeBrowserProxyImpl} from '../../lifetime_browser_proxy.js'; import {recordSettingChange} from '../metrics_recorder.js'; import {getTemplate} from './change_device_language_dialog.html.js'; -import {LanguagesMetricsProxy, LanguagesMetricsProxyImpl, LanguagesPageInteraction} from './languages_metrics_proxy.js'; +import {LanguagesMetricsProxyImpl, LanguagesPageInteraction} from './languages_metrics_proxy.js'; import {LanguageHelper, LanguagesModel} from './languages_types.js'; -/** - * @constructor - * @extends {PolymerElement} - * @implements {CrScrollableBehaviorInterface} - * @implements {I18nBehaviorInterface} - */ -const OsSettingsChangeDeviceLanguageDialogElementBase = - mixinBehaviors([CrScrollableBehavior, I18nBehavior], PolymerElement); +export interface OsSettingsChangeDeviceLanguageDialogElement { + $: { + dialog: CrDialogElement, + search: CrSearchFieldElement, + }; +} -/** @polymer */ -class OsSettingsChangeDeviceLanguageDialogElement extends +const OsSettingsChangeDeviceLanguageDialogElementBase = + I18nMixin(CrScrollableMixin(PolymerElement)); + +export class OsSettingsChangeDeviceLanguageDialogElement extends OsSettingsChangeDeviceLanguageDialogElementBase { static get is() { - return 'os-settings-change-device-language-dialog'; + return 'os-settings-change-device-language-dialog' as const; } static get template() { @@ -51,38 +53,31 @@ static get properties() { return { - /** @type {!LanguagesModel|undefined} */ languages: Object, - /** @private {!Array<!chrome.languageSettingsPrivate.Language>} */ displayedLanguages_: { type: Array, computed: `getPossibleDeviceLanguages_(languages.supported, languages.enabled.*, lowercaseQueryString_)`, }, - /** @private {boolean} */ displayedLanguagesEmpty_: { type: Boolean, computed: 'isZero_(displayedLanguages_.length)', }, - /** @type {!LanguageHelper} */ languageHelper: Object, - /** @private {?chrome.languageSettingsPrivate.Language} */ selectedLanguage_: { type: Object, value: null, }, - /** @private */ disableActionButton_: { type: Boolean, computed: 'shouldDisableActionButton_(selectedLanguage_)', }, - /** @private */ lowercaseQueryString_: { type: String, value: '', @@ -90,24 +85,34 @@ }; } - /** - * @param {!CustomEvent<string>} e - * @private - */ - onSearchChanged_(e) { + // Public API: Downwards data flow. + languages: LanguagesModel|undefined; + languageHelper: LanguageHelper; + + // Internal state. + private lowercaseQueryString_: string; + private selectedLanguage_: chrome.languageSettingsPrivate.Language|null; + + // Computed properties. + private disableActionButton_: boolean; + private displayedLanguages_: chrome.languageSettingsPrivate.Language[]; + private displayedLanguagesEmpty_: boolean; + + private onSearchChanged_(e: CustomEvent<string>): void { this.lowercaseQueryString_ = e.detail.toLowerCase(); } - /** - * @return {!Array<!chrome.languageSettingsPrivate.Language>} A list of - * possible device language. - * @private - */ - getPossibleDeviceLanguages_() { - return this.languages.supported + private getPossibleDeviceLanguages_(): + chrome.languageSettingsPrivate.Language[] { + // This assertion of `this.languages` is potentially unsafe and could fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. + return this.languages!.supported .filter(language => { if (!language.supportsUI || language.isProhibitedLanguage || - language.code === this.languages.prospectiveUILanguage) { + // Safety: We checked that `this.languages` is defined above, and + // `prospectiveUILanguage` is always define on CrOS. + language.code === this.languages!.prospectiveUILanguage!) { return false; } @@ -127,32 +132,20 @@ }); } - /** - * @param {boolean} selected - * @private - */ - getItemClass_(selected) { + private getItemClass_(selected: boolean): 'selected'|'' { return selected ? 'selected' : ''; } - /** - * @param {!chrome.languageSettingsPrivate.Language} item - * @param {boolean} selected - * @return {!string} - * @private - */ - getAriaLabelForItem_(item, selected) { + private getAriaLabelForItem_( + item: chrome.languageSettingsPrivate.Language, + selected: boolean): string { const instruction = selected ? 'selectedDeviceLanguageInstruction' : 'notSelectedDeviceLanguageInstruction'; return this.i18n(instruction, this.getDisplayText_(item)); } - /** - * @param {!chrome.languageSettingsPrivate.Language} language - * @return {string} The text to be displayed. - * @private - */ - getDisplayText_(language) { + private getDisplayText_(language: chrome.languageSettingsPrivate.Language): + string { let displayText = language.nativeDisplayName; // If the local name is different, add it. if (language.displayName !== language.nativeDisplayName) { @@ -161,21 +154,21 @@ return displayText; } - /** @private */ - shouldDisableActionButton_() { + private shouldDisableActionButton_(): boolean { return this.selectedLanguage_ === null; } - /** @private */ - onCancelButtonTap_() { + private onCancelButtonTap_(): void { this.$.dialog.close(); } /** * Sets device language and restarts device. - * @private */ - onActionButtonTap_() { + private onActionButtonTap_(): void { + // Safety: This method is only called as an event listener on the action + // button, which is only enabled if `disableActionButton_` is false - i.e. + // `this.selectedLanguage_ !== null`. assert(this.selectedLanguage_); const languageCode = this.selectedLanguage_.code; this.languageHelper.setProspectiveUiLanguage(languageCode); @@ -193,11 +186,7 @@ LifetimeBrowserProxyImpl.getInstance().signOutAndRestart(); } - /** - * @param {!KeyboardEvent} e - * @private - */ - onKeydown_(e) { + private onKeydown_(e: KeyboardEvent): void { // Close dialog if 'esc' is pressed and the search box is already empty. if (e.key === 'Escape' && !this.$.search.getValue().trim()) { this.$.dialog.close(); @@ -206,12 +195,7 @@ } } - /** - * @param {number} num - * @return {boolean} - * @private - */ - isZero_(num) { + private isZero_(num: number): boolean { return num === 0; } } @@ -219,3 +203,10 @@ customElements.define( OsSettingsChangeDeviceLanguageDialogElement.is, OsSettingsChangeDeviceLanguageDialogElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsChangeDeviceLanguageDialogElement.is]: + OsSettingsChangeDeviceLanguageDialogElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.js b/chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.ts similarity index 64% rename from chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.ts index 56f72cf..5e72f0a 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/cr_checkbox_with_policy.ts
@@ -29,10 +29,9 @@ import {getTemplate} from './cr_checkbox_with_policy.html.js'; -/** @polymer */ -class CrCheckboxWithPolicyElement extends PolymerElement { +export class CrCheckboxWithPolicyElement extends PolymerElement { static get is() { - return 'cr-checkbox-with-policy'; + return 'cr-checkbox-with-policy' as const; } static get template() { @@ -67,20 +66,42 @@ }; } + // All properties except `policyTooltip` are forwarded to the internal + // <cr-checkbox>. + + // Public API: Bidirectional data flow. + checked: boolean; + + // Public API: Downwards data flow. + policyTooltip: string; + ariaDescription: string; + disabled: boolean; + override tabIndex: number; + /** * Focuses the correct element (icon if disabled, otherwise checkbox). * - * Overrides focus() defined on HTMLElement. - * @override + * Do not call this method after setting `disabled` to true until this element + * is re-rendered. */ - focus() { + override focus(): void { + // We use getElementById here instead of this.$ as #icon does not exist if + // this.disabled is false. const elementId = this.disabled ? 'icon' : 'checkbox'; - const element = this.shadowRoot.getElementById(elementId); - element.focus(); + const element = this.shadowRoot!.getElementById(elementId); + // Safety: This assumes that an element with an id of `elementId` exists in + // the shadow root. + // The element with id 'checkbox' should always exist here as it is + // unconditionally rendered. + // The element with id 'icon' should always exist here as it is enforced by + // documentation. This method should always be called after a render if + // `this.disabled` was set to true, so the aforementioned element should + // have been already rendered by the `dom-if` in the template before this + // method is called. + element!.focus(); } - /** @private */ - onTabIndexChanged_() { + private onTabIndexChanged_(): void { // :host shouldn't have a tabindex because it's set on the appropriate // element instead. this.removeAttribute('tabindex'); @@ -88,22 +109,24 @@ /** * Returns the correct tab index for the checkbox (-1 if it is disabled). - * @private - * @return {number} */ - getCheckboxTabIndex_() { + private getCheckboxTabIndex_(): number { return this.disabled ? -1 : this.tabIndex; } /** * Returns the correct tab index for the icon (-1 if it is enabled). - * @private - * @return {number} */ - getIconTabIndex_() { + private getIconTabIndex_(): number { return this.disabled ? this.tabIndex : -1; } } customElements.define( CrCheckboxWithPolicyElement.is, CrCheckboxWithPolicyElement); + +declare global { + interface HTMLElementTagNameMap { + [CrCheckboxWithPolicyElement.is]: CrCheckboxWithPolicyElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.html b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.html index 397fc3c..9bb680a 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.html +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.html
@@ -42,6 +42,9 @@ </cr-toggle> </template> <template is="dom-if" if="[[isDropdown_(option.uiType)]]"> + <!-- TODO(b/265557721): Stop using Polymer "two-way native binding" + on <select>s as values are casted to strings, and use + <dom-repeat> events instead. --> <select class="md-select" value="{{option.value::change}}" on-change="onToggleButtonOrDropdownChange_" aria-label="[[option.label]]"> @@ -75,9 +78,12 @@ </cr-toggle> </template> <template is="dom-if" if="[[isDropdown_(dependant.uiType)]]"> + <!-- TODO(b/265557721): Stop using Polymer "two-way native + binding" on <select>s as values are casted to strings, and + use <dom-repeat> events instead. --> <select class="md-select" value="{{dependant.value::change}}" on-change="onToggleButtonOrDropdownChange_" - aria-label="[[dependant.label]]""> + aria-label="[[dependant.label]]"> <template is="dom-repeat" items="[[dependant.menuItems]]"> <option selected="[[item.selected]]" value="[[item.value]]"> @@ -100,6 +106,7 @@ </div> <template is="dom-if" if="[[showClearPersonalizedData_]]" restamp> + <!-- TODO(b/238031866): Remove languages and language-helper if not used. --> <os-settings-japanese-clear-ime-data-dialog languages="[[languages]]" language-helper="[[languageHelper]]" on-close="onClearPersonalizedDataClose_">
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.js deleted file mode 100644 index fde58b4..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.js +++ /dev/null
@@ -1,409 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview 'settings-input-method-options-page' is the settings sub-page - * to allow users to change options for each input method. - */ -import 'chrome://resources/cr_elements/md_select.css.js'; -import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js'; -import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; -import '../../settings_shared.css.js'; -import './os_japanese_clear_ime_data_dialog.js'; -import './os_japanese_manage_user_dictionary_page.js'; - -import {assert, assertNotReached} from 'chrome://resources/ash/common/assert.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {afterNextRender, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {routes} from '../os_route.js'; -import {OsSettingsSubpageElement} from '../os_settings_page/os_settings_subpage.js'; -import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js'; -import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js'; -import {Route, Router} from '../router.js'; - -import {getTemplate} from './input_method_options_page.html.js'; -import {AUTOCORRECT_OPTION_MAP_OVERRIDE, generateOptions, getDefaultValue, getFirstPartyInputMethodEngineId, getOptionLabelName, getOptionMenuItems, getOptionSubtitleName, getOptionUiType, getOptionUrl, getSubmenuButtonType, getUntranslatedOptionLabelName, hasOptionsPageInSettings, isOptionLabelTranslated, OptionType, PHYSICAL_KEYBOARD_AUTOCORRECT_ENABLED_BY_DEFAULT, shouldStoreAsNumber, SubmenuButton, UiType} from './input_method_util.js'; -import {LanguageHelper} from './languages_types.js'; - -/** - * The root path of input method options in Prefs. - */ -const PREFS_PATH = 'settings.language.input_method_specific_settings'; - -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - * @implements {PrefsBehaviorInterface} - * @implements {RouteObserverBehaviorInterface} - */ -const SettingsInputMethodOptionsPageElementBase = mixinBehaviors( - [I18nBehavior, PrefsBehavior, RouteObserverBehavior], PolymerElement); - -/** @polymer */ -class SettingsInputMethodOptionsPageElement extends - SettingsInputMethodOptionsPageElementBase { - static get is() { - return 'settings-input-method-options-page'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /** @type {!LanguageHelper} */ - languageHelper: Object, - - /** Preferences state. */ - prefs: { - type: Object, - notify: true, - }, - - /** - * Input method ID. - * @private - */ - id_: String, - - /** - * Input method engine ID. - * @private - */ - engineId_: String, - - /** - * The content to be displayed in the page, auto generated every time when - * the user enters the page. - * @private {!Array<{title: string, options:!Array<!Object<string, *>>}>} - */ - optionSections_: { - type: Array, - value: [], - }, - - /** @private */ - showClearPersonalizedData_: { - type: Boolean, - value: false, - }, - }; - } - - /** - * RouteObserverBehavior - * @param {!Route} route - * @param {!Route=} oldRoute - * @protected - */ - currentRouteChanged(route, oldRoute) { - if (route !== routes.OS_LANGUAGES_INPUT_METHOD_OPTIONS) { - this.id_ = ''; - // During tests, the parent node is not a <os-settings-subpage>. - if (this.parentNode instanceof OsSettingsSubpageElement) { - this.parentNode.pageTitle = ''; - } - this.optionSections_ = []; - return; - } - - const queryParams = Router.getInstance().getQueryParameters(); - this.id_ = queryParams.get('id') || ''; - const displayName = this.languageHelper.getInputMethodDisplayName(this.id_); - // During tests, the parent node is not a <os-settings-subpage>. - if (this.parentNode instanceof OsSettingsSubpageElement) { - this.parentNode.pageTitle = displayName; - } - assert(displayName !== '', `Input method ID '${this.id_}' is invalid`); - this.engineId_ = getFirstPartyInputMethodEngineId(this.id_); - this.populateOptionSections_(); - } - - onSubmenuButtonClick_(e) { - const submenuButtonType = e.target.getAttribute('submenu-button-type'); - if (submenuButtonType === - SubmenuButton.JAPANESE_CLEAR_PERSONALIZATION_DATA) { - this.showClearPersonalizedData_ = true; - return; - } - console.error( - `SubmenuButton with invalid type clicked : ${submenuButtonType}`); - } - - onClearPersonalizedDataClose_() { - this.showClearPersonalizedData_ = false; - } - - /** - * For some engineId, we want to store the data in a different storage - * engineId. i.e. we want to use the nacl_mozc_jp settings data for - * the nacl_mozc_us settings. - */ - getStorageEngineId_() { - return this.engineId_ !== 'nacl_mozc_us' ? this.engineId_ : 'nacl_mozc_jp'; - } - - /** - * Get menu items for an option, and enrich the items with selected status and - * i18n label. - * @param {OptionType} name - * @param {*} value - */ - getMenuItems(name, value) { - return getOptionMenuItems(name).map(menuItem => { - return { - ...menuItem, - selected: menuItem.value === value, - label: menuItem.name ? this.i18n(menuItem.name) : menuItem.value, - }; - }); - } - - /** - * Generate the sections of options according to the engine ID and Prefs. - * @private - */ - populateOptionSections_() { - const options = generateOptions( - this.engineId_, loadTimeData.getBoolean('allowPredictiveWriting'), - loadTimeData.getBoolean('allowDiacriticsOnPhysicalKeyboardLongpress'), - loadTimeData.getBoolean('systemJapanesePhysicalTyping')); - const inputMethodSpecificSettings = this.getPref(PREFS_PATH).value; - // The settings for Japanese for both engine nacl_mozc_us and nacl_mozc_jp - // types will be stored in nacl_mozc_us. See: - // https://crsrc.org/c/chrome/browser/ash/input_method/input_method_settings.cc;drc=5b784205e8043fb7d1c11e3d80521e80704947ca;l=25 - const engineId = this.getStorageEngineId_(); - const currentSettings = engineId in inputMethodSpecificSettings ? - inputMethodSpecificSettings[engineId] : - {}; - const defaultOverrides = this.getDefaultValueOverrides_(engineId); - - const makeOption = (option) => { - const name = option.name; - const uiType = getOptionUiType(name); - - let value = name in currentSettings ? - currentSettings[name] : - getDefaultValue(name, defaultOverrides); - if (loadTimeData.getBoolean('allowAutocorrectToggle') && - name in AUTOCORRECT_OPTION_MAP_OVERRIDE) { - value = AUTOCORRECT_OPTION_MAP_OVERRIDE[name].mapValueForDisplay(value); - } - if (!this.isSettingValueValid_(name, value)) { - value = getDefaultValue(name, defaultOverrides); - this.updatePref_(name, value); - } - - const label = isOptionLabelTranslated(name) ? - this.i18n(getOptionLabelName(name)) : - getUntranslatedOptionLabelName(name); - - const subtitleStringName = getOptionSubtitleName(name); - const subtitle = subtitleStringName && this.i18n(subtitleStringName); - - return { - name: name, - uiType: uiType, - value: value, - label: label, - subtitle: subtitle, - menuItems: this.getMenuItems(name, value), - url: getOptionUrl(name), - dependentOptions: option.dependentOptions ? - option.dependentOptions.map(t => makeOption({name: t})) : - [], - submenuButtonType: this.isSubmenuButton_(uiType) ? - getSubmenuButtonType(name) : - undefined, - }; - }; - - // If there is no option name in a section, this section, including the - // section title, should not be displayed. - this.optionSections_ = - options.filter(section => section.optionNames.length > 0) - .map(section => { - return { - title: this.getSectionTitleI18n_(section.title), - options: section.optionNames.map(makeOption, false), - }; - }); - } - - /** - * Returns an object specifying the default values to be used for a subset - * of options. - * - * @param engineId string The engine id we want default values for. - * @return {Object<OptionType, *>} Default value overrides. - */ - getDefaultValueOverrides_(engineId) { - if (!loadTimeData.getBoolean('autocorrectEnableByDefault')) { - return {}; - } - const enabledByDefaultKey = - PHYSICAL_KEYBOARD_AUTOCORRECT_ENABLED_BY_DEFAULT; - const prefBlob = this.getPref(PREFS_PATH).value; - const isAutocorrectDefaultEnabled = - prefBlob?.[engineId]?.[enabledByDefaultKey]; - return !isAutocorrectDefaultEnabled ? {} : { - [OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: 1, - }; - } - - /** - * - * @param {*} value - * @private - */ - dependentOptionsDisabled_(value) { - // TODO(b/189909728): Sometimes the value comes as a string, other times as - // an integer, other times as a boolean, so handle all cases. Try to - // understand and fix this. - return value === '0' || value === 0 || value === false; - } - - /** - * Handler for toggle button and dropdown change. Update the value of the - * changing option in Cros prefs. - * @param {{model: {option: Object}}} e - * @private - */ - onToggleButtonOrDropdownChange_(e) { - // e.model isn't correctly set for dependent options, due to nested - // dom-repeat, so figure out what option was actually set. - const option = e.model.dependant ? e.model.dependant : e.model.option; - // The value of dropdown is not updated immediately when the event is fired. - // Wait for the polymer state to update to make sure we write the latest - // to Cros Prefs. - afterNextRender(this, () => { - this.updatePref_(option.name, option.value); - }); - } - - isSettingValueValid_(name, value) { - const uiType = getOptionUiType(name); - if (uiType !== UiType.DROPDOWN) { - return true; - } - const menuItems = getOptionMenuItems(name); - return !!menuItems.find((item) => item.value === value); - } - - /** - * Update an input method pref. - * @param {!OptionType} optionName - * @param {*} newValue - * @private - */ - updatePref_(optionName, newValue) { - // Get the existing settings dictionary, in order to update it later. - // |PrefsBehavior.setPrefValue| will update Cros Prefs only if the reference - // of variable has changed, so we need to copy the current content into a - // new variable. - const updatedSettings = {}; - Object.assign(updatedSettings, this.getPref(PREFS_PATH).value); - - const engineId = this.getStorageEngineId_(); - if (updatedSettings[engineId] === undefined) { - updatedSettings[engineId] = {}; - } - if (loadTimeData.getBoolean('allowAutocorrectToggle') && - optionName in AUTOCORRECT_OPTION_MAP_OVERRIDE) { - newValue = AUTOCORRECT_OPTION_MAP_OVERRIDE[optionName].mapValueForWrite( - newValue); - } else if (shouldStoreAsNumber(optionName)) { - newValue = parseInt(newValue, 10); - } - updatedSettings[engineId][optionName] = newValue; - - this.setPrefValue(PREFS_PATH, updatedSettings); - } - - /** - * Opens external link in Chrome. - * @param {{model: {option: {url: !Route}}}} e - * @private - */ - navigateToOtherPageInSettings_(e) { - Router.getInstance().navigateTo(e.model.option.url); - } - - /** - * @param {string} section the name of the section. - * @return {string} the i18n string for the section title. - * @private - */ - getSectionTitleI18n_(section) { - switch (section) { - case 'basic': - return this.i18n('inputMethodOptionsBasicSectionTitle'); - case 'advanced': - return this.i18n('inputMethodOptionsAdvancedSectionTitle'); - case 'physicalKeyboard': - return this.i18n('inputMethodOptionsPhysicalKeyboardSectionTitle'); - case 'virtualKeyboard': - return this.i18n('inputMethodOptionsVirtualKeyboardSectionTitle'); - case 'suggestions': - return this.i18n('inputMethodOptionsSuggestionsSectionTitle'); - // Japanese section - case 'inputAssistance': - return this.i18n('inputMethodOptionsInputAssistanceSectionTitle'); - // Japanese section - case 'userDictionaries': - return this.i18n('inputMethodOptionsUserDictionariesSectionTitle'); - // Japanese section - case 'privacy': - return this.i18n('inputMethodOptionsPrivacySectionTitle'); - - default: - assertNotReached(); - } - } - - /** - * @param {!UiType} item - * @return {boolean} true if |item| is a toggle button. - * @private - */ - isToggleButton_(item) { - return item === UiType.TOGGLE_BUTTON; - } - - - /** - * @param {!UiType} item - * @return {boolean} true if |item| is a toggle button. - * @private - */ - isSubmenuButton_(item) { - return item === UiType.SUBMENU_BUTTON; - } - - /** - * @param {!UiType} item - * @return {boolean} true if |item| is a dropdown. - * @private - */ - isDropdown_(item) { - return item === UiType.DROPDOWN; - } - - /** - * @param {!UiType} item - * @return {boolean} true if |item| is an external link. - * @private - */ - isLink_(item) { - return item === UiType.LINK; - } -} - -customElements.define( - SettingsInputMethodOptionsPageElement.is, - SettingsInputMethodOptionsPageElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.ts new file mode 100644 index 0000000..123f968 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.ts
@@ -0,0 +1,545 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'settings-input-method-options-page' is the settings sub-page + * to allow users to change options for each input method. + */ +import 'chrome://resources/cr_elements/md_select.css.js'; +import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js'; +import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; +import '../../settings_shared.css.js'; +import './os_japanese_clear_ime_data_dialog.js'; +import './os_japanese_manage_user_dictionary_page.js'; + +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {afterNextRender, DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {PrefsMixin} from '../../prefs/prefs_mixin.js'; +import {routes} from '../os_route.js'; +import {OsSettingsSubpageElement} from '../os_settings_page/os_settings_subpage.js'; +import {RouteObserverMixin} from '../route_observer_mixin.js'; +import {Route, Router} from '../router.js'; + +import {getTemplate} from './input_method_options_page.html.js'; +import {AUTOCORRECT_OPTION_MAP_OVERRIDE, generateOptions, getDefaultValue, getFirstPartyInputMethodEngineId, getOptionLabelName, getOptionMenuItems, getOptionSubtitleName, getOptionUiType, getOptionUrl, getSubmenuButtonType, getUntranslatedOptionLabelName, isOptionLabelTranslated, OPTION_DEFAULT, OptionType, PHYSICAL_KEYBOARD_AUTOCORRECT_ENABLED_BY_DEFAULT, SettingsHeaders, shouldStoreAsNumber, SubmenuButton, UiType} from './input_method_util.js'; +import {LanguageHelper} from './languages_types.js'; + +/** + * The root path of input method options in Prefs. + */ +const PREFS_PATH = 'settings.language.input_method_specific_settings'; + +// This type seems incorrect, as this includes +// OPTION_DEFAULT[OptionType.PINYIN_FUZZY_CONFIG] which is a big object literal. +// TODO(b/263829863): Investigate and fix this type. +type OptionValue = ReturnType<typeof getDefaultValue>; + +// This type is the expected type of the dictionary pref stored in PREFS_PATH, +// but may not reflect reality as dictionary prefs are effectively unstructured +// JSON objects. +// In practice, the pref should only ever written to by us, so it should be +// consistent with this type. +type PrefsObjectType = + Partial<Record<string, Partial<Record<string, OptionValue>>>>; + +/** + * An Option for use in the template. + */ +// TODO(b/263829863): Use a discriminated union for better type-safety. +interface Option { + name: OptionType; + uiType: UiType; + value: OptionValue; + label: string; + subtitle: string; + menuItems: Array<{name?: string, value: unknown}>; + url: Route|undefined; + dependentOptions: Option[]; + submenuButtonType: SubmenuButton|undefined; +} + +interface Section { + title: string; + options: Option[]; +} + +interface OptionDomRepeatModel { + section: Section; + option: Option; + dependant?: Option; +} + +type OptionDomRepeatEvent<T = unknown, E extends Event = Event> = + DomRepeatEvent<T, E>&{model: OptionDomRepeatModel}; + +// For working around https://github.com/microsoft/TypeScript/issues/21732. +// As of writing, it is marked as fixed by +// https://github.com/microsoft/TypeScript/pull/50666, but that PR does not +// address this specific issue of narrowing a `string` down to keys of an +// object. +type AutocorrectOptionMapKey = keyof typeof AUTOCORRECT_OPTION_MAP_OVERRIDE; + +const SettingsInputMethodOptionsPageElementBase = + I18nMixin(PrefsMixin(RouteObserverMixin(PolymerElement))); + +class SettingsInputMethodOptionsPageElement extends + SettingsInputMethodOptionsPageElementBase { + static get is() { + return 'settings-input-method-options-page' as const; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + languageHelper: Object, + + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in PrefsMixin. + /** Preferences state. */ + prefs: { + type: Object, + notify: true, + }, + + /** + * Input method ID. + */ + id_: String, + + /** + * Input method engine ID. + */ + engineId_: String, + + /** + * The content to be displayed in the page, auto generated every time when + * the user enters the page. + */ + optionSections_: { + type: Array, + // This array is shared between all instances of the class: + // https://crrev.com/c/3897703/comment/fa845200_e10503c6/ + // TODO(b/265556004): Move this to the constructor to avoid this. + value: [], + }, + + showClearPersonalizedData_: { + type: Boolean, + value: false, + }, + }; + } + + // Public API: Bidirectional data flow. + // override prefs: any; // From PrefsMixin. + + // Public API: Downwards data flow. + languageHelper: LanguageHelper; + + // Internal state. + // This property does not have a default value in `static get properties()`, + // but is set in `currentRouteChanged()`. + // TODO(b/265556480): Update the initial value to be ''. + private id_: string; + // This property does not have a default value in `static get properties()`. + // TODO(b/265556480): Update the initial value to be false. + private showClearPersonalizedData_: boolean; + + // Manually computed properties. + // TODO(b/238031866): Convert these to be Polymer computed properties. + /** Computed from id_. */ + private engineId_: string; + /** Computed from engineId_ */ + private optionSections_: Section[]; + + /** + * Overrides RouteObserverBehavior. + */ + override currentRouteChanged(route: Route): void { + if (route !== routes.OS_LANGUAGES_INPUT_METHOD_OPTIONS) { + this.id_ = ''; + // During tests, the parent node is not a <os-settings-subpage>. + if (this.parentNode instanceof OsSettingsSubpageElement) { + this.parentNode.pageTitle = ''; + } + this.optionSections_ = []; + return; + } + + const queryParams = Router.getInstance().getQueryParameters(); + this.id_ = queryParams.get('id') || ''; + const displayName = this.languageHelper.getInputMethodDisplayName(this.id_); + // During tests, the parent node is not a <os-settings-subpage>. + if (this.parentNode instanceof OsSettingsSubpageElement) { + this.parentNode.pageTitle = displayName; + } + // Safety: As this page (under normal use) can only be navigated to via + // the inputs settings page, we should always have a valid input method ID + // here. + assert(displayName !== '', `Input method ID '${this.id_}' is invalid`); + this.engineId_ = getFirstPartyInputMethodEngineId(this.id_); + this.populateOptionSections_(); + } + + private onSubmenuButtonClick_(e: DomRepeatEvent<Option, MouseEvent>): void { + // Safety: The submenu button is always a <cr-button>, which is an Element. + const submenuButtonType = + (e.target as Element).getAttribute('submenu-button-type'); + if (submenuButtonType === + SubmenuButton.JAPANESE_CLEAR_PERSONALIZATION_DATA) { + this.showClearPersonalizedData_ = true; + return; + } + console.error( + `SubmenuButton with invalid type clicked : ${submenuButtonType}`); + } + + private onClearPersonalizedDataClose_(): void { + this.showClearPersonalizedData_ = false; + } + + /** + * For some engineId, we want to store the data in a different storage + * engineId. i.e. we want to use the nacl_mozc_jp settings data for + * the nacl_mozc_us settings. + */ + private getStorageEngineId_(): string { + return this.engineId_ !== 'nacl_mozc_us' ? this.engineId_ : 'nacl_mozc_jp'; + } + + /** + * Get menu items for an option, and enrich the items with selected status and + * i18n label. + */ + getMenuItems(name: OptionType, value: OptionValue): Array<{ + selected: boolean, + label: string|number, + name?: string, value: string|number, + }> { + return getOptionMenuItems(name).map(menuItem => { + return { + ...menuItem, + selected: menuItem.value === value, + label: menuItem.name ? this.i18n(menuItem.name) : menuItem.value, + }; + }); + } + + /** + * Generate the sections of options according to the engine ID and Prefs. + */ + private populateOptionSections_(): void { + const options = generateOptions( + this.engineId_, loadTimeData.getBoolean('allowPredictiveWriting'), + loadTimeData.getBoolean('allowDiacriticsOnPhysicalKeyboardLongpress'), + loadTimeData.getBoolean('systemJapanesePhysicalTyping')); + const inputMethodSpecificSettings = + this.getPref<PrefsObjectType>(PREFS_PATH).value; + // The settings for Japanese for both engine nacl_mozc_us and nacl_mozc_jp + // types will be stored in nacl_mozc_us. See: + // https://crsrc.org/c/chrome/browser/ash/input_method/input_method_settings.cc;drc=5b784205e8043fb7d1c11e3d80521e80704947ca;l=25 + const engineId = this.getStorageEngineId_(); + const currentSettings = engineId in inputMethodSpecificSettings ? + // Safety: We checked that `engineId` is a key above, and we ASSUME that + // we are the only writers to this pref. Therefore, as we never set + // `undefined` or `null` properties on `inputMethodSpecificSettings`, + // the property should always be non-null here. + // This could possibly be unsafe if our assumptions above are incorrect, + // or we mistakenly set `undefined` properties (which TypeScript allows + // us to do). + // TODO(b/265558129): Use `inputMethodSpecificSettings[engineId] !== + // undefined` above to guard against `undefined` properties if they do + // ever occur. + inputMethodSpecificSettings[engineId]! : + {}; + const defaultOverrides = this.getDefaultValueOverrides_(engineId); + + const makeOption = (option: { + name: OptionType, + dependentOptions?: OptionType[], + }): Option => { + const name = option.name; + const uiType = getOptionUiType(name); + + let value = name in currentSettings ? + // Safety: See the `currentSettings` safety comment above. + // TODO(b/265558129): Use `currentSettings[name] !== undefined` above + // to guard against `undefined` properties if they do ever occur. + currentSettings[name]! : + getDefaultValue( + // This cast is VERY unsafe, as `OPTION_DEFAULT` only contains + // a small subset of options as keys. + // TODO(b/263829863): Investigate and fix this type cast. + name as keyof typeof OPTION_DEFAULT, defaultOverrides); + if (loadTimeData.getBoolean('allowAutocorrectToggle') && + name in AUTOCORRECT_OPTION_MAP_OVERRIDE) { + /// Safety: We checked that `name` is a key above. + value = AUTOCORRECT_OPTION_MAP_OVERRIDE[name as AutocorrectOptionMapKey] + // Safety: All autocorrect prefs have values that are + // numbers in `getOptionMenuItems` as well as + // `OPTION_DEFAULT`. + .mapValueForDisplay(value as number); + } + if (!this.isSettingValueValid_(name, value)) { + value = getDefaultValue( + // This cast is VERY unsafe, as `OPTION_DEFAULT` only contains + // a small subset of options as keys. + // TODO(b/263829863): Investigate and fix this type cast. + name as keyof typeof OPTION_DEFAULT, defaultOverrides); + // This function call is unsafe under these conditions: + // - This option is `JAPANESE_NUMBER_OF_SUGGESTIONS`, or + // `allowAutocorrectToggle` is off and this option is an autocorrect + // option. + // In this case, `this.updatePref_` expects the value to be a string, + // as the `shouldStoreAsNumber` branch is hit - but `getDefaultValue` + // returns a number, not a string, in this case. + // TODO(b/265557721): Fix the use of Polymer two-way native bindings + // in the dropdown part of the template, and remove the + // `shouldStoreAsNumber` branch. + // + // - `allowAutocorrectToggle` is on, this option is an autocorrect + // option, AND `this.isSettingValueValid_` returns false. + // This currently is impossible as `this.isSettingValueValid_` is true + // for all toggles, but may change in the future. + // In this case, `value` would be the value in the prefs store, not + // the displayed value, so storing it in the prefs store may result in + // errors, and may be displayed incorrectly too. + // TODO(b/238031866): Map the default value to the value for display + // AFTER setting it to the default value if it is invalid. + this.updatePref_(name, value); + } + + const label = isOptionLabelTranslated(name) ? + this.i18n(getOptionLabelName(name)) : + getUntranslatedOptionLabelName(name); + + const subtitleStringName = getOptionSubtitleName(name); + const subtitle = subtitleStringName && this.i18n(subtitleStringName); + + return { + name: name, + uiType: uiType, + value: value, + label: label, + subtitle: subtitle, + menuItems: this.getMenuItems(name, value), + url: getOptionUrl(name), + dependentOptions: option.dependentOptions ? + option.dependentOptions.map(t => makeOption({name: t})) : + [], + submenuButtonType: this.isSubmenuButton_(uiType) ? + getSubmenuButtonType(name) : + undefined, + }; + }; + + // If there is no option name in a section, this section, including the + // section title, should not be displayed. + this.optionSections_ = + options.filter(section => section.optionNames.length > 0) + .map(section => { + return { + title: this.getSectionTitleI18n_(section.title), + options: section.optionNames.map(makeOption, false), + }; + }); + } + + /** + * Returns an object specifying the default values to be used for a subset + * of options. + * + * @param engineId The engine id we want default values for. + * @return Default value overrides. + */ + private getDefaultValueOverrides_(engineId: string): + {[OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL]?: 1} { + if (!loadTimeData.getBoolean('autocorrectEnableByDefault')) { + return {}; + } + const enabledByDefaultKey = + PHYSICAL_KEYBOARD_AUTOCORRECT_ENABLED_BY_DEFAULT; + const prefBlob = this.getPref<PrefsObjectType>(PREFS_PATH).value; + const isAutocorrectDefaultEnabled = + prefBlob?.[engineId]?.[enabledByDefaultKey]; + return !isAutocorrectDefaultEnabled ? {} : { + [OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: 1, + }; + } + + private dependentOptionsDisabled_(value: OptionValue): boolean { + // TODO(b/189909728): Sometimes the value comes as a string, other times as + // an integer, other times as a boolean, so handle all cases. Try to + // understand and fix this. + return value === '0' || value === 0 || value === false; + } + + /** + * Handler for toggle button and dropdown change. Update the value of the + * changing option in Cros prefs. + */ + private onToggleButtonOrDropdownChange_(e: OptionDomRepeatEvent): void { + // e.model isn't correctly set for dependent options, due to nested + // dom-repeat, so figure out what option was actually set. + const option = e.model.dependant ? e.model.dependant : e.model.option; + // The value of dropdown is not updated immediately when the event is fired. + // Wait for the polymer state to update to make sure we write the latest + // to Cros Prefs. + afterNextRender(this, () => { + this.updatePref_(option.name, option.value); + }); + } + + private isSettingValueValid_(name: OptionType, value: OptionValue): boolean { + // TODO(b/238031866): Move this to be a function, as this method does not + // use `this`. + const uiType = getOptionUiType(name); + if (uiType !== UiType.DROPDOWN) { + return true; + } + const menuItems = getOptionMenuItems(name); + return !!menuItems.find((item) => item.value === value); + } + + /** + * Update an input method pref. + * + * Callers must ensure that `newValue` is the value DISPLAYED for `optionName` + * as this method maps back displayed values to stored prefs values. + */ + private updatePref_(optionName: OptionType, newValue: OptionValue): void { + // Get the existing settings dictionary, in order to update it later. + // |PrefsBehavior.setPrefValue| will update Cros Prefs only if the reference + // of variable has changed, so we need to copy the current content into a + // new variable. + const updatedSettings: PrefsObjectType = {}; + Object.assign( + updatedSettings, this.getPref<PrefsObjectType>(PREFS_PATH).value); + + const engineId = this.getStorageEngineId_(); + if (updatedSettings[engineId] === undefined) { + updatedSettings[engineId] = {}; + } + if (loadTimeData.getBoolean('allowAutocorrectToggle') && + optionName in AUTOCORRECT_OPTION_MAP_OVERRIDE) { + // newValue is passed in as the value for display, so map it back to a + // number. + newValue = + // Safety: We checked that optionName is a key above. + AUTOCORRECT_OPTION_MAP_OVERRIDE[optionName as AutocorrectOptionMapKey] + // Safety: Enforced in documentation. As newValue must be the + // value displayed for an autocorrect option, newValue should be + // a boolean here. + .mapValueForWrite(newValue as boolean); + } else if (shouldStoreAsNumber(optionName)) { + // Safety: The above if statements ensure that `optionName` is one of: + // - `PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL, if `allowAutocorrectToggle` + // is not set + // - `VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL, if `allowAutocorrectToggle` + // is not set + // - `JAPANESE_NUMBER_OF_SUGGESTIONS` + // All of the above returns `UiType.DROPDOWN` in `getOptionUiType`, so + // they are incorrectly passed as a string from Polymer's two-way native + // binding, and all of the above return numbers from `getOptionMenuItems`. + // TODO(b/265557721): Remove this when we remove Polymer's two-way native + // binding of value changes. + newValue = parseInt(newValue as string, 10); + } + // Safety: `updatedSettings[engineId]` is guaranteed to be defined as we + // defined it above. + updatedSettings[engineId]![optionName] = newValue; + + this.setPrefValue(PREFS_PATH, updatedSettings); + } + + /** + * Opens external link in Chrome. + */ + private navigateToOtherPageInSettings_(e: OptionDomRepeatEvent): void { + // Safety: This method is only called from an option if + // `isLink_(option.uiType)` is true, i.e. `option.uiType === UiType.LINK`, + // which, as of writing, is only true if it is EDIT_USER_DICT or + // JAPANESE_MANAGE_USER_DICTIONARY - both of which should have a valid url + // in `getOptionUrl`. + Router.getInstance().navigateTo(e.model.option.url!); + } + + /** + * @param section the name of the section. + * @return the i18n string for the section title. + */ + private getSectionTitleI18n_(section: SettingsHeaders): string { + switch (section) { + case SettingsHeaders.BASIC: + return this.i18n('inputMethodOptionsBasicSectionTitle'); + case SettingsHeaders.ADVANCED: + return this.i18n('inputMethodOptionsAdvancedSectionTitle'); + case SettingsHeaders.PHYSICAL_KEYBOARD: + return this.i18n('inputMethodOptionsPhysicalKeyboardSectionTitle'); + case SettingsHeaders.VIRTUAL_KEYBOARD: + return this.i18n('inputMethodOptionsVirtualKeyboardSectionTitle'); + case SettingsHeaders.SUGGESTIONS: + return this.i18n('inputMethodOptionsSuggestionsSectionTitle'); + // Japanese section + case SettingsHeaders.INPUT_ASSISTANCE: + return this.i18n('inputMethodOptionsInputAssistanceSectionTitle'); + // Japanese section + case SettingsHeaders.USER_DICTIONARIES: + return this.i18n('inputMethodOptionsUserDictionariesSectionTitle'); + // Japanese section + case SettingsHeaders.PRIVACY: + return this.i18n('inputMethodOptionsPrivacySectionTitle'); + + default: + // Safety: `section` has type `never` here. + // TODO(b/265559342): Use a compile-time exhaustive check here. + assertNotReached(); + } + } + + /** + * @return true if |item| is a toggle button. + */ + private isToggleButton_(item: UiType): item is UiType.TOGGLE_BUTTON { + return item === UiType.TOGGLE_BUTTON; + } + + /** + * @return true if |item| is a toggle button. + */ + private isSubmenuButton_(item: UiType): item is UiType.SUBMENU_BUTTON { + return item === UiType.SUBMENU_BUTTON; + } + + /** + * @return true if |item| is a dropdown. + */ + private isDropdown_(item: UiType): item is UiType.DROPDOWN { + return item === UiType.DROPDOWN; + } + + /** + * @return true if |item| is an external link. + */ + private isLink_(item: UiType): item is UiType.LINK { + return item === UiType.LINK; + } +} + +customElements.define( + SettingsInputMethodOptionsPageElement.is, + SettingsInputMethodOptionsPageElement); + +declare global { + interface HTMLElementTagNameMap { + [SettingsInputMethodOptionsPageElement.is]: + SettingsInputMethodOptionsPageElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_settings.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_settings.ts similarity index 89% rename from chrome/browser/resources/settings/chromeos/os_languages_page/input_method_settings.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/input_method_settings.ts index a07ceb8..59cfe6f 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_settings.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_settings.ts
@@ -4,29 +4,26 @@ /** * Type of settings to use for an input method. - * @enum {number} */ -export const SettingsType = { - LATIN_SETTINGS: 0, - ZHUYIN_SETTINGS: 1, - KOREAN_SETTINGS: 2, - PINYIN_SETTINGS: 3, - PINYIN_FUZZY_SETTINGS: 4, - BASIC_SETTINGS: 5, - ENGLISH_BASIC_WITH_AUTOSHIFT_SETTINGS: 6, - SUGGESTION_SETTINGS: 7, - PK_DIACRITICS_SETTINGS: 8, - JAPANESE_SETTINGS: 9, -}; +export enum SettingsType { + LATIN_SETTINGS = 0, + ZHUYIN_SETTINGS = 1, + KOREAN_SETTINGS = 2, + PINYIN_SETTINGS = 3, + PINYIN_FUZZY_SETTINGS = 4, + BASIC_SETTINGS = 5, + ENGLISH_BASIC_WITH_AUTOSHIFT_SETTINGS = 6, + SUGGESTION_SETTINGS = 7, + PK_DIACRITICS_SETTINGS = 8, + JAPANESE_SETTINGS = 9, +} -/** - * @param {boolean} predictiveWritingEnabled . - * @param {boolean} physicalKeyboardDiacriticsEnabled . - * @return {Object<string,!Array<!SettingsType>>} - */ +type SettingsMap = Partial<Record<string, SettingsType[]>>; + export function getInputMethodSettings( - predictiveWritingEnabled, physicalKeyboardDiacriticsEnabled, - isJapaneseSettingsEnabled) { + predictiveWritingEnabled: boolean, + physicalKeyboardDiacriticsEnabled: boolean, + isJapaneseSettingsEnabled: boolean): SettingsMap { const usEnglishSettings = [SettingsType.LATIN_SETTINGS]; if (predictiveWritingEnabled) { usEnglishSettings.push(SettingsType.SUGGESTION_SETTINGS); @@ -34,7 +31,7 @@ if (physicalKeyboardDiacriticsEnabled) { usEnglishSettings.push(SettingsType.PK_DIACRITICS_SETTINGS); } - const settingsMap = { + const settingsMap: SettingsMap = { // NOTE: Please group by SettingsType, and keep entries sorted // alphabetically // by ID within each group, just for readability.
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_types.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_types.js deleted file mode 100644 index f5cbf96..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_types.js +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @enum {string} - */ -export const JapaneseInputMode = { - KANA: 'Kana', - ROMAJI: 'Romaji', -}; - -/** - * @enum {string} - */ -export const JapanesePunctuationStyle = { - KUTEN_TOUTEN: 'KutenTouten', - COMMA_PERIOD: 'CommaPeriod', - KUTEN_PERIOD: 'KutenPeriod', - COMMA_TOUTEN: 'CommaTouten', -}; - -/** - * @enum {string} - */ -export const JapaneseSymbolStyle = { - CORNER_BRACKET_MIDDLE_DOT: 'CornerBracketMiddleDot', - SQUARE_BRACKET_SLASH: 'SquareBracketSlash', - CORNER_BRACKET_SLASH: 'CornerBracketSlash', - SQUARE_BRACKET_MIDDLE_DOT: 'SquareBracketMiddleDot', -}; - -/** - * @enum {string} - */ -export const JapaneseSpaceInputStyle = { - INPUT_MODE: 'InputMode', - FULLWIDTH: 'Fullwidth', - HALFWIDTH: 'Halfwidth', -}; - -/** - * @enum {string} - */ -export const JapaneseSectionShortcut = { - NO_SHORTCUT: 'NoShortcut', - DIGITS_123456789: 'Digits123456789', - ASDFGHJKL: 'ASDFGHJKL', -}; - -/** - * @enum {string} - */ -export const JapaneseKeymapStyle = { - CUSTOM: 'Custom', - ATOK: 'Atok', - MS_IME: 'MsIme', - KOTOERI: 'Kotoeri', - MOBILE: 'Mobile', - CHROME_OS: 'ChromeOs', -}; - -export const JapaneseShiftKeyModeStyle = { - OFF: 'Off', - ALPHANUMERIC: 'Alphanumeric', - KATAKANA: 'Katakana', -};
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_types.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_types.ts new file mode 100644 index 0000000..67b5f7b --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_types.ts
@@ -0,0 +1,49 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +export enum JapaneseInputMode { + KANA = 'Kana', + ROMAJI = 'Romaji', +} + +export enum JapanesePunctuationStyle { + KUTEN_TOUTEN = 'KutenTouten', + COMMA_PERIOD = 'CommaPeriod', + KUTEN_PERIOD = 'KutenPeriod', + COMMA_TOUTEN = 'CommaTouten', +} + +export enum JapaneseSymbolStyle { + CORNER_BRACKET_MIDDLE_DOT = 'CornerBracketMiddleDot', + SQUARE_BRACKET_SLASH = 'SquareBracketSlash', + CORNER_BRACKET_SLASH = 'CornerBracketSlash', + SQUARE_BRACKET_MIDDLE_DOT = 'SquareBracketMiddleDot', +} + +export enum JapaneseSpaceInputStyle { + INPUT_MODE = 'InputMode', + FULLWIDTH = 'Fullwidth', + HALFWIDTH = 'Halfwidth', +} + +export enum JapaneseSectionShortcut { + NO_SHORTCUT = 'NoShortcut', + DIGITS_123456789 = 'Digits123456789', + ASDFGHJKL = 'ASDFGHJKL', +} + +export enum JapaneseKeymapStyle { + CUSTOM = 'Custom', + ATOK = 'Atok', + MS_IME = 'MsIme', + KOTOERI = 'Kotoeri', + MOBILE = 'Mobile', + CHROME_OS = 'ChromeOs', +} + +export enum JapaneseShiftKeyModeStyle { + OFF = 'Off', + ALPHANUMERIC = 'Alphanumeric', + KATAKANA = 'Katakana', +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.ts similarity index 74% rename from chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.ts index 3443277e..21190be6 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.ts
@@ -6,7 +6,7 @@ * @fileoverview constants related to input method options. */ -import {assert, assertNotReached} from 'chrome://resources/ash/common/assert.js'; +import {assert, assertNotReached} from 'chrome://resources/js/assert_ts.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {routes} from '../os_route.js'; @@ -17,7 +17,6 @@ /** * The prefix string shared by all first party input method ID. - * @private @const */ export const FIRST_PARTY_INPUT_METHOD_ID_PREFIX = '_comp_ime_jkghodnilhceideoidjikpgommlajknk'; @@ -32,103 +31,97 @@ /** * All possible keyboard layouts. Should match Google3. - * - * @enum {string} */ -const KeyboardLayout = { - STANDARD: 'Default', - GINYIEH: 'Gin Yieh', - ETEN: 'Eten', - IBM: 'IBM', - HSU: 'Hsu', - ETEN26: 'Eten 26', - SET2: '2 Set / 두벌식', - SET2Y: '2 Set (Old Hangul) / 두벌식 (옛글)', - SET390: '3 Set (390) / 세벌식 (390)', - SET3_FINAL: '3 Set (Final) / 세벌식 (최종)', - SET3_SUN: '3 Set (No Shift) / 세벌식 (순아래)', - SET3_YET: '3 Set (Old Hangul) / 세벌식 (옛글)', - XKB_US: 'US', - XKB_DVORAK: 'Dvorak', - XKB_COLEMAK: 'Colemak', -}; +enum KeyboardLayout { + STANDARD = 'Default', + GINYIEH = 'Gin Yieh', + ETEN = 'Eten', + IBM = 'IBM', + HSU = 'Hsu', + ETEN26 = 'Eten 26', + SET2 = '2 Set / 두벌식', + SET2Y = '2 Set (Old Hangul) / 두벌식 (옛글)', + SET390 = '3 Set (390) / 세벌식 (390)', + SET3_FINAL = '3 Set (Final) / 세벌식 (최종)', + SET3_SUN = '3 Set (No Shift) / 세벌식 (순아래)', + SET3_YET = '3 Set (Old Hangul) / 세벌식 (옛글)', + XKB_US = 'US', + XKB_DVORAK = 'Dvorak', + XKB_COLEMAK = 'Colemak', +} /** * All possible options on options pages. Should match Gooogle3. - * - * @enum {string} */ -export const OptionType = { - EDIT_USER_DICT: 'editUserDict', - ENABLE_COMPLETION: 'enableCompletion', - ENABLE_DOUBLE_SPACE_PERIOD: 'enableDoubleSpacePeriod', - ENABLE_GESTURE_TYPING: 'enableGestureTyping', - ENABLE_PREDICTION: 'enablePrediction', - ENABLE_SOUND_ON_KEYPRESS: 'enableSoundOnKeypress', - PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL: +export enum OptionType { + EDIT_USER_DICT = 'editUserDict', + ENABLE_COMPLETION = 'enableCompletion', + ENABLE_DOUBLE_SPACE_PERIOD = 'enableDoubleSpacePeriod', + ENABLE_GESTURE_TYPING = 'enableGestureTyping', + ENABLE_PREDICTION = 'enablePrediction', + ENABLE_SOUND_ON_KEYPRESS = 'enableSoundOnKeypress', + PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL = 'physicalKeyboardAutoCorrectionLevel', - PHYSICAL_KEYBOARD_ENABLE_CAPITALIZATION: + PHYSICAL_KEYBOARD_ENABLE_CAPITALIZATION = 'physicalKeyboardEnableCapitalization', - PHYSICAL_KEYBOARD_ENABLE_PREDICTIVE_WRITING: + PHYSICAL_KEYBOARD_ENABLE_PREDICTIVE_WRITING = 'physicalKeyboardEnablePredictiveWriting', - PHYSICAL_KEYBOARD_ENABLE_DIACRITICS_ON_LONGPRESS: + PHYSICAL_KEYBOARD_ENABLE_DIACRITICS_ON_LONGPRESS = 'physicalKeyboardEnableDiacriticsOnLongpress', - VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL: 'virtualKeyboardAutoCorrectionLevel', - VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION: 'virtualKeyboardEnableCapitalization', - XKB_LAYOUT: 'xkbLayout', + VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL = 'virtualKeyboardAutoCorrectionLevel', + VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION = + 'virtualKeyboardEnableCapitalization', + XKB_LAYOUT = 'xkbLayout', // Options for Japanese input method. - JAPANESE_AUTOMATICALLY_SWITCH_TO_HALFWIDTH: 'AutomaticallySwitchToHalfwidth', - JAPANESE_SHIFT_KEY_MODE_STYLE: 'ShiftKeyModeStyle', - JAPANESE_USE_INPUT_HISTORY: 'UseInputHistory', - JAPANESE_USE_SYSTEM_DICTIONARY: 'UseSystemDictionary', - JAPANESE_NUMBER_OF_SUGGESTIONS: 'numberOfSuggestions', - JAPANESE_INPUT_MODE: 'JapaneseInputMode', - JAPANESE_PUNCTUATION_STYLE: 'JapanesePunctuationStyle', - JAPANESE_SYMBOL_STYLE: 'JapaneseSymbolStyle', - JAPANESE_SPACE_INPUT_STYLE: 'JapaneseSpaceInputStyle', - JAPANESE_SECTION_SHORTCUT: 'JapaneseSectionShortcut', - JAPANESE_KEYMAP_STYLE: 'JapaneseKeymapStyle', - JAPANESE_MANAGE_USER_DICTIONARY: 'JapaneseManageUserDictionary', - JAPANESE_CLEAR_PERSONALIZATION_DATA: 'JapaneseClearPersonalizationData', - JAPANESE_DISABLE_PERSONALIZED_SUGGESTIONS: 'JapaneseDisableSuggestions', - JAPANESE_AUTOMATICALLY_SEND_STATISTICS_TO_GOOGLE: + JAPANESE_AUTOMATICALLY_SWITCH_TO_HALFWIDTH = 'AutomaticallySwitchToHalfwidth', + JAPANESE_SHIFT_KEY_MODE_STYLE = 'ShiftKeyModeStyle', + JAPANESE_USE_INPUT_HISTORY = 'UseInputHistory', + JAPANESE_USE_SYSTEM_DICTIONARY = 'UseSystemDictionary', + JAPANESE_NUMBER_OF_SUGGESTIONS = 'numberOfSuggestions', + JAPANESE_INPUT_MODE = 'JapaneseInputMode', + JAPANESE_PUNCTUATION_STYLE = 'JapanesePunctuationStyle', + JAPANESE_SYMBOL_STYLE = 'JapaneseSymbolStyle', + JAPANESE_SPACE_INPUT_STYLE = 'JapaneseSpaceInputStyle', + JAPANESE_SECTION_SHORTCUT = 'JapaneseSectionShortcut', + JAPANESE_KEYMAP_STYLE = 'JapaneseKeymapStyle', + JAPANESE_MANAGE_USER_DICTIONARY = 'JapaneseManageUserDictionary', + JAPANESE_CLEAR_PERSONALIZATION_DATA = 'JapaneseClearPersonalizationData', + JAPANESE_DISABLE_PERSONALIZED_SUGGESTIONS = 'JapaneseDisableSuggestions', + JAPANESE_AUTOMATICALLY_SEND_STATISTICS_TO_GOOGLE = 'AutomaticallySendStatisticsToGoogle', // Options for Korean input method. - KOREAN_ENABLE_SYLLABLE_INPUT: 'koreanEnableSyllableInput', - KOREAN_KEYBOARD_LAYOUT: 'koreanKeyboardLayout', + KOREAN_ENABLE_SYLLABLE_INPUT = 'koreanEnableSyllableInput', + KOREAN_KEYBOARD_LAYOUT = 'koreanKeyboardLayout', // Options for pinyin input method. - PINYIN_CHINESE_PUNCTUATION: 'pinyinChinesePunctuation', - PINYIN_DEFAULT_CHINESE: 'pinyinDefaultChinese', - PINYIN_ENABLE_FUZZY: 'pinyinEnableFuzzy', - PINYIN_ENABLE_LOWER_PAGING: 'pinyinEnableLowerPaging', - PINYIN_ENABLE_UPPER_PAGING: 'pinyinEnableUpperPaging', - PINYIN_FULL_WIDTH_CHARACTER: 'pinyinFullWidthCharacter', - PINYIN_FUZZY_CONFIG: 'pinyinFuzzyConfig', - PINYIN_EN_ENG: 'en:eng', - PINYIN_AN_ANG: 'an:ang', - PINYIN_IAN_IANG: 'ian:iang', - PINYIN_K_G: 'k:g', - PINYIN_R_L: 'r:l', - PINYIN_UAN_UANG: 'uan:uang', - PINYIN_C_CH: 'c:ch', - PINYIN_F_H: 'f:h', - PINYIN_IN_ING: 'in:ing', - PINYIN_L_N: 'l:n', - PINYIN_S_SH: 's:sh', - PINYIN_Z_ZH: 'z:zh', + PINYIN_CHINESE_PUNCTUATION = 'pinyinChinesePunctuation', + PINYIN_DEFAULT_CHINESE = 'pinyinDefaultChinese', + PINYIN_ENABLE_FUZZY = 'pinyinEnableFuzzy', + PINYIN_ENABLE_LOWER_PAGING = 'pinyinEnableLowerPaging', + PINYIN_ENABLE_UPPER_PAGING = 'pinyinEnableUpperPaging', + PINYIN_FULL_WIDTH_CHARACTER = 'pinyinFullWidthCharacter', + PINYIN_FUZZY_CONFIG = 'pinyinFuzzyConfig', + PINYIN_EN_ENG = 'en:eng', + PINYIN_AN_ANG = 'an:ang', + PINYIN_IAN_IANG = 'ian:iang', + PINYIN_K_G = 'k:g', + PINYIN_R_L = 'r:l', + PINYIN_UAN_UANG = 'uan:uang', + PINYIN_C_CH = 'c:ch', + PINYIN_F_H = 'f:h', + PINYIN_IN_ING = 'in:ing', + PINYIN_L_N = 'l:n', + PINYIN_S_SH = 's:sh', + PINYIN_Z_ZH = 'z:zh', // Options for zhuyin input method. - ZHUYIN_KEYBOARD_LAYOUT: 'zhuyinKeyboardLayout', - ZHUYIN_PAGE_SIZE: 'zhuyinPageSize', - ZHUYIN_SELECT_KEYS: 'zhuyinSelectKeys', -}; + ZHUYIN_KEYBOARD_LAYOUT = 'zhuyinKeyboardLayout', + ZHUYIN_PAGE_SIZE = 'zhuyinPageSize', + ZHUYIN_SELECT_KEYS = 'zhuyinSelectKeys', +} /** * Default values for each option type. * * WARNING: Keep this in sync with corresponding Google3 file for extension. - * - * @type {Object<OptionType, *>} - * @const */ export const OPTION_DEFAULT = { [OptionType.ENABLE_COMPLETION]: false, @@ -190,86 +183,82 @@ [OptionType.ZHUYIN_KEYBOARD_LAYOUT]: KeyboardLayout.STANDARD, [OptionType.ZHUYIN_PAGE_SIZE]: '10', [OptionType.ZHUYIN_SELECT_KEYS]: '1234567890', -}; +} satisfies Partial<Record<OptionType, unknown>>; /** - * @param {OptionType} optionName The option we want the default value for. - * @param {Object<OptionType, *>} overrides List of values to use instead of - * the default values. - * @return {*} The default, or overriden value. + * @param optionName The option we want the default value for. + * @param overrides List of values to use instead of the default values. + * @return The default, or overridden value. */ -export function getDefaultValue(optionName, overrides) { +export function getDefaultValue<T extends keyof typeof OPTION_DEFAULT>( + optionName: T, overrides: {[K in T]?: (typeof OPTION_DEFAULT)[K]}): + (typeof OPTION_DEFAULT)[T] { // Overrides are only coming from the following flag, let's be safe here and // only enable this branch if the flag is also enabled. if (!loadTimeData.getBoolean('autocorrectEnableByDefault')) { return OPTION_DEFAULT[optionName]; } - return optionName in overrides ? overrides[optionName] : - OPTION_DEFAULT[optionName]; + return optionName in overrides ? + // This assertion is unsafe, as TypeScript's optional property types + // include `undefined` in properties, as + // https://www.typescriptlang.org/tsconfig#exactOptionalPropertyTypes is + // not set in our tsconfig. + // TODO(b/265558129): Use `overrides[optionName] !== undefined` instead. + overrides[optionName]! : + OPTION_DEFAULT[optionName]; } /** * Type conversions functions for reading and writing options. Use these for * reading and writing pref values when we don't want the default mappings. This * is only used if allow autocorrect toggle is on. - * - * @const */ export const AUTOCORRECT_OPTION_MAP_OVERRIDE = { [OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: { - mapValueForDisplay: (value) => value > 0 ? true : false, - mapValueForWrite: (value) => value ? 1 : 0, + mapValueForDisplay: (value: number): boolean => value > 0 ? true : false, + mapValueForWrite: (value: boolean): 1 | 0 => value ? 1 : 0, }, [OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: { - mapValueForDisplay: (value) => value > 0 ? true : false, - mapValueForWrite: (value) => value ? 1 : 0, + mapValueForDisplay: (value: number): boolean => value > 0 ? true : false, + mapValueForWrite: (value: boolean): 1 | 0 => value ? 1 : 0, }, }; /** * All possible UI elements for options. - * - * @enum {string} */ -export const UiType = { - DROPDOWN: 'dropdown', - LINK: 'link', - SUBMENU_BUTTON: 'submenuButton', - TOGGLE_BUTTON: 'toggleButton', -}; +export enum UiType { + DROPDOWN = 'dropdown', + LINK = 'link', + SUBMENU_BUTTON = 'submenuButton', + TOGGLE_BUTTON = 'toggleButton', +} /** * All possible submenu button types. - * - * @enum {string} */ -export const SubmenuButton = { - JAPANESE_CLEAR_PERSONALIZATION_DATA: 'SubmenuButtonClearPersonalizedData', -}; +export enum SubmenuButton { + JAPANESE_CLEAR_PERSONALIZATION_DATA = 'SubmenuButtonClearPersonalizedData', +} /** * All possible Settings headers - * - * @enum {string} */ -const SettingsHeaders = { - ADVANCED: 'advanced', - BASIC: 'basic', - INPUT_ASSISTANCE: 'inputAssistance', - PHYSICAL_KEYBOARD: 'physicalKeyboard', - PRIVACY: 'privacy', - SUGGESTIONS: 'suggestions', - USER_DICTIONARIES: 'userDictionaries', - VIRTUAL_KEYBOARD: 'virtualKeyboard', -}; +export enum SettingsHeaders { + ADVANCED = 'advanced', + BASIC = 'basic', + INPUT_ASSISTANCE = 'inputAssistance', + PHYSICAL_KEYBOARD = 'physicalKeyboard', + PRIVACY = 'privacy', + SUGGESTIONS = 'suggestions', + USER_DICTIONARIES = 'userDictionaries', + VIRTUAL_KEYBOARD = 'virtualKeyboard', +} /** * Contents of the settings page for different settings types. * These should be in the order they are expected to appear in * the actual settings pages. - * - * @type {Object<SettingsType, !Array<{title: SettingsHeaders, optionNames: - * !Array<OptionType>}>>} */ const Settings = { [SettingsType.LATIN_SETTINGS]: [ @@ -412,26 +401,32 @@ optionNames: [{name: OptionType.PHYSICAL_KEYBOARD_ENABLE_DIACRITICS_ON_LONGPRESS}], }], -}; +} satisfies Record<SettingsType, Array<{ + title: SettingsHeaders, + optionNames: Array<{ + name: OptionType, + dependentOptions?: OptionType[], + }>, + }>>; /** - * @param {string} id Input method ID. - * @return {string} The corresponding engind ID of the input method. + * @param id A first party input method ID. + * @return The corresponding engind ID of the input method. */ -export function getFirstPartyInputMethodEngineId(id) { +export function getFirstPartyInputMethodEngineId(id: string): string { + // Safety: Enforced by documentation. assert(isFirstPartyInputMethodId(id)); return id.substring(FIRST_PARTY_INPUT_METHOD_ID_PREFIX.length); } /** - * @param {string} id Input method ID. - * @param {boolean} predictiveWritingEnabled . - * @param {boolean} physicalKeyboardDiacriticsEnabled . - * @return {boolean} true if the input method's options page is implemented. + * @param id Input method ID. + * @return true if the input method's options page is implemented. */ export function hasOptionsPageInSettings( - id, predictiveWritingEnabled, physicalKeyboardDiacriticsEnabled, - isJapaneseSettingsEnabled) { + id: string, predictiveWritingEnabled: boolean, + physicalKeyboardDiacriticsEnabled: boolean, + isJapaneseSettingsEnabled: boolean): boolean { if (!isFirstPartyInputMethodId(id)) { return false; } @@ -445,23 +440,26 @@ /** * Generates options to be displayed in the options page, grouped by sections. - * @param {string} engineId Input method engine ID. - * @param {boolean} predictiveWritingEnabled . - * @param {boolean} physicalKeyboardDiacriticsEnabled . - * @return {!Array<{title: string, optionNames: - * !Array<OptionType>}>} the options to be - * displayed. + * @param engineId Input method engine ID. + * @return the options to be displayed. */ export function generateOptions( - engineId, predictiveWritingEnabled, physicalKeyboardDiacriticsEnabled, - isJapaneseSettingsEnabled) { - const options = []; + engineId: string, predictiveWritingEnabled: boolean, + physicalKeyboardDiacriticsEnabled: boolean, + isJapaneseSettingsEnabled: boolean): Array<{ + title: SettingsHeaders, + optionNames: Array<{name: OptionType, dependentOptions?: OptionType[]}>, +}> { + const options: Array<{ + title: SettingsHeaders, + optionNames: Array<{name: OptionType, dependentOptions?: OptionType[]}>, + }> = []; const inputMethodSettings = getInputMethodSettings( predictiveWritingEnabled, physicalKeyboardDiacriticsEnabled, isJapaneseSettingsEnabled); const engineSettings = inputMethodSettings[engineId]; if (engineSettings) { - const pushedOptions = new Map(); + const pushedOptions = new Map<SettingsHeaders, number>(); engineSettings.forEach((settingType) => { const settings = Settings[settingType]; @@ -486,10 +484,10 @@ } /** - * @param {!OptionType} option The option type. - * @return {UiType} The UI type of |option|. + * @param option The option type. + * @return The UI type of |option|. */ -export function getOptionUiType(option) { +export function getOptionUiType(option: OptionType): UiType { switch (option) { // TODO(b/191608723): Clean up switch statements. case OptionType.ENABLE_COMPLETION: @@ -551,11 +549,21 @@ case OptionType.JAPANESE_CLEAR_PERSONALIZATION_DATA: return UiType.SUBMENU_BUTTON; default: + // This assert is unsafe, as `option` could be + // `OptionType.PINYIN_FUZZY_CONFIG` here. + // TODO(b/265559342): Handle the aforementioned cases of `option`, and use + // use a compile-time exhaustive check here to avoid backsliding. assertNotReached(); } } -export function isOptionLabelTranslated(option) { +export function isOptionLabelTranslated(option: OptionType): option is Exclude< + OptionType, + OptionType.PINYIN_AN_ANG|OptionType.PINYIN_EN_ENG|OptionType + .PINYIN_IAN_IANG|OptionType.PINYIN_K_G|OptionType.PINYIN_R_L| + OptionType.PINYIN_UAN_UANG|OptionType.PINYIN_C_CH| + OptionType.PINYIN_F_H|OptionType.PINYIN_IN_ING| + OptionType.PINYIN_L_N|OptionType.PINYIN_S_SH|OptionType.PINYIN_Z_ZH> { switch (option) { // TODO(b/191608723): Clean up switch statements. case OptionType.PINYIN_AN_ANG: @@ -577,10 +585,11 @@ } /** - * @param {!OptionType} option The option type. - * @return {string} The name of the i18n string for the label of |option|. + * `isOptionLabelTranslated(option)` must be true. + * @param option The option type. + * @return The name of the i18n string for the label of |option|. */ -export function getOptionLabelName(option) { +export function getOptionLabelName(option: OptionType): string { switch (option) { case OptionType.ENABLE_DOUBLE_SPACE_PERIOD: return 'inputMethodOptionsEnableDoubleSpacePeriod'; @@ -657,16 +666,21 @@ case OptionType.KOREAN_ENABLE_SYLLABLE_INPUT: return 'inputMethodOptionsKoreanSyllableInput'; default: + // This assertion is unsafe, as `option` could be + // `OptionType.ENABLE_COMPLETION` or `OptionType.PINYIN_FUZZY_CONFIG` here + // (assuming that `isOptionLabelTranslated(option)` is true). + // TODO(b/265559342): Handle the aforementioned cases of `option`, and use + // use a compile-time exhaustive check here to avoid backsliding. assertNotReached(); } } /** - * @param {!OptionType} option The option type. - * @return {string} The name of the string for the subtitle of |option|. Returns - * empty string if no subtitle. + * @param option The option type. + * @return The name of the string for the subtitle of |option|. Returns empty + * string if no subtitle. */ -export function getOptionSubtitleName(option) { +export function getOptionSubtitleName(option: OptionType): string { switch (option) { case OptionType.PHYSICAL_KEYBOARD_ENABLE_DIACRITICS_ON_LONGPRESS: return 'inputMethodOptionsDiacriticsOnPhysicalKeyboardLongpressSubtitle'; @@ -683,7 +697,10 @@ } } -export function getUntranslatedOptionLabelName(option) { +/** + * `isOptionLabelTranslated(option)` must be false. + */ +export function getUntranslatedOptionLabelName(option: OptionType): string { switch (option) { case OptionType.PINYIN_AN_ANG: return 'an_ang'; @@ -710,16 +727,19 @@ case OptionType.PINYIN_Z_ZH: return 'z_zh'; default: + // Safety: Assuming that `isOptionLabelTranslated(option)` is false, + // `option` cannot be anything here. + // TODO(b/265559342): Use a compile-time exhaustive check here. assertNotReached(); } } /** - * @param {!OptionType} option The option type. - * @return {!Array<{value: *, name: string}>} The list of items to be - * displayed in the dropdown for |option|. + * @param option The option type. + * @return The list of items to be displayed in the dropdown for |option|. */ -export function getOptionMenuItems(option) { +export function getOptionMenuItems(option: OptionType): + Array<{name?: string, value: string | number}> { switch (option) { case OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL: case OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL: @@ -924,23 +944,29 @@ } } - /** - * - * @param {!OptionType} option The option type. - * @return {boolean} true if the value for |option| is a number. + * Used to work around dropdowns in the UI always storing their values as + * strings. + * @param option The option type. + * @return true if the value for |option| is a number and |option| is a + * dropdown. */ -export function shouldStoreAsNumber(option) { +// TODO(b/265557721): Remove this when we remove Polymer's two-way native +// binding of value changes. +export function shouldStoreAsNumber(option: OptionType): + option is OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL| + OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL| + OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS { return option === OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL || option === OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL || option === OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS; } /** - * @param {!OptionType} option The option type. - * @return {Route|undefined} The url to open for |option|, returns - * undefined if |option| does not have a url. + * @param option The option type. + * @return The url to open for |option|, returns undefined if |option| does not + * have a url. */ -export function getOptionUrl(option) { +export function getOptionUrl(option: OptionType): Route|undefined { if (option === OptionType.EDIT_USER_DICT) { return routes.OS_LANGUAGES_EDIT_DICTIONARY; } @@ -951,11 +977,12 @@ } /** - * @param {!OptionType} option The option type. - * @return {SubmenuButton|undefined} The submenu button type for - * |option|, returns undefined if |option| does not have a submenu button type. + * @param option The option type. + * @return The submenu button type for |option|, returns undefined if |option| + * does not have a submenu button type. */ -export function getSubmenuButtonType(option) { +export function getSubmenuButtonType(option: OptionType): SubmenuButton| + undefined { if (option === OptionType.JAPANESE_CLEAR_PERSONALIZATION_DATA) { return SubmenuButton.JAPANESE_CLEAR_PERSONALIZATION_DATA; } @@ -963,10 +990,9 @@ } /** - * @param {string} id Input method ID. - * @return {boolean} true if |id| is a first party input method ID. - * @private + * @param id Input method ID. + * @return true if |id| is a first party input method ID. */ -function isFirstPartyInputMethodId(id) { +function isFirstPartyInputMethodId(id: string): boolean { return id.startsWith(FIRST_PARTY_INPUT_METHOD_ID_PREFIX); }
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js deleted file mode 100644 index 33beb92..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js +++ /dev/null
@@ -1,725 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview 'os-settings-input-page' is the input sub-page - * for language and input method settings. - */ - -import 'chrome://resources/cr_components/localized_link/localized_link.js'; -import 'chrome://resources/cr_elements/cr_button/cr_button.js'; -import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; -import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; -import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; -import './add_input_methods_dialog.js'; -import './add_spellcheck_languages_dialog.js'; -import './os_edit_dictionary_page.js'; -import '../keyboard_shortcut_banner/keyboard_shortcut_banner.js'; -import '../../controls/settings_toggle_button.js'; -import '../../settings_shared.css.js'; -import '../os_settings_page/os_settings_animated_pages.js'; - -import {assert} from 'chrome://resources/ash/common/assert.js'; -import {focusWithoutInk} from 'chrome://resources/ash/common/focus_without_ink_js.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {Setting} from '../../mojom-webui/setting.mojom-webui.js'; -import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js'; -import {recordSettingChange} from '../metrics_recorder.js'; -import {routes} from '../os_route.js'; -import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js'; -import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js'; -import {Route, Router} from '../router.js'; - -import {hasOptionsPageInSettings} from './input_method_util.js'; -import {getTemplate} from './input_page.html.js'; -import {InputsShortcutReminderState, LanguagesMetricsProxy, LanguagesMetricsProxyImpl, LanguagesPageInteraction} from './languages_metrics_proxy.js'; -import {LanguageHelper, LanguagesModel, LanguageState, SpellCheckLanguageState} from './languages_types.js'; - -/** - * @constructor - * @extends {PolymerElement} - * @implements {DeepLinkingBehaviorInterface} - * @implements {I18nBehaviorInterface} - * @implements {PrefsBehaviorInterface} - * @implements {RouteObserverBehaviorInterface} - */ -const OsSettingsInputPageElementBase = mixinBehaviors( - [DeepLinkingBehavior, I18nBehavior, PrefsBehavior, RouteObserverBehavior], - PolymerElement); - -/** @polymer */ -class OsSettingsInputPageElement extends OsSettingsInputPageElementBase { - static get is() { - return 'os-settings-input-page'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /* Preferences state. */ - prefs: { - type: Object, - notify: true, - }, - - /** @type {!Map<string, (string|Function)>} */ - focusConfig: { - type: Object, - observer: 'focusConfigChanged_', - }, - - /** - * Read-only reference to the languages model provided by the - * 'os-settings-languages' instance. - * @type {!LanguagesModel|undefined} - */ - languages: { - type: Object, - }, - - /** @type {!LanguageHelper} */ - languageHelper: Object, - - /** - * @private {!Array<!LanguageState|!SpellCheckLanguageState>|undefined} - */ - spellCheckLanguages_: { - type: Array, - computed: `getSpellCheckLanguages_(languageSettingsV2Update2Enabled_, - languages.spellCheckOnLanguages.*, languages.enabled.*)`, - }, - - /** @private */ - showAddInputMethodsDialog_: { - type: Boolean, - value: false, - }, - - /** @private */ - showAddSpellcheckLanguagesDialog_: { - type: Boolean, - value: false, - }, - - /** - * Used by DeepLinkingBehavior to focus this page's deep links. - * @type {!Set<!Setting>} - */ - supportedSettingIds: { - type: Object, - value: () => new Set([ - Setting.kShowInputOptionsInShelf, - Setting.kAddInputMethod, - Setting.kSpellCheck, - ]), - }, - - /** @private */ - languageSettingsV2Update2Enabled_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('enableLanguageSettingsV2Update2'); - }, - }, - - /** @private */ - languageSettingsJapaneseEnabled_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('systemJapanesePhysicalTyping'); - }, - }, - - /** @private */ - shouldShowLanguagePacksNotice_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('languagePacksHandwritingEnabled'); - }, - }, - - /** - * Whether the shortcut reminder for the last used IME is currently - * showing. - * @private - */ - showLastUsedImeShortcutReminder_: { - type: Boolean, - computed: `shouldShowLastUsedImeShortcutReminder_( - languages.inputMethods.enabled.length, - prefs.ash.shortcut_reminders.last_used_ime_dismissed.value)`, - }, - - /** - * Whether the shortcut reminder for the next IME is currently showing. - * @private - */ - showNextImeShortcutReminder_: { - type: Boolean, - computed: `shouldShowNextImeShortcutReminder_( - languages.inputMethods.enabled.length, - prefs.ash.shortcut_reminders.next_ime_dismissed.value)`, - }, - - /** - * The body of the currently showing shortcut reminders. - * @private {!Array<string>} - */ - shortcutReminderBody_: { - type: Array, - computed: `getShortcutReminderBody_(showLastUsedImeShortcutReminder_, - showNextImeShortcutReminder_)`, - }, - - /** @private */ - onDeviceGrammarCheckEnabled_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('onDeviceGrammarCheckEnabled'); - }, - }, - }; - } - - /** @override */ - constructor() { - super(); - - /** @private {!LanguagesMetricsProxy} */ - this.languagesMetricsProxy_ = LanguagesMetricsProxyImpl.getInstance(); - } - - /** - * @param {!Route} route - * @param {!Route=} oldRoute - */ - currentRouteChanged(route, oldRoute) { - // Does not apply to this page. - if (route !== routes.OS_LANGUAGES_INPUT) { - return; - } - - this.attemptDeepLink(); - } - - /** - * @param {!Map<string, (string|Function)>} newConfig - * @param {?Map<string, (string|Function)>} oldConfig - * @private - */ - focusConfigChanged_(newConfig, oldConfig) { - // focusConfig is set only once on the parent, so this observer should - // only fire once. - assert(!oldConfig); - this.focusConfig.set( - routes.OS_LANGUAGES_EDIT_DICTIONARY.path, - () => focusWithoutInk(this.$.editDictionarySubpageTrigger)); - } - - /** - * @param {!Event} e - * @private - */ - onShowImeMenuChange_(e) { - this.languagesMetricsProxy_.recordToggleShowInputOptionsOnShelf( - e.target.checked); - } - - /** - * @return {boolean} - * @private - */ - inputMethodsLimitedByPolicy_() { - const allowedInputMethodsPref = - this.getPref('settings.language.allowed_input_methods'); - return !!allowedInputMethodsPref && allowedInputMethodsPref.value.length; - } - - /** - * Handler for click events on an input method on the main page, - * which sets it as the current input method. - * @param {{model: {item: !chrome.languageSettingsPrivate.InputMethod}, - * target: {tagName: string}}} e - * @private - */ - onInputMethodClick_(e) { - // Clicks on the button are handled in onInputMethodOptionsClick_. - if (e.target.tagName === 'CR-ICON-BUTTON') { - return; - } - - this.languageHelper.setCurrentInputMethod(e.model.item.id); - this.languagesMetricsProxy_.recordInteraction( - LanguagesPageInteraction.SWITCH_INPUT_METHOD); - recordSettingChange(); - } - - /** - * Handler for <Enter> events on an input method on the main page, - * which sets it as the current input method. - * @param {{model: {item: !chrome.languageSettingsPrivate.InputMethod}, - * key: string}} e - * @private - */ - onInputMethodKeyPress_(e) { - // Ignores key presses other than <Enter>. - if (e.key !== 'Enter') { - return; - } - - this.languageHelper.setCurrentInputMethod(e.model.item.id); - } - - /** - * Opens the input method extension's options page in a new tab (or focuses - * an existing instance of the IME's options). - * @param {{model: {item: chrome.languageSettingsPrivate.InputMethod}}} e - * @private - */ - openExtensionOptionsPage_(e) { - this.languageHelper.openInputMethodOptions(e.model.item.id); - } - - - /** - * @param {string} id The input method ID. - * @return {boolean} True if there is a options page in ChromeOS settings - * for the input method ID. - * @private - */ - hasOptionsPageInSettings_(id) { - return hasOptionsPageInSettings( - id, loadTimeData.getBoolean('allowPredictiveWriting'), - loadTimeData.getBoolean('allowDiacriticsOnPhysicalKeyboardLongpress'), - loadTimeData.getBoolean('systemJapanesePhysicalTyping')); - } - - /** - * @param {{model: {item: chrome.languageSettingsPrivate.InputMethod}}} e - * @private - */ - navigateToOptionsPageInSettings_(e) { - const params = new URLSearchParams(); - params.append('id', e.model.item.id); - Router.getInstance().navigateTo( - routes.OS_LANGUAGES_INPUT_METHOD_OPTIONS, params); - } - - /** - * @param {string} id The input method ID. - * @param {string} currentId The ID of the currently enabled input method. - * @return {boolean} True if the IDs match. - * @private - */ - isCurrentInputMethod_(id, currentId) { - return id === currentId; - } - - /** - * @param {string} id The input method ID. - * @param {string} currentId The ID of the currently enabled input method. - * @return {string} The class for the input method item. - * @private - */ - getInputMethodItemClass_(id, currentId) { - return this.isCurrentInputMethod_(id, currentId) ? 'selected' : ''; - } - - /** - * @param {string} id The selected input method ID. - * @param {string} currentId The ID of the currently enabled input method. - * @return {string} The default tab index '0' if the selected input method - * is not currently enabled; otherwise, returns an empty string which - * effectively unsets the tabindex attribute. - * @private - */ - getInputMethodTabIndex_(id, currentId) { - return id === currentId ? '' : '0'; - } - - /** - * @param {string} inputMethodName - * @return {string} - * @private - */ - getOpenOptionsPageLabel_(inputMethodName) { - return this.i18n('openOptionsPage', inputMethodName); - } - - /** @private */ - onAddInputMethodClick_() { - this.languagesMetricsProxy_.recordAddInputMethod(); - this.showAddInputMethodsDialog_ = true; - } - - /** @private */ - onAddInputMethodsDialogClose_() { - this.showAddInputMethodsDialog_ = false; - focusWithoutInk(assert(this.$.addInputMethod)); - } - - /** @private */ - onAddSpellcheckLanguagesClick_() { - this.showAddSpellcheckLanguagesDialog_ = true; - } - - /** @private */ - onAddSpellcheckLanguagesDialogClose_() { - this.showAddSpellcheckLanguagesDialog_ = false; - - if (this.languages.spellCheckOnLanguages.length > 0) { - // User has at least one spell check language after closing the dialog. - // If spell checking is disabled, enabled it. - this.setPrefValue('browser.enable_spellchecking', true); - } - - // Because #addSpellcheckLanguages is not statically created (as it is - // within a <template is="dom-if">), we need to use - // this.shadowRoot.querySelector("#addSpellcheckLanguages") instead of - // this.$.addSpellCheckLanguages. - focusWithoutInk( - assert(this.shadowRoot.querySelector('#addSpellcheckLanguages'))); - } - - /** - * @param {!chrome.languageSettingsPrivate.InputMethod} targetInputMethod - * @private - */ - disableRemoveInputMethod_(targetInputMethod) { - // Third-party IMEs can always be removed. - if (!this.languageHelper.isComponentIme(targetInputMethod)) { - return false; - } - - // Disable remove if there is no other component IME (pre-installed - // system IMES) enabled. - return !this.languages.inputMethods.enabled.some( - inputMethod => inputMethod.id !== targetInputMethod.id && - this.languageHelper.isComponentIme(inputMethod)); - } - - /** - * @param {!chrome.languageSettingsPrivate.InputMethod} inputMethod - * @private - */ - getRemoveInputMethodTooltip_(inputMethod) { - return this.i18n('removeInputMethodTooltip', inputMethod.displayName); - } - - /** - * @param {{model: {item: chrome.languageSettingsPrivate.InputMethod}}} e - * @private - */ - onRemoveInputMethodClick_(e) { - this.languageHelper.removeInputMethod(e.model.item.id); - recordSettingChange(); - } - - /** - * @param {!SpellCheckLanguageState} lang - * @private - */ - getRemoveSpellcheckLanguageTooltip_(lang) { - return this.i18n( - 'removeSpellCheckLanguageTooltip', lang.language.displayName); - } - - /** - * @param {{model: {item: SpellCheckLanguageState}}} e - * @private - */ - onRemoveSpellcheckLanguageClick_(e) { - this.languageHelper.toggleSpellCheck(e.model.item.language.code, false); - recordSettingChange(); - } - - /** - * Called whenever the spell check toggle is changed by the user. - * @param {!Event} e - * @private - */ - onSpellcheckToggleChange_(e) { - const toggle = /** @type {SettingsToggleButtonElement} */ (e.target); - - this.languagesMetricsProxy_.recordToggleSpellCheck(toggle.checked); - - if (this.languageSettingsV2Update2Enabled_ && toggle.checked && - this.languages.spellCheckOnLanguages.length === 0) { - // In LSV2 Update 2, we never want to enable spell check without the user - // having a spell check language. When this happens, we try estimating - // their expected spell check language (their device language, assuming - // that the user has an input method which supports that language). - // If that doesn't work, we fall back on prompting the user to enable a - // spell check language and immediately disable spell check before this - // happens. If the user then adds a spell check language, we finally - // enable spell check (see |onAddSpellcheckLanguagesDialogClose_|). - - // This assert is safe as prospectiveUILanguage is always defined in - // languages.js' |createModel_()|. - const deviceLanguageCode = assert(this.languages.prospectiveUILanguage); - // However, deviceLanguage itself may be undefined as it is possible that - // it was set outside of CrOS language settings (normally when debugging - // or in tests). - const deviceLanguage = - this.languageHelper.getLanguage(deviceLanguageCode); - if (deviceLanguage && deviceLanguage.supportsSpellcheck && - this.languages.inputMethods.enabled.some( - inputMethod => - inputMethod.languageCodes.includes(deviceLanguageCode))) { - this.languageHelper.toggleSpellCheck(deviceLanguageCode, true); - } else { - this.onAddSpellcheckLanguagesClick_(); - - // "Undo" the toggle change by reverting it back to the original pref - // value. The toggle will be flipped on once the user finishes adding - // a spell check language. - toggle.resetToPrefValue(); - // We don't need to commit the pref change below, so early return. - return; - } - } - - // Manually commit the pref change as we've set noSetPref on the toggle - // button. - toggle.sendPrefChange(); - } - - /** - * Returns the value to use as the |pref| attribute for the policy indicator - * of spellcheck languages, based on whether or not the language is enabled. - * @param {boolean} isEnabled Whether the language is enabled or not. - * @private - */ - getIndicatorPrefForManagedSpellcheckLanguage_(isEnabled) { - return isEnabled ? this.getPref('spellcheck.forced_dictionaries') : - this.getPref('spellcheck.blocked_dictionaries'); - } - - /** - * Returns an array of spell check languages for the UI. - * @return {!Array<!LanguageState|!SpellCheckLanguageState>|undefined} - * @private - */ - getSpellCheckLanguages_() { - if (this.languages === undefined) { - return undefined; - } - if (this.languageSettingsV2Update2Enabled_) { - const languages = [...this.languages.spellCheckOnLanguages]; - languages.sort( - (a, b) => - a.language.displayName.localeCompare(b.language.displayName)); - return languages; - } - /** @type {!Array<!LanguageState|!SpellCheckLanguageState>} */ - const enabledLanguages = this.languages.enabled; - const combinedLanguages = - enabledLanguages.concat(this.languages.spellCheckOnLanguages); - const supportedSpellcheckLanguagesSet = new Set(); - const supportedSpellcheckLanguages = []; - - combinedLanguages.forEach(languageState => { - if (!supportedSpellcheckLanguagesSet.has(languageState.language.code) && - languageState.language.supportsSpellcheck) { - supportedSpellcheckLanguages.push(languageState); - supportedSpellcheckLanguagesSet.add(languageState.language.code); - } - }); - - return supportedSpellcheckLanguages; - } - - /** - * Handler for enabling or disabling spell check for a specific language. - * @param {{target: Element, model: {item: !LanguageState}}} e - * @private - */ - onSpellCheckLanguageChange_(e) { - const item = e.model.item; - if (!item.language.supportsSpellcheck) { - return; - } - - this.languageHelper.toggleSpellCheck( - item.language.code, !item.spellCheckEnabled); - } - - /** - * Handler for clicking on the name of the language. The action taken must - * match the control that is available. - * @param {{target: Element, model: {item: !LanguageState}}} e - * @private - */ - onSpellCheckNameClick_(e) { - assert(!this.isSpellCheckNameClickDisabled_(e.model.item)); - this.onSpellCheckLanguageChange_(e); - } - - /** - * Name only supports clicking when language is not managed, supports - * spellcheck, and the dictionary has been downloaded with no errors. - * @param {!LanguageState|!SpellCheckLanguageState} item - * @return {boolean} - * @private - */ - isSpellCheckNameClickDisabled_(item) { - return item.isManaged || item.downloadDictionaryFailureCount > 0 || - !this.getPref('browser.enable_spellchecking').value; - } - - /** - * Handler to initiate another attempt at downloading the spell check - * dictionary for a specified language. - * @param {{target: Element, model: {item: !LanguageState}}} e - * @private - */ - onRetryDictionaryDownloadClick_(e) { - assert(e.model.item.downloadDictionaryFailureCount > 0); - this.languageHelper.retryDownloadDictionary(e.model.item.language.code); - } - - /** - * @param {!LanguageState} item - * @return {!string} - * @private - */ - getDictionaryDownloadRetryAriaLabel_(item) { - return this.i18n( - 'languagesDictionaryDownloadRetryDescription', - item.language.displayName); - } - - /** - * Opens the Custom Dictionary page. - * @private - */ - onEditDictionaryClick_() { - this.languagesMetricsProxy_.recordInteraction( - LanguagesPageInteraction.OPEN_CUSTOM_SPELL_CHECK); - Router.getInstance().navigateTo(routes.OS_LANGUAGES_EDIT_DICTIONARY); - } - - - /** - * @private - */ - onJapaneseManageUserDictionaryClick_() { - Router.getInstance().navigateTo( - routes.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY); - } - - /** - * Gets the appropriate CSS class for the Enhanced spell check toggle - * depending on whether Update 2 is enabled or not. - * @private - */ - getEnhancedSpellCheckClass_() { - return this.languageSettingsV2Update2Enabled_ ? '' : 'hr'; - } - - /** - * @private - */ - isEnableSpellcheckingDisabled_() { - return !this.languageSettingsV2Update2Enabled_ && - (!!this.spellCheckLanguages_ && this.spellCheckLanguages_.length === 0); - } - - /** - * @param {boolean} update2Enabled - * @param {boolean} spellCheckOn - * @return {boolean} - */ - isCollapseOpened_(update2Enabled, spellCheckOn) { - return !update2Enabled || spellCheckOn; - } - - /** @private */ - onLanguagePackNoticeLinkClick_() { - this.languagesMetricsProxy_.recordInteraction( - LanguagesPageInteraction.OPEN_LANGUAGE_PACKS_LEARN_MORE); - } - - /** - * @return {boolean} - * @private - */ - shouldShowLastUsedImeShortcutReminder_() { - // User has already dismissed the shortcut reminder. - if (this.getPref('ash.shortcut_reminders.last_used_ime_dismissed').value) { - return false; - } - // Need at least 2 input methods to be shown the reminder. - return !!this.languages && this.languages.inputMethods.enabled.length >= 2; - } - - /** - * @return {boolean} - * @private - */ - shouldShowNextImeShortcutReminder_() { - // User has already dismissed the shortcut reminder. - if (this.getPref('ash.shortcut_reminders.next_ime_dismissed').value) { - return false; - } - // Need at least 3 input methods to be shown the reminder. - return !!this.languages && this.languages.inputMethods.enabled.length >= 3; - } - - /** - * @return {!Array<string>} - * @private - */ - getShortcutReminderBody_() { - const /** !Array<string> */ reminderBody = []; - if (this.showLastUsedImeShortcutReminder_) { - reminderBody.push(this.i18nAdvanced('imeShortcutReminderLastUsed')); - } - if (this.showNextImeShortcutReminder_) { - reminderBody.push(this.i18nAdvanced('imeShortcutReminderNext')); - } - return reminderBody; - } - - /** - * @return {boolean} - * @private - */ - shouldShowShortcutReminder_() { - return this.languageSettingsV2Update2Enabled_ && - this.shortcutReminderBody_ && this.shortcutReminderBody_.length > 0; - } - - /** @private */ - onShortcutReminderDismiss_() { - // Record the metric - assume that both reminders were dismissed unless one - // of them wasn't shown. - assert( - this.showLastUsedImeShortcutReminder_ || - this.showNextImeShortcutReminder_); - let dismissedState = InputsShortcutReminderState.LAST_USED_IME_AND_NEXT_IME; - if (!this.showLastUsedImeShortcutReminder_) { - dismissedState = InputsShortcutReminderState.NEXT_IME; - } else if (!this.showNextImeShortcutReminder_) { - dismissedState = InputsShortcutReminderState.LAST_USED_IME; - } - this.languagesMetricsProxy_.recordShortcutReminderDismissed(dismissedState); - - if (this.showLastUsedImeShortcutReminder_) { - this.setPrefValue('ash.shortcut_reminders.last_used_ime_dismissed', true); - } - if (this.showNextImeShortcutReminder_) { - this.setPrefValue('ash.shortcut_reminders.next_ime_dismissed', true); - } - } -} - -customElements.define( - OsSettingsInputPageElement.is, OsSettingsInputPageElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.ts new file mode 100644 index 0000000..90429dd --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.ts
@@ -0,0 +1,704 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'os-settings-input-page' is the input sub-page + * for language and input method settings. + */ + +import 'chrome://resources/cr_components/localized_link/localized_link.js'; +import 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; +import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; +import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; +import './add_input_methods_dialog.js'; +import './add_spellcheck_languages_dialog.js'; +import './os_edit_dictionary_page.js'; +import '../keyboard_shortcut_banner/keyboard_shortcut_banner.js'; +import '../../controls/settings_toggle_button.js'; +import '../../settings_shared.css.js'; +import '../os_settings_page/os_settings_animated_pages.js'; + +import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import {CrLinkRowElement} from 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {assert} from 'chrome://resources/js/assert_ts.js'; +import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {SettingsToggleButtonElement} from '../../controls/settings_toggle_button.js'; +import {FocusConfig} from '../../focus_config.js'; +import {Setting} from '../../mojom-webui/setting.mojom-webui.js'; +import {PrefsMixin} from '../../prefs/prefs_mixin.js'; +import {castExists} from '../assert_extras.js'; +import {DeepLinkingMixin} from '../deep_linking_mixin.js'; +import {recordSettingChange} from '../metrics_recorder.js'; +import {routes} from '../os_route.js'; +import {RouteObserverMixin} from '../route_observer_mixin.js'; +import {Route, Router} from '../router.js'; + +import {hasOptionsPageInSettings} from './input_method_util.js'; +import {getTemplate} from './input_page.html.js'; +import {InputsShortcutReminderState, LanguagesMetricsProxyImpl, LanguagesPageInteraction} from './languages_metrics_proxy.js'; +import {LanguageHelper, LanguagesModel, LanguageState, SpellCheckLanguageState} from './languages_types.js'; + +const OsSettingsInputPageElementBase = + RouteObserverMixin(PrefsMixin(I18nMixin(DeepLinkingMixin(PolymerElement)))); + +interface OsSettingsInputPageElement { + $: { + addInputMethod: CrButtonElement, + editDictionarySubpageTrigger: CrLinkRowElement, + }; +} + +class OsSettingsInputPageElement extends OsSettingsInputPageElementBase { + static get is() { + return 'os-settings-input-page' as const; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in PrefsMixin. + /* Preferences state. */ + prefs: { + type: Object, + notify: true, + }, + + focusConfig: { + type: Object, + observer: 'focusConfigChanged_', + }, + + /** + * Read-only reference to the languages model provided by the + * 'os-settings-languages' instance. + */ + languages: { + type: Object, + }, + + languageHelper: Object, + + spellCheckLanguages_: { + type: Array, + computed: `getSpellCheckLanguages_(languageSettingsV2Update2Enabled_, + languages.spellCheckOnLanguages.*, languages.enabled.*)`, + }, + + showAddInputMethodsDialog_: { + type: Boolean, + value: false, + }, + + showAddSpellcheckLanguagesDialog_: { + type: Boolean, + value: false, + }, + + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in DeepLinkingMixin, and move the default value to + // the field initializer. + /** + * Used by DeepLinkingMixin to focus this page's deep links. + */ + supportedSettingIds: { + type: Object, + value: () => new Set([ + Setting.kShowInputOptionsInShelf, + Setting.kAddInputMethod, + Setting.kSpellCheck, + ]), + }, + + languageSettingsV2Update2Enabled_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('enableLanguageSettingsV2Update2'); + }, + }, + + languageSettingsJapaneseEnabled_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('systemJapanesePhysicalTyping'); + }, + }, + + shouldShowLanguagePacksNotice_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('languagePacksHandwritingEnabled'); + }, + }, + + /** + * Whether the shortcut reminder for the last used IME is currently + * showing. + */ + showLastUsedImeShortcutReminder_: { + type: Boolean, + computed: `shouldShowLastUsedImeShortcutReminder_( + languages.inputMethods.enabled.length, + prefs.ash.shortcut_reminders.last_used_ime_dismissed.value)`, + }, + + /** + * Whether the shortcut reminder for the next IME is currently showing. + */ + showNextImeShortcutReminder_: { + type: Boolean, + computed: `shouldShowNextImeShortcutReminder_( + languages.inputMethods.enabled.length, + prefs.ash.shortcut_reminders.next_ime_dismissed.value)`, + }, + + /** + * The body of the currently showing shortcut reminders. + */ + shortcutReminderBody_: { + type: Array, + computed: `getShortcutReminderBody_(showLastUsedImeShortcutReminder_, + showNextImeShortcutReminder_)`, + }, + + onDeviceGrammarCheckEnabled_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('onDeviceGrammarCheckEnabled'); + }, + }, + }; + } + + // Public API: Bidirectional data flow. + // override prefs: any; // From PrefsMixin. + + // Public API: Downwards data flow. + languages: LanguagesModel|undefined; + languageHelper: LanguageHelper; + // Note that even though this passed in using downwards data flow, we mutate + // this variable in focusConfigChanged_. This is OK, as the place where we use + // focusConfig (<os-settings-animated-pages>) lazily reads focusConfig and + // does not need to be notified of mutations. + focusConfig: FocusConfig; + + // API proxies. + private languagesMetricsProxy_ = LanguagesMetricsProxyImpl.getInstance(); + + // Internal properties for mixins. + // From DeepLinkingMixin. + // override supportedSettingIds = new Set([ + // Setting.kShowInputOptionsInShelf, + // Setting.kAddInputMethod, + // Setting.kSpellCheck, + // ]); + + // Internal state. + private showAddSpellcheckLanguagesDialog_: boolean; + private showAddInputMethodsDialog_: boolean; + + // loadTimeData flags. + private onDeviceGrammarCheckEnabled_: boolean; + private languageSettingsV2Update2Enabled_: boolean; + private languageSettingsJapaneseEnabled_: boolean; + private shouldShowLanguagePacksNotice_: boolean; + + // Computed properties. + private spellCheckLanguages_?: Array<LanguageState|SpellCheckLanguageState>; + private showLastUsedImeShortcutReminder_: boolean; + private showNextImeShortcutReminder_: boolean; + // This is passed into a <keyboard-shortcut-banner> as a `body`, but that + // takes in a `string[]`, not `TrustedHTML[]`. + // TODO(b/238031866): Update <keyboard-shortcut-banner> to take in + // `TrustedHTML[]`, or update this and `getShortcutReminderBody` to be a a + // `string[]`. + private shortcutReminderBody_: TrustedHTML[]; + + override currentRouteChanged(route: Route): void { + // Does not apply to this page. + if (route !== routes.OS_LANGUAGES_INPUT) { + return; + } + + this.attemptDeepLink(); + } + + private focusConfigChanged_( + _newConfig: FocusConfig, oldConfig: FocusConfig|null): void { + // Safety: focusConfig is set only once on the parent, so this observer + // should only fire once. + assert(!oldConfig); + this.focusConfig.set( + routes.OS_LANGUAGES_EDIT_DICTIONARY.path, + () => focusWithoutInk(this.$.editDictionarySubpageTrigger)); + } + + private onShowImeMenuChange_(e: Event): void { + this.languagesMetricsProxy_.recordToggleShowInputOptionsOnShelf( + // Safety: This method is only called from a + // <settings-toggle-button> event handler. + (e.target as SettingsToggleButtonElement).checked); + } + + private inputMethodsLimitedByPolicy_(): boolean { + const allowedInputMethodsPref = + this.getPref('settings.language.allowed_input_methods'); + return !!allowedInputMethodsPref && allowedInputMethodsPref.value.length; + } + + /** + * Handler for click events on an input method on the main page, + * which sets it as the current input method. + */ + private onInputMethodClick_( + e: DomRepeatEvent<chrome.languageSettingsPrivate.InputMethod>): void { + // Clicks on the button are handled in onInputMethodOptionsClick_. + // Safety: This event comes from the DOM, so the target should always be an + // element. + if ((e.target as Element).tagName === 'CR-ICON-BUTTON') { + return; + } + + this.languageHelper.setCurrentInputMethod(e.model.item.id); + this.languagesMetricsProxy_.recordInteraction( + LanguagesPageInteraction.SWITCH_INPUT_METHOD); + recordSettingChange(); + } + + /** + * Handler for <Enter> events on an input method on the main page, + * which sets it as the current input method. + */ + private onInputMethodKeyPress_( + e: DomRepeatEvent< + chrome.languageSettingsPrivate.InputMethod, KeyboardEvent>): void { + // Ignores key presses other than <Enter>. + if (e.key !== 'Enter') { + return; + } + + this.languageHelper.setCurrentInputMethod(e.model.item.id); + } + + /** + * Opens the input method extension's options page in a new tab (or focuses + * an existing instance of the IME's options). + */ + private openExtensionOptionsPage_( + e: DomRepeatEvent<chrome.languageSettingsPrivate.InputMethod>): void { + this.languageHelper.openInputMethodOptions(e.model.item.id); + } + + /** + * @param id The input method ID. + * @return True if there is a options page in ChromeOS settings for the input + * method ID. + */ + private hasOptionsPageInSettings_(id: string): boolean { + return hasOptionsPageInSettings( + id, loadTimeData.getBoolean('allowPredictiveWriting'), + loadTimeData.getBoolean('allowDiacriticsOnPhysicalKeyboardLongpress'), + loadTimeData.getBoolean('systemJapanesePhysicalTyping')); + } + + private navigateToOptionsPageInSettings_( + e: DomRepeatEvent<chrome.languageSettingsPrivate.InputMethod>): void { + const params = new URLSearchParams(); + params.append('id', e.model.item.id); + Router.getInstance().navigateTo( + routes.OS_LANGUAGES_INPUT_METHOD_OPTIONS, params); + } + + /** + * @param id The input method ID. + * @param currentId The ID of the currently enabled input method. + * @return True if the IDs match. + */ + private isCurrentInputMethod_(id: string, currentId: string): boolean { + return id === currentId; + } + + /** + * @param id The input method ID. + * @param currentId The ID of the currently enabled input method. + * @return The class for the input method item. + */ + private getInputMethodItemClass_(id: string, currentId: string): string { + return this.isCurrentInputMethod_(id, currentId) ? 'selected' : ''; + } + + /** + * @param id The selected input method ID. + * @param currentId The ID of the currently enabled input method. + * @return The default tab index '0' if the selected input method is not + * currently enabled; otherwise, returns an empty string which effectively + * unsets the tabindex attribute. + */ + private getInputMethodTabIndex_(id: string, currentId: string): string { + return id === currentId ? '' : '0'; + } + + private getOpenOptionsPageLabel_(inputMethodName: string): string { + return this.i18n('openOptionsPage', inputMethodName); + } + + private onAddInputMethodClick_(): void { + this.languagesMetricsProxy_.recordAddInputMethod(); + this.showAddInputMethodsDialog_ = true; + } + + private onAddInputMethodsDialogClose_(): void { + this.showAddInputMethodsDialog_ = false; + focusWithoutInk(this.$.addInputMethod); + } + + private onAddSpellcheckLanguagesClick_(): void { + this.showAddSpellcheckLanguagesDialog_ = true; + } + + private onAddSpellcheckLanguagesDialogClose_(): void { + this.showAddSpellcheckLanguagesDialog_ = false; + + // This assertion of `this.languages` is potentially unsafe and could fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. + if (this.languages!.spellCheckOnLanguages.length > 0) { + // User has at least one spell check language after closing the dialog. + // If spell checking is disabled, enabled it. + this.setPrefValue('browser.enable_spellchecking', true); + } + + // Because #addSpellcheckLanguages is not statically created (as it is + // within a <template is="dom-if">), we need to use + // this.shadowRoot.querySelector("#addSpellcheckLanguages") instead of + // this.$.addSpellCheckLanguages. + // TODO(b/263823772): Move addSpellcheckLanguages to `this.$` once we remove + // LSV2 Update 2 code. + focusWithoutInk( + // Safety: This method is only called when the spell check + // language dialog is closed, but that can only be opened if + // #addSpellchecklanguages was clicked. + castExists(this.shadowRoot!.querySelector('#addSpellcheckLanguages'))); + } + + private disableRemoveInputMethod_( + targetInputMethod: chrome.languageSettingsPrivate.InputMethod): boolean { + // Third-party IMEs can always be removed. + if (!this.languageHelper.isComponentIme(targetInputMethod)) { + return false; + } + + // Disable remove if there is no other component IME (pre-installed + // system IMES) enabled. + // Safety: This method is only called from a button inside a `dom-repeat` + // over `languages.inputMethods.enabled`, so if this method is called, + // `this.languages` must be defined. + return !this.languages! + // Safety: `LanguagesModel.inputMethods` is always defined on + // CrOS. + .inputMethods!.enabled.some( + inputMethod => inputMethod.id !== targetInputMethod.id && + this.languageHelper.isComponentIme(inputMethod)); + } + + private getRemoveInputMethodTooltip_( + inputMethod: chrome.languageSettingsPrivate.InputMethod): string { + return this.i18n('removeInputMethodTooltip', inputMethod.displayName); + } + + private onRemoveInputMethodClick_( + e: DomRepeatEvent<chrome.languageSettingsPrivate.InputMethod>): void { + this.languageHelper.removeInputMethod(e.model.item.id); + recordSettingChange(); + } + + private getRemoveSpellcheckLanguageTooltip_(lang: SpellCheckLanguageState): + string { + return this.i18n( + 'removeSpellCheckLanguageTooltip', lang.language.displayName); + } + + private onRemoveSpellcheckLanguageClick_( + e: DomRepeatEvent<LanguageState|SpellCheckLanguageState>): void { + this.languageHelper.toggleSpellCheck(e.model.item.language.code, false); + recordSettingChange(); + } + + /** + * Called whenever the spell check toggle is changed by the user. + */ + private onSpellcheckToggleChange_(e: Event): void { + // Safety: This is only called from a 'settings-boolean-control-changed' + // event from a <settings-toggle-button>, so the event target must be a + // <settings-toggle-button>. + const toggle = (e.target as SettingsToggleButtonElement); + + this.languagesMetricsProxy_.recordToggleSpellCheck(toggle.checked); + + if (this.languageSettingsV2Update2Enabled_ && toggle.checked && + // This assertion of `this.languages` is potentially unsafe and could + // fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + this.languages!.spellCheckOnLanguages.length === 0) { + // In LSV2 Update 2, we never want to enable spell check without the user + // having a spell check language. When this happens, we try estimating + // their expected spell check language (their device language, assuming + // that the user has an input method which supports that language). + // If that doesn't work, we fall back on prompting the user to enable a + // spell check language and immediately disable spell check before this + // happens. If the user then adds a spell check language, we finally + // enable spell check (see |onAddSpellcheckLanguagesDialogClose_|). + + // Safety: `LanguagesModel.prospectiveUILanguage` is always defined on + // CrOS, and we checked that `this.languages` is defined above. + const deviceLanguageCode = + castExists(this.languages!.prospectiveUILanguage); + // However, deviceLanguage itself may be undefined as it is possible that + // it was set outside of CrOS language settings (normally when debugging + // or in tests). + const deviceLanguage = + this.languageHelper.getLanguage(deviceLanguageCode); + if (deviceLanguage && deviceLanguage.supportsSpellcheck && + // Safety: `LanguagesModel.inputMethods` is always defined on CrOS, + // and we checked that `this.languages` is defined above. + this.languages!.inputMethods!.enabled.some( + inputMethod => + inputMethod.languageCodes.includes(deviceLanguageCode))) { + this.languageHelper.toggleSpellCheck(deviceLanguageCode, true); + } else { + this.onAddSpellcheckLanguagesClick_(); + + // "Undo" the toggle change by reverting it back to the original pref + // value. The toggle will be flipped on once the user finishes adding + // a spell check language. + toggle.resetToPrefValue(); + // We don't need to commit the pref change below, so early return. + return; + } + } + + // Manually commit the pref change as we've set noSetPref on the toggle + // button. + toggle.sendPrefChange(); + } + + /** + * Returns the value to use as the |pref| attribute for the policy indicator + * of spellcheck languages, based on whether or not the language is enabled. + * @param isEnabled Whether the language is enabled or not. + */ + private getIndicatorPrefForManagedSpellcheckLanguage_(isEnabled: boolean): + chrome.settingsPrivate.PrefObject<string[]> { + return isEnabled ? + this.getPref<string[]>('spellcheck.forced_dictionaries') : + this.getPref<string[]>('spellcheck.blocked_dictionaries'); + } + + /** + * Returns an array of spell check languages for the UI. + */ + private getSpellCheckLanguages_(): + Array<LanguageState|SpellCheckLanguageState>|undefined { + if (this.languages === undefined) { + return undefined; + } + if (this.languageSettingsV2Update2Enabled_) { + const languages = [...this.languages.spellCheckOnLanguages]; + languages.sort( + (a, b) => + a.language.displayName.localeCompare(b.language.displayName)); + return languages; + } + const enabledLanguages: Array<LanguageState|SpellCheckLanguageState> = + this.languages.enabled; + const combinedLanguages = + enabledLanguages.concat(this.languages.spellCheckOnLanguages); + const supportedSpellcheckLanguagesSet = new Set<string>(); + const supportedSpellcheckLanguages: + Array<LanguageState|SpellCheckLanguageState> = []; + + combinedLanguages.forEach(languageState => { + if (!supportedSpellcheckLanguagesSet.has(languageState.language.code) && + languageState.language.supportsSpellcheck) { + supportedSpellcheckLanguages.push(languageState); + supportedSpellcheckLanguagesSet.add(languageState.language.code); + } + }); + + return supportedSpellcheckLanguages; + } + + /** + * Handler for enabling or disabling spell check for a specific language. + */ + private onSpellCheckLanguageChange_( + e: DomRepeatEvent<LanguageState|SpellCheckLanguageState>): void { + const item = e.model.item; + if (!item.language.supportsSpellcheck) { + return; + } + + this.languageHelper.toggleSpellCheck( + item.language.code, !item.spellCheckEnabled); + } + + /** + * Handler for clicking on the name of the language. The action taken must + * match the control that is available. + */ + private onSpellCheckNameClick_( + e: DomRepeatEvent<LanguageState|SpellCheckLanguageState>): void { + // Safety: The button associated with this event listener is disabled in + // the template if the below is true. + assert(!this.isSpellCheckNameClickDisabled_(e.model.item)); + this.onSpellCheckLanguageChange_(e); + } + + /** + * Name only supports clicking when language is not managed, supports + * spellcheck, and the dictionary has been downloaded with no errors. + */ + private isSpellCheckNameClickDisabled_(item: LanguageState| + SpellCheckLanguageState): boolean { + return item.isManaged || item.downloadDictionaryFailureCount > 0 || + !this.getPref('browser.enable_spellchecking').value; + } + + /** + * Handler to initiate another attempt at downloading the spell check + * dictionary for a specified language. + */ + private onRetryDictionaryDownloadClick_( + e: DomRepeatEvent<LanguageState|SpellCheckLanguageState>): void { + // Safety: The button associated with this event listener is disabled in + // the template if `!item.downloadDictionaryFailureCount`, and dictionary + // download failure count cannot ever be negative. + assert(e.model.item.downloadDictionaryFailureCount > 0); + this.languageHelper.retryDownloadDictionary(e.model.item.language.code); + } + + private getDictionaryDownloadRetryAriaLabel_(item: LanguageState): string { + return this.i18n( + 'languagesDictionaryDownloadRetryDescription', + item.language.displayName); + } + + private onEditDictionaryClick_(): void { + this.languagesMetricsProxy_.recordInteraction( + LanguagesPageInteraction.OPEN_CUSTOM_SPELL_CHECK); + Router.getInstance().navigateTo(routes.OS_LANGUAGES_EDIT_DICTIONARY); + } + + private onJapaneseManageUserDictionaryClick_(): void { + Router.getInstance().navigateTo( + routes.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY); + } + + /** + * Gets the appropriate CSS class for the Enhanced spell check toggle + * depending on whether Update 2 is enabled or not. + */ + private getEnhancedSpellCheckClass_(): ''|'hr' { + return this.languageSettingsV2Update2Enabled_ ? '' : 'hr'; + } + + private isEnableSpellcheckingDisabled_(): boolean { + return !this.languageSettingsV2Update2Enabled_ && + (!!this.spellCheckLanguages_ && this.spellCheckLanguages_.length === 0); + } + + private isCollapseOpened_(update2Enabled: boolean, spellCheckOn: boolean): + boolean { + return !update2Enabled || spellCheckOn; + } + + private onLanguagePackNoticeLinkClick_(): void { + this.languagesMetricsProxy_.recordInteraction( + LanguagesPageInteraction.OPEN_LANGUAGE_PACKS_LEARN_MORE); + } + + private shouldShowLastUsedImeShortcutReminder_(): boolean { + // User has already dismissed the shortcut reminder. + if (this.getPref('ash.shortcut_reminders.last_used_ime_dismissed').value) { + return false; + } + // Need at least 2 input methods to be shown the reminder. + // Safety: `LanguagesModel.inputMethods` is always defined on CrOS. + return !!this.languages && this.languages.inputMethods!.enabled.length >= 2; + } + + private shouldShowNextImeShortcutReminder_(): boolean { + // User has already dismissed the shortcut reminder. + if (this.getPref('ash.shortcut_reminders.next_ime_dismissed').value) { + return false; + } + // Need at least 3 input methods to be shown the reminder. + // Safety: `LanguagesModel.inputMethods` is always defined on CrOS. + return !!this.languages && this.languages.inputMethods!.enabled.length >= 3; + } + + private getShortcutReminderBody_(): TrustedHTML[] { + const reminderBody: TrustedHTML[] = []; + if (this.showLastUsedImeShortcutReminder_) { + reminderBody.push(this.i18nAdvanced('imeShortcutReminderLastUsed')); + } + if (this.showNextImeShortcutReminder_) { + reminderBody.push(this.i18nAdvanced('imeShortcutReminderNext')); + } + return reminderBody; + } + + private shouldShowShortcutReminder_(): boolean { + return this.languageSettingsV2Update2Enabled_ && + // `this.shortcutReminderBody_` should always be truthy here. + // TODO(b/238031866): Remove `this.shortcutReminderBody_` here, or + // investigate why removing it does not work. + this.shortcutReminderBody_ && this.shortcutReminderBody_.length > 0; + } + + private onShortcutReminderDismiss_(): void { + // Record the metric - assume that both reminders were dismissed unless one + // of them wasn't shown. + // Safety: The shortcut reminder is only shown if + // `shouldShowShortcutReminder_` is true, so `this.shortcutReminderBody` + // contains at least one thing, so at least one of + // `this.showLastUsedImeShortcutReminder_` or + // `this.showNextImeShortcutReminder_` should be true. + assert( + this.showLastUsedImeShortcutReminder_ || + this.showNextImeShortcutReminder_); + let dismissedState = InputsShortcutReminderState.LAST_USED_IME_AND_NEXT_IME; + if (!this.showLastUsedImeShortcutReminder_) { + dismissedState = InputsShortcutReminderState.NEXT_IME; + } else if (!this.showNextImeShortcutReminder_) { + dismissedState = InputsShortcutReminderState.LAST_USED_IME; + } + this.languagesMetricsProxy_.recordShortcutReminderDismissed(dismissedState); + + if (this.showLastUsedImeShortcutReminder_) { + this.setPrefValue('ash.shortcut_reminders.last_used_ime_dismissed', true); + } + if (this.showNextImeShortcutReminder_) { + this.setPrefValue('ash.shortcut_reminders.next_ime_dismissed', true); + } + } +} + +customElements.define( + OsSettingsInputPageElement.is, OsSettingsInputPageElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsInputPageElement.is]: OsSettingsInputPageElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/languages.js b/chrome/browser/resources/settings/chromeos/os_languages_page/languages.ts similarity index 64% rename from chrome/browser/resources/settings/chromeos/os_languages_page/languages.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/languages.ts index eaf12942..62e327d31 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/languages.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/languages.ts
@@ -10,19 +10,22 @@ * this class via languageHelper. */ +// TODO(b/263828712): Upstream and downstream changes from browser settings, and +// consider merging the two. + import '../../prefs/prefs.js'; -import {assert} from 'chrome://resources/ash/common/assert.js'; -import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; -import {PromiseResolver} from 'chrome://resources/ash/common/promise_resolver.js'; -import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {assert} from 'chrome://resources/js/assert_ts.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {PrefsMixin} from '../../prefs/prefs_mixin.js'; import {CrSettingsPrefs} from '../../prefs/prefs_types.js'; -import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js'; +import {castExists} from '../assert_extras.js'; import {LanguagesBrowserProxy, LanguagesBrowserProxyImpl} from './languages_browser_proxy.js'; -import {InputMethodsModel, LanguageHelper, LanguagesModel, LanguageState, SpellCheckLanguageState} from './languages_types.js'; - +import {LanguageHelper, LanguagesModel, LanguageState, SpellCheckLanguageState} from './languages_types.js'; const MoveType = chrome.languageSettingsPrivate.MoveType; @@ -34,7 +37,7 @@ 'zh-HK': 'zh-TW', 'zh-MO': 'zh-TW', 'zh-SG': 'zh-CN', -}; +} as const; // Some ISO 639 language codes have been renamed, e.g. "he" to "iw", but // Translate still uses the old versions. TODO(michaelpg): Chrome does too. @@ -42,78 +45,70 @@ const kTranslateLanguageSynonyms = { 'he': 'iw', 'jv': 'jw', -}; +} as const; // The fake language name used for ARC IMEs. The value must be in sync with the // one in ui/base/ime/ash/extension_ime_util.h. const kArcImeLanguage = '_arc_ime_language_'; // The IME ID for the Accessibility Common extension used by Dictation. -/** @type {string} */ const ACCESSIBILITY_COMMON_IME_ID = '_ext_ime_egfdjlfmgnehecnclamagfafdccgfndpdictation'; -/** - * @typedef {{ - * supportedLanguages: !Array<!chrome.languageSettingsPrivate.Language>, - * translateTarget: string, - * alwaysTranslateCodes: !Array<string>, - * neverTranslateCodes: !Array<string>, - * startingUILanguage: string, - * supportedInputMethods: - * (!Array<!chrome.languageSettingsPrivate.InputMethod>|undefined), - * currentInputMethodId: (string|undefined) - * }} - */ -let ModelArgs; +interface ModelArgs { + // Unused. + supportedLanguages: chrome.languageSettingsPrivate.Language[]; + translateTarget: string; + alwaysTranslateCodes: string[]; + neverTranslateCodes: string[]; + startingUILanguage: string; + // TODO(b/263824661): Remove undefined from these definitions if we do not + // share this file with Chrome browser. + /** Always defined on CrOS. */ + supportedInputMethods: (chrome.languageSettingsPrivate.InputMethod[]| + undefined); + /** Always defined on CrOS. */ + currentInputMethodId: (string|undefined); +} /** * Singleton element that generates the languages model on start-up and * updates it whenever Chrome's pref store and other settings change. */ +const SettingsLanguagesElementBase = PrefsMixin(PolymerElement); -/** - * @constructor - * @extends {PolymerElement} - * @implements {LanguageHelper} - * @implements {PrefsBehaviorInterface} - */ -const SettingsLanguagesElementBase = - mixinBehaviors([PrefsBehavior], PolymerElement); - -/** @polymer */ -class SettingsLanguagesElement extends SettingsLanguagesElementBase { +class SettingsLanguagesElement extends SettingsLanguagesElementBase implements + LanguageHelper { static get is() { - return 'settings-languages'; + return 'settings-languages' as const; } static get properties() { return { - /** - * @type {!LanguagesModel|undefined} - */ languages: { type: Object, notify: true, + // TODO(b/238031866): Remove readOnly here and set `this.languages` with + // an assignment instead of a `this._setProperty`. See + // https://crrev.com/c/3176181/comment/63b644b9_ee7ad7df/ for more + // details. readOnly: true, }, /** * This element, as a LanguageHelper instance for API usage. - * @type {!LanguageHelper} */ languageHelper: { type: Object, notify: true, readOnly: true, - value() { - return /** @type {!LanguageHelper} */ (this); + value(this: SettingsLanguagesElement): LanguageHelper { + return this; }, }, /** * PromiseResolver to be resolved when the singleton has been initialized. - * @private {!PromiseResolver} */ resolver_: { type: Object, @@ -124,7 +119,6 @@ /** * Hash map of supported languages by language codes for fast lookup. - * @private {!Map<string, !chrome.languageSettingsPrivate.Language>} */ supportedLanguageMap_: { type: Object, @@ -135,7 +129,6 @@ /** * Hash set of enabled language codes for membership testing. - * @private {!Set<string>} */ enabledLanguageSet_: { type: Object, @@ -146,7 +139,6 @@ /** * Hash map of supported input methods by ID for fast lookup. - * @private {!Map<string, chrome.languageSettingsPrivate.InputMethod>} */ supportedInputMethodMap_: { type: Object, @@ -157,9 +149,6 @@ /** * Hash map of input methods supported for each language. - * @type {!Map<string, - * !Array<!chrome.languageSettingsPrivate.InputMethod>>} - * @private */ languageInputMethods_: { type: Object, @@ -170,7 +159,6 @@ /** * Hash set of enabled input methods id for mebership testings - * @private {!Set<string>} */ enabledInputMethodSet_: { type: Object, @@ -179,7 +167,7 @@ }, }, - /** @private Prospective UI language when the page was loaded. */ + /** Prospective UI language when the page was loaded. */ originalProspectiveUILanguage_: String, }; } @@ -217,34 +205,53 @@ ]; } - constructor() { - super(); + // Public API: Bidirectional data flow. + // override prefs: any; // From PrefsMixin. - /** @private {?Function} */ - this.boundOnSpellcheckDictionariesChanged_ = null; + // Public API: Upwards data flow. + languages?: LanguagesModel; + languageHelper: LanguageHelper; - /** @private {!LanguagesBrowserProxy} */ - this.browserProxy_ = LanguagesBrowserProxyImpl.getInstance(); + // API proxies. + private browserProxy_: LanguagesBrowserProxy = + LanguagesBrowserProxyImpl.getInstance(); + private languageSettingsPrivate_: typeof chrome.languageSettingsPrivate = + this.browserProxy_.getLanguageSettingsPrivate(); + private inputMethodPrivate_: typeof chrome.inputMethodPrivate = + this.browserProxy_.getInputMethodPrivate(); - /** @private {!LanguageSettingsPrivate} */ - this.languageSettingsPrivate_ = - this.browserProxy_.getLanguageSettingsPrivate(); + // Internal state. + private resolver_: PromiseResolver<undefined>; + private supportedLanguageMap_: + Map<string, chrome.languageSettingsPrivate.Language>; + private enabledLanguageSet_: Set<string>; + private supportedInputMethodMap_: + Map<string, chrome.languageSettingsPrivate.InputMethod>; + private languageInputMethods_: + Map<string, chrome.languageSettingsPrivate.InputMethod[]>; + private enabledInputMethodSet_: Set<string>; + private originalProspectiveUILanguage_?: string; - /** @private {!InputMethodPrivate} */ - this.inputMethodPrivate_ = this.browserProxy_.getInputMethodPrivate(); + // Bound methods. + // Instances of SettingsLanguagesElement below should be replaced with + // (typeof this) due to possible subclasses of SettingsLanguagesElement + // replacing these methods with a Liskov substitution principle-compatible + // method. However, that type is too complicated for TypeScript to check (it + // results in incorrect type errors), and we don't expect there to be any + // subclasses. + private boundOnSpellcheckDictionariesChanged_: OmitThisParameter< + SettingsLanguagesElement['onSpellcheckDictionariesChanged_']>|null = null; + private boundOnInputMethodAdded_: + OmitThisParameter<SettingsLanguagesElement['onInputMethodAdded_']>|null = + null; + private boundOnInputMethodRemoved_: + OmitThisParameter<SettingsLanguagesElement['onInputMethodRemoved_']>| + null = null; + private boundOnInputMethodChanged_: + OmitThisParameter<SettingsLanguagesElement['onInputMethodChanged_']>| + null = null; - /** @private {?Function} */ - this.boundOnInputMethodAdded_ = null; - - /** @private {?Function} */ - this.boundOnInputMethodRemoved_ = null; - - /** @private {?Function} */ - this.boundOnInputMethodChanged_ = null; - } - - /** @override */ - connectedCallback() { + override connectedCallback(): void { super.connectedCallback(); const promises = []; @@ -252,16 +259,14 @@ /** * An object passed into createModel to keep track of platform-specific * arguments, populated by the "promises" array. - * @type {!ModelArgs} */ - const args = { + const args: ModelArgs = { supportedLanguages: [], translateTarget: '', alwaysTranslateCodes: [], neverTranslateCodes: [], startingUILanguage: '', - // Only used by ChromeOS supportedInputMethods: [], currentInputMethodId: '', }; @@ -321,12 +326,12 @@ this.languageSettingsPrivate_.getSpellcheckDictionaryStatuses().then( this.boundOnSpellcheckDictionariesChanged_); - this.resolver_.resolve(); + this.resolver_.resolve(undefined); }); this.boundOnInputMethodChanged_ = this.onInputMethodChanged_.bind(this); this.inputMethodPrivate_.onChanged.addListener( - assert(this.boundOnInputMethodChanged_)); + this.boundOnInputMethodChanged_); this.boundOnInputMethodAdded_ = this.onInputMethodAdded_.bind(this); this.languageSettingsPrivate_.onInputMethodAdded.addListener( this.boundOnInputMethodAdded_); @@ -335,18 +340,19 @@ this.boundOnInputMethodRemoved_); } - /** @override */ - disconnectedCallback() { + override disconnectedCallback(): void { super.disconnectedCallback(); + // Safety: All bound methods here were set in `connectedCallback`, + // which is guaranteed to be run before `disconnectedCallback`. this.inputMethodPrivate_.onChanged.removeListener( - assert(this.boundOnInputMethodChanged_)); + castExists(this.boundOnInputMethodChanged_)); this.boundOnInputMethodChanged_ = null; this.languageSettingsPrivate_.onInputMethodAdded.removeListener( - assert(this.boundOnInputMethodAdded_)); + castExists(this.boundOnInputMethodAdded_)); this.boundOnInputMethodAdded_ = null; this.languageSettingsPrivate_.onInputMethodRemoved.removeListener( - assert(this.boundOnInputMethodRemoved_)); + castExists(this.boundOnInputMethodRemoved_)); this.boundOnInputMethodRemoved_ = null; if (this.boundOnSpellcheckDictionariesChanged_) { @@ -358,10 +364,8 @@ /** * Updates the prospective UI language based on the new pref value. - * @param {string} prospectiveUILanguage - * @private */ - prospectiveUiLanguageChanged_(prospectiveUILanguage) { + private prospectiveUiLanguageChanged_(prospectiveUILanguage: string): void { this.set( 'languages.prospectiveUILanguage', prospectiveUILanguage || this.originalProspectiveUILanguage_); @@ -369,9 +373,8 @@ /** * Updates the list of enabled languages from the preferred languages pref. - * @private */ - preferredLanguagesPrefChanged_() { + private preferredLanguagesPrefChanged_(): void { if (this.prefs === undefined || this.languages === undefined) { return; } @@ -400,21 +403,18 @@ /** * Updates the spellCheckEnabled state of each enabled language. - * @private */ - spellCheckDictionariesPrefChanged_() { + private spellCheckDictionariesPrefChanged_(): void { if (this.prefs === undefined || this.languages === undefined) { return; } - const spellCheckSet = this.makeSetFromArray_(/** @type {!Array<string>} */ ( - this.getPref('spellcheck.dictionaries').value)); - const spellCheckForcedSet = - this.makeSetFromArray_(/** @type {!Array<string>} */ ( - this.getPref('spellcheck.forced_dictionaries').value)); - const spellCheckBlockedSet = - this.makeSetFromArray_(/** @type {!Array<string>} */ ( - this.getPref('spellcheck.blocked_dictionaries').value)); + const spellCheckSet = this.makeSetFromArray_( + this.getPref<string[]>('spellcheck.dictionaries').value); + const spellCheckForcedSet = this.makeSetFromArray_( + this.getPref<string[]>('spellcheck.forced_dictionaries').value); + const spellCheckBlockedSet = this.makeSetFromArray_( + this.getPref<string[]>('spellcheck.blocked_dictionaries').value); for (let i = 0; i < this.languages.enabled.length; i++) { const languageState = this.languages.enabled[i]; @@ -436,29 +436,25 @@ /** * Returns two arrays of SpellCheckLanguageStates for spell check languages: * one for spell check on, one for spell check off. - * @param {!Array<!chrome.languageSettingsPrivate.Language>} - * supportedLanguages The list of supported languages, normally + * @param supportedLanguages The list of supported languages, normally * this.languages.supported. - * @return {{on: !Array<SpellCheckLanguageState>, off: - * !Array<SpellCheckLanguageState>}} - * @private */ - getSpellCheckLanguages_(supportedLanguages) { + private getSpellCheckLanguages_( + supportedLanguages: chrome.languageSettingsPrivate.Language[]): + {on: SpellCheckLanguageState[], off: SpellCheckLanguageState[]} { // The spell check preferences are prioritised in this order: // forced_dictionaries, blocked_dictionaries, dictionaries. // The set of all language codes seen thus far. - const /** !Set<string> */ seenCodes = new Set(); + const seenCodes = new Set<string>(); /** * Gets the list of language codes indicated by the preference name, and * de-duplicates it with all other language codes. - * @param {string} prefName - * @return {!Array<string>} */ - const getPrefAndDedupe = prefName => { - const /** !Array<string> */ result = - this.getPref(prefName).value.filter(x => !seenCodes.has(x)); + const getPrefAndDedupe = (prefName: string): string[] => { + const result = + this.getPref<string[]>(prefName).value.filter(x => !seenCodes.has(x)); result.forEach(code => seenCodes.add(code)); return result; }; @@ -469,7 +465,7 @@ const blockedCodesSet = new Set(blockedCodes); const enabledCodes = getPrefAndDedupe('spellcheck.dictionaries'); - const /** !Array<SpellCheckLanguageState> */ on = []; + const on: SpellCheckLanguageState[] = []; // We want to add newly enabled languages to the end of the "on" list, so we // should explicitly move the forced languages to the front of the list. for (const code of [...forcedCodes, ...enabledCodes]) { @@ -496,7 +492,7 @@ // We don't want to split this list in "forced" / "not-forced" like the // spell check on list above, as we don't want to explicitly surface / hide // blocked languages to the user. - const /** !Array<SpellCheckLanguageState> */ off = []; + const off: SpellCheckLanguageState[] = []; for (const language of supportedLanguages) { // If spell check is off for this language, it must either not be in any @@ -522,44 +518,47 @@ /** * Updates the list of always translate languages from translate prefs. - * @private */ - alwaysTranslateLanguagesPrefChanged_() { + private alwaysTranslateLanguagesPrefChanged_(): void { if (this.prefs === undefined || this.languages === undefined) { return; } const alwaysTranslateCodes = Object.keys( - /** @type {!Object} */ (this.getPref('translate_allowlists').value)); + this.getPref<Record<string, string>>('translate_allowlists').value); const alwaysTranslateLanguages = - alwaysTranslateCodes.map(code => this.getLanguage(code)); + // This `getLanguage` assertion is potentially unsafe and could fail. + // TODO(b/265554088): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + alwaysTranslateCodes.map(code => this.getLanguage(code)!); this.set('languages.alwaysTranslate', alwaysTranslateLanguages); } /** * Updates the list of never translate languages from translate prefs. - * @private */ - neverTranslateLanguagesPrefChanged_() { + private neverTranslateLanguagesPrefChanged_(): void { if (this.prefs === undefined || this.languages === undefined) { return; } const neverTranslateCodes = - /** @type {!Object} */ ( - this.getPref('translate_blocked_languages').value); + this.getPref<string[]>('translate_blocked_languages').value; const neverTranslateLanguages = - neverTranslateCodes.map(code => this.getLanguage(code)); + // This `getLanguage` assertion is potentially unsafe and could fail. + // TODO(b/265554088): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + neverTranslateCodes.map(code => this.getLanguage(code)!); this.set('languages.neverTranslate', neverTranslateLanguages); } - /** @private */ - translateLanguagesPrefChanged_() { + private translateLanguagesPrefChanged_(): void { if (this.prefs === undefined || this.languages === undefined) { return; } - const translateBlockedPref = this.getPref('translate_blocked_languages'); - const translateBlockedSet = this.makeSetFromArray_( - /** @type {!Array<string>} */ (translateBlockedPref.value)); + const translateBlockedPref = + this.getPref<string[]>('translate_blocked_languages'); + const translateBlockedSet = + this.makeSetFromArray_(translateBlockedPref.value); for (let i = 0; i < this.languages.enabled.length; i++) { const language = this.languages.enabled[i].language; @@ -571,8 +570,7 @@ } } - /** @private */ - translateTargetPrefChanged_() { + private translateTargetPrefChanged_(): void { if (this.prefs === undefined || this.languages === undefined) { return; } @@ -583,11 +581,9 @@ /** * Constructs the languages model. - * @param {!ModelArgs} args used to populate the model - * above. - * @private + * @param args used to populate the model above. */ - createModel_(args) { + private createModel_(args: ModelArgs): void { // Populate the hash map of supported languages. for (let i = 0; i < args.supportedLanguages.length; i++) { const language = args.supportedLanguages[i]; @@ -598,11 +594,19 @@ this.supportedLanguageMap_.set(language.code, language); } - let prospectiveUILanguage; - // eslint-disable-next-line prefer-const - prospectiveUILanguage = - /** @type {string} */ (this.getPref('intl.app_locale').value) || - this.originalProspectiveUILanguage_; + // The below getPref call should always be defined, so the + // `this.originalProspectiveUILanguage_` part of this expression is + // redundant. + // TODO(b/238031866): Investigate why we have two ways of getting the + // prospective UI language, and simplify this expression if necessary. + const prospectiveUILanguage = + this.getPref<string>('intl.app_locale').value || + // Safety: This method is only called after all the promises + // in `connectedCallback()` have resolved, which includes a promise + // which sets `this.originalProspectiveUILanguage_`. + // TODO(b/238031866): Move this variable to `ModelArgs` to avoid this + // assertion. + this.originalProspectiveUILanguage_!; // Create a list of enabled languages from the supported languages. const enabledLanguageStates = this.getEnabledLanguageStates_( @@ -616,12 +620,19 @@ this.getSpellCheckLanguages_(args.supportedLanguages); const alwaysTranslateLanguages = - args.alwaysTranslateCodes.map(code => this.getLanguage(code)); + // This `getLanguage` assertion is potentially unsafe and could fail. + // TODO(b/265554088): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + args.alwaysTranslateCodes.map(code => this.getLanguage(code)!); const neverTranslateLangauges = - args.neverTranslateCodes.map(code => this.getLanguage(code)); + // This `getLanguage` assertion is potentially unsafe and could fail. + // TODO(b/265554088): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + args.neverTranslateCodes.map(code => this.getLanguage(code)!); - const model = /** @type {!LanguagesModel} */ ({ + // TODO(b/238031866): Remove the use of Partial here. + const model: Partial<LanguagesModel> = { supported: args.supportedLanguages, enabled: enabledLanguageStates, translateTarget: args.translateTarget, @@ -629,58 +640,63 @@ neverTranslate: neverTranslateLangauges, spellCheckOnLanguages, spellCheckOffLanguages, - }); + }; model.prospectiveUILanguage = prospectiveUILanguage; if (args.supportedInputMethods) { this.createInputMethodModel_(args.supportedInputMethods); } - model.inputMethods = /** @type {!InputMethodsModel} */ ({ - supported: args.supportedInputMethods, + model.inputMethods = { + // Safety: `ModelArgs.supportedInputMethods` is always defined on CrOS. + supported: args.supportedInputMethods!, enabled: this.getEnabledInputMethods_(), - currentId: args.currentInputMethodId, - }); + // Safety: `ModelArgs.currentInputMethodId` is always defined on CrOS. + currentId: args.currentInputMethodId!, + }; // Initialize the Polymer languages model. - this._setLanguages(model); + // Safety: All properties of `LanguagesModel` were set above. + this._setProperty('languages', model as LanguagesModel); } /** * Returns a list of LanguageStates for each enabled language in the supported * languages list. - * @param {string} translateTarget Language code of the default translate + * This must be called after `whenReady()` is resolved. + * @param translateTarget Language code of the default translate * target language. - * @param {(string|undefined)} prospectiveUILanguage Prospective UI display + * @param prospectiveUILanguage Prospective UI display * language. Only defined on Windows and Chrome OS. - * @return {!Array<!LanguageState>} - * @private */ - getEnabledLanguageStates_(translateTarget, prospectiveUILanguage) { + private getEnabledLanguageStates_( + translateTarget: string, + prospectiveUILanguage: (string|undefined)): LanguageState[] { + // Safety: Enforced in documentation. assert(CrSettingsPrefs.isInitialized); - const pref = this.getPref('intl.accept_languages'); + const pref = this.getPref<string>('intl.accept_languages'); const enabledLanguageCodes = pref.value.split(','); - const languagesForcedPref = this.getPref('intl.forced_languages'); - const spellCheckPref = this.getPref('spellcheck.dictionaries'); - const spellCheckForcedPref = this.getPref('spellcheck.forced_dictionaries'); + const languagesForcedPref = this.getPref<string[]>('intl.forced_languages'); + const spellCheckPref = this.getPref<string[]>('spellcheck.dictionaries'); + const spellCheckForcedPref = + this.getPref<string[]>('spellcheck.forced_dictionaries'); const spellCheckBlockedPref = - this.getPref('spellcheck.blocked_dictionaries'); - const languageForcedSet = this.makeSetFromArray_( - /** @type {!Array<string>} */ (languagesForcedPref.value)); + this.getPref<string[]>('spellcheck.blocked_dictionaries'); + const languageForcedSet = this.makeSetFromArray_(languagesForcedPref.value); const spellCheckSet = this.makeSetFromArray_( - /** @type {!Array<string>} */ ( - spellCheckPref.value.concat(spellCheckForcedPref.value))); - const spellCheckForcedSet = this.makeSetFromArray_( - /** @type {!Array<string>} */ (spellCheckForcedPref.value)); - const spellCheckBlockedSet = this.makeSetFromArray_( - /** @type {!Array<string>} */ (spellCheckBlockedPref.value)); + (spellCheckPref.value.concat(spellCheckForcedPref.value))); + const spellCheckForcedSet = + this.makeSetFromArray_(spellCheckForcedPref.value); + const spellCheckBlockedSet = + this.makeSetFromArray_(spellCheckBlockedPref.value); - const translateBlockedPref = this.getPref('translate_blocked_languages'); - const translateBlockedSet = this.makeSetFromArray_( - /** @type {!Array<string>} */ (translateBlockedPref.value)); + const translateBlockedPref = + this.getPref<string[]>('translate_blocked_languages'); + const translateBlockedSet = + this.makeSetFromArray_(translateBlockedPref.value); - const enabledLanguageStates = []; + const enabledLanguageStates: LanguageState[] = []; for (let i = 0; i < enabledLanguageCodes.length; i++) { const code = enabledLanguageCodes[i]; @@ -689,7 +705,8 @@ if (!language) { continue; } - const languageState = /** @type {LanguageState} */ ({}); + // TODO(b/238031866): Remove the use of Partial here. + const languageState: Partial<LanguageState> = {}; languageState.language = language; languageState.spellCheckEnabled = spellCheckSet.has(code) && !spellCheckBlockedSet.has(code) || @@ -701,28 +718,29 @@ spellCheckForcedSet.has(code) || spellCheckBlockedSet.has(code); languageState.isForced = languageForcedSet.has(code); languageState.downloadDictionaryFailureCount = 0; - enabledLanguageStates.push(languageState); + // This cast is very unsafe as `downloadDictionaryStatus` and `removable` + // have not been set. + // TODO(b/265554105): Investigate and remove this cast if possible. + enabledLanguageStates.push(languageState as LanguageState); } return enabledLanguageStates; } /** * True iff we translate pages that are in the given language. - * @param {string} code Language code. - * @param {boolean} supportsTranslate If translation supports the given + * @param code Language code. + * @param supportsTranslate If translation supports the given language. + * @param translateBlockedSet Set of languages for which translation is + * blocked. + * @param translateTarget Language code of the default translate target * language. - * @param {!Set<string>} translateBlockedSet Set of languages for which - * translation is blocked. - * @param {string} translateTarget Language code of the default translate - * target language. - * @param {(string|undefined)} prospectiveUILanguage Prospective UI display - * language. Only defined on Windows and Chrome OS. - * @return {boolean} - * @private + * @param prospectiveUILanguage Prospective UI display language. Only defined + * on Windows and Chrome OS. */ - isTranslateEnabled_( - code, supportsTranslate, translateBlockedSet, translateTarget, - prospectiveUILanguage) { + private isTranslateEnabled_( + code: string, supportsTranslate: boolean, + translateBlockedSet: Set<string>, translateTarget: string, + prospectiveUILanguage: (string|undefined)): boolean { const translateCode = this.convertLanguageCodeForTranslate(code); return supportsTranslate && !translateBlockedSet.has(translateCode) && translateCode !== translateTarget && @@ -732,20 +750,24 @@ /** * Updates the dictionary download status for spell check languages in order * to track the number of times a spell check dictionary download has failed. - * @param {!Array<!chrome.languageSettingsPrivate.SpellcheckDictionaryStatus>} - * statuses - * @private */ - onSpellcheckDictionariesChanged_(statuses) { - const statusMap = new Map(); + private onSpellcheckDictionariesChanged_( + statuses: chrome.languageSettingsPrivate.SpellcheckDictionaryStatus[]): + void { + const statusMap = new Map< + string, chrome.languageSettingsPrivate.SpellcheckDictionaryStatus>(); statuses.forEach(status => { statusMap.set(status.languageCode, status); }); const collectionNames = - ['enabled', 'spellCheckOnLanguages', 'spellCheckOffLanguages']; + ['enabled', 'spellCheckOnLanguages', 'spellCheckOffLanguages'] as const; for (const collectionName of collectionNames) { - this.languages[collectionName].forEach((languageState, index) => { + // This assertion of `this.languages` is potentially unsafe and could + // fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + this.languages![collectionName].forEach((languageState, index) => { const status = statusMap.get(languageState.language.code); if (!status) { return; @@ -771,9 +793,8 @@ /** * Updates the |removable| property of the enabled language states based * on what other languages and input methods are enabled. - * @private */ - updateRemovableLanguages_() { + private updateRemovableLanguages_(): void { if (this.prefs === undefined || this.languages === undefined) { return; } @@ -793,62 +814,60 @@ /** * Creates a Set from the elements of the array. - * @param {!Array<T>} list - * @return {!Set<T>} - * @template T - * @private */ - makeSetFromArray_(list) { + private makeSetFromArray_<T>(list: T[]): Set<T> { + // TODO(b/238031866): Inline these calls. return new Set(list); } // LanguageHelper implementation. // TODO(michaelpg): replace duplicate docs with @override once b/24294625 // is fixed. - - /** @return {!Promise} */ - whenReady() { + whenReady(): Promise<void> { return this.resolver_.promise; } /** * Sets the prospective UI language to the chosen language. This won't affect * the actual UI language until a restart. - * @param {string} languageCode */ - setProspectiveUiLanguage(languageCode) { + setProspectiveUiLanguage(languageCode: string): void { this.browserProxy_.setProspectiveUiLanguage(languageCode); } /** * True if the prospective UI language was changed from its starting value. - * @return {boolean} */ - requiresRestart() { + // TODO(b/263824661): Remove this unused method if we do not share this file + // with browser settings. + requiresRestart(): boolean { return this.originalProspectiveUILanguage_ !== - this.languages.prospectiveUILanguage; + // This assertion of `this.languages` is potentially unsafe and could + // fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + this.languages!.prospectiveUILanguage; } /** - * @return {string} The language code for ARC IMEs. + * @return The language code for ARC IMEs. */ - getArcImeLanguageCode() { + getArcImeLanguageCode(): string { return kArcImeLanguage; } /** - * @param {string} languageCode - * @return {boolean} True if the language is for ARC IMEs. + * @return True if the language is for ARC IMEs. */ - isLanguageCodeForArcIme(languageCode) { + isLanguageCodeForArcIme(languageCode: string): boolean { return languageCode === kArcImeLanguage; } /** - * @param {!chrome.languageSettingsPrivate.Language} language - * @return {boolean} True if the language can be translated by Chrome. + * @return True if the language can be translated by Chrome. */ - isLanguageTranslatable(language) { + isLanguageTranslatable(language: chrome.languageSettingsPrivate.Language): + boolean { if (language.code === 'zh-CN' || language.code === 'zh-TW') { // In Translate, general Chinese is not used, and the sub code is // necessary as a language code for the Translate server. @@ -862,18 +881,16 @@ } /** - * @param {string} languageCode - * @return {boolean} True if the language is enabled. + * @return True if the language is enabled. */ - isLanguageEnabled(languageCode) { + isLanguageEnabled(languageCode: string): boolean { return this.enabledLanguageSet_.has(languageCode); } /** * Enables the language, making it available for spell check and input. - * @param {string} languageCode */ - enableLanguage(languageCode) { + enableLanguage(languageCode: string): void { if (!CrSettingsPrefs.isInitialized) { return; } @@ -883,9 +900,8 @@ /** * Disables the language. - * @param {string} languageCode */ - disableLanguage(languageCode) { + disableLanguage(languageCode: string): void { if (!CrSettingsPrefs.isInitialized) { return; } @@ -900,32 +916,27 @@ this.languageSettingsPrivate_.disableLanguage(languageCode); } - /** - * @return {boolean} - * @private - */ - isChromeOsLanguageSettingsV2Update2_() { + private isChromeOsLanguageSettingsV2Update2_(): boolean { return loadTimeData.valueExists('enableLanguageSettingsV2Update2') && loadTimeData.getBoolean('enableLanguageSettingsV2Update2'); } - /** - * @param {!LanguageState} languageState - * @return {boolean} - */ - isOnlyTranslateBlockedLanguage(languageState) { + isOnlyTranslateBlockedLanguage(languageState: LanguageState): boolean { return !languageState.translateEnabled && - this.languages.enabled.filter(lang => !lang.translateEnabled).length === - 1; + // This assertion of `this.languages` is potentially unsafe and could + // fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this + // to avoid this assertion. + this.languages!.enabled.filter(lang => !lang.translateEnabled) + .length === 1; } - /** - * @param {!LanguageState} languageState - * @return {boolean} - */ - canDisableLanguage(languageState) { + canDisableLanguage(languageState: LanguageState): boolean { // Cannot disable the only enabled language. - if (this.languages.enabled.length === 1) { + // This assertion of `this.languages` is potentially unsafe and could fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. + if (this.languages!.enabled.length === 1) { return false; } @@ -938,10 +949,10 @@ } /** - * @param {!chrome.languageSettingsPrivate.Language} language - * @return {boolean} true if the given language can be enabled + * @return true if the given language can be enabled */ - canEnableLanguage(language) { + canEnableLanguage(language: chrome.languageSettingsPrivate.Language): + boolean { return !( this.isLanguageEnabled(language.code) || language.isProhibitedLanguage || @@ -950,10 +961,9 @@ /** * Sets whether a given language should always be automatically translated. - * @param {string} languageCode - * @param {boolean} alwaysTranslate */ - setLanguageAlwaysTranslateState(languageCode, alwaysTranslate) { + setLanguageAlwaysTranslateState( + languageCode: string, alwaysTranslate: boolean): void { this.languageSettingsPrivate_.setLanguageAlwaysTranslateState( languageCode, alwaysTranslate); } @@ -961,11 +971,10 @@ /** * Moves the language in the list of enabled languages either up (toward the * front of the list) or down (toward the back). - * @param {string} languageCode - * @param {boolean} upDirection True if we need to move up, false if we + * @param upDirection True if we need to move up, false if we * need to move down */ - moveLanguage(languageCode, upDirection) { + moveLanguage(languageCode: string, upDirection: boolean): void { if (!CrSettingsPrefs.isInitialized) { return; } @@ -979,9 +988,8 @@ /** * Moves the language directly to the front of the list of enabled languages. - * @param {string} languageCode */ - moveLanguageToFront(languageCode) { + moveLanguageToFront(languageCode: string): void { if (!CrSettingsPrefs.isInitialized) { return; } @@ -992,9 +1000,8 @@ /** * Enables translate for the given language by removing the translate * language from the blocked languages preference. - * @param {string} languageCode */ - enableTranslateLanguage(languageCode) { + enableTranslateLanguage(languageCode: string): void { this.languageSettingsPrivate_.setEnableTranslationForLanguage( languageCode, true); } @@ -1002,9 +1009,8 @@ /** * Disables translate for the given language by adding the translate * language to the blocked languages preference. - * @param {string} languageCode */ - disableTranslateLanguage(languageCode) { + disableTranslateLanguage(languageCode: string): void { this.languageSettingsPrivate_.setEnableTranslationForLanguage( languageCode, false); } @@ -1012,24 +1018,20 @@ /** * Sets the translate target language and adds it to the content languages if * not already there. - * @param {string} languageCode */ - setTranslateTargetLanguage(languageCode) { + setTranslateTargetLanguage(languageCode: string): void { this.languageSettingsPrivate_.setTranslateTargetLanguage(languageCode); } /** * Enables or disables spell check for the given language. - * @param {string} languageCode - * @param {boolean} enable */ - toggleSpellCheck(languageCode, enable) { + toggleSpellCheck(languageCode: string, enable: boolean): void { if (!this.languages) { return; } if (enable) { - const spellCheckPref = this.getPref('spellcheck.dictionaries'); this.appendPrefListItem('spellcheck.dictionaries', languageCode); } else { this.deletePrefListItem('spellcheck.dictionaries', languageCode); @@ -1040,12 +1042,18 @@ * Converts the language code for translate. There are some differences * between the language set the Translate server uses and that for * Accept-Language. - * @param {string} languageCode - * @return {string} The converted language code. + * @return The converted language code. */ - convertLanguageCodeForTranslate(languageCode) { + convertLanguageCodeForTranslate(languageCode: string): string { if (languageCode in kLanguageCodeToTranslateCode) { - return kLanguageCodeToTranslateCode[languageCode]; + // Work around https://github.com/microsoft/TypeScript/issues/21732. + // As of writing, it is marked as fixed by + // https://github.com/microsoft/TypeScript/pull/50666, but that PR does + // not address this specific issue of narrowing a `string` down to keys of + // an object. + type LanguageCode = keyof typeof kLanguageCodeToTranslateCode; + // Safety: We checked that languageCode is a key above. + return kLanguageCodeToTranslateCode[languageCode as LanguageCode]; } const main = languageCode.split('-')[0]; @@ -1055,7 +1063,9 @@ return languageCode; } if (main in kTranslateLanguageSynonyms) { - return kTranslateLanguageSynonyms[main]; + type TranslateSynonymKey = keyof typeof kTranslateLanguageSynonyms; + // Safety: We checked that languageCode is a key above. + return kTranslateLanguageSynonyms[main as TranslateSynonymKey]; } return main; @@ -1064,10 +1074,8 @@ /** * Given a language code, returns just the base language. E.g., converts * 'en-GB' to 'en'. - * @param {string} languageCode - * @return {string} */ - getLanguageCodeWithoutRegion(languageCode) { + getLanguageCodeWithoutRegion(languageCode: string): string { // The Norwegian languages fall under the 'no' macrolanguage. if (languageCode === 'nb' || languageCode === 'nn') { return 'no'; @@ -1085,16 +1093,17 @@ } // Match the characters before the hyphen. - const result = languageCode.match(/^([^-]+)-?/); + // This assertion is unsafe if `languageCode` is an empty string, or starts + // with a hyphen. + // TODO(b/265554105): Gracefully handle this case. + const result = languageCode.match(/^([^-]+)-?/)!; + // Safety: The regex above has one non-optional capturing group. assert(result.length === 2); return result[1]; } - /** - * @param {string} languageCode - * @return {!chrome.languageSettingsPrivate.Language|undefined} - */ - getLanguage(languageCode) { + getLanguage(languageCode: string): chrome.languageSettingsPrivate.Language + |undefined { // If a languageCode is not found, try language without location. return this.supportedLanguageMap_.get(languageCode) || this.supportedLanguageMap_.get( @@ -1103,19 +1112,17 @@ /** * Retries downloading the dictionary for |languageCode|. - * @param {string} languageCode */ - retryDownloadDictionary(languageCode) { + retryDownloadDictionary(languageCode: string): void { this.languageSettingsPrivate_.retryDownloadDictionary(languageCode); } /** * Constructs the input method part of the languages model. - * @param {!Array<!chrome.languageSettingsPrivate.InputMethod>} - * supportedInputMethods Input methods. - * @private */ - createInputMethodModel_(supportedInputMethods) { + private createInputMethodModel_( + supportedInputMethods: chrome.languageSettingsPrivate.InputMethod[]): + void { // Populate the hash map of supported input methods. this.supportedInputMethodMap_.clear(); this.languageInputMethods_.clear(); @@ -1144,16 +1151,19 @@ /** * Returns a list of enabled input methods. - * @return {!Array<!chrome.languageSettingsPrivate.InputMethod>} - * @private + * + * This must be called after `whenReady()` is resolved. */ - getEnabledInputMethods_() { + private getEnabledInputMethods_(): + chrome.languageSettingsPrivate.InputMethod[] { + // Safety: Enforced in documentation. assert(CrSettingsPrefs.isInitialized); let enabledInputMethodIds = - this.getPref('settings.language.preload_engines').value.split(','); + this.getPref<string>('settings.language.preload_engines') + .value.split(','); enabledInputMethodIds = enabledInputMethodIds.concat( - this.getPref('settings.language.enabled_extension_imes') + this.getPref<string>('settings.language.enabled_extension_imes') .value.split(',')); this.enabledInputMethodSet_ = new Set(enabledInputMethodIds); @@ -1161,72 +1171,73 @@ // (Accessibility Common) input method. return enabledInputMethodIds .map(id => this.supportedInputMethodMap_.get(id)) - .filter(inputMethod => !!inputMethod) + .filter( + <T>(inputMethod: T): inputMethod is NonNullable<T> => !!inputMethod) .filter(inputMethod => inputMethod.id !== ACCESSIBILITY_COMMON_IME_ID); } - /** @private */ - async updateSupportedInputMethods_() { + private async updateSupportedInputMethods_(): Promise<void> { const lists = await this.languageSettingsPrivate_.getInputMethodLists(); const supportedInputMethods = lists.componentExtensionImes.concat(lists.thirdPartyExtensionImes); this.createInputMethodModel_(supportedInputMethods); + // The two lines below are potentially unsafe and could fail, as they assume + // that `this.languages` is defined. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. this.set('languages.inputMethods.supported', supportedInputMethods); this.updateEnabledInputMethods_(); } - /** @private */ - updateEnabledInputMethods_() { + private updateEnabledInputMethods_(): void { const enabledInputMethods = this.getEnabledInputMethods_(); const enabledInputMethodSet = this.makeSetFromArray_(enabledInputMethods); - for (let i = 0; i < this.languages.inputMethods.supported.length; i++) { + // This assertion of `this.languages` is potentially unsafe and could fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. + // Safety: `LanguagesModel.inputMethods` is always defined on CrOS. + for (let i = 0; i < this.languages!.inputMethods!.supported.length; i++) { this.set( 'languages.inputMethods.supported.' + i + '.enabled', - enabledInputMethodSet.has(this.languages.inputMethods.supported[i])); + enabledInputMethodSet.has( + this.languages!.inputMethods!.supported[i])); } this.set('languages.inputMethods.enabled', enabledInputMethods); } - /** @param {string} id */ - addInputMethod(id) { + addInputMethod(id: string): void { if (!this.supportedInputMethodMap_.has(id)) { return; } this.languageSettingsPrivate_.addInputMethod(id); } - /** @param {string} id */ - removeInputMethod(id) { + removeInputMethod(id: string): void { if (!this.supportedInputMethodMap_.has(id)) { return; } this.languageSettingsPrivate_.removeInputMethod(id); } - /** @param {string} id */ - setCurrentInputMethod(id) { + setCurrentInputMethod(id: string): void { this.inputMethodPrivate_.setCurrentInputMethod(id); } - /** - * @param {string} languageCode - * @return {!Array<!chrome.languageSettingsPrivate.InputMethod>} - */ - getInputMethodsForLanguage(languageCode) { + getInputMethodsForLanguage(languageCode: string): + chrome.languageSettingsPrivate.InputMethod[] { return this.languageInputMethods_.get(languageCode) || []; } /** * Returns the input methods that support any of the given languages. - * @param {!Array<string>} languageCodes - * @return {!Array<!chrome.languageSettingsPrivate.InputMethod>} */ - getInputMethodsForLanguages(languageCodes) { + getInputMethodsForLanguages(languageCodes: string[]): + chrome.languageSettingsPrivate.InputMethod[] { // Input methods that have already been listed for this language. - const /** !Set<string> */ usedInputMethods = new Set(); - /** @type {!Array<chrome.languageSettingsPrivate.InputMethod>} */ - const combinedInputMethods = []; + const usedInputMethods = new Set<string>(); + const combinedInputMethods: chrome.languageSettingsPrivate.InputMethod[] = + []; for (const languageCode of languageCodes) { const inputMethods = this.getInputMethodsForLanguage(languageCode); // Get the language's unused input methods and mark them as used. @@ -1240,53 +1251,49 @@ } /** - * @return {!Set<string>} list of enabled language code. + * @return list of enabled language code. */ - getEnabledLanguageCodes() { + getEnabledLanguageCodes(): Set<string> { return this.enabledLanguageSet_; } /** - * @param {string} id the input method id - * @return {boolean} True if the input method is enabled + * @param id the input method id + * @return True if the input method is enabled */ - isInputMethodEnabled(id) { + isInputMethodEnabled(id: string): boolean { return this.enabledInputMethodSet_.has(id); } - /** - * @param {!chrome.languageSettingsPrivate.InputMethod} inputMethod - * @return {boolean} - */ - isComponentIme(inputMethod) { + isComponentIme(inputMethod: chrome.languageSettingsPrivate.InputMethod): + boolean { return inputMethod.id.startsWith('_comp_'); } - /** @param {string} id Input method ID. */ - openInputMethodOptions(id) { + /** @param id Input method ID. */ + openInputMethodOptions(id: string): void { this.inputMethodPrivate_.openOptionsPage(id); } - /** @param {string} id New current input method ID. */ - onInputMethodChanged_(id) { + /** @param id New current input method ID. */ + private onInputMethodChanged_(id: string): void { this.set('languages.inputMethods.currentId', id); } - /** @param {string} id Added input method ID. */ - onInputMethodAdded_(id) { + /** @param _id Added input method ID. */ + private onInputMethodAdded_(_id: string): void { this.updateSupportedInputMethods_(); } - /** @param {string} id Removed input method ID. */ - onInputMethodRemoved_(id) { + /** @param id Removed input method ID. */ + private onInputMethodRemoved_(_id: string): void { this.updateSupportedInputMethods_(); } /** - * @param {string} id Input method ID. - * @return {string} + * @param id Input method ID. */ - getInputMethodDisplayName(id) { + getInputMethodDisplayName(id: string): string { const inputMethod = this.supportedInputMethodMap_.get(id); if (inputMethod === undefined) { return ''; @@ -1296,3 +1303,9 @@ } customElements.define(SettingsLanguagesElement.is, SettingsLanguagesElement); + +declare global { + interface HTMLElementTagNameMap { + [SettingsLanguagesElement.is]: SettingsLanguagesElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_browser_proxy.js b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_browser_proxy.js deleted file mode 100644 index b9be38d7..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_browser_proxy.js +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview A helper object used from the languages section - * to interact with the browser. - */ - -import {sendWithPromise} from 'chrome://resources/ash/common/cr.m.js'; - -/** @interface */ -export class LanguagesBrowserProxy { - /** - * Sets the prospective UI language to the chosen language. This won't - * affect the actual UI language until a restart. - * @param {string} languageCode - */ - setProspectiveUiLanguage(languageCode) {} - - /** @return {!Promise<string>} */ - getProspectiveUiLanguage() {} - - /** @return {!LanguageSettingsPrivate} */ - getLanguageSettingsPrivate() {} - - /** @return {!InputMethodPrivate} */ - getInputMethodPrivate() {} -} - -/** @type {?LanguagesBrowserProxy} */ -let instance = null; - -/** - * @implements {LanguagesBrowserProxy} - */ -export class LanguagesBrowserProxyImpl { - /** @return {!LanguagesBrowserProxy} */ - static getInstance() { - return instance || (instance = new LanguagesBrowserProxyImpl()); - } - - /** @param {!LanguagesBrowserProxy} obj */ - static setInstanceForTesting(obj) { - instance = obj; - } - - /** @override */ - setProspectiveUiLanguage(languageCode) { - chrome.send('setProspectiveUILanguage', [languageCode]); - } - - /** @override */ - getProspectiveUiLanguage() { - return sendWithPromise('getProspectiveUILanguage'); - } - - /** @override */ - getLanguageSettingsPrivate() { - return /** @type {!LanguageSettingsPrivate} */ ( - chrome.languageSettingsPrivate); - } - - /** @override */ - getInputMethodPrivate() { - return /** @type {!InputMethodPrivate} */ (chrome.inputMethodPrivate); - } -}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_browser_proxy.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_browser_proxy.ts new file mode 100644 index 0000000..c1e7635 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_browser_proxy.ts
@@ -0,0 +1,52 @@ +// Copyright 2017 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview A helper object used from the languages section + * to interact with the browser. + */ + +import {sendWithPromise} from 'chrome://resources/js/cr.js'; + +export interface LanguagesBrowserProxy { + /** + * Sets the prospective UI language to the chosen language. This won't + * affect the actual UI language until a restart. + */ + setProspectiveUiLanguage(languageCode: string): void; + + getProspectiveUiLanguage(): Promise<string>; + + getLanguageSettingsPrivate(): typeof chrome.languageSettingsPrivate; + + getInputMethodPrivate(): typeof chrome.inputMethodPrivate; +} + +let instance: LanguagesBrowserProxy|null = null; + +export class LanguagesBrowserProxyImpl implements LanguagesBrowserProxy { + static getInstance(): LanguagesBrowserProxy { + return instance || (instance = new LanguagesBrowserProxyImpl()); + } + + static setInstanceForTesting(obj: LanguagesBrowserProxy): void { + instance = obj; + } + + setProspectiveUiLanguage(languageCode: string): void { + chrome.send('setProspectiveUILanguage', [languageCode]); + } + + getProspectiveUiLanguage(): Promise<string> { + return sendWithPromise('getProspectiveUILanguage'); + } + + getLanguageSettingsPrivate(): typeof chrome.languageSettingsPrivate { + return chrome.languageSettingsPrivate; + } + + getInputMethodPrivate(): typeof chrome.inputMethodPrivate { + return chrome.inputMethodPrivate; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_metrics_proxy.js b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_metrics_proxy.js deleted file mode 100644 index 93437bd..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_metrics_proxy.js +++ /dev/null
@@ -1,160 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview - * Handles metrics for ChromeOS's languages OS settings. - * TODO(crbug/1109431): Remove these metrics when languages settings migration - * is completed and data analysed. - */ - -/** - * Keeps in sync with SettingsLanguagesPageInteraction - * in tools/metrics/histograms/enums.xml. - * @enum {number} - */ -export const LanguagesPageInteraction = { - SWITCH_SYSTEM_LANGUAGE: 0, - RESTART: 1, - SWITCH_INPUT_METHOD: 2, - RESTART_LATER: 3, - OPEN_CUSTOM_SPELL_CHECK: 4, - OPEN_MANAGE_GOOGLE_ACCOUNT_LANGUAGE: 5, - OPEN_WEB_LANGUAGES_LEARN_MORE: 6, - OPEN_LANGUAGE_PACKS_LEARN_MORE: 7, -}; - -/** - * Keeps in sync with SettingsInputsShortcutReminderState - * in tools/metrics/histograms/enums.xml. - * @enum {number} - */ -export const InputsShortcutReminderState = { - NONE: 0, - LAST_USED_IME: 1, - NEXT_IME: 2, - LAST_USED_IME_AND_NEXT_IME: 3, -}; - -/** @interface */ -export class LanguagesMetricsProxy { - /** - * Records the interaction to enumerated histogram. - * @param {!LanguagesPageInteraction} interaction - */ - recordInteraction(interaction) {} - - /** Records when users select "Add input method". */ - recordAddInputMethod() {} - - /** Records when users select "Add languages". */ - recordAddLanguages() {} - - /** Records when users select "Manage input methods". */ - recordManageInputMethods() {} - - /** - * Records when users toggle "Show Input Options On Shelf" option. - * @param {boolean} value - */ - recordToggleShowInputOptionsOnShelf(value) {} - - /** - * Records when users toggle "Spell check" option. - * @param {boolean} value - */ - recordToggleSpellCheck(value) {} - - /** - * Records when users toggle "Offer to translate languages you don't read" - * option. - * @param {boolean} value - */ - recordToggleTranslate(value) {} - - /** - * Records when users check/uncheck "Offer to translate pages in this - * language" checkbox. - * @param {boolean} value - */ - recordTranslateCheckboxChanged(value) {} - - /** - * Records when users dismiss the shortcut reminder. - * @param {InputsShortcutReminderState} value - */ - recordShortcutReminderDismissed(value) {} -} - -/** @type {?LanguagesMetricsProxy} */ -let instance = null; - -/** @implements {LanguagesMetricsProxy} */ -export class LanguagesMetricsProxyImpl { - /** @return {!LanguagesMetricsProxy} */ - static getInstance() { - return instance || (instance = new LanguagesMetricsProxyImpl()); - } - - /** @param {!LanguagesMetricsProxy} obj */ - static setInstanceForTesting(obj) { - instance = obj; - } - - /** @override */ - recordInteraction(interaction) { - chrome.metricsPrivate.recordEnumerationValue( - 'ChromeOS.Settings.Languages.Interaction', interaction, - Object.keys(LanguagesPageInteraction).length); - } - - /** @override */ - recordAddInputMethod() { - chrome.metricsPrivate.recordUserAction( - 'ChromeOS.Settings.Languages.AddInputMethod'); - } - - /** @override */ - recordAddLanguages() { - chrome.metricsPrivate.recordUserAction( - 'ChromeOS.Settings.Languages.AddLanguages'); - } - - /** @override */ - recordManageInputMethods() { - chrome.metricsPrivate.recordUserAction( - 'ChromeOS.Settings.Languages.ManageInputMethods'); - } - - /** @override */ - recordToggleShowInputOptionsOnShelf(value) { - chrome.metricsPrivate.recordBoolean( - 'ChromeOS.Settings.Languages.Toggle.ShowInputOptionsOnShelf', value); - } - - /** @override */ - recordToggleSpellCheck(value) { - chrome.metricsPrivate.recordBoolean( - 'ChromeOS.Settings.Languages.Toggle.SpellCheck', value); - } - - /** @override */ - recordToggleTranslate(value) { - chrome.metricsPrivate.recordBoolean( - 'ChromeOS.Settings.Languages.Toggle.Translate', value); - } - - /** @override */ - recordTranslateCheckboxChanged(value) { - chrome.metricsPrivate.recordBoolean( - 'ChromeOS.Settings.Languages.OfferToTranslateCheckbox', value); - } - - /** @override */ - recordShortcutReminderDismissed(value) { - chrome.metricsPrivate.recordEnumerationValue( - 'ChromeOS.Settings.Inputs.ShortcutReminderDismissed', value, - Object.keys(InputsShortcutReminderState).length); - } -}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_metrics_proxy.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_metrics_proxy.ts new file mode 100644 index 0000000..d068730 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_metrics_proxy.ts
@@ -0,0 +1,138 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * Handles metrics for ChromeOS's languages OS settings. + * TODO(crbug/1109431): Remove these metrics when languages settings migration + * is completed and data analysed. + */ + +/** + * Keeps in sync with SettingsLanguagesPageInteraction + * in tools/metrics/histograms/enums.xml. + */ +export enum LanguagesPageInteraction { + SWITCH_SYSTEM_LANGUAGE = 0, + RESTART = 1, + SWITCH_INPUT_METHOD = 2, + RESTART_LATER = 3, + OPEN_CUSTOM_SPELL_CHECK = 4, + OPEN_MANAGE_GOOGLE_ACCOUNT_LANGUAGE = 5, + OPEN_WEB_LANGUAGES_LEARN_MORE = 6, + OPEN_LANGUAGE_PACKS_LEARN_MORE = 7, +} + +/** + * Keeps in sync with SettingsInputsShortcutReminderState + * in tools/metrics/histograms/enums.xml. + */ +export enum InputsShortcutReminderState { + NONE = 0, + LAST_USED_IME = 1, + NEXT_IME = 2, + LAST_USED_IME_AND_NEXT_IME = 3, +} + +export interface LanguagesMetricsProxy { + /** + * Records the interaction to enumerated histogram. + */ + recordInteraction(interaction: LanguagesPageInteraction): void; + + /** Records when users select "Add input method". */ + recordAddInputMethod(): void; + + /** Records when users select "Add languages". */ + recordAddLanguages(): void; + + /** Records when users select "Manage input methods". */ + recordManageInputMethods(): void; + + /** + * Records when users toggle "Show Input Options On Shelf" option. + */ + recordToggleShowInputOptionsOnShelf(value: boolean): void; + + /** + * Records when users toggle "Spell check" option. + */ + recordToggleSpellCheck(value: boolean): void; + + /** + * Records when users toggle "Offer to translate languages you don't read" + * option. + */ + recordToggleTranslate(value: boolean): void; + + /** + * Records when users check/uncheck "Offer to translate pages in this + * language" checkbox. + */ + recordTranslateCheckboxChanged(value: boolean): void; + + /** + * Records when users dismiss the shortcut reminder. + */ + recordShortcutReminderDismissed(value: InputsShortcutReminderState): void; +} + +let instance: LanguagesMetricsProxy|null = null; + +export class LanguagesMetricsProxyImpl implements LanguagesMetricsProxy { + static getInstance(): LanguagesMetricsProxy { + return instance || (instance = new LanguagesMetricsProxyImpl()); + } + + static setInstanceForTesting(obj: LanguagesMetricsProxy): void { + instance = obj; + } + + recordInteraction(interaction: LanguagesPageInteraction): void { + chrome.metricsPrivate.recordEnumerationValue( + 'ChromeOS.Settings.Languages.Interaction', interaction, + Object.keys(LanguagesPageInteraction).length); + } + + recordAddInputMethod(): void { + chrome.metricsPrivate.recordUserAction( + 'ChromeOS.Settings.Languages.AddInputMethod'); + } + + recordAddLanguages(): void { + chrome.metricsPrivate.recordUserAction( + 'ChromeOS.Settings.Languages.AddLanguages'); + } + + recordManageInputMethods(): void { + chrome.metricsPrivate.recordUserAction( + 'ChromeOS.Settings.Languages.ManageInputMethods'); + } + + recordToggleShowInputOptionsOnShelf(value: boolean): void { + chrome.metricsPrivate.recordBoolean( + 'ChromeOS.Settings.Languages.Toggle.ShowInputOptionsOnShelf', value); + } + + recordToggleSpellCheck(value: boolean): void { + chrome.metricsPrivate.recordBoolean( + 'ChromeOS.Settings.Languages.Toggle.SpellCheck', value); + } + + recordToggleTranslate(value: boolean): void { + chrome.metricsPrivate.recordBoolean( + 'ChromeOS.Settings.Languages.Toggle.Translate', value); + } + + recordTranslateCheckboxChanged(value: boolean): void { + chrome.metricsPrivate.recordBoolean( + 'ChromeOS.Settings.Languages.OfferToTranslateCheckbox', value); + } + + recordShortcutReminderDismissed(value: InputsShortcutReminderState): void { + chrome.metricsPrivate.recordEnumerationValue( + 'ChromeOS.Settings.Inputs.ShortcutReminderDismissed', value, + Object.keys(InputsShortcutReminderState).length); + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_types.js b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_types.js deleted file mode 100644 index 16f215bf6..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_types.js +++ /dev/null
@@ -1,273 +0,0 @@ -// Copyright 2015 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview Closure typedefs for dictionaries and interfaces used by - * language settings. - */ - -/** - * Settings and state for a particular enabled language. - * @typedef {{ - * language: !chrome.languageSettingsPrivate.Language, - * removable: boolean, - * spellCheckEnabled: boolean, - * translateEnabled: boolean, - * isManaged: boolean, - * isForced: boolean, - * downloadDictionaryFailureCount: number, - * downloadDictionaryStatus: - * ?chrome.languageSettingsPrivate.SpellcheckDictionaryStatus, - * }} - */ -export let LanguageState; - -/** - * Settings and state for spellcheck languages. - * @typedef {{ - * language: !chrome.languageSettingsPrivate.Language, - * spellCheckEnabled: boolean, - * isManaged: boolean, - * downloadDictionaryFailureCount: number, - * downloadDictionaryStatus: - * ?chrome.languageSettingsPrivate.SpellcheckDictionaryStatus, - * }} - */ -export let SpellCheckLanguageState; - -/** - * Input method data to expose to consumers (Chrome OS only). - * supported: an array of supported input methods set once at initialization. - * enabled: an array of the currently enabled input methods. - * currentId: ID of the currently active input method. - * @typedef {{ - * supported: !Array<!chrome.languageSettingsPrivate.InputMethod>, - * enabled: !Array<!chrome.languageSettingsPrivate.InputMethod>, - * currentId: string, - * }} - */ -export let InputMethodsModel; - -/** - * Languages data to expose to consumers. - * supported: an array of languages, ordered alphabetically, set once - * at initialization. - * enabled: an array of enabled language states, ordered by preference. - * translateTarget: the default language to translate into. - * prospectiveUILanguage: the "prospective" UI language, i.e., the one to be - * used on next restart. Matches the current UI language preference unless - * the user has chosen a different language without restarting. May differ - * from the actually used language (navigator.language). Chrome OS and - * Windows only. - * inputMethods: the InputMethodsModel (Chrome OS only). - * spellCheckOnLanguages: an array of spell check languages that are currently - * in use, including the languages force-enabled by policy. - * spellCheckOffLanguages: an array of spell check languages that are currently - * not in use, including the languages force-disabled by policy. - * @typedef {{ - * supported: !Array<!chrome.languageSettingsPrivate.Language>, - * enabled: !Array<!LanguageState>, - * translateTarget: string, - * prospectiveUILanguage: (string|undefined), - * inputMethods: (!InputMethodsModel|undefined), - * alwaysTranslate: !Array<!chrome.languageSettingsPrivate.Language>, - * neverTranslate: !Array<!chrome.languageSettingsPrivate.Language>, - * spellCheckOnLanguages: !Array<!SpellCheckLanguageState>, - * spellCheckOffLanguages: !Array<!SpellCheckLanguageState>, - * }} - */ -export let LanguagesModel; - -/** - * Helper methods for reading and writing language settings. - * @interface - */ -export class LanguageHelper { - /** @return {!Promise} */ - whenReady() {} - - /** - * Sets the prospective UI language to the chosen language. This won't affect - * the actual UI language until a restart. - * @param {string} languageCode - */ - setProspectiveUiLanguage(languageCode) {} - - /** - * True if the prospective UI language has been changed. - * @return {boolean} - */ - requiresRestart() {} - - /** - * @return {string} The language code for ARC IMEs. - */ - getArcImeLanguageCode() {} - - /** - * @param {string} languageCode - * @return {boolean} - */ - isLanguageCodeForArcIme(languageCode) {} - - /** - * @param {!chrome.languageSettingsPrivate.Language} language - * @return {boolean} - */ - isLanguageTranslatable(language) {} - - /** - * @param {string} languageCode - * @return {boolean} - */ - isLanguageEnabled(languageCode) {} - - /** - * Enables the language, making it available for spell check and input. - * @param {string} languageCode - */ - enableLanguage(languageCode) {} - - /** - * Disables the language. - * @param {string} languageCode - */ - disableLanguage(languageCode) {} - - /** - * Returns true iff provided languageState is the only blocked language. - * @param {!LanguageState} languageState - * @return {boolean} - */ - isOnlyTranslateBlockedLanguage(languageState) {} - - /** - * Returns true iff provided languageState can be disabled. - * @param {!LanguageState} languageState - * @return {boolean} - */ - canDisableLanguage(languageState) {} - - /** - * @param {!chrome.languageSettingsPrivate.Language} language - * @return {boolean} true if the given language can be enabled - */ - canEnableLanguage(language) {} - - /** - * Moves the language in the list of enabled languages by the given offset. - * @param {string} languageCode - * @param {boolean} upDirection True if we need to move toward the front, - * false if we need to move toward the back. - */ - moveLanguage(languageCode, upDirection) {} - - /** - * Moves the language directly to the front of the list of enabled languages. - * @param {string} languageCode - */ - moveLanguageToFront(languageCode) {} - - /** - * Enables translate for the given language by removing the translate - * language from the blocked languages preference. - * @param {string} languageCode - */ - enableTranslateLanguage(languageCode) {} - - /** - * Disables translate for the given language by adding the translate - * language to the blocked languages preference. - * @param {string} languageCode - */ - disableTranslateLanguage(languageCode) {} - - /** - * Sets whether a given language should always be automatically translated. - * @param {string} languageCode - * @param {boolean} alwaysTranslate - */ - setLanguageAlwaysTranslateState(languageCode, alwaysTranslate) {} - - /** - * Enables or disables spell check for the given language. - * @param {string} languageCode - * @param {boolean} enable - */ - toggleSpellCheck(languageCode, enable) {} - - /** - * Converts the language code for translate. There are some differences - * between the language set the Translate server uses and that for - * Accept-Language. - * @param {string} languageCode - * @return {string} The converted language code. - */ - convertLanguageCodeForTranslate(languageCode) {} - - /** - * Given a language code, returns just the base language. E.g., converts - * 'en-GB' to 'en'. - * @param {string} languageCode - * @return {string} - */ - getLanguageCodeWithoutRegion(languageCode) {} - - /** - * @param {string} languageCode - * @return {!chrome.languageSettingsPrivate.Language|undefined} - */ - getLanguage(languageCode) {} - - /** @param {string} languageCode */ - retryDownloadDictionary(languageCode) {} - - /** @param {string} id */ - addInputMethod(id) {} - - /** @param {string} id */ - removeInputMethod(id) {} - - /** @param {string} id */ - setCurrentInputMethod(id) {} - - /** - * @param {string} languageCode - * @return {!Array<!chrome.languageSettingsPrivate.InputMethod>} - */ - getInputMethodsForLanguage(languageCode) {} - - /** - * Returns the input methods that support any of the given languages. - * @param {!Array<string>} languageCodes - * @return {!Array<!chrome.languageSettingsPrivate.InputMethod>} - */ - getInputMethodsForLanguages(languageCodes) {} - - /** - * @return {!Set<string>} list of enabled language code. - */ - getEnabledLanguageCodes() {} - - /** - * @param {string} id the input method id - * @return {boolean} True if the input method is enabled - */ - isInputMethodEnabled(id) {} - - /** - * @param {!chrome.languageSettingsPrivate.InputMethod} inputMethod - * @return {boolean} - */ - isComponentIme(inputMethod) {} - - /** @param {string} id Input method ID. */ - openInputMethodOptions(id) {} - - /** - * @param {string} id Input method ID. - * @return {string} - */ - getInputMethodDisplayName(id) {} -}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/languages_types.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_types.ts new file mode 100644 index 0000000..1b5fd674 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/languages_types.ts
@@ -0,0 +1,226 @@ +// Copyright 2015 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Closure typedefs for dictionaries and interfaces used by + * language settings. + */ + +/** + * Settings and state for a particular enabled language. + */ +export interface LanguageState { + language: chrome.languageSettingsPrivate.Language; + removable: boolean; + spellCheckEnabled: boolean; + translateEnabled: boolean; + isManaged: boolean; + isForced: boolean; + downloadDictionaryFailureCount: number; + downloadDictionaryStatus: + chrome.languageSettingsPrivate.SpellcheckDictionaryStatus|null; +} + +/** + * Settings and state for spellcheck languages. + */ +export interface SpellCheckLanguageState { + language: chrome.languageSettingsPrivate.Language; + spellCheckEnabled: boolean; + isManaged: boolean; + downloadDictionaryFailureCount: number; + downloadDictionaryStatus: + chrome.languageSettingsPrivate.SpellcheckDictionaryStatus|null; +} + +/** + * Input method data to expose to consumers (Chrome OS only). + * supported: an array of supported input methods set once at initialization. + * enabled: an array of the currently enabled input methods. + * currentId: ID of the currently active input method. + */ +export interface InputMethodsModel { + supported: chrome.languageSettingsPrivate.InputMethod[]; + enabled: chrome.languageSettingsPrivate.InputMethod[]; + currentId: string; +} + +/** + * Languages data to expose to consumers. + * supported: an array of languages, ordered alphabetically, set once + * at initialization. + * enabled: an array of enabled language states, ordered by preference. + * translateTarget: the default language to translate into. + * prospectiveUILanguage: the "prospective" UI language, i.e., the one to be + * used on next restart. Matches the current UI language preference unless + * the user has chosen a different language without restarting. May differ + * from the actually used language (navigator.language). Chrome OS and + * Windows only. + * inputMethods: the InputMethodsModel (Chrome OS only). + * spellCheckOnLanguages: an array of spell check languages that are currently + * in use, including the languages force-enabled by policy. + * spellCheckOffLanguages: an array of spell check languages that are currently + * not in use, including the languages force-disabled by policy. + */ +export interface LanguagesModel { + supported: chrome.languageSettingsPrivate.Language[]; + enabled: LanguageState[]; + translateTarget: string; + // TODO(b/263824661): Remove undefined from these definitions if we do not + // share this file with browser settings. + /** Always defined on CrOS, set in `createModel_()` in `languages.ts`. */ + prospectiveUILanguage: (string|undefined); + /** Always defined on CrOS, set in `createModel_()` in `languages.ts`. */ + inputMethods: (InputMethodsModel|undefined); + alwaysTranslate: chrome.languageSettingsPrivate.Language[]; + neverTranslate: chrome.languageSettingsPrivate.Language[]; + spellCheckOnLanguages: SpellCheckLanguageState[]; + spellCheckOffLanguages: SpellCheckLanguageState[]; +} + +/** + * Helper methods for reading and writing language settings. + */ +export interface LanguageHelper { + whenReady(): Promise<void>; + + /** + * Sets the prospective UI language to the chosen language. This won't affect + * the actual UI language until a restart. + */ + setProspectiveUiLanguage(languageCode: string): void; + + /** + * True if the prospective UI language has been changed. + */ + requiresRestart(): boolean; + + /** + * @return The language code for ARC IMEs. + */ + getArcImeLanguageCode(): string; + + isLanguageCodeForArcIme(languageCode: string): boolean; + + isLanguageTranslatable(language: chrome.languageSettingsPrivate.Language): + boolean; + + isLanguageEnabled(languageCode: string): boolean; + + /** + * Enables the language, making it available for spell check and input. + */ + enableLanguage(languageCode: string): void; + + /** + * Disables the language. + */ + disableLanguage(languageCode: string): void; + + /** + * Returns true iff provided languageState is the only blocked language. + */ + isOnlyTranslateBlockedLanguage(languageState: LanguageState): boolean; + + /** + * Returns true iff provided languageState can be disabled. + */ + canDisableLanguage(languageState: LanguageState): boolean; + + /** + * @return true if the given language can be enabled + */ + canEnableLanguage(language: chrome.languageSettingsPrivate.Language): boolean; + + /** + * Moves the language in the list of enabled languages by the given offset. + * @param upDirection True if we need to move toward the front, false if we + * need to move toward the back. + */ + moveLanguage(languageCode: string, upDirection: boolean): void; + + /** + * Moves the language directly to the front of the list of enabled languages. + */ + moveLanguageToFront(languageCode: string): void; + + /** + * Enables translate for the given language by removing the translate + * language from the blocked languages preference. + */ + enableTranslateLanguage(languageCode: string): void; + + /** + * Disables translate for the given language by adding the translate + * language to the blocked languages preference. + */ + disableTranslateLanguage(languageCode: string): void; + + /** + * Sets whether a given language should always be automatically translated. + */ + setLanguageAlwaysTranslateState( + languageCode: string, alwaysTranslate: boolean): void; + + /** + * Enables or disables spell check for the given language. + */ + toggleSpellCheck(languageCode: string, enable: boolean): void; + + /** + * Converts the language code for translate. There are some differences + * between the language set the Translate server uses and that for + * Accept-Language. + * @return The converted language code. + */ + convertLanguageCodeForTranslate(languageCode: string): string; + + /** + * Given a language code, returns just the base language. E.g., converts + * 'en-GB' to 'en'. + */ + getLanguageCodeWithoutRegion(languageCode: string): string; + + getLanguage(languageCode: string): chrome.languageSettingsPrivate.Language + |undefined; + + retryDownloadDictionary(languageCode: string): void; + + addInputMethod(id: string): void; + + removeInputMethod(id: string): void; + + setCurrentInputMethod(id: string): void; + + getInputMethodsForLanguage(languageCode: string): + chrome.languageSettingsPrivate.InputMethod[]; + + /** + * Returns the input methods that support any of the given languages. + */ + getInputMethodsForLanguages(languageCodes: string[]): + chrome.languageSettingsPrivate.InputMethod[]; + + /** + * @return list of enabled language code. + */ + getEnabledLanguageCodes(): Set<string>; + + /** + * @param id the input method id + * @return True if the input method is enabled + */ + isInputMethodEnabled(id: string): boolean; + + isComponentIme(inputMethod: chrome.languageSettingsPrivate.InputMethod): + boolean; + + /** @param id Input method ID. */ + openInputMethodOptions(id: string): void; + + /** + * @param id Input method ID. + */ + getInputMethodDisplayName(id: string): string; +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.ts similarity index 66% rename from chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.ts index 4f34ddb3..3c823b84 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.ts
@@ -15,10 +15,9 @@ import {LanguageHelper, LanguagesModel} from './languages_types.js'; import {getTemplate} from './os_add_languages_dialog.html.js'; -/** @polymer */ class OsSettingsAddLanguagesDialogElement extends PolymerElement { static get is() { - return 'os-settings-add-languages-dialog'; + return 'os-settings-add-languages-dialog' as const; } static get template() { @@ -27,23 +26,26 @@ static get properties() { return { - /** @type {!LanguagesModel|undefined} */ languages: { type: Object, notify: true, }, - - /** @type {!LanguageHelper} */ languageHelper: Object, }; } + // Public API: Downwards data flow. + languages: LanguagesModel|undefined; + languageHelper: LanguageHelper; + /** - * @return {!Array<!Item>} A list of languages to be displayed in the dialog. - * @private + * @return A list of languages to be displayed in the dialog. */ - getLanguages_() { - return this.languages.supported + private getLanguages_(): Item[] { + // This assertion of `this.languages` is potentially unsafe and could fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. + return this.languages!.supported .filter(language => this.languageHelper.canEnableLanguage(language)) .map(language => ({ id: language.code, @@ -54,11 +56,10 @@ } /** - * @param {!chrome.languageSettingsPrivate.Language} language - * @return {string} The text to be displayed. - * @private + * @return The text to be displayed. */ - getDisplayText_(language) { + private getDisplayText_(language: chrome.languageSettingsPrivate.Language): + string { let displayText = language.displayName; // If the native name is different, add it. if (language.displayName !== language.nativeDisplayName) { @@ -69,10 +70,8 @@ /** * Enables the checked languages. - * @param {!CustomEvent<!Set<string>>} e - * @private */ - onItemsAdded_(e) { + private onItemsAdded_(e: HTMLElementEventMap['items-added']): void { e.detail.forEach(languageCode => { this.languageHelper.enableLanguage(languageCode); }); @@ -82,3 +81,10 @@ customElements.define( OsSettingsAddLanguagesDialogElement.is, OsSettingsAddLanguagesDialogElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsAddLanguagesDialogElement.is]: + OsSettingsAddLanguagesDialogElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.ts similarity index 60% rename from chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.ts index c859cf3..3fd69c5 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.ts
@@ -15,43 +15,50 @@ import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; import '../../settings_shared.css.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {IronA11yKeysElement} from 'chrome://resources/polymer/v3_0/iron-a11y-keys/iron-a11y-keys.js'; +import {DomRepeatEvent, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {Route} from '../router.js'; import {GlobalScrollTargetBehavior, GlobalScrollTargetBehaviorInterface} from '../global_scroll_target_behavior.js'; import {recordSettingChange} from '../metrics_recorder.js'; import {routes} from '../os_route.js'; -import {LanguagesBrowserProxy, LanguagesBrowserProxyImpl} from './languages_browser_proxy.js'; +import {LanguagesBrowserProxyImpl} from './languages_browser_proxy.js'; import {getTemplate} from './os_edit_dictionary_page.html.js'; // Max valid word size, keep in sync with kMaxCustomDictionaryWordBytes in // //components/spellcheck/common/spellcheck_common.h const MAX_CUSTOM_DICTIONARY_WORD_BYTES = 99; -/** @enum {number} */ -const NewWordState = { - NO_WORD: 0, - VALID_WORD: 1, - WORD_ALREADY_ADDED: 2, - WORD_TOO_LONG: 3, -}; +enum NewWordState { + NO_WORD = 0, + VALID_WORD = 1, + WORD_ALREADY_ADDED = 2, + WORD_TOO_LONG = 3, +} -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - * @implements {GlobalScrollTargetBehaviorInterface} - */ -const OsSettingsEditDictionaryPageElementBase = - mixinBehaviors([I18nBehavior, GlobalScrollTargetBehavior], PolymerElement); +const OsSettingsEditDictionaryPageElementBase = I18nMixin(PolymerElement); -/** @polymer */ +const OsSettingsEditDictionaryPageElementBaseWithBehaviors = + mixinBehaviors( + // TODO(b/265559727): Remove GlobalScrollTargetBehavior if it is unused. + [GlobalScrollTargetBehavior], + OsSettingsEditDictionaryPageElementBase) as + typeof OsSettingsEditDictionaryPageElementBase & + (new (...args: any[]) => GlobalScrollTargetBehaviorInterface); + +interface OsSettingsEditDictionaryPageElement { + $: { + keys: IronA11yKeysElement, + newWord: CrInputElement, + }; +} + class OsSettingsEditDictionaryPageElement extends - OsSettingsEditDictionaryPageElementBase { + OsSettingsEditDictionaryPageElementBaseWithBehaviors { static get is() { - return 'os-settings-edit-dictionary-page'; + return 'os-settings-edit-dictionary-page' as const; } static get template() { @@ -60,40 +67,36 @@ static get properties() { return { - /** @private */ newWordValue_: { type: String, value: '', }, + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in GlobalScrollTargetBehavior, and move the default + // value to the field initializer. /** * Needed for GlobalScrollTargetBehavior. - * @type {!Route} - * @override */ subpageRoute: { type: Object, value: routes.OS_LANGUAGES_EDIT_DICTIONARY, }, - /** @private {!Array<string>} */ words_: Array, - /** @private */ hasWords_: { type: Boolean, value: false, computed: 'computeHasWords_(words_.length)', }, - /** @private */ disableAddButton_: { type: Boolean, value: true, computed: 'shouldDisableAddButton_(newWordState_)', }, - /** @private */ newWordState_: { type: Number, value: NewWordState.NO_WORD, @@ -102,22 +105,27 @@ }; } - /** @override */ - constructor() { - super(); + // API proxies. + private languageSettingsPrivate_ = + LanguagesBrowserProxyImpl.getInstance().getLanguageSettingsPrivate(); - this.words_ = []; + // Internal properties for mixins. + // From GlobalScrollTargetBehavior. + // protected override subpageRoute = routes.OS_LANGUAGES_EDIT_DICTIONARY; - /** @private {!LanguageSettingsPrivate} */ - this.languageSettingsPrivate_ = - LanguagesBrowserProxyImpl.getInstance().getLanguageSettingsPrivate(); - } + // Internal state. + private words_: string[] = []; + private newWordValue_: string; - /** @override */ - ready() { + // Computed properties. + private hasWords_: boolean; + private newWordState_: number; + private disableAddButton_: boolean; + + override ready(): void { super.ready(); - this.languageSettingsPrivate_.getSpellcheckWords(words => { + this.languageSettingsPrivate_.getSpellcheckWords().then(words => { this.words_ = words; }); @@ -128,19 +136,14 @@ this.$.keys.target = this.$.newWord; } - /** - * @return {boolean} - * @private - */ - computeHasWords_() { + private computeHasWords_(): boolean { return this.words_.length > 0; } /** * Adds the word in the new-word input to the dictionary. - * @private */ - addWordFromInput_() { + private addWordFromInput_(): void { // Spaces are allowed, but removing leading and trailing whitespace. const word = this.getTrimmedNewWord_(); this.newWordValue_ = ''; @@ -150,19 +153,11 @@ } } - /** - * @return {string} - * @private - */ - getTrimmedNewWord_() { + private getTrimmedNewWord_(): string { return this.newWordValue_.trim(); } - /** - * @return {NewWordState} - * @private - */ - updateNewWordState_() { + private updateNewWordState_(): NewWordState { const trimmedNewWord = this.getTrimmedNewWord_(); if (!trimmedNewWord.length) { return NewWordState.NO_WORD; @@ -176,19 +171,11 @@ return NewWordState.VALID_WORD; } - /** - * @return {boolean} - * @private - */ - shouldDisableAddButton_() { + private shouldDisableAddButton_(): boolean { return this.newWordState_ !== NewWordState.VALID_WORD; } - /** - * @return {string} - * @private - */ - getErrorMessage_() { + private getErrorMessage_(): string { switch (this.newWordState_) { case NewWordState.WORD_TOO_LONG: return this.i18n('addDictionaryWordLengthError'); @@ -199,20 +186,15 @@ } } - /** - * @return {boolean} - * @private - */ - isNewWordInvalid_() { + private isNewWordInvalid_(): boolean { return this.newWordState_ === NewWordState.WORD_TOO_LONG || this.newWordState_ === NewWordState.WORD_ALREADY_ADDED; } /** * Handles tapping on the Add Word button. - * @private */ - onAddWordTap_() { + private onAddWordTap_(): void { this.addWordFromInput_(); this.$.newWord.focus(); } @@ -220,11 +202,8 @@ /** * Handles updates to the word list. Additions are unshifted to the top * of the list so that users can see them easily. - * @param {!Array<string>} added - * @param {!Array<string>} removed - * @private */ - onCustomDictionaryChanged_(added, removed) { + private onCustomDictionaryChanged_(added: string[], removed: string[]): void { for (const word of removed) { const index = this.words_.indexOf(word); if (index !== -1) { @@ -241,23 +220,23 @@ /** * Handles Enter and Escape key presses for the new-word input. - * @param {!CustomEvent<{key: string}>} e - * @private */ - onKeysPress_(e) { + private onKeysPress_( + e: CustomEvent<{key: string, keyboardEvent: KeyboardEvent}>): void { if (e.detail.key === 'enter' && !this.disableAddButton_) { this.addWordFromInput_(); } else if (e.detail.key === 'esc') { - e.detail.keyboardEvent.target.value = ''; + // Safety: This method is only used as an event listener for an + // <iron-a11y-keys> which has its target set to `this.$.newWord` in + // `ready()`, so the target must always be a CrInputElement. + (e.detail.keyboardEvent.target as CrInputElement).value = ''; } } /** * Handles tapping on a "Remove word" icon button. - * @param {{model: {item: string}}} e - * @private */ - onRemoveWordTap_(e) { + private onRemoveWordTap_(e: DomRepeatEvent<string>): void { this.languageSettingsPrivate_.removeSpellcheckWord(e.model.item); recordSettingChange(); } @@ -266,3 +245,10 @@ customElements.define( OsSettingsEditDictionaryPageElement.is, OsSettingsEditDictionaryPageElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsEditDictionaryPageElement.is]: + OsSettingsEditDictionaryPageElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_clear_ime_data_dialog.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_clear_ime_data_dialog.ts similarity index 64% rename from chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_clear_ime_data_dialog.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_clear_ime_data_dialog.ts index 188513d..1410428 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_clear_ime_data_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_clear_ime_data_dialog.ts
@@ -7,14 +7,20 @@ * manage clearing personalized data for the Japanese input decoder. */ +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './os_japanese_clear_ime_data_dialog.html.js'; -/** @polymer */ +interface OsSettingsClearPersonalizedDataDialogElement { + $: { + dialog: CrDialogElement, + }; +} + class OsSettingsClearPersonalizedDataDialogElement extends PolymerElement { static get is() { - return 'os-settings-japanese-clear-ime-data-dialog'; + return 'os-settings-japanese-clear-ime-data-dialog' as const; } static get template() { @@ -25,8 +31,7 @@ return {}; } - /** @private */ - onCancelButtonClick_() { + private onCancelButtonClick_(): void { this.$.dialog.close(); } } @@ -34,3 +39,10 @@ customElements.define( OsSettingsClearPersonalizedDataDialogElement.is, OsSettingsClearPersonalizedDataDialogElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsClearPersonalizedDataDialogElement.is]: + OsSettingsClearPersonalizedDataDialogElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_manage_user_dictionary_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_manage_user_dictionary_page.js deleted file mode 100644 index e48219b5..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_manage_user_dictionary_page.js +++ /dev/null
@@ -1,59 +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. - -/** - * @fileoverview 'os-settings-japanese-manage-user-dictionary-page' is a - * sub-page for editing the dictionary of words used for Japanese input - * methods. - */ - -import '../../settings_shared.css.js'; - -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {Route} from '../router.js'; -import {GlobalScrollTargetBehavior, GlobalScrollTargetBehaviorInterface} from '../global_scroll_target_behavior.js'; -import {routes} from '../os_route.js'; - -import {getTemplate} from './os_japanese_manage_user_dictionary_page.html.js'; - -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - * @implements {GlobalScrollTargetBehaviorInterface} - */ -const OsSettingsJapaneseManageUserDictionaryPageElementBase = - mixinBehaviors([I18nBehavior, GlobalScrollTargetBehavior], PolymerElement); - -/** @polymer */ -class OsSettingsJapaneseManageUserDictionaryPageElement extends - OsSettingsJapaneseManageUserDictionaryPageElementBase { - static get is() { - return 'os-settings-japanese-manage-user-dictionary-page'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /** - * Needed for GlobalScrollTargetBehavior. - * @type {!Route} - * @override - */ - subpageRoute: { - type: Object, - value: routes.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY, - }, - }; - } -} - -customElements.define( - OsSettingsJapaneseManageUserDictionaryPageElement.is, - OsSettingsJapaneseManageUserDictionaryPageElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_manage_user_dictionary_page.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_manage_user_dictionary_page.ts new file mode 100644 index 0000000..5391ec1 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_japanese_manage_user_dictionary_page.ts
@@ -0,0 +1,74 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'os-settings-japanese-manage-user-dictionary-page' is a + * sub-page for editing the dictionary of words used for Japanese input + * methods. + */ + +import '../../settings_shared.css.js'; + +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {GlobalScrollTargetBehavior, GlobalScrollTargetBehaviorInterface} from '../global_scroll_target_behavior.js'; +import {routes} from '../os_route.js'; + +import {getTemplate} from './os_japanese_manage_user_dictionary_page.html.js'; + +// TODO(b/265559727): Remove I18nMixin if `this.i18n` methods are not being used +// by this element. +const OsSettingsJapaneseManageUserDictionaryPageElementBase = + I18nMixin(PolymerElement); + +const OsSettingsJapaneseManageUserDictionaryPageElementBaseWithBehaviors = + mixinBehaviors( + // TODO(b/265559727): Remove GlobalScrollTargetBehavior if it is unused. + [GlobalScrollTargetBehavior], + OsSettingsJapaneseManageUserDictionaryPageElementBase) as + typeof OsSettingsJapaneseManageUserDictionaryPageElementBase & + (new (...args: any[]) => GlobalScrollTargetBehaviorInterface); + +class OsSettingsJapaneseManageUserDictionaryPageElement extends + OsSettingsJapaneseManageUserDictionaryPageElementBaseWithBehaviors { + static get is() { + return 'os-settings-japanese-manage-user-dictionary-page' as const; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in GlobalScrollTargetBehavior, and move the default + // value to the field initializer. + /** + * Needed for GlobalScrollTargetBehavior. + */ + subpageRoute: { + type: Object, + value: routes.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY, + }, + }; + } + + // Internal properties for mixins. + // From GlobalScrollTargetBehavior. + // protected override subpageRoute = + // routes.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY; +} + +customElements.define( + OsSettingsJapaneseManageUserDictionaryPageElement.is, + OsSettingsJapaneseManageUserDictionaryPageElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsJapaneseManageUserDictionaryPageElement.is]: + OsSettingsJapaneseManageUserDictionaryPageElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html index 04458cbf..39c844ab 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html
@@ -199,6 +199,7 @@ </template> <template is="dom-if" if="[[showAddLanguagesDialog_]]" restamp> + <!-- TODO(b/238031866): Change this two-way binding to be one-way. --> <os-settings-add-languages-dialog languages="{{languages}}" language-helper="[[languageHelper]]" on-close="onAddLanguagesDialogClose_">
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.js deleted file mode 100644 index 8f3b7b3..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.js +++ /dev/null
@@ -1,468 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview 'os-settings-languages-page-v2' is the languages sub-page - * for languages and inputs settings. - */ - -import 'chrome://resources/cr_elements/cr_button/cr_button.js'; -import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; -import 'chrome://resources/js/action_link.js'; -import 'chrome://resources/cr_elements/action_link.css.js'; -import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; -import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; -import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; -import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; -import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js'; -import './change_device_language_dialog.js'; -import './os_add_languages_dialog.js'; -import 'chrome://resources/cr_components/localized_link/localized_link.js'; -import '../../controls/settings_toggle_button.js'; -import '../../settings_shared.css.js'; - -import {assert} from 'chrome://resources/ash/common/assert.js'; -import {focusWithoutInk} from 'chrome://resources/ash/common/focus_without_ink_js.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {Setting} from '../../mojom-webui/setting.mojom-webui.js'; -import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js'; -import {recordSettingChange} from '../metrics_recorder.js'; -import {routes} from '../os_route.js'; -import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js'; -import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js'; -import {Route, Router} from '../router.js'; - -import {LanguagesMetricsProxy, LanguagesMetricsProxyImpl, LanguagesPageInteraction} from './languages_metrics_proxy.js'; -import {LanguageHelper, LanguagesModel, LanguageState} from './languages_types.js'; -import {getTemplate} from './os_languages_page_v2.html.js'; - -/** - * @type {number} Millisecond delay that can be used when closing an action - * menu to keep it briefly on-screen so users can see the changes. - */ -const MENU_CLOSE_DELAY = 100; - -/** - * @constructor - * @extends {PolymerElement} - * @implements {DeepLinkingBehaviorInterface} - * @implements {I18nBehaviorInterface} - * @implements {PrefsBehaviorInterface} - * @implements {RouteObserverBehaviorInterface} - */ -const OsSettingsLanguagesPageV2ElementBase = mixinBehaviors( - [DeepLinkingBehavior, I18nBehavior, PrefsBehavior, RouteObserverBehavior], - PolymerElement); - -/** @polymer */ -class OsSettingsLanguagesPageV2Element extends - OsSettingsLanguagesPageV2ElementBase { - static get is() { - return 'os-settings-languages-page-v2'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /** - * Preferences state. - */ - prefs: { - type: Object, - notify: true, - }, - - /** - * Read-only reference to the languages model provided by the - * 'os-settings-languages' instance. - * @type {!LanguagesModel|undefined} - */ - languages: { - type: Object, - notify: true, - }, - - /** @type {!LanguageHelper} */ - languageHelper: Object, - - /** - * The language to display the details for and its index. - * @type {{state: !LanguageState, index: number}|undefined} - * @private - */ - detailLanguage_: Object, - - /** @private */ - showAddLanguagesDialog_: Boolean, - - /** @private */ - showChangeDeviceLanguageDialog_: { - type: Boolean, - value: false, - }, - - /** @private */ - isGuest_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('isGuest'); - }, - }, - - /** @private */ - isSecondaryUser_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('isSecondaryUser'); - }, - }, - - /** @private */ - primaryUserEmail_: { - type: String, - value() { - return loadTimeData.getString('primaryUserEmail'); - }, - }, - - /** - * Used by DeepLinkingBehavior to focus this page's deep links. - * @type {!Set<!Setting>} - */ - supportedSettingIds: { - type: Object, - value: () => new Set([ - Setting.kAddLanguage, - Setting.kChangeDeviceLanguage, - Setting.kOfferTranslation, - ]), - }, - - /** @private */ - languageSettingsV2Update2Enabled_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('enableLanguageSettingsV2Update2'); - }, - }, - }; - } - - /** @override */ - constructor() { - super(); - - /** @private {!LanguagesMetricsProxy} */ - this.languagesMetricsProxy_ = LanguagesMetricsProxyImpl.getInstance(); - } - - /** - * @param {!Route} route - * @param {!Route=} oldRoute - */ - currentRouteChanged(route, oldRoute) { - // Does not apply to this page. - if (route !== routes.OS_LANGUAGES_LANGUAGES) { - return; - } - - this.attemptDeepLink(); - } - - /** - * @param {string} language - * @return {string} - * @private - */ - getLanguageDisplayName_(language) { - return this.languageHelper.getLanguage(language).displayName; - } - - /** @private */ - onChangeDeviceLanguageClick_() { - this.showChangeDeviceLanguageDialog_ = true; - } - - /** @private */ - onChangeDeviceLanguageDialogClose_() { - this.showChangeDeviceLanguageDialog_ = false; - focusWithoutInk( - assert(this.shadowRoot.querySelector('#changeDeviceLanguage'))); - } - - /** - * @param {string} language - * @return {string} - * @private - */ - getChangeDeviceLanguageButtonDescription_(language) { - return this.i18n( - 'changeDeviceLanguageButtonDescription', - this.getLanguageDisplayName_(language)); - } - - /** - * Stamps and opens the Add Languages dialog, registering a listener to - * disable the dialog's dom-if again on close. - * @param {!Event} e - * @private - */ - onAddLanguagesClick_(e) { - e.preventDefault(); - this.languagesMetricsProxy_.recordAddLanguages(); - this.showAddLanguagesDialog_ = true; - } - - /** @private */ - onAddLanguagesDialogClose_() { - this.showAddLanguagesDialog_ = false; - focusWithoutInk(assert(this.$.addLanguages)); - } - - /** - * Checks if there are supported languages that are not enabled but can be - * enabled. - * @param {LanguagesModel|undefined} languages - * @return {boolean} True if there is at least one available language. - * @private - */ - canEnableSomeSupportedLanguage_(languages) { - return languages !== undefined && languages.supported.some(language => { - return this.languageHelper.canEnableLanguage(language); - }); - } - - /** - * @return {boolean} True if the translate checkbox should be disabled. - * @private - */ - disableTranslateCheckbox_() { - if (!this.detailLanguage_ || !this.detailLanguage_.state) { - return true; - } - - const languageState = this.detailLanguage_.state; - if (!languageState.language || !languageState.language.supportsTranslate) { - return true; - } - - if (this.languageHelper.isOnlyTranslateBlockedLanguage(languageState)) { - return true; - } - - return this.languageHelper.convertLanguageCodeForTranslate( - languageState.language.code) === this.languages.translateTarget; - } - - /** - * Handler for changes to the translate checkbox. - * @param {{target: !Element}} e - * @private - */ - onTranslateCheckboxChange_(e) { - if (e.target.checked) { - this.languageHelper.enableTranslateLanguage( - this.detailLanguage_.state.language.code); - } else { - this.languageHelper.disableTranslateLanguage( - this.detailLanguage_.state.language.code); - } - this.languagesMetricsProxy_.recordTranslateCheckboxChanged( - e.target.checked); - recordSettingChange(); - this.closeMenuSoon_(); - } - - /** - * Closes the shared action menu after a short delay, so when a checkbox is - * clicked it can be seen to change state before disappearing. - * @private - */ - closeMenuSoon_() { - const menu = /** @type {!CrActionMenuElement} */ ( - this.shadowRoot.querySelector('#menu').get()); - setTimeout(() => { - if (menu.open) { - menu.close(); - } - }, MENU_CLOSE_DELAY); - } - - /** - * @return {boolean} True if the "Move to top" option for |language| should - * be visible. - * @private - */ - showMoveToTop_() { - // "Move To Top" is a no-op for the top language. - return this.detailLanguage_ !== undefined && - this.detailLanguage_.index === 0; - } - - /** - * @return {boolean} True if the "Move up" option for |language| should - * be visible. - * @private - */ - showMoveUp_() { - // "Move up" is a no-op for the top language, and redundant with - // "Move to top" for the 2nd language. - return this.detailLanguage_ !== undefined && - this.detailLanguage_.index !== 0 && this.detailLanguage_.index !== 1; - } - - /** - * @return {boolean} True if the "Move down" option for |language| should be - * visible. - * @private - */ - showMoveDown_() { - return this.languages !== undefined && this.detailLanguage_ !== undefined && - this.detailLanguage_.index !== this.languages.enabled.length - 1; - } - - /** - * Moves the language to the top of the list. - * @private - */ - onMoveToTopClick_() { - /** @type {!CrActionMenuElement} */ (this.$.menu.get()).close(); - this.languageHelper.moveLanguageToFront( - this.detailLanguage_.state.language.code); - recordSettingChange(); - } - - /** - * Moves the language up in the list. - * @private - */ - onMoveUpClick_() { - /** @type {!CrActionMenuElement} */ (this.$.menu.get()).close(); - this.languageHelper.moveLanguage( - this.detailLanguage_.state.language.code, /*upDirection=*/ true); - recordSettingChange(); - } - - /** - * Moves the language down in the list. - * @private - */ - onMoveDownClick_() { - /** @type {!CrActionMenuElement} */ (this.$.menu.get()).close(); - this.languageHelper.moveLanguage( - this.detailLanguage_.state.language.code, /*upDirection=*/ false); - recordSettingChange(); - } - - /** - * Disables the language. - * @private - */ - onRemoveLanguageClick_() { - /** @type {!CrActionMenuElement} */ (this.$.menu.get()).close(); - this.languageHelper.disableLanguage( - this.detailLanguage_.state.language.code); - recordSettingChange(); - } - - /** - * @param {!Event} e - * @private - */ - onDotsClick_(e) { - // Sets a copy of the LanguageState object since it is not data-bound to - // the languages model directly. - this.detailLanguage_ = - /** @type {{state: !LanguageState, index: number}} */ ({ - state: /** @type {!LanguageState} */ (e.model.item), - index: /** @type {number} */ (e.model.index), - }); - - const menu = /** @type {!CrActionMenuElement} */ (this.$.menu.get()); - menu.showAt(/** @type {!HTMLElement} */ (e.target)); - } - - /** - * @param {!Event} e - * @private - */ - onTranslateToggleChange_(e) { - this.languagesMetricsProxy_.recordToggleTranslate(e.target.checked); - } - - /** - * @param {string} languageCode The language code identifying a language. - * @param {string} translateTarget The translate target language. - * @return {string} class name for whether it's a translate-target or not. - * @private - */ - getTranslationTargetClass_(languageCode, translateTarget) { - return this.languageHelper.convertLanguageCodeForTranslate(languageCode) === - translateTarget ? - 'translate-target' : - 'non-translate-target'; - } - - /** - * @param {boolean} update2Enabled - * @return {string} - * @private - */ - getOfferTranslationLabel_(update2Enabled) { - return this.i18n( - update2Enabled ? 'offerGoogleTranslateLabel' : 'offerTranslationLabel'); - } - - /** - * @param {boolean} update2Enabled - * @return {string} - * @private - */ - getOfferTranslationSublabel_(update2Enabled) { - return update2Enabled ? '' : this.i18n('offerTranslationSublabel'); - } - - /** - * @param {boolean} update2Enabled - * @return {string} - * @private - */ - getLanguagePreferenceTitle_(update2Enabled) { - return this.i18n( - update2Enabled ? 'websiteLanguagesTitle' : 'languagesPreferenceTitle'); - } - - /** - * @param {boolean} update2Enabled - * @return {string} - * @private - */ - getLanguagePreferenceDescription_(update2Enabled) { - return this.i18nAdvanced( - update2Enabled ? 'websiteLanguagesDescription' : - 'languagesPreferenceDescription'); - } - - /** @private */ - openManageGoogleAccountLanguage_() { - this.languagesMetricsProxy_.recordInteraction( - LanguagesPageInteraction.OPEN_MANAGE_GOOGLE_ACCOUNT_LANGUAGE); - window.open(loadTimeData.getString('googleAccountLanguagesURL')); - } - - /** @private */ - onLanguagePreferenceDescriptionLinkClick_() { - this.languagesMetricsProxy_.recordInteraction( - LanguagesPageInteraction.OPEN_WEB_LANGUAGES_LEARN_MORE); - } -} - -customElements.define( - OsSettingsLanguagesPageV2Element.is, OsSettingsLanguagesPageV2Element);
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.ts new file mode 100644 index 0000000..5adc374d --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.ts
@@ -0,0 +1,468 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'os-settings-languages-page-v2' is the languages sub-page + * for languages and inputs settings. + */ + +import 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; +import 'chrome://resources/js/action_link.js'; +import 'chrome://resources/cr_elements/action_link.css.js'; +import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; +import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; +import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; +import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; +import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js'; +import './change_device_language_dialog.js'; +import './os_add_languages_dialog.js'; +import 'chrome://resources/cr_components/localized_link/localized_link.js'; +import '../../controls/settings_toggle_button.js'; +import '../../settings_shared.css.js'; + +import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; +import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; +import {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {SettingsToggleButtonElement} from '../../controls/settings_toggle_button.js'; +import {Setting} from '../../mojom-webui/setting.mojom-webui.js'; +import {PrefsMixin} from '../../prefs/prefs_mixin.js'; +import {castExists} from '../assert_extras.js'; +import {DeepLinkingMixin} from '../deep_linking_mixin.js'; +import {recordSettingChange} from '../metrics_recorder.js'; +import {routes} from '../os_route.js'; +import {RouteObserverMixin} from '../route_observer_mixin.js'; +import {Route} from '../router.js'; + +import {LanguagesMetricsProxyImpl, LanguagesPageInteraction} from './languages_metrics_proxy.js'; +import {LanguageHelper, LanguagesModel, LanguageState} from './languages_types.js'; +import {getTemplate} from './os_languages_page_v2.html.js'; + +/** + * Millisecond delay that can be used when closing an action menu to keep it + * briefly on-screen so users can see the changes. + */ +const MENU_CLOSE_DELAY = 100; + +const OsSettingsLanguagesPageV2ElementBase = + RouteObserverMixin(PrefsMixin(I18nMixin(DeepLinkingMixin(PolymerElement)))); + +interface OsSettingsLanguagesPageV2Element { + $: { + addLanguages: CrButtonElement, + menu: CrLazyRenderElement<CrActionMenuElement>, + }; +} + +class OsSettingsLanguagesPageV2Element extends + OsSettingsLanguagesPageV2ElementBase { + static get is() { + return 'os-settings-languages-page-v2' as const; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in PrefsMixin. + /** + * Preferences state. + */ + prefs: { + type: Object, + notify: true, + }, + + /** + * Read-only reference to the languages model provided by the + * 'os-settings-languages' instance. + */ + languages: { + type: Object, + notify: true, + }, + + languageHelper: Object, + + /** + * The language to display the details for and its index. + */ + detailLanguage_: Object, + + showAddLanguagesDialog_: Boolean, + + showChangeDeviceLanguageDialog_: { + type: Boolean, + value: false, + }, + + isGuest_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('isGuest'); + }, + }, + + isSecondaryUser_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('isSecondaryUser'); + }, + }, + + primaryUserEmail_: { + type: String, + value() { + return loadTimeData.getString('primaryUserEmail'); + }, + }, + + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in DeepLinkingMixin, and move the default value to + // the field initializer. + /** + * Used by DeepLinkingMixin to focus this page's deep links. + */ + supportedSettingIds: { + type: Object, + value: () => new Set([ + Setting.kAddLanguage, + Setting.kChangeDeviceLanguage, + Setting.kOfferTranslation, + ]), + }, + + languageSettingsV2Update2Enabled_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('enableLanguageSettingsV2Update2'); + }, + }, + }; + } + + // Public API: Bidirectional data flow. + // override prefs: any; // From PrefsMixin. + + // Public API: Downwards data flow. + languages: LanguagesModel|undefined; + languageHelper: LanguageHelper; + + // API proxies. + private languagesMetricsProxy_ = LanguagesMetricsProxyImpl.getInstance(); + + // Internal properties for mixins. + // From DeepLinkingMixin. + // override supportedSettingIds = new Set([ + // Setting.kAddLanguage, + // Setting.kChangeDeviceLanguage, + // Setting.kOfferTranslation, + // ]); + + // Internal state. + private detailLanguage_?: {state: LanguageState, index: number}; + // This property does not have a default value in `static get properties()`. + // TODO(b/265556480): Update the initial value to be false. + private showAddLanguagesDialog_: boolean; + private showChangeDeviceLanguageDialog_: boolean; + + // loadTimeData flags and strings. + private isGuest_: boolean; + private isSecondaryUser_: boolean; + private primaryUserEmail_: string; + private languageSettingsV2Update2Enabled_: boolean; + + override currentRouteChanged(route: Route): void { + // Does not apply to this page. + if (route !== routes.OS_LANGUAGES_LANGUAGES) { + return; + } + + this.attemptDeepLink(); + } + + private getLanguageDisplayName_(language: string): string { + // This `getLanguage` assertion is potentially unsafe and could fail. + // TODO(b/265554088): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. + return this.languageHelper.getLanguage(language)!.displayName; + } + + private onChangeDeviceLanguageClick_(): void { + this.showChangeDeviceLanguageDialog_ = true; + } + + private onChangeDeviceLanguageDialogClose_(): void { + this.showChangeDeviceLanguageDialog_ = false; + focusWithoutInk( + // Safety: This method is only called when the change device + // language dialog is closed, but that can only be opened if + // #changeDeviceLanguage was clicked. + castExists(this.shadowRoot!.querySelector('#changeDeviceLanguage'))); + } + + private getChangeDeviceLanguageButtonDescription_(language: string): string { + return this.i18n( + 'changeDeviceLanguageButtonDescription', + this.getLanguageDisplayName_(language)); + } + + /** + * Stamps and opens the Add Languages dialog, registering a listener to + * disable the dialog's dom-if again on close. + */ + private onAddLanguagesClick_(e: Event): void { + e.preventDefault(); + this.languagesMetricsProxy_.recordAddLanguages(); + this.showAddLanguagesDialog_ = true; + } + + private onAddLanguagesDialogClose_(): void { + this.showAddLanguagesDialog_ = false; + focusWithoutInk(this.$.addLanguages); + } + + /** + * Checks if there are supported languages that are not enabled but can be + * enabled. + * @return True if there is at least one available language. + */ + private canEnableSomeSupportedLanguage_(languages: LanguagesModel| + undefined): boolean { + return languages !== undefined && languages.supported.some(language => { + return this.languageHelper.canEnableLanguage(language); + }); + } + + /** + * @return True if the translate checkbox should be disabled. + */ + private disableTranslateCheckbox_(): boolean { + if (!this.detailLanguage_ || !this.detailLanguage_.state) { + return true; + } + + const languageState = this.detailLanguage_.state; + if (!languageState.language || !languageState.language.supportsTranslate) { + return true; + } + + if (this.languageHelper.isOnlyTranslateBlockedLanguage(languageState)) { + return true; + } + + // This assertion of `this.languages` is potentially unsafe and could fail. + // TODO(b/265553377): Prove that this assertion is safe, or rewrite this to + // avoid this assertion. + return this.languageHelper.convertLanguageCodeForTranslate( + languageState.language.code) === this.languages!.translateTarget; + } + + /** + * Handler for changes to the translate checkbox. + */ + private onTranslateCheckboxChange_(e: CustomEvent<boolean>): void { + // Safety: This method is only called from a 'change' event from a + // <cr-checkbox>, so the event target must be a <cr-checkbox>. + if ((e.target! as CrCheckboxElement).checked) { + this.languageHelper.enableTranslateLanguage( + // Safety: This method is only called from the action menu, which only + // appears when `onDotsClick_()` is called, so `this.detailLanguage_` + // should always be defined here. + this.detailLanguage_!.state.language.code); + } else { + this.languageHelper.disableTranslateLanguage( + // Safety: This method is only called from the action menu, which only + // appears when `onDotsClick_()` is called, so `this.detailLanguage_` + // should always be defined here. + this.detailLanguage_!.state.language.code); + } + this.languagesMetricsProxy_.recordTranslateCheckboxChanged( + // Safety: This method is only called from a 'change' event from a + // <cr-checkbox>, so the event target must be a <cr-checkbox>. + (e.target! as CrCheckboxElement).checked); + recordSettingChange(); + this.closeMenuSoon_(); + } + + /** + * Closes the shared action menu after a short delay, so when a checkbox is + * clicked it can be seen to change state before disappearing. + */ + private closeMenuSoon_(): void { + const menu = this.$.menu.get(); + setTimeout(() => { + if (menu.open) { + menu.close(); + } + }, MENU_CLOSE_DELAY); + } + + /** + * @return True if the "Move to top" option for |language| should be visible. + */ + private showMoveToTop_(): boolean { + // "Move To Top" is a no-op for the top language. + return this.detailLanguage_ !== undefined && + this.detailLanguage_.index === 0; + } + + /** + * @return True if the "Move up" option for |language| should be visible. + */ + private showMoveUp_(): boolean { + // "Move up" is a no-op for the top language, and redundant with + // "Move to top" for the 2nd language. + return this.detailLanguage_ !== undefined && + this.detailLanguage_.index !== 0 && this.detailLanguage_.index !== 1; + } + + /** + * @return True if the "Move down" option for |language| should be visible. + */ + private showMoveDown_(): boolean { + return this.languages !== undefined && this.detailLanguage_ !== undefined && + this.detailLanguage_.index !== this.languages.enabled.length - 1; + } + + /** + * Moves the language to the top of the list. + */ + private onMoveToTopClick_(): void { + this.$.menu.get().close(); + this.languageHelper.moveLanguageToFront( + // Safety: This method is only called from the action menu, which only + // appears when `onDotsClick_()` is called, so `this.detailLanguage_` + // should always be defined here. + this.detailLanguage_!.state.language.code); + recordSettingChange(); + } + + /** + * Moves the language up in the list. + */ + private onMoveUpClick_(): void { + this.$.menu.get().close(); + this.languageHelper.moveLanguage( + // Safety: This method is only called from the action menu, which only + // appears when `onDotsClick_()` is called, so `this.detailLanguage_` + // should always be defined here. + this.detailLanguage_!.state.language.code, + /*upDirection=*/ true); + recordSettingChange(); + } + + /** + * Moves the language down in the list. + */ + private onMoveDownClick_(): void { + this.$.menu.get().close(); + this.languageHelper.moveLanguage( + // Safety: This method is only called from the action menu, which only + // appears when `onDotsClick_()` is called, so `this.detailLanguage_` + // should always be defined here. + this.detailLanguage_!.state.language.code, + /*upDirection=*/ false); + recordSettingChange(); + } + + /** + * Disables the language. + */ + private onRemoveLanguageClick_(): void { + this.$.menu.get().close(); + this.languageHelper.disableLanguage( + // Safety: This method is only called from the action menu, which only + // appears when `onDotsClick_()` is called, so `this.detailLanguage_` + // should always be defined here. + this.detailLanguage_!.state.language.code); + recordSettingChange(); + } + + private onDotsClick_(e: DomRepeatEvent<LanguageState>): void { + // Sets a copy of the LanguageState object since it is not data-bound to + // the languages model directly. + this.detailLanguage_ = { + state: e.model.item, + index: e.model.index, + }; + + const menu = this.$.menu.get(); + // Safety: This event comes from the DOM, so the target should always be an + // element. + menu.showAt(e.target as HTMLElement); + } + + private onTranslateToggleChange_(e: CustomEvent<unknown>): void { + this.languagesMetricsProxy_.recordToggleTranslate( + // Safety: This method is only called from a + // 'settings-boolean-control-changed' event from a + // <settings-toggle-button>, so the event target must be a + // <settings-toggle-button>. + (e.target as SettingsToggleButtonElement).checked); + } + + /** + * @param languageCode The language code identifying a language. + * @param translateTarget The translate target language. + * @return class name for whether it's a translate-target or not. + */ + private getTranslationTargetClass_( + languageCode: string, translateTarget: string): string { + return this.languageHelper.convertLanguageCodeForTranslate(languageCode) === + translateTarget ? + 'translate-target' : + 'non-translate-target'; + } + + private getOfferTranslationLabel_(update2Enabled: boolean): string { + return this.i18n( + update2Enabled ? 'offerGoogleTranslateLabel' : 'offerTranslationLabel'); + } + + private getOfferTranslationSublabel_(update2Enabled: boolean): string { + return update2Enabled ? '' : this.i18n('offerTranslationSublabel'); + } + + private getLanguagePreferenceTitle_(update2Enabled: boolean): string { + return this.i18n( + update2Enabled ? 'websiteLanguagesTitle' : 'languagesPreferenceTitle'); + } + + private getLanguagePreferenceDescription_(update2Enabled: boolean): + TrustedHTML { + return this.i18nAdvanced( + update2Enabled ? 'websiteLanguagesDescription' : + 'languagesPreferenceDescription'); + } + + private openManageGoogleAccountLanguage_(): void { + this.languagesMetricsProxy_.recordInteraction( + LanguagesPageInteraction.OPEN_MANAGE_GOOGLE_ACCOUNT_LANGUAGE); + window.open(loadTimeData.getString('googleAccountLanguagesURL')); + } + + private onLanguagePreferenceDescriptionLinkClick_(): void { + this.languagesMetricsProxy_.recordInteraction( + LanguagesPageInteraction.OPEN_WEB_LANGUAGES_LEARN_MORE); + } +} + +customElements.define( + OsSettingsLanguagesPageV2Element.is, OsSettingsLanguagesPageV2Element); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsLanguagesPageV2Element.is]: OsSettingsLanguagesPageV2Element; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.ts similarity index 66% rename from chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.js rename to chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.ts index cea7449..9985336 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.ts
@@ -21,10 +21,11 @@ import '../../settings_shared.css.js'; import '../../settings_vars.css.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {FocusConfig} from '../../focus_config.js'; import {routes} from '../os_route.js'; import {Router} from '../router.js'; @@ -32,23 +33,15 @@ import {getTemplate} from './os_languages_section.html.js'; // The IME ID for the Accessibility Common extension used by Dictation. -/** @type {string} */ const ACCESSIBILITY_COMMON_IME_ID = '_ext_ime_egfdjlfmgnehecnclamagfafdccgfndpdictation'; -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const OsSettingsLanguagesSectionElementBase = - mixinBehaviors([I18nBehavior], PolymerElement); +const OsSettingsLanguagesSectionElementBase = I18nMixin(PolymerElement); -/** @polymer */ class OsSettingsLanguagesSectionElement extends OsSettingsLanguagesSectionElementBase { static get is() { - return 'os-settings-languages-section'; + return 'os-settings-languages-section' as const; } static get template() { @@ -59,16 +52,13 @@ return { prefs: Object, - /** @type {!LanguagesModel|undefined} */ languages: { type: Object, notify: true, }, - /** @type {!LanguageHelper} */ languageHelper: Object, - /** @private {!Map<string, string>} */ focusConfig_: { type: Object, value() { @@ -82,10 +72,9 @@ }, }, - /** @private */ inputPageTitle_: { type: String, - value() { + value(this: OsSettingsLanguagesSectionElement): string { const isUpdate2 = loadTimeData.getBoolean('enableLanguageSettingsV2Update2'); return this.i18n(isUpdate2 ? 'inputPageTitleV2' : 'inputPageTitle'); @@ -94,8 +83,7 @@ /** * This is enabled when any of the smart inputs features is allowed. - * @private - * */ + */ smartInputsEnabled_: { type: Boolean, value() { @@ -107,28 +95,39 @@ }; } - /** @private */ - onLanguagesV2Click_() { + // Public API: Bidirectional data flow. + /** Passed down to children. Do not access without using PrefsMixin. */ + prefs: unknown; + + // Internal state. + private languages: LanguagesModel|undefined; + // Only defined after a render. + private languageHelper: LanguageHelper; + private focusConfig_: FocusConfig; + + // loadTimeData flags and strings. + private inputPageTitle_: string; + private smartInputsEnabled_: boolean; + + private onLanguagesV2Click_(): void { Router.getInstance().navigateTo(routes.OS_LANGUAGES_LANGUAGES); } - /** @private */ - onInputClick_() { + private onInputClick_(): void { Router.getInstance().navigateTo(routes.OS_LANGUAGES_INPUT); } - /** @private */ - onSmartInputsClick_() { + private onSmartInputsClick_(): void { Router.getInstance().navigateTo(routes.OS_LANGUAGES_SMART_INPUTS); } /** - * @param {string|undefined} code The language code of the language. - * @param {!LanguageHelper} languageHelper The LanguageHelper object. - * @return {string} The display name of the language specified. - * @private + * @param code The language code of the language. + * @param languageHelper The LanguageHelper object. + * @return The display name of the language specified. */ - getLanguageDisplayName_(code, languageHelper) { + private getLanguageDisplayName_( + code: string|undefined, languageHelper: LanguageHelper): string { if (!code) { return ''; } @@ -140,12 +139,12 @@ } /** - * @param {string|undefined} id The input method ID. - * @param {!LanguageHelper} languageHelper The LanguageHelper object. - * @return {string} The display name of the input method. - * @private + * @param id The input method ID. + * @param languageHelper The LanguageHelper object. + * @return The display name of the input method. */ - getInputMethodDisplayName_(id, languageHelper) { + private getInputMethodDisplayName_( + id: string|undefined, languageHelper: LanguageHelper): string { if (id === undefined) { return ''; } @@ -160,3 +159,9 @@ customElements.define( OsSettingsLanguagesSectionElement.is, OsSettingsLanguagesSectionElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsLanguagesSectionElement.is]: OsSettingsLanguagesSectionElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.js deleted file mode 100644 index 3934e5e..0000000 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.js +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview 'os-settings-smart-inputs-page' is the settings sub-page - * to provide users with assistive or expressive input options. - */ - -import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js'; -import '../../controls/settings_toggle_button.js'; -import '../../settings_shared.css.js'; - -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {Setting} from '../../mojom-webui/setting.mojom-webui.js'; -import {DeepLinkingBehavior, DeepLinkingBehaviorInterface} from '../deep_linking_behavior.js'; -import {routes} from '../os_route.js'; -import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js'; -import {RouteObserverBehavior, RouteObserverBehaviorInterface} from '../route_observer_behavior.js'; -import {Route} from '../router.js'; - -import {getTemplate} from './smart_inputs_page.html.js'; - -/** - * @constructor - * @extends {PolymerElement} - * @implements {DeepLinkingBehaviorInterface} - * @implements {I18nBehaviorInterface} - * @implements {PrefsBehaviorInterface} - * @implements {RouteObserverBehaviorInterface} - */ -const OsSettingsSmartInputsPageElementBase = mixinBehaviors( - [DeepLinkingBehavior, I18nBehavior, PrefsBehavior, RouteObserverBehavior], - PolymerElement); - -/** @polymer */ -class OsSettingsSmartInputsPageElement extends - OsSettingsSmartInputsPageElementBase { - static get is() { - return 'os-settings-smart-inputs-page'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /** Preferences state. */ - prefs: { - type: Object, - notify: true, - }, - - /** @private */ - allowAssistivePersonalInfo_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('allowAssistivePersonalInfo'); - }, - }, - - /** @private */ - allowEmojiSuggestion_: { - type: Boolean, - value() { - return loadTimeData.getBoolean('allowEmojiSuggestion'); - }, - }, - - /** - * Used by DeepLinkingBehavior to focus this page's deep links. - * @type {!Set<!Setting>} - */ - supportedSettingIds: { - type: Object, - value: () => new Set([ - Setting.kShowPersonalInformationSuggestions, - Setting.kShowEmojiSuggestions, - ]), - }, - }; - } - - /** - * @param {!Route} route - * @param {!Route=} oldRoute - */ - currentRouteChanged(route, oldRoute) { - // Does not apply to this page. - if (route !== routes.OS_LANGUAGES_SMART_INPUTS) { - return; - } - - this.attemptDeepLink(); - } - - /** - * Opens Chrome browser's autofill manage addresses setting page. - * @private - */ - onManagePersonalInfoClick_() { - window.open('chrome://settings/addresses'); - } - - /** - * @param {!Event} e - * @private - */ - onPersonalInfoSuggestionToggled_(e) { - this.setPrefValue( - 'assistive_input.personal_info_enabled', e.target.checked); - } -} - -customElements.define( - OsSettingsSmartInputsPageElement.is, OsSettingsSmartInputsPageElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.ts b/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.ts new file mode 100644 index 0000000..b3862b8 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.ts
@@ -0,0 +1,125 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'os-settings-smart-inputs-page' is the settings sub-page + * to provide users with assistive or expressive input options. + */ + +import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js'; +import '../../controls/settings_toggle_button.js'; +import '../../settings_shared.css.js'; + +import {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {Setting} from '../../mojom-webui/setting.mojom-webui.js'; +import {PrefsMixin} from '../../prefs/prefs_mixin.js'; +import {DeepLinkingMixin} from '../deep_linking_mixin.js'; +import {routes} from '../os_route.js'; +import {RouteObserverMixin} from '../route_observer_mixin.js'; +import {Route} from '../router.js'; + +import {getTemplate} from './smart_inputs_page.html.js'; + +const OsSettingsSmartInputsPageElementBase = + RouteObserverMixin(PrefsMixin(I18nMixin(DeepLinkingMixin(PolymerElement)))); + +class OsSettingsSmartInputsPageElement extends + OsSettingsSmartInputsPageElementBase { + static get is() { + return 'os-settings-smart-inputs-page' as const; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + // TODO(b/265554350): Remove this property from properties() as it is + // already specified in PrefsMixin. + /** Preferences state. */ + prefs: { + type: Object, + notify: true, + }, + + allowAssistivePersonalInfo_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('allowAssistivePersonalInfo'); + }, + }, + + allowEmojiSuggestion_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('allowEmojiSuggestion'); + }, + }, + + /** + * Used by DeepLinkingMixin to focus this page's deep links. + */ + supportedSettingIds: { + type: Object, + value: () => new Set([ + Setting.kShowPersonalInformationSuggestions, + Setting.kShowEmojiSuggestions, + ]), + }, + }; + } + + // Public API: Bidirectional data flow. + // override prefs: any; // From PrefsMixin. + + // Internal properties for mixins. + // From DeepLinkingMixin. + // override supportedSettingIds = new Set([ + // Setting.kShowPersonalInformationSuggestions, + // Setting.kShowEmojiSuggestions, + // ]); + + // loadTimeData flags. + private allowAssistivePersonalInfo_: boolean; + private allowEmojiSuggestion_: boolean; + + override currentRouteChanged(route: Route): void { + // Does not apply to this page. + if (route !== routes.OS_LANGUAGES_SMART_INPUTS) { + return; + } + + this.attemptDeepLink(); + } + + /** + * Opens Chrome browser's autofill manage addresses setting page. + */ + private onManagePersonalInfoClick_(): void { + window.open('chrome://settings/addresses'); + } + + // 'change' event listener on a <cr-toggle>. + private onPersonalInfoSuggestionToggled_(e: CustomEvent<boolean>): void { + // Safety: This method is only called from a 'change' event from a + // <cr-checkbox>, so the event target must be a <cr-checkbox>. + this.setPrefValue( + 'assistive_input.personal_info_enabled', + (e.target! as CrCheckboxElement).checked); + } +} + +customElements.define( + OsSettingsSmartInputsPageElement.is, OsSettingsSmartInputsPageElement); + +declare global { + interface HTMLElementTagNameMap { + [OsSettingsSmartInputsPageElement.is]: OsSettingsSmartInputsPageElement; + } +}
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/tools/.style.yapf b/chrome/browser/resources/settings/chromeos/os_languages_page/tools/.style.yapf new file mode 100644 index 0000000..557fa7b --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/tools/.style.yapf
@@ -0,0 +1,2 @@ +[style] +based_on_style = pep8
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/tools/editor_tsconfig.py b/chrome/browser/resources/settings/chromeos/os_languages_page/tools/editor_tsconfig.py new file mode 100755 index 0000000..900f060 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/tools/editor_tsconfig.py
@@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Script for generating tsconfig.json files for editors during development. + +WARNING: This script is NOT supported by the WebUI team. This script may break +at any time due to changes to the build system. Use at your own risk. + +Before using this script, please consider using +ash/webui/personalization_app/tools/gen_tsconfig.py, as it is more maintained. +Unlike gen_tsconfig.py, editor_tsconfig.py tries to mimic the tsconfig used for +the build as much as possible. +Unfortunately, this also means that this script needs to be re-run every time +that files are added or removed from the ts_library() to keep it in sync. + +This script parses a tsconfig.json file built by a ts_library() GN rule, and +rewrites paths to point to source files instead of files generated by +preprocess_if_expr(). As a result, the resulting tsconfig.json might result in +different behaviour compared to the build process, as if expressions such as +<if expr="is_win"> are not evaluated. + +Files that are completely generated by the build process, such as those +generated by html_to_wrapper() and css_to_wrapper(), will not be affected by the +"generated-file-to-source" path rewrite. Files that are listed in deps or +definitions are also unaffected, so this script will need to be run for every +ts_library() you are working on. + +This script will need to be re-run whenever the ts_library()'s tsconfig.json is +updated, such as when files are added or removed to the build rule. + +When using the generated tsconfig.json for editor purposes, editors might +prioritise symbols from lazy_load.ts when symbols are automatically imported, +instead of the file where the symbols are defined. To mitigate this, an option +is provided to remove lazy_load.ts from the resulting tsconfig.json. + + +Example invocations: +$ ./chrome/browser/resources/settings/chromeos/os_languages_page/tools/\ +editor_tsconfig.py \ +--remove_lazy_load \ +./out/Debug/gen/chrome/browser/resources/settings/tsconfig_build_ts.json +$ ./chrome/browser/resources/settings/chromeos/os_languages_page/tools/\ +editor_tsconfig.py \ +--root_dir=".." \ +--remove_lazy_load \ +./out/Debug/gen/chrome/browser/resources/settings/chromeos/\ +tsconfig_build_ts.json +$ ./chrome/browser/resources/settings/chromeos/os_languages_page/tools/\ +editor_tsconfig.py \ +./out/Debug/gen/ui/webui/resources/cr_components/most_visited/\ +tsconfig_build_ts.json +""" + +import argparse +import json +import os.path +import pathlib +import sys +from typing import Dict, List + +_HERE_DIR = pathlib.Path(__file__).parent +_SRC_DIR = _HERE_DIR.parent.parent.parent.parent.parent.parent.parent + + +def _relative_to_with_parents(path: pathlib.Path, other: pathlib.Path) -> str: + """Gets 'path' relative to 'other', adding '..'s if needed.""" + # This '.' is required, as tsc seems to not understand relative paths + # without it. + parts: List[str] = ['.'] + while not path.is_relative_to(other): + if other == other.parent: + raise ValueError(f'path ({path}) and other ({other}) do not share' + ' any parents') + other = other.parent + parts.append('..') + parts.append(str(path.relative_to(other))) + return os.path.join(*parts) + + +def _rebase_relative_path( + path: str, + originally_relative_to: pathlib.Path, + newly_relative_to: pathlib.Path, +) -> str: + original_path = originally_relative_to.joinpath(path).resolve() + return _relative_to_with_parents(original_path, newly_relative_to) + + +def _convert_tsconfig_for_editor( + tsconfig: dict, + original_dir: pathlib.Path, + editor_dir: pathlib.Path, + editor_root_dir: str, + remove_lazy_load: bool, +) -> dict: + original_dir = original_dir.resolve() + editor_dir = editor_dir.resolve() + + compiler_options = tsconfig['compilerOptions'] + original_root_dir: str = compiler_options['rootDir'] + paths: Dict[str, List[str]] = compiler_options['paths'] + files: List[str] = tsconfig['files'] + + editor_files: List[str] = [] + # editor_files tries to use original source files if possible, but falls + # back to using generated files if needed. We don't add _both_ source and + # generated, as TypeScript sometimes gets confused with two identical + # definitions of the same thing. Notably, it dislikes repeated definitions + # of the same key, but different values, in HTMLElementTagNameMap. + for file in files: + file_path = pathlib.Path(file) + if remove_lazy_load and file_path.stem == 'lazy_load': + continue + if file_path.is_relative_to(original_root_dir): + relative_path = file_path.relative_to(original_root_dir) + source_path = editor_dir.joinpath(editor_root_dir, + relative_path).resolve() + if source_path.is_file(): + editor_files.append( + _relative_to_with_parents(source_path, editor_dir)) + continue + + # This file is generated, or is not under the root directory. + # Add it as-is. + editor_files.append( + _rebase_relative_path(file, original_dir, editor_dir)) + + # As of Python 3.7, dicts are guaranteed to be ordered: + # https://mail.python.org/pipermail/python-dev/2017-December/151283.html + # Note that dicts are already ordered in CPython 3.6 - Python 3.7 ensures it + # as part of the language spec so other implementations should also have + # ordered dicts. + editor_tsconfig = { + **({ + 'extends': + _rebase_relative_path(tsconfig['extends'], original_dir, editor_dir) + } if 'extends' in tsconfig else {}), + 'compilerOptions': { + 'rootDirs': [ + editor_root_dir, + _rebase_relative_path(original_root_dir, original_dir, + editor_dir), + ], + 'noEmit': + True, + 'paths': { + path: [ + _rebase_relative_path(mapping, original_dir, editor_dir) + for mapping in mappings + ] + for path, mappings in paths.items() + } + }, + 'files': + editor_files, + **({ + 'references': [{ + 'path': + _rebase_relative_path( + reference['path'], + original_dir, + editor_dir, + ) + } for reference in tsconfig['references']] + } if 'references' in tsconfig else {}), + } + return editor_tsconfig + + +def main(argv: List[str]) -> None: + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument( + 'original_tsconfig', + type=pathlib.Path, + help= + 'path to tsconfig.json generated by ts_library in the out directory', + ) + parser.add_argument( + '--root_dir', + help=( + 'relative path to the root directory of source files specified in ' + 'tsconfig.json (default: \'.\')'), + default='.', + ) + parser.add_argument( + '--remove_lazy_load', + action=argparse.BooleanOptionalAction, + help=('removes all files named lazy_load from the tsconfig to prevent ' + 'automatic imports prioritising it'), + default=False, + ) + args = parser.parse_args(argv) + original_tsconfig: pathlib.Path = args.original_tsconfig.resolve( + strict=True) + editor_root_dir: str = args.root_dir + remove_lazy_load: bool = args.remove_lazy_load + + # ts_library.gni always generates a tsconfig to + # '$target_gen_dir/tsconfig_$target_name.json' as of writing. + if not (original_tsconfig.stem.startswith('tsconfig_') + and original_tsconfig.suffix == '.json'): + raise ValueError(f'original_tsconfig ({original_tsconfig}) is not' + ' named tsconfig_$target_name.json') + + # Figure out where the target tsconfig should go, using the /gen/ part of + # the supplied. + gen_dir = original_tsconfig + while gen_dir.name != "gen": + if gen_dir == gen_dir.parent: + raise ValueError(f'original_tsconfig ({original_tsconfig}) does' + ' not have a parent "gen" directory') + gen_dir = gen_dir.parent + + original_tsconfig_dir = original_tsconfig.parent + # Directory relative to _SRC_DIR where the original BUILD.gn should be in. + relative_tsconfig_dir = original_tsconfig_dir.relative_to(gen_dir) + new_tsconfig_dir = _SRC_DIR.joinpath(relative_tsconfig_dir) + + with original_tsconfig.open('r', encoding='utf-8') as f: + original_tsconfig_obj = json.load(f) + + new_tsconfig_obj = _convert_tsconfig_for_editor( + original_tsconfig_obj, + original_tsconfig_dir, + new_tsconfig_dir, + editor_root_dir, + remove_lazy_load, + ) + + new_tsconfig = new_tsconfig_dir.joinpath('tsconfig.json') + with new_tsconfig.open('w', encoding='utf-8') as f: + json.dump(new_tsconfig_obj, f, indent=2) + + +if __name__ == '__main__': + main(sys.argv[1:])
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni index 1c458ca..62077f1 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.gni +++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -9,6 +9,8 @@ "//tools/typescript/definitions/bluetooth.d.ts", "//tools/typescript/definitions/bluetooth_private.d.ts", "//tools/typescript/definitions/chrome_send.d.ts", + "//tools/typescript/definitions/input_method_private.d.ts", + "//tools/typescript/definitions/language_settings_private.d.ts", "//tools/typescript/definitions/metrics_private.d.ts", "//tools/typescript/definitions/pending.d.ts", "//tools/typescript/definitions/quick_unlock_private.d.ts", @@ -166,20 +168,20 @@ "chromeos/os_files_page/office_page.ts", "chromeos/os_files_page/os_files_page.ts", "chromeos/os_files_page/smb_shares_page.ts", - "chromeos/os_languages_page/add_input_methods_dialog.js", - "chromeos/os_languages_page/add_items_dialog.js", - "chromeos/os_languages_page/add_spellcheck_languages_dialog.js", - "chromeos/os_languages_page/change_device_language_dialog.js", - "chromeos/os_languages_page/cr_checkbox_with_policy.js", - "chromeos/os_languages_page/input_method_options_page.js", - "chromeos/os_languages_page/input_page.js", - "chromeos/os_languages_page/os_add_languages_dialog.js", - "chromeos/os_languages_page/os_edit_dictionary_page.js", - "chromeos/os_languages_page/os_japanese_clear_ime_data_dialog.js", - "chromeos/os_languages_page/os_japanese_manage_user_dictionary_page.js", - "chromeos/os_languages_page/os_languages_page_v2.js", - "chromeos/os_languages_page/os_languages_section.js", - "chromeos/os_languages_page/smart_inputs_page.js", + "chromeos/os_languages_page/add_input_methods_dialog.ts", + "chromeos/os_languages_page/add_items_dialog.ts", + "chromeos/os_languages_page/add_spellcheck_languages_dialog.ts", + "chromeos/os_languages_page/change_device_language_dialog.ts", + "chromeos/os_languages_page/cr_checkbox_with_policy.ts", + "chromeos/os_languages_page/input_method_options_page.ts", + "chromeos/os_languages_page/input_page.ts", + "chromeos/os_languages_page/os_add_languages_dialog.ts", + "chromeos/os_languages_page/os_edit_dictionary_page.ts", + "chromeos/os_languages_page/os_japanese_clear_ime_data_dialog.ts", + "chromeos/os_languages_page/os_japanese_manage_user_dictionary_page.ts", + "chromeos/os_languages_page/os_languages_page_v2.ts", + "chromeos/os_languages_page/os_languages_section.ts", + "chromeos/os_languages_page/smart_inputs_page.ts", "chromeos/os_people_page/account_manager.js", "chromeos/os_people_page/fingerprint_list.js", "chromeos/os_people_page/local_data_recovery_dialog.js", @@ -361,13 +363,13 @@ "chromeos/os_apps_page/app_notifications_page/mojo_interface_provider.ts", "chromeos/os_bluetooth_page/os_bluetooth_devices_subpage_browser_proxy.ts", "chromeos/os_bluetooth_page/settings_fast_pair_constants.ts", - "chromeos/os_languages_page/input_method_settings.js", - "chromeos/os_languages_page/input_method_types.js", - "chromeos/os_languages_page/input_method_util.js", - "chromeos/os_languages_page/languages.js", - "chromeos/os_languages_page/languages_browser_proxy.js", - "chromeos/os_languages_page/languages_metrics_proxy.js", - "chromeos/os_languages_page/languages_types.js", + "chromeos/os_languages_page/input_method_settings.ts", + "chromeos/os_languages_page/input_method_types.ts", + "chromeos/os_languages_page/input_method_util.ts", + "chromeos/os_languages_page/languages.ts", + "chromeos/os_languages_page/languages_browser_proxy.ts", + "chromeos/os_languages_page/languages_metrics_proxy.ts", + "chromeos/os_languages_page/languages_types.ts", "chromeos/os_page_visibility.js", "chromeos/os_people_page/account_manager_browser_proxy.js", "chromeos/os_people_page/fingerprint_browser_proxy.js", @@ -434,6 +436,37 @@ "mojom-webui/setting.mojom-webui.js", ] +# Files below are from Nearby Share and shared with ChromeOS Settings +nearby_share_shared_files = [ + "shared/nearby_contact_visibility.js", + "shared/nearby_contact_visibility.html.js", + "shared/nearby_device_icon.js", + "shared/nearby_device_icon.html.js", + "shared/nearby_device.js", + "shared/nearby_device.html.js", + "shared/nearby_onboarding_one_page.js", + "shared/nearby_onboarding_one_page.html.js", + "shared/nearby_onboarding_page.js", + "shared/nearby_onboarding_page.html.js", + "shared/nearby_page_template.js", + "shared/nearby_page_template.html.js", + "shared/nearby_preview.js", + "shared/nearby_preview.html.js", + "shared/nearby_progress.js", + "shared/nearby_progress.html.js", + "shared/nearby_visibility_page.js", + "shared/nearby_visibility_page.html.js", + + "shared/nearby_contact_manager.js", + "shared/nearby_metrics_logger.js", + "shared/nearby_share_settings_behavior.js", + "shared/nearby_share_settings.js", + "shared/types.js", + + "shared/nearby_shared_icons.html.js", + "shared/nearby_shared_share_type_icons.html.js", +] + # Files sourced from their checked-in version under src # TODO(crbug/1315757) JS files here are available for TS conversion src_ts_files = non_web_component_files + web_component_files
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts index 9022669..f137169 100644 --- a/chrome/browser/resources/settings/lazy_load.ts +++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -116,11 +116,6 @@ export {PaymentsManagerImpl, PaymentsManagerProxy} from './autofill_page/payments_manager_proxy.js'; export {SettingsPaymentsSectionElement} from './autofill_page/payments_section.js'; export {SettingsVirtualCardUnenrollDialogElement} from './autofill_page/virtual_card_unenroll_dialog.js'; -// <if expr="_google_chrome and is_win"> -export {ChromeCleanerScannerResults, ChromeCleanupFilePath, ChromeCleanupIdleReason, SettingsChromeCleanupPageElement} from './chrome_cleanup_page/chrome_cleanup_page.js'; -export {ChromeCleanupProxy, ChromeCleanupProxyImpl} from './chrome_cleanup_page/chrome_cleanup_proxy.js'; -export {CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW, ItemsToRemoveListElement} from './chrome_cleanup_page/items_to_remove_list.js'; -// </if> export {ClearBrowsingDataBrowserProxy, ClearBrowsingDataBrowserProxyImpl, ClearBrowsingDataResult, UpdateSyncStateEvent} from './clear_browsing_data_dialog/clear_browsing_data_browser_proxy.js'; export {SettingsClearBrowsingDataDialogElement} from './clear_browsing_data_dialog/clear_browsing_data_dialog.js'; export {SettingsHistoryDeletionDialogElement} from './clear_browsing_data_dialog/history_deletion_dialog.js';
diff --git a/chrome/browser/resources/settings/metrics_browser_proxy.ts b/chrome/browser/resources/settings/metrics_browser_proxy.ts index 87e5108..647e84c 100644 --- a/chrome/browser/resources/settings/metrics_browser_proxy.ts +++ b/chrome/browser/resources/settings/metrics_browser_proxy.ts
@@ -56,11 +56,14 @@ PASSWORDS_MANAGE_COMPROMISED_PASSWORDS = 2, SAFE_BROWSING_MANAGE = 3, EXTENSIONS_REVIEW = 4, + // Deprecated in https://crbug.com/1407233. CHROME_CLEANER_REBOOT = 5, + // Deprecated in https://crbug.com/1407233. CHROME_CLEANER_REVIEW_INFECTED_STATE = 6, PASSWORDS_CARET_NAVIGATION = 7, SAFE_BROWSING_CARET_NAVIGATION = 8, EXTENSIONS_CARET_NAVIGATION = 9, + // Deprecated in https://crbug.com/1407233. CHROME_CLEANER_CARET_NAVIGATION = 10, PASSWORDS_MANAGE_WEAK_PASSWORDS = 11, // Leave this at the end. @@ -245,7 +248,7 @@ recordSafetyCheckNotificationsListCountHistogram(suggestions: number) { chrome.send('metricsHandler:recordInHistogram', [ 'Settings.SafetyCheck.NotificationsListCount', - suggestions, 3999 /*max value for Notification suggestions*/, + suggestions, 99 /*max value for Notification suggestions*/, ]); }
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.html b/chrome/browser/resources/settings/reset_page/reset_page.html index 898dfc5..f317009 100644 --- a/chrome/browser/resources/settings/reset_page/reset_page.html +++ b/chrome/browser/resources/settings/reset_page/reset_page.html
@@ -12,30 +12,8 @@ </settings-reset-profile-dialog> </template> </cr-lazy-render> -<if expr="_google_chrome and is_win"> - <cr-link-row class="hr" id="chromeCleanupSubpageTrigger" - label="$i18n{resetCleanupComputerTrigger}" - on-click="onChromeCleanupTap_" - role-description="$i18n{subpageArrowRoleDescription}"></cr-link-row> - <template is="dom-if" if="[[showIncompatibleApplications_]]" restamp> - <cr-link-row class="hr" id="incompatibleApplicationsSubpageTrigger" - label="$i18n{incompatibleApplicationsResetCardTitle}" - on-click="onIncompatibleApplicationsTap_" - role-description="$i18n{subpageArrowRoleDescription}"> - </cr-link-row> - </template> -</if> </div> <if expr="_google_chrome and is_win"> - <template is="dom-if" route-path="/cleanup"> - <settings-subpage id="chromeCleanupSubpage" - associated-control="[[$$('#chromeCleanupSubpageTrigger')]]" - page-title="$i18n{resetCleanupComputerTrigger}" - learn-more-url="$i18n{chromeCleanupLearnMoreUrl}"> - <settings-chrome-cleanup-page prefs="{{prefs}}"> - </settings-chrome-cleanup-page> - </settings-subpage> - </template> <template is="dom-if" if="[[showIncompatibleApplications_]]"> <template is="dom-if" route-path="/incompatibleApplications"> <settings-subpage id="incompatibleApplicationsSubpage"
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.ts b/chrome/browser/resources/settings/reset_page/reset_page.ts index d1a9064..8ea601a 100644 --- a/chrome/browser/resources/settings/reset_page/reset_page.ts +++ b/chrome/browser/resources/settings/reset_page/reset_page.ts
@@ -12,7 +12,6 @@ import '../settings_shared.css.js'; import './reset_profile_dialog.js'; // <if expr="_google_chrome and is_win"> -import '../chrome_cleanup_page/chrome_cleanup_page.js'; import '../incompatible_applications_page/incompatible_applications_page.js'; // </if>
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.ts b/chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.ts index 8c12e3f..7cdcc61 100644 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.ts +++ b/chrome/browser/resources/settings/safety_check_page/safety_check_browser_proxy.ts
@@ -22,7 +22,6 @@ PASSWORDS_CHANGED = 'safety-check-passwords-status-changed', SAFE_BROWSING_CHANGED = 'safety-check-safe-browsing-status-changed', EXTENSIONS_CHANGED = 'safety-check-extensions-status-changed', - CHROME_CLEANER_CHANGED = 'safety-check-chrome-cleaner-status-changed', } /**
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.html b/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.html deleted file mode 100644 index d9f4c2b..0000000 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.html +++ /dev/null
@@ -1,17 +0,0 @@ -<template is="dom-if" if="[[showChild_(status_)]]" - restamp> - <settings-safety-check-child - id="safetyCheckChild" - icon-status="[[getIconStatus_(status_)]]" - label="$i18n{safetyCheckChromeCleanerPrimaryLabel}" - sub-label="[[displayString_]]" - button-label="[[getButtonLabel_(status_)]]" - button-aria-label="[[getButtonAriaLabel_(status_)]]" - button-class="[[getButtonClass_(status_)]]" - on-button-click="onButtonClick_" - managed-icon="[[getManagedIcon_(status_)]]" - on-click="onRowClick_" - row-clickable="[[isRowClickable_(status_)]]" - role="presentation"> - </settings-safety-check-child> -</template>
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.ts b/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.ts deleted file mode 100644 index e12181e..0000000 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.ts +++ /dev/null
@@ -1,219 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * 'settings-safety-passwords-child' is the settings page containing the - * safety check child showing the password status. - */ -import {assertNotReached} from 'chrome://resources/js/assert_ts.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; -import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; -import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {ChromeCleanupProxy, ChromeCleanupProxyImpl} from '../chrome_cleanup_page/chrome_cleanup_proxy.js'; -import {MetricsBrowserProxy, MetricsBrowserProxyImpl, SafetyCheckInteractions} from '../metrics_browser_proxy.js'; -import {routes} from '../route.js'; -import {Router} from '../router.js'; - -import {SafetyCheckCallbackConstants, SafetyCheckChromeCleanerStatus} from './safety_check_browser_proxy.js'; -import {SafetyCheckIconStatus} from './safety_check_child.js'; -import {getTemplate} from './safety_check_chrome_cleaner_child.html.js'; - -interface ChromeCleanerChangedEvent { - newState: SafetyCheckChromeCleanerStatus; - displayString: string; -} - -const SettingsSafetyCheckChromeCleanerChildElementBase = - WebUiListenerMixin(I18nMixin(PolymerElement)); - -export class SettingsSafetyCheckChromeCleanerChildElement extends - SettingsSafetyCheckChromeCleanerChildElementBase { - static get is() { - return 'settings-safety-check-chrome-cleaner-child'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /** - * Current state of the safety check Chrome cleaner child. - */ - status_: { - type: Number, - value: SafetyCheckChromeCleanerStatus.HIDDEN, - }, - - /** - * UI string to display for this child, received from the backend. - */ - displayString_: String, - - /** - * A set of statuses that the entire row is clickable. - */ - rowClickableStatuses: { - readOnly: true, - type: Object, - value: () => new Set([ - SafetyCheckChromeCleanerStatus.SCANNING_FOR_UWS, - SafetyCheckChromeCleanerStatus.REMOVING_UWS, - SafetyCheckChromeCleanerStatus.ERROR, - SafetyCheckChromeCleanerStatus.NO_UWS_FOUND_WITH_TIMESTAMP, - SafetyCheckChromeCleanerStatus.NO_UWS_FOUND_WITHOUT_TIMESTAMP, - ]), - }, - }; - } - - private status_: SafetyCheckChromeCleanerStatus; - private displayString_: string; - private rowClickableStatuses: Set<SafetyCheckChromeCleanerStatus>; - private metricsBrowserProxy_: MetricsBrowserProxy = - MetricsBrowserProxyImpl.getInstance(); - private chromeCleanupBrowserProxy_: ChromeCleanupProxy = - ChromeCleanupProxyImpl.getInstance(); - - override connectedCallback() { - super.connectedCallback(); - - // Register for safety check status updates. - this.addWebUiListener( - SafetyCheckCallbackConstants.CHROME_CLEANER_CHANGED, - this.onSafetyCheckChromeCleanerChanged_.bind(this)); - } - - private onSafetyCheckChromeCleanerChanged_(event: ChromeCleanerChangedEvent) { - this.status_ = event.newState; - this.displayString_ = event.displayString; - } - - private showChild_(): boolean { - return this.status_ !== SafetyCheckChromeCleanerStatus.HIDDEN; - } - - private getIconStatus_(): SafetyCheckIconStatus { - switch (this.status_) { - case SafetyCheckChromeCleanerStatus.HIDDEN: - case SafetyCheckChromeCleanerStatus.CHECKING: - case SafetyCheckChromeCleanerStatus.SCANNING_FOR_UWS: - case SafetyCheckChromeCleanerStatus.REMOVING_UWS: - return SafetyCheckIconStatus.RUNNING; - case SafetyCheckChromeCleanerStatus.NO_UWS_FOUND_WITH_TIMESTAMP: - return SafetyCheckIconStatus.SAFE; - case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED: - case SafetyCheckChromeCleanerStatus.DISABLED_BY_ADMIN: - case SafetyCheckChromeCleanerStatus.ERROR: - case SafetyCheckChromeCleanerStatus.NO_UWS_FOUND_WITHOUT_TIMESTAMP: - return SafetyCheckIconStatus.INFO; - case SafetyCheckChromeCleanerStatus.INFECTED: - return SafetyCheckIconStatus.WARNING; - default: - assertNotReached(); - } - } - - private getButtonLabel_(): string|null { - switch (this.status_) { - case SafetyCheckChromeCleanerStatus.INFECTED: - return this.i18n('safetyCheckReview'); - case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED: - return this.i18n('chromeCleanupRestartButtonLabel'); - default: - return null; - } - } - - private getButtonAriaLabel_(): string|null { - switch (this.status_) { - case SafetyCheckChromeCleanerStatus.INFECTED: - return this.i18n('safetyCheckChromeCleanerButtonAriaLabel'); - case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED: - return this.i18n('chromeCleanupRestartButtonLabel'); - default: - return null; - } - } - - private getButtonClass_(): string { - switch (this.status_) { - case SafetyCheckChromeCleanerStatus.INFECTED: - case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED: - return 'action-button'; - default: - return ''; - } - } - - private logUserInteraction_( - safetyCheckInteraction: SafetyCheckInteractions, userAction: string) { - // Log user interaction both in user action and histogram. - this.metricsBrowserProxy_.recordSafetyCheckInteractionHistogram( - safetyCheckInteraction); - this.metricsBrowserProxy_.recordAction(userAction); - } - - private onButtonClick_() { - switch (this.status_) { - case SafetyCheckChromeCleanerStatus.INFECTED: - this.logUserInteraction_( - SafetyCheckInteractions.CHROME_CLEANER_REVIEW_INFECTED_STATE, - 'Settings.SafetyCheck.ChromeCleanerReviewInfectedState'); - // Navigate to Chrome cleaner UI. - this.navigateToFoilPage_(); - break; - case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED: - this.logUserInteraction_( - SafetyCheckInteractions.CHROME_CLEANER_REBOOT, - 'Settings.SafetyCheck.ChromeCleanerReboot'); - this.chromeCleanupBrowserProxy_.restartComputer(); - break; - default: - // This is a state without an action. - break; - } - } - - private getManagedIcon_(): string|null { - switch (this.status_) { - case SafetyCheckChromeCleanerStatus.DISABLED_BY_ADMIN: - return 'cr20:domain'; - default: - return null; - } - } - - private isRowClickable_(): boolean { - return this.rowClickableStatuses.has(this.status_); - } - - private onRowClick_() { - if (this.isRowClickable_()) { - this.logUserInteraction_( - SafetyCheckInteractions.CHROME_CLEANER_CARET_NAVIGATION, - 'Settings.SafetyCheck.ChromeCleanerCaretNavigation'); - this.navigateToFoilPage_(); - } - } - - private navigateToFoilPage_() { - Router.getInstance().navigateTo( - routes.CHROME_CLEANUP, - /* dynamicParams= */ undefined, /* removeSearch= */ true); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'settings-safety-check-chrome-cleaner-child': - SettingsSafetyCheckChromeCleanerChildElement; - } -} - -customElements.define( - SettingsSafetyCheckChromeCleanerChildElement.is, - SettingsSafetyCheckChromeCleanerChildElement);
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_page.html b/chrome/browser/resources/settings/safety_check_page/safety_check_page.html index 1feb708..a678c0b5 100644 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_page.html +++ b/chrome/browser/resources/settings/safety_check_page/safety_check_page.html
@@ -43,10 +43,6 @@ </settings-safety-check-safe-browsing-child> <settings-safety-check-extensions-child> </settings-safety-check-extensions-child> -<if expr="_google_chrome and is_win"> - <settings-safety-check-chrome-cleaner-child id="chromeCleanerChild"> - </settings-safety-check-chrome-cleaner-child> -</if> </iron-collapse> <template is="dom-if" if="[[shouldShowUnusedSitePermissions_(
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_page.ts b/chrome/browser/resources/settings/safety_check_page/safety_check_page.ts index d6bdbacb..01b26f1 100644 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_page.ts +++ b/chrome/browser/resources/settings/safety_check_page/safety_check_page.ts
@@ -20,10 +20,6 @@ import './safety_check_passwords_child.js'; import './safety_check_safe_browsing_child.js'; import './safety_check_updates_child.js'; -// <if expr="_google_chrome and is_win"> -import './safety_check_chrome_cleaner_child.js'; - -// </if> import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js'; import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
diff --git a/chrome/browser/resources/settings/settings.ts b/chrome/browser/resources/settings/settings.ts index c467d0a..65fc54e 100644 --- a/chrome/browser/resources/settings/settings.ts +++ b/chrome/browser/resources/settings/settings.ts
@@ -79,9 +79,6 @@ export {Route, Router, SettingsRoutes} from './router.js'; export {SafetyCheckBrowserProxy, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckChromeCleanerStatus, SafetyCheckExtensionsStatus, SafetyCheckParentStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus} from './safety_check_page/safety_check_browser_proxy.js'; export {SafetyCheckIconStatus, SettingsSafetyCheckChildElement} from './safety_check_page/safety_check_child.js'; -// <if expr="_google_chrome and is_win"> -export {SettingsSafetyCheckChromeCleanerChildElement} from './safety_check_page/safety_check_chrome_cleaner_child.js'; -// </if> export {SettingsSafetyCheckExtensionsChildElement} from './safety_check_page/safety_check_extensions_child.js'; export {SettingsSafetyCheckNotificationPermissionsElement} from './safety_check_page/safety_check_notification_permissions.js'; export {SettingsSafetyCheckPageElement} from './safety_check_page/safety_check_page.js';
diff --git a/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn b/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn index e91035b5..0f280a3 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn +++ b/chrome/browser/resources/side_panel/customize_chrome/BUILD.gn
@@ -22,6 +22,7 @@ "cards.ts", "categories.ts", "check_mark_wrapper.ts", + "chrome_colors.ts", "color.ts", "colors.ts", "hover_button.ts", @@ -32,6 +33,7 @@ non_web_component_files = [ "chrome_cart_proxy.ts", + "color_utils.ts", "customize_chrome_api_proxy.ts", ]
diff --git a/chrome/browser/resources/side_panel/customize_chrome/app.html b/chrome/browser/resources/side_panel/customize_chrome/app.html index 38a1688c91..3ed36c8 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/app.html +++ b/chrome/browser/resources/side_panel/customize_chrome/app.html
@@ -35,7 +35,8 @@ customize-chrome-shortcuts, customize-chrome-cards, customize-chrome-categories, - customize-chrome-themes { + customize-chrome-themes, + customize-chrome-chrome-colors { display: block; max-width: 320px; width: 100%; @@ -58,10 +59,14 @@ </div> <customize-chrome-categories on-back-click="onBackClick_" on-collection-select="onCollectionSelect_" page-name="categories" - id="categoriesPage" on-local-image-upload="onLocalImageUpload_"> + id="categoriesPage" on-local-image-upload="onLocalImageUpload_" + on-chrome-colors-select="onChromeColorsSelect_"> </customize-chrome-categories> <customize-chrome-themes on-back-click="onBackClick_" page-name="themes" id="themesPage" selected-collection="[[selectedCollection_]]"> </customize-chrome-themes> + <customize-chrome-chrome-colors on-back-click="onBackClick_" + page-name="chrome-colors" id="chromeColorsPage"> + </customize-chrome-chrome-colors> </iron-pages>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/app.ts b/chrome/browser/resources/side_panel/customize_chrome/app.ts index 2ee4402d..fb00159 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/app.ts +++ b/chrome/browser/resources/side_panel/customize_chrome/app.ts
@@ -5,6 +5,7 @@ import './appearance.js'; import './cards.js'; import './categories.js'; +import './chrome_colors.js'; import './shortcuts.js'; import './themes.js'; @@ -14,6 +15,7 @@ import {getTemplate} from './app.html.js'; import {AppearanceElement} from './appearance.js'; import {CategoriesElement} from './categories.js'; +import {ChromeColorsElement} from './chrome_colors.js'; import {BackgroundCollection} from './customize_chrome.mojom-webui.js'; import {ThemesElement} from './themes.js'; @@ -21,6 +23,7 @@ OVERVIEW = 'overview', CATEGORIES = 'categories', THEMES = 'themes', + CHROME_COLORS = 'chrome-colors', } export interface AppElement { @@ -29,6 +32,7 @@ categoriesPage: CategoriesElement, themesPage: ThemesElement, appearanceElement: AppearanceElement, + chromeColorsPage: ChromeColorsElement, }; } @@ -69,6 +73,9 @@ case CustomizeChromePage.THEMES: this.page_ = CustomizeChromePage.CATEGORIES; break; + case CustomizeChromePage.CHROME_COLORS: + this.page_ = CustomizeChromePage.CATEGORIES; + break; } } @@ -84,6 +91,10 @@ private onLocalImageUpload_() { this.page_ = CustomizeChromePage.OVERVIEW; } + + private onChromeColorsSelect_() { + this.page_ = CustomizeChromePage.CHROME_COLORS; + } } declare global {
diff --git a/chrome/browser/resources/side_panel/customize_chrome/categories.html b/chrome/browser/resources/side_panel/customize_chrome/categories.html index 469d3f7..a519c57 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/categories.html +++ b/chrome/browser/resources/side_panel/customize_chrome/categories.html
@@ -23,7 +23,7 @@ --cr-column-width: 1fr; --cr-grid-gap: 16px 12px; display: block; - margin: 0 16px 32px; + padding: 0 16px 32px; } .tile { @@ -169,7 +169,8 @@ </div> <div class="label">$i18n{uploadImage}</div> </div> - <div class="tile" tabindex="0" role="button"> + <div class="tile" tabindex="0" id="chromeColorsTile" + role="button" on-click="onChromeColorsClick_"> <div class="image-container"> <div class="chrome-color"></div> <div class="chrome-color"></div>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/categories.ts b/chrome/browser/resources/side_panel/customize_chrome/categories.ts index 80a146b9..16d229f0 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/categories.ts +++ b/chrome/browser/resources/side_panel/customize_chrome/categories.ts
@@ -19,6 +19,7 @@ classicChromeTile: HTMLElement, uploadImageTile: HTMLElement, chromeWebStoreTile: HTMLElement, + chromeColorsTile: HTMLElement, }; } @@ -60,6 +61,10 @@ } } + private async onChromeColorsClick_() { + this.dispatchEvent(new Event('chrome-colors-select')); + } + private onCollectionClick_(e: DomRepeatEvent<BackgroundCollection>) { this.dispatchEvent(new CustomEvent<BackgroundCollection>( 'collection-select', {detail: e.model.item}));
diff --git a/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.html b/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.html new file mode 100644 index 0000000..07db0fa --- /dev/null +++ b/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.html
@@ -0,0 +1,100 @@ +<style include="cr-hidden-style cr-icons"> + #headerContainer { + align-items: center; + display: flex; + margin: 16px 16px 0; + } + + cr-icon-button { + --cr-icon-button-fill-color: var(--cr-secondary-text-color); + --cr-icon-button-margin-start: -8px; + } + + h1 { + color: var(--cr-primary-text-color); + font-size: 14px; + font-weight: 500; + line-height: 20px; + margin: 0; + margin-inline-start: 6px; + } + + cr-grid { + --cr-column-width: 1fr; + --cr-grid-gap: 16px 12px; + --cr-grid-width: 100%; + display: block; + padding: 16px 16px 32px; + } + + .tile { + cursor: pointer; + outline-width: 0; + place-self: stretch; + } + + :host-context(.focus-outline-visible) .tile:focus { + box-shadow: 0 0 0 2px var(--cr-focus-outline-color); + } + + #customColorContainer { + position: relative; + } + + #colorPickerIcon { + -webkit-mask-image: url(chrome://resources/cr_components/customize_themes/colorize.svg); + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 100%; + background-color: var(--google-grey-700); + height: 20px; + left: calc(50% - 10px); + pointer-events: none; + position: absolute; + top: calc(50% - 10px); + width: 20px; + } + + customize-chrome-color { + --customize-chrome-color-border-radius: 12px; + padding: 0; + } +</style> +<div id="headerContainer"> + <cr-icon-button on-click="onBackClick_" id="backButton" + class="icon-arrow-back" title="$i18n{backButton}"> + </cr-icon-button> + <h1 id="header">$i18n{chromeColors}</h1> +</div> +<cr-grid columns="3"> + <div id="customColorContainer" + class="tile" + title="$i18n{colorPickerLabel}" + aria-label="$i18n{colorPickerLabel}" + tabindex="0"> + <customize-chrome-color + id="customColor" + background-color="[[customColor_.background]]" + foreground-color="[[customColor_.foreground]]"> + </customize-chrome-color> + <div id="colorPickerIcon"></div> + </div> + <customize-chrome-color + id="defaultColor" + class="tile" + background-color="[[defaultColor_.background]]" + foreground-color="[[defaultColor_.foreground]]" + title="$i18n{defaultColorName}" + aria-label="$i18n{defaultColorName}" + tabindex="0"> + </customize-chrome-color> + <template is="dom-repeat" id="chromeColorsRepeat" items="[[colors_]]"> + <customize-chrome-color + class="chrome-color tile" + background-color="[[item.background]]" + foreground-color="[[item.foreground]]" + title="[[item.name]]" + aria-label$="[[item.name]]" + tabindex="0"> + </customize-chrome-color> + </template> +</cr-grid>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.ts b/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.ts new file mode 100644 index 0000000..0d05863 --- /dev/null +++ b/chrome/browser/resources/side_panel/customize_chrome/chrome_colors.ts
@@ -0,0 +1,98 @@ +// Copyright 2023 The Chromium Authors +// 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_hidden_style.css.js'; +import 'chrome://resources/cr_elements/cr_grid/cr_grid.js'; +import 'chrome://resources/cr_elements/cr_icons.css.js'; +import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; +import './color.js'; + +import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {getTemplate} from './chrome_colors.html.js'; +import {Color, DARK_DEFAULT_COLOR, LIGHT_DEFAULT_COLOR} from './color_utils.js'; +import {ChromeColor, Theme} from './customize_chrome.mojom-webui.js'; +import {CustomizeChromeApiProxy} from './customize_chrome_api_proxy.js'; + +export interface ChromeColorsElement { + $: { + backButton: HTMLElement, + colorPicker: HTMLInputElement, + colorPickerIcon: HTMLElement, + }; +} + +export class ChromeColorsElement extends PolymerElement { + static get is() { + return 'customize-chrome-chrome-colors'; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + defaultColor_: { + type: Object, + computed: 'computeDefaultColor_(theme_)', + }, + colors_: Array, + theme_: Object, + customColor_: { + type: Object, + value: { + background: {value: 0xffffffff}, + foreground: {value: 0xfff1f3f4}, + }, + }, + }; + } + + private colors_: ChromeColor[]; + private theme_: Theme; + private setThemeListenerId_: number|null = null; + + constructor() { + super(); + CustomizeChromeApiProxy.getInstance().handler.getChromeColors().then( + ({colors}) => { + this.colors_ = colors; + }); + } + + override connectedCallback() { + super.connectedCallback(); + this.setThemeListenerId_ = + CustomizeChromeApiProxy.getInstance() + .callbackRouter.setTheme.addListener((theme: Theme) => { + this.theme_ = theme; + }); + CustomizeChromeApiProxy.getInstance().handler.updateTheme(); + FocusOutlineManager.forDocument(document); + } + + override disconnectedCallback() { + super.disconnectedCallback(); + CustomizeChromeApiProxy.getInstance().callbackRouter.removeListener( + this.setThemeListenerId_!); + } + + private computeDefaultColor_(): Color { + return this.theme_.systemDarkMode ? DARK_DEFAULT_COLOR : + LIGHT_DEFAULT_COLOR; + } + + private onBackClick_() { + this.dispatchEvent(new Event('back-click')); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'customize-chrome-chrome-colors': ChromeColorsElement; + } +} + +customElements.define(ChromeColorsElement.is, ChromeColorsElement);
diff --git a/chrome/browser/resources/side_panel/customize_chrome/color.html b/chrome/browser/resources/side_panel/customize_chrome/color.html index 2b1e109..7aadbc7 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/color.html +++ b/chrome/browser/resources/side_panel/customize_chrome/color.html
@@ -1,5 +1,6 @@ <style> :host { + --customize-chrome-color-border-radius: 50%; box-sizing: border-box; cursor: pointer; display: block; @@ -13,7 +14,9 @@ } svg { - border-radius: 50%; + border: 1px solid var(--customize-chrome-color-foreground-color); + border-radius: var(--customize-chrome-color-border-radius); + box-sizing: border-box; display: block; width: 100%; } @@ -30,8 +33,8 @@ fill: var(--customize-chrome-color-background-color); } - :host([checked]) #background { - r: 25px; + :host([checked]) svg { + border: none; } :host([background-color-hidden]) #background { @@ -45,12 +48,9 @@ <customize-chrome-check-mark-wrapper checked="[[checked]]"> <svg viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> - <circle id="foreground" cx="25" cy="25" r="25"> - </circle> - <clipPath id="bottomHalf"> - <rect x="1" y="25" width="50" height="25"></rect> - </clipPath> - <circle id="background" cx="25" cy="25" r="24" - clip-path="url(#bottomHalf)"></circle> + <rect id="foreground" x="0" y="0" width="50" height="50"> + </rect> + <rect id="background" x="0" y="25" width="50" height="25"> + </rect> </svg> </customize-chrome-check-mark-wrapper>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/color_utils.ts b/chrome/browser/resources/side_panel/customize_chrome/color_utils.ts new file mode 100644 index 0000000..d4eca9b --- /dev/null +++ b/chrome/browser/resources/side_panel/customize_chrome/color_utils.ts
@@ -0,0 +1,32 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import {SkColor} from 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js'; + +export interface Color { + background: SkColor; + foreground: SkColor; +} + +export const LIGHT_DEFAULT_COLOR: Color = { + background: {value: 0xffffffff}, + foreground: {value: 0xffdee1e6}, +}; + +export const DARK_DEFAULT_COLOR: Color = { + background: {value: 0xff323639}, + foreground: {value: 0xff202124}, +}; + +export enum ColorType { + NONE, + DEFAULT, + MAIN, + CHROME, + CUSTOM, +} + +export interface SelectedColor { + type: ColorType; + chromeColor?: SkColor; +}
diff --git a/chrome/browser/resources/side_panel/customize_chrome/colors.ts b/chrome/browser/resources/side_panel/customize_chrome/colors.ts index 400f594..0ef27b1 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/colors.ts +++ b/chrome/browser/resources/side_panel/customize_chrome/colors.ts
@@ -12,38 +12,11 @@ import {DomRepeat, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ColorElement} from './color.js'; +import {Color, ColorType, DARK_DEFAULT_COLOR, LIGHT_DEFAULT_COLOR, SelectedColor} from './color_utils.js'; import {getTemplate} from './colors.html.js'; import {ChromeColor, Theme} from './customize_chrome.mojom-webui.js'; import {CustomizeChromeApiProxy} from './customize_chrome_api_proxy.js'; -export interface Color { - background: SkColor; - foreground: SkColor; -} - -export const LIGHT_DEFAULT_COLOR: Color = { - background: {value: 0xffffffff}, - foreground: {value: 0xffdee1e6}, -}; - -export const DARK_DEFAULT_COLOR: Color = { - background: {value: 0xff323639}, - foreground: {value: 0xff202124}, -}; - -enum ColorType { - NONE, - DEFAULT, - MAIN, - CHROME, - CUSTOM, -} - -interface SelectedColor { - type: ColorType; - chromeColor?: SkColor; -} - export interface ColorsElement { $: { chromeColors: DomRepeat, @@ -118,8 +91,9 @@ constructor() { super(); - CustomizeChromeApiProxy.getInstance().handler.getChromeColors().then( - ({colors}) => { + CustomizeChromeApiProxy.getInstance() + .handler.getOverviewChromeColors() + .then(({colors}) => { this.colors_ = colors; }); }
diff --git a/chrome/browser/resources/side_panel/customize_chrome/themes.html b/chrome/browser/resources/side_panel/customize_chrome/themes.html index 73f4ab2..9247b22 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/themes.html +++ b/chrome/browser/resources/side_panel/customize_chrome/themes.html
@@ -24,7 +24,7 @@ --cr-grid-gap: 16px 12px; --cr-grid-width: 100%; display: block; - margin: 16px 16px 32px; + padding: 16px 16px 32px; } .tile { @@ -69,7 +69,7 @@ #refreshDailyToggleContainer { display: flex; justify-content: space-between; - margin: 8px 16px 32px; + margin: 8px 16px 16px; } #refreshDailyToggleTitle {
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts index 4d6739d..a612b111 100644 --- a/chrome/browser/resources/side_panel/read_anything/app.ts +++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -86,11 +86,12 @@ private buildSubtree_(nodeId: number): Node { let htmlTag = chrome.readAnything.getHtmlTag(nodeId); + // Text nodes do not have an html tag. if (!htmlTag.length) { - const textContent = chrome.readAnything.getTextContent(nodeId); - return document.createTextNode(textContent); + return this.createTextNode_(nodeId); } + // getHtmlTag might return '#document' which is not a valid to pass to // createElement. if (htmlTag === '#document') { @@ -113,6 +114,7 @@ if (language) { element.setAttribute('lang', language); } + this.appendChildSubtrees_(element, nodeId); return element; } @@ -124,6 +126,25 @@ } } + private createTextNode_(nodeId: number): Node { + const textContent = chrome.readAnything.getTextContent(nodeId); + const textNode = document.createTextNode(textContent); + const shouldBold = chrome.readAnything.shouldBold(nodeId); + const isOverline = chrome.readAnything.isOverline(nodeId); + + if (!shouldBold && !isOverline) { + return textNode; + } + + const htmlTag = shouldBold ? 'b' : 'span'; + const parentElement = document.createElement(htmlTag); + if (isOverline) { + parentElement.style.textDecoration = 'overline'; + } + parentElement.appendChild(textNode); + return parentElement; + } + updateContent() { const shadowRoot = this.shadowRoot; if (!shadowRoot) {
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts index e1548b1..d29c58a 100644 --- a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts +++ b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
@@ -44,6 +44,12 @@ // Returns the url of the AXNode for the provided AXNodeID. function getUrl(nodeId: number): string; + // Returns true if the text node / element should be bolded. + function shouldBold(nodeId: number): boolean; + + // Returns true if the element has overline text styling. + function isOverline(nodeId: number): boolean; + // Connects to the browser process. Called by ts when the read anything // element is added to the document. function onConnected(): void;
diff --git a/chrome/browser/resources/side_panel/user_notes/app.ts b/chrome/browser/resources/side_panel/user_notes/app.ts index e82ec6a0..d6976ee0 100644 --- a/chrome/browser/resources/side_panel/user_notes/app.ts +++ b/chrome/browser/resources/side_panel/user_notes/app.ts
@@ -6,7 +6,6 @@ import '../strings.m.js'; import './user_note.js'; -import {assert} from 'chrome://resources/js/assert_ts.js'; import {listenOnce} from 'chrome://resources/js/util_ts.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -41,15 +40,20 @@ private notes_: Note[]; private userNotesApi_: UserNotesApiProxy = UserNotesApiProxyImpl.getInstance(); - private listenerId_: number|null = null; + private listenerIds_: number[] = []; override connectedCallback() { super.connectedCallback(); const callbackRouter = this.userNotesApi_.getCallbackRouter(); - this.listenerId_ = callbackRouter.notesChanged.addListener(() => { - this.updateNotes(); - }); + this.listenerIds_.push( + callbackRouter.notesChanged.addListener(() => { + this.updateNotes(); + }), + callbackRouter.currentTabUrlChanged.addListener(() => { + this.updateNotes(); + }), + ); listenOnce(this.$.notesList, 'dom-change', () => { // Push the ShowUi() callback to the event queue to allow deferred @@ -62,9 +66,9 @@ override disconnectedCallback() { super.disconnectedCallback(); - assert(this.listenerId_); - this.userNotesApi_.getCallbackRouter().removeListener(this.listenerId_); - this.listenerId_ = null; + this.listenerIds_.forEach( + id => this.userNotesApi_.getCallbackRouter().removeListener(id)); + this.listenerIds_ = []; } /**
diff --git a/chrome/browser/resources/side_panel/user_notes/user_note.html b/chrome/browser/resources/side_panel/user_notes/user_note.html index 2812300..7da5f4df 100644 --- a/chrome/browser/resources/side_panel/user_notes/user_note.html +++ b/chrome/browser/resources/side_panel/user_notes/user_note.html
@@ -116,7 +116,7 @@ <template is="dom-if" if="[[editing_]]" restamp> <div id="editingFooter"> <span id="characterCounter">[[characterCounter_]]/176</span> - <cr-button id="cancelButton" on-click="onCancelClick_"> + <cr-button id="cancelButton" class="tonal-button" on-click="onCancelClick_"> $i18n{cancel} </cr-button> <cr-button id="addButton" class="action-button" on-click="onAddClick_">
diff --git a/chrome/browser/resources/side_panel/user_notes/user_notes.html b/chrome/browser/resources/side_panel/user_notes/user_notes.html index 2ef5c8cf..3fe2812 100644 --- a/chrome/browser/resources/side_panel/user_notes/user_notes.html +++ b/chrome/browser/resources/side_panel/user_notes/user_notes.html
@@ -1,5 +1,6 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="$i18n{textdirection}" lang="$i18n{language}" + $i18n{chromeRefresh2023Attribute}> <head> <meta charset="utf-8"> <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> @@ -9,4 +10,4 @@ <user-notes-app></user-notes-app> <script type="module" src="app.js"></script> </body> -</html> \ No newline at end of file +</html>
diff --git a/chrome/browser/resources/webui_gallery/demos/buttons_demo.html b/chrome/browser/resources/webui_gallery/demos/buttons_demo.html index 2bee8c1..f497cf68 100644 --- a/chrome/browser/resources/webui_gallery/demos/buttons_demo.html +++ b/chrome/browser/resources/webui_gallery/demos/buttons_demo.html
@@ -13,17 +13,27 @@ cr-expand-button { padding: 0 12px; } + + /* Some button styles are not available before Chrome Refresh 2023. + * These buttons fallback to the default style. */ + html:not([chrome-refresh-2023]) .tonal-button { + display: none; + } </style> </head> <body> <h1>cr-button</h1> <div class="demos"> - <cr-button>Primary button</cr-button> + <cr-button>Default button</cr-button> <cr-button class="action-button">Action button</cr-button> - <cr-button disabled>Disabled primary button</cr-button> + <cr-button class="tonal-button">Tonal button</cr-button> + <cr-button disabled>Disabled default button</cr-button> <cr-button disabled class="action-button"> Disabled action button </cr-button> + <cr-button disabled class="tonal-button"> + Disabled tonal button + </cr-button> <div class="flex"> <cr-button class="cancel-button">Cancel</cr-button> <cr-button class="action-button">Confirm</cr-button>
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index d505f88..50770aa2 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -270,6 +270,8 @@ "extension_telemetry/extension_signal_processor.h", "extension_telemetry/extension_signal_util.cc", "extension_telemetry/extension_signal_util.h", + "extension_telemetry/extension_telemetry_config_manager.cc", + "extension_telemetry/extension_telemetry_config_manager.h", "extension_telemetry/extension_telemetry_file_processor.cc", "extension_telemetry/extension_telemetry_file_processor.h", "extension_telemetry/extension_telemetry_persister.cc",
diff --git a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.cc b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.cc new file mode 100644 index 0000000..e4981c3 --- /dev/null +++ b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.cc
@@ -0,0 +1,144 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.h" +#include "base/logging.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_number_conversions_win.h" +#include "base/values.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/extension_telemetry/extension_signal.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/common/proto/csd.pb.h" +#include "components/safe_browsing/core/common/safe_browsing_prefs.h" + +namespace safe_browsing { + +namespace { +// Default values for the ExtensionTelemetryConfigManager and the +// string key values for the `configuration_` dict. +constexpr const uint32_t kDefaultWritesPerInterval = 1u; +constexpr const uint32_t kDefaultReportingInterval = 3600u; +constexpr const uint32_t kDefaultConfigVersion = 0u; +constexpr const uint64_t kDefaultSignalEnables = 0xffffffffffffffff; +constexpr const char kConfigurationVersion[] = "version"; +constexpr const char kWritesPerInterval[] = "writes_per_interval"; +constexpr const char kReportingInterval[] = "reporting_interval"; +constexpr const char kSignalEnables0[] = "signal_enables_0"; +constexpr const char kSignalEnables1[] = "signal_enables_1"; +} // namespace + +ExtensionTelemetryConfigManager::~ExtensionTelemetryConfigManager() = default; + +ExtensionTelemetryConfigManager::ExtensionTelemetryConfigManager( + PrefService* pref_service) + : pref_service_(pref_service) {} + +void ExtensionTelemetryConfigManager::LoadConfig() { + configuration_ = GetExtensionTelemetryConfig(*pref_service_).Clone(); +} + +// A copy of the configuration data stored in prefs. The configuration +// data is organized as a dictionary (see example below). +// "safe_browsing.extension_telemetry_configuration": <- DICT +// "version":1 +// "reporting_interval":3600 +// "writes_per_interval":1 +// "<extension_id_1>": <- DICT +// "signal_enables_0" : 0x0000000f +// "signal_enables_1" : 0x00000000 +// "<extension_id_2>": <- DICT +// "signal_enables_0" : 0x0000000c +// "signal_enables_1" : 0x00000000 +void ExtensionTelemetryConfigManager::SaveConfig( + const ExtensionTelemetryReportResponse_Configuration& telemetry_config) { + if (!telemetry_config.has_configuration_version()) { + return; + } + uint32_t configuration_version = telemetry_config.configuration_version(); + if (configuration_version <= GetConfigVersion()) { + return; + } + base::Value::Dict telemetry_config_dict; + telemetry_config_dict.Set(kConfigurationVersion, + static_cast<int>(configuration_version)); + if (telemetry_config.has_reporting_interval_seconds()) { + telemetry_config_dict.Set( + kReportingInterval, + static_cast<int>(telemetry_config.reporting_interval_seconds())); + } + if (telemetry_config.has_writes_per_interval()) { + telemetry_config_dict.Set( + kWritesPerInterval, + static_cast<int>(telemetry_config.writes_per_interval())); + } + // Extract signal enables represented as bitmasks. + for (auto& proto_extension_parameter : + telemetry_config.extension_parameters()) { + uint64_t signal_enables_bitmask = + proto_extension_parameter.signal_enable_mask(); + base::Value::Dict extension_dict; + // In order to store the bitmask into the base::value::dict object + // the `signal_enables` bitmask must be split from it's uint64 form + // into two int32 variables. + extension_dict.Set(kSignalEnables0, + static_cast<int>(signal_enables_bitmask)); + extension_dict.Set(kSignalEnables1, + static_cast<int>(signal_enables_bitmask >> 32)); + telemetry_config_dict.Set(proto_extension_parameter.extension_id(), + std::move(extension_dict)); + } + SetExtensionTelemetryConfig(*pref_service_, telemetry_config_dict); + configuration_ = std::move(telemetry_config_dict); +} + +bool ExtensionTelemetryConfigManager::IsSignalEnabled( + const extensions::ExtensionId& extension_id, + ExtensionSignalType signal_type) const { + auto* extension_dict = configuration_.FindDict(extension_id); + if (!extension_dict) { + return true; + } + // Construct the uint64 `signal_enables` bitmask from the uint32_t + // `signal_enables_0` and `signal_enables_1` variables. + uint64_t signal_enables_bitmask = + (static_cast<uint64_t>(*extension_dict->FindInt(kSignalEnables1)) << 32 | + static_cast<uint32_t>(*extension_dict->FindInt(kSignalEnables0))); + return (signal_enables_bitmask & (1 << (static_cast<int>(signal_type)))); +} + +uint32_t ExtensionTelemetryConfigManager::GetWritesPerInterval() const { + absl::optional<int> param = configuration_.FindInt(kWritesPerInterval); + int value = param.has_value() ? param.value() : kDefaultWritesPerInterval; + return static_cast<uint32_t>(value); +} + +uint32_t ExtensionTelemetryConfigManager::GetConfigVersion() const { + absl::optional<int> param = configuration_.FindInt(kConfigurationVersion); + int value = param.has_value() ? param.value() : kDefaultConfigVersion; + return static_cast<uint32_t>(value); +} + +uint32_t ExtensionTelemetryConfigManager::GetReportingInterval() const { + absl::optional<int> param = configuration_.FindInt(kReportingInterval); + int value = param.has_value() ? param.value() : kDefaultReportingInterval; + return static_cast<uint32_t>(value); +} + +uint64_t ExtensionTelemetryConfigManager::GetSignalEnables( + const extensions::ExtensionId& extension_id) const { + auto* extension_dict = configuration_.FindDict(extension_id); + if (!extension_dict) { + // By default, all signals are enabled for extensions. + return kDefaultSignalEnables; + } + absl::optional<uint64_t> param = + (static_cast<uint64_t>(*extension_dict->FindInt(kSignalEnables1)) << 32 | + static_cast<uint32_t>(*extension_dict->FindInt(kSignalEnables0))); + uint64_t value = param.has_value() ? param.value() : kDefaultSignalEnables; + return value; +} +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.h b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.h new file mode 100644 index 0000000..6031be0 --- /dev/null +++ b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.h
@@ -0,0 +1,92 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_EXTENSION_TELEMETRY_CONFIG_MANAGER_H_ +#define CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_EXTENSION_TELEMETRY_CONFIG_MANAGER_H_ + +#include "base/values.h" +#include "extensions/common/extension_id.h" + +class PrefService; + +namespace safe_browsing { + +enum class ExtensionSignalType; +class ExtensionTelemetryReportResponse_Configuration; + +// The ExtensionTelemetryConfigManager manages the configuration of the +// Extension Telemetry Service. Configuration data includes items such as: +// - how often telemetry reports are uploaded +// - how often telemetry reports are persisted to disk +// - which extensions and signals are to be included in telemetry +// reports +// ExtensionTelemetryConfigManager persists the configuration data using +// Chrome's pref service. It also provides methods to look up this data. +// This object is instantiated and owned by the ExtensionTelemetryService +// and lives on the Browser UI thread. +class ExtensionTelemetryConfigManager { + public: + explicit ExtensionTelemetryConfigManager(PrefService* pref_service); + + ExtensionTelemetryConfigManager(const ExtensionTelemetryConfigManager&) = + delete; + ExtensionTelemetryConfigManager& operator=( + const ExtensionTelemetryConfigManager&) = delete; + + virtual ~ExtensionTelemetryConfigManager(); + + // Loads telemetry configuration data from prefs into its own internal + // copy. If there is no configuration data present, the internal copy + // becomes/remains empty. All configuration getters return default + // values. + void LoadConfig(); + + // The telemetry configuration is sent by a telemetry server in response + // to an uploaded telemetry report. The ExtensionTelemetryService calls + // this method to pass the response protobuf to the + // ExtensionTelemetryConfigManager. If the protobuf has a newer + // version than the currently saved config, it extracts the + // configuration data and persists it in Chrome's pref service. + // A copy of the configuration data is also kept in an internal member. + void SaveConfig( + const ExtensionTelemetryReportResponse_Configuration& telemetry_config); + + // Determines if the specified signal_type should be processed for the + // specified extension. Returns true if no configuration data has been + // saved. + bool IsSignalEnabled(const extensions::ExtensionId& extension_id, + ExtensionSignalType signal_type) const; + + // Returns the writes per interval determined by the current + // configuration or a default value if no configuration data has been + // saved. + uint32_t GetWritesPerInterval() const; + + // Returns the reporting interval determined by the current + // configuration or a default value if no configuration data has been + // saved. + uint32_t GetReportingInterval() const; + + // Returns the config version determined by the current + // configuration or a default value if no configuration data has been + // saved. + uint32_t GetConfigVersion() const; + + // Returns the signal enables bitmask for the `extension_id` determined + // by the current configuration or a default value if no configuration + // data has been saved. + uint64_t GetSignalEnables(const extensions::ExtensionId& extension_id) const; + + private: + // Holds string values that map to the configurable Extension Telemetry + // Service variables. Packed into a base::Value::Dict so it can be + // stored in Chrome prefs. + base::Value::Dict configuration_; + + // ExtensionTelemetryConfigManager uses the pref service to store + // the telemetry config. + raw_ptr<PrefService> pref_service_; +}; +} // namespace safe_browsing +#endif // CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_EXTENSION_TELEMETRY_CONFIG_MANAGER_H_
diff --git a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager_unittest.cc b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager_unittest.cc new file mode 100644 index 0000000..67b83b6 --- /dev/null +++ b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager_unittest.cc
@@ -0,0 +1,150 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.h" + +#include "chrome/browser/safe_browsing/extension_telemetry/extension_signal.h" +#include "chrome/test/base/testing_profile.h" +#include "components/safe_browsing/core/common/proto/csd.pb.h" +#include "content/public/test/browser_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ExtensionInfo = + safe_browsing::ExtensionTelemetryReportRequest_ExtensionInfo; +using TelemetryReport = safe_browsing::ExtensionTelemetryReportRequest; + +namespace safe_browsing { + +static constexpr const uint32_t kMaxUintValue = 0xffffffff; +static constexpr const uint64_t kMaxUint64Value = 0xffffffffffffffff; +static constexpr const uint32_t kDefaultReportingInterval = 3600u; +static constexpr const uint32_t kDefaultWritesPerInterval = 1u; +static constexpr const uint32_t kDefaultVersion = 0; +static constexpr const uint32_t kReportingInterval = 500u; +static constexpr const uint32_t kWritesPerInterval = 4u; +static constexpr const uint32_t kVersion = 3; +static constexpr const uint64_t kExtension1SignalEnables = 0x2B; +static constexpr const uint64_t kExtension2SignalEnables = 0xfffffffffffffff5; +static constexpr const char kExtension1[] = "extension1"; +static constexpr const char kExtension2[] = "extension2"; + +class ExtensionTelemetryConfigManagerTest : public ::testing::Test { + protected: + ExtensionTelemetryConfigManagerTest(); + void SetUp() override { ASSERT_NE(config_manager_, nullptr); } + + void ReloadConfig(); + void InitConfig(); + void InitConfigWithMaxValues(); + content::BrowserTaskEnvironment task_environment_; + TestingProfile profile_; + std::unique_ptr<ExtensionTelemetryConfigManager> config_manager_; +}; + +ExtensionTelemetryConfigManagerTest::ExtensionTelemetryConfigManagerTest() + : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { + config_manager_ = + std::make_unique<ExtensionTelemetryConfigManager>(profile_.GetPrefs()); +} + +void ExtensionTelemetryConfigManagerTest::InitConfigWithMaxValues() { + ExtensionTelemetryReportResponse::Configuration config; + config.set_configuration_version(kMaxUintValue); + config.set_reporting_interval_seconds(kMaxUintValue); + config.set_writes_per_interval(kMaxUintValue); + safe_browsing::ExtensionTelemetryReportResponse_ExtensionParameters* + extension = config.add_extension_parameters(); + extension->set_extension_id(kExtension1); + extension->set_signal_enable_mask(kMaxUint64Value); + config_manager_->SaveConfig(config); +} + +void ExtensionTelemetryConfigManagerTest::InitConfig() { + ExtensionTelemetryReportResponse::Configuration config; + config.set_configuration_version(kVersion); + config.set_reporting_interval_seconds(kReportingInterval); + config.set_writes_per_interval(kWritesPerInterval); + safe_browsing::ExtensionTelemetryReportResponse_ExtensionParameters* + extension = config.add_extension_parameters(); + extension->set_extension_id(kExtension1); + extension->set_signal_enable_mask(kExtension1SignalEnables); + extension = config.add_extension_parameters(); + extension->set_extension_id(kExtension2); + extension->set_signal_enable_mask(kExtension2SignalEnables); + config_manager_->SaveConfig(config); +} + +TEST_F(ExtensionTelemetryConfigManagerTest, InitializesSignalEnables) { + // Standard configuration check of multiple signals. + InitConfig(); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension1, ExtensionSignalType::kTabsExecuteScript)); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension2, ExtensionSignalType::kTabsExecuteScript)); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension2, ExtensionSignalType::kCookiesGetAll)); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension1, ExtensionSignalType::kRemoteHostContacted)); + EXPECT_FALSE(config_manager_->IsSignalEnabled( + kExtension2, ExtensionSignalType::kRemoteHostContacted)); + EXPECT_FALSE(config_manager_->IsSignalEnabled( + kExtension2, ExtensionSignalType::kPasswordReuse)); + EXPECT_EQ(config_manager_->GetSignalEnables(kExtension1), + kExtension1SignalEnables); + EXPECT_EQ(config_manager_->GetSignalEnables(kExtension2), + kExtension2SignalEnables); +} + +TEST_F(ExtensionTelemetryConfigManagerTest, InitializesWithMaxInputValues) { + // Check that max input ranges are stored correctly. + InitConfigWithMaxValues(); + EXPECT_EQ(config_manager_->GetWritesPerInterval(), kMaxUintValue); + EXPECT_EQ(config_manager_->GetReportingInterval(), kMaxUintValue); + EXPECT_EQ(config_manager_->GetConfigVersion(), kMaxUintValue); + EXPECT_EQ(config_manager_->GetSignalEnables(kExtension1), kMaxUint64Value); +} + +TEST_F(ExtensionTelemetryConfigManagerTest, SavesAndLoadsConfigFromPrefs) { + // Store a config in prefs and reset the `config_manager_`. + InitConfig(); + config_manager_ = + std::make_unique<ExtensionTelemetryConfigManager>(profile_.GetPrefs()); + + // Check the `config_manager_` doesn't have a loaded config and returns + // default values. + EXPECT_EQ(config_manager_->GetWritesPerInterval(), kDefaultWritesPerInterval); + EXPECT_EQ(config_manager_->GetReportingInterval(), kDefaultReportingInterval); + EXPECT_EQ(config_manager_->GetConfigVersion(), kDefaultVersion); + + // Now load the saved config from prefs. + config_manager_->LoadConfig(); + + // Check that `config_manager_` has the config values loaded from prefs. + EXPECT_EQ(config_manager_->GetWritesPerInterval(), kWritesPerInterval); + EXPECT_EQ(config_manager_->GetReportingInterval(), kReportingInterval); + EXPECT_EQ(config_manager_->GetConfigVersion(), kVersion); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension1, ExtensionSignalType::kRemoteHostContacted)); + EXPECT_FALSE(config_manager_->IsSignalEnabled( + kExtension2, ExtensionSignalType::kRemoteHostContacted)); +} + +TEST_F(ExtensionTelemetryConfigManagerTest, + ReturnsDefaultValuesIfNoPrefsDataPresent) { + // Test to ensure that all signals are enabled if no configuration + // is found and default values are used. + EXPECT_EQ(config_manager_->GetWritesPerInterval(), kDefaultWritesPerInterval); + EXPECT_EQ(config_manager_->GetReportingInterval(), kDefaultReportingInterval); + EXPECT_EQ(config_manager_->GetConfigVersion(), kDefaultVersion); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension1, ExtensionSignalType::kCookiesGetAll)); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension2, ExtensionSignalType::kCookiesGetAll)); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension1, ExtensionSignalType::kTabsExecuteScript)); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension2, ExtensionSignalType::kTabsExecuteScript)); + EXPECT_TRUE(config_manager_->IsSignalEnabled( + kExtension2, ExtensionSignalType::kCookiesGet)); +} +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.cc b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.cc index daea39b..63dc786 100644 --- a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.cc +++ b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/safe_browsing/extension_telemetry/cookies_get_all_signal_processor.h" #include "chrome/browser/safe_browsing/extension_telemetry/cookies_get_signal_processor.h" #include "chrome/browser/safe_browsing/extension_telemetry/extension_signal.h" +#include "chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager.h" #include "chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_persister.h" #include "chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_uploader.h" #include "chrome/browser/safe_browsing/extension_telemetry/potential_password_theft_signal_processor.h" @@ -194,7 +195,6 @@ return; enabled_ = enable; - if (enabled_) { // Create signal processors. // Map the processors to the signals they eventually generate. @@ -240,14 +240,16 @@ std::move(subscribers_for_remote_host_contacted)); signal_subscribers_.emplace(ExtensionSignalType::kPasswordReuse, std::move(subscribers_for_password_reuse)); - + if (base::FeatureList::IsEnabled(kExtensionTelemetryConfiguration)) { + config_manager_ = + std::make_unique<ExtensionTelemetryConfigManager>(pref_service_); + config_manager_->LoadConfig(); + } if (current_reporting_interval_.is_positive()) { int max_files_supported = ExtensionTelemetryPersister::MaxFilesSupported(); int writes_per_interval = std::min( max_files_supported, kExtensionTelemetryWritesPerInterval.Get()); - if (writes_per_interval < 1) - writes_per_interval = 1; // Configure persister for the maximum number of reports to be persisted // on disk. This number is the sum of reports written at every // write interval plus an additional allocation (3) for files written at @@ -319,6 +321,12 @@ return (extension_store_.size() > 0); } +bool ExtensionTelemetryService::IsSignalEnabled( + const extensions::ExtensionId& extension_id, + ExtensionSignalType signal_type) { + return config_manager_->IsSignalEnabled(extension_id, signal_type); +} + void ExtensionTelemetryService::AddSignal( std::unique_ptr<ExtensionSignal> signal) { ExtensionSignalType signal_type = signal->GetType(); @@ -368,6 +376,8 @@ } void ExtensionTelemetryService::OnUploadComplete(bool success) { + // TODO(https://crbug.com/1408126): Add `config_manager_` implementation + // to check server response and update config. if (success) { SetLastUploadTimeForExtensionTelemetry(*pref_service_, base::Time::Now()); }
diff --git a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.h b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.h index 054bbeb..10500ddee 100644 --- a/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.h +++ b/chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.h
@@ -42,6 +42,7 @@ class ExtensionTelemetryUploader; class ExtensionTelemetryPersister; class SafeBrowsingTokenFetcher; +class ExtensionTelemetryConfigManager; // This class process extension signals and reports telemetry for a given // profile (regular profile only). It is used exclusively on the UI thread. @@ -85,6 +86,11 @@ // Accepts extension telemetry signals for processing. void AddSignal(std::unique_ptr<ExtensionSignal> signal); + // Checks the `extension_id` and `signal_type` against the + // configuration and reports true if the signal should be created. + bool IsSignalEnabled(const extensions::ExtensionId& extension_id, + ExtensionSignalType signal_type); + base::TimeDelta current_reporting_interval() { return current_reporting_interval_; } @@ -140,6 +146,12 @@ // destroyed cleanly while running tasks during Chrome shutdown. base::SequenceBound<ExtensionTelemetryPersister> persister_; + // The `config_manager_` manages all configurable variables of the + // Extension Telemetry Service. Variables are stored in Chrome Prefs + // between sessions. + std::unique_ptr<safe_browsing::ExtensionTelemetryConfigManager> + config_manager_; + // The profile with which this instance of the service is associated. const raw_ptr<Profile> profile_;
diff --git a/chrome/browser/selection/android/BUILD.gn b/chrome/browser/selection/android/BUILD.gn index 1e286e4..3d653ba 100644 --- a/chrome/browser/selection/android/BUILD.gn +++ b/chrome/browser/selection/android/BUILD.gn
@@ -24,8 +24,11 @@ deps = [ "//base:base_java", "//base:base_java_test_support", + "//chrome/android:chrome_java", + "//chrome/browser/back_press/android:java", "//chrome/browser/flags:java", "//chrome/test/android:chrome_java_integration_test_support", + "//components/browser_ui/widget/android:java", "//content/public/android:content_full_java", "//content/public/test/android:content_java_test_support", "//third_party/android_deps:espresso_java",
diff --git a/chrome/browser/selection/android/java/src/org/chromium/chrome/browser/selection/SelectionPopupBackPressTest.java b/chrome/browser/selection/android/java/src/org/chromium/chrome/browser/selection/SelectionPopupBackPressTest.java index 988a0049..3bc0261 100644 --- a/chrome/browser/selection/android/java/src/org/chromium/chrome/browser/selection/SelectionPopupBackPressTest.java +++ b/chrome/browser/selection/android/java/src/org/chromium/chrome/browser/selection/SelectionPopupBackPressTest.java
@@ -19,12 +19,14 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Matchers; import org.chromium.base.test.util.UrlUtils; +import org.chromium.chrome.browser.back_press.BackPressManager; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; +import org.chromium.components.browser_ui.widget.gesture.BackPressHandler; import org.chromium.content_public.browser.SelectionPopupController; import org.chromium.content_public.browser.test.util.DOMUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils; @@ -88,6 +90,15 @@ Assert.assertTrue("Selection popup should be triggered after long press.", controller.isSelectActionBarShowingSupplier().get()); + TestThreadUtils.runOnUiThreadBlocking(() -> { + BackPressManager backPressManager = + mActivityTestRule.getActivity().getBackPressManagerForTesting(); + if (backPressManager.has(BackPressHandler.Type.TEXT_BUBBLE)) { + mActivityTestRule.getActivity().getBackPressManagerForTesting().removeHandler( + BackPressHandler.Type.TEXT_BUBBLE); + } + }); + Espresso.pressBack(); CriteriaHelper.pollUiThread(() -> {
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java index 689ebd8..6d51276 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java
@@ -280,11 +280,8 @@ @Test @MediumTest - @Features.EnableFeatures({ChromeFeatureList.ENABLE_IPH}) - @Features.DisableFeatures( - {ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, ChromeFeatureList.SNOOZABLE_IPH}) - public void - createRecyclerViews_toggleOff_showsIph() { + @Features.DisableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) + public void createRecyclerViews_toggleOff_showsIph() { String fileContentType = "image/gif"; ShareSheetBottomSheetContent shareSheetBottomSheetContent = new ShareSheetBottomSheetContent(mActivity, new MockLargeIconBridge(), null,
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc index 06985f5..c8bc716 100644 --- a/chrome/browser/signin/dice_browsertest.cc +++ b/chrome/browser/signin/dice_browsertest.cc
@@ -896,7 +896,7 @@ auto web_auth_flow = std::make_unique<extensions::WebAuthFlow>( nullptr, browser()->profile(), https_server_.GetURL(kSigninURL), extensions::WebAuthFlow::INTERACTIVE, - extensions::WebAuthFlow::LAUNCH_WEB_AUTH_FLOW); + extensions::WebAuthFlow::LAUNCH_WEB_AUTH_FLOW, "extension_name"); web_auth_flow->Start(); if (dice_request_header_.empty()) @@ -923,7 +923,7 @@ auto web_auth_flow = std::make_unique<extensions::WebAuthFlow>( &delegate, browser()->profile(), https_server_.GetURL(kSigninURL), extensions::WebAuthFlow::INTERACTIVE, - extensions::WebAuthFlow::GET_AUTH_TOKEN); + extensions::WebAuthFlow::GET_AUTH_TOKEN, "extension_name"); web_auth_flow->Start(); // Check that the token was requested and added to the token service.
diff --git a/chrome/browser/signin/mirror_browsertest.cc b/chrome/browser/signin/mirror_browsertest.cc index f653b68b..7b4501e 100644 --- a/chrome/browser/signin/mirror_browsertest.cc +++ b/chrome/browser/signin/mirror_browsertest.cc
@@ -120,7 +120,7 @@ auto web_auth_flow = std::make_unique<extensions::WebAuthFlow>( nullptr, browser()->profile(), https_server.GetURL("google.com", kAuthPath), - extensions::WebAuthFlow::INTERACTIVE, partition); + extensions::WebAuthFlow::INTERACTIVE, partition, "extension_name"); web_auth_flow->Start(); run_loop.Run();
diff --git a/chrome/browser/sync/test/integration/configuration_refresher.cc b/chrome/browser/sync/test/integration/configuration_refresher.cc deleted file mode 100644 index 123a071..0000000 --- a/chrome/browser/sync/test/integration/configuration_refresher.cc +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/sync/test/integration/configuration_refresher.h" - -#include "components/sync/base/model_type.h" - -ConfigurationRefresher::ConfigurationRefresher() = default; -ConfigurationRefresher::~ConfigurationRefresher() = default; - -void ConfigurationRefresher::Observe(syncer::SyncService* sync_service) { - scoped_observations_.AddObservation(sync_service); -} - -void ConfigurationRefresher::OnSyncConfigurationCompleted( - syncer::SyncService* sync_service) { - sync_service->TriggerRefresh(syncer::ModelTypeSet::All()); -} - -void ConfigurationRefresher::OnSyncShutdown(syncer::SyncService* sync_service) { - scoped_observations_.RemoveObservation(sync_service); -}
diff --git a/chrome/browser/sync/test/integration/configuration_refresher.h b/chrome/browser/sync/test/integration/configuration_refresher.h deleted file mode 100644 index 249d56f..0000000 --- a/chrome/browser/sync/test/integration/configuration_refresher.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_CONFIGURATION_REFRESHER_H_ -#define CHROME_BROWSER_SYNC_TEST_INTEGRATION_CONFIGURATION_REFRESHER_H_ - -#include "base/scoped_multi_source_observation.h" -#include "components/sync/driver/sync_service.h" -#include "components/sync/driver/sync_service_observer.h" - -// Triggers a GetUpdates via refresh for any observed SyncService after a -// configuration. This class was created to be used in conjunction with fake -// invalidations. It turns out there's a race during configuration, after the -// initial GetUpdates was called, but before invalidations were re-subscribed to -// that caused updates to be missed. This resulted in some flakey test cases, -// see crbug,com/644367 for more details. This class fills the gap by forcing a -// GetUpdates after configuration to fetch anything missed while a client was -// not subscribed to invalidation(s). -class ConfigurationRefresher : public syncer::SyncServiceObserver { - public: - ConfigurationRefresher(); - - ConfigurationRefresher(const ConfigurationRefresher&) = delete; - ConfigurationRefresher& operator=(const ConfigurationRefresher&) = delete; - - ~ConfigurationRefresher() override; - void Observe(syncer::SyncService* sync_service); - - private: - // syncer::SyncServiceObserver implementation. - void OnSyncConfigurationCompleted(syncer::SyncService* sync_service) override; - void OnSyncShutdown(syncer::SyncService* sync_service) override; - - base::ScopedMultiSourceObservation<syncer::SyncService, - syncer::SyncServiceObserver> - scoped_observations_{this}; -}; - -#endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_CONFIGURATION_REFRESHER_H_
diff --git a/chrome/browser/sync/test/integration/device_info_helper.cc b/chrome/browser/sync/test/integration/device_info_helper.cc index 7b80a74..8e7adc3 100644 --- a/chrome/browser/sync/test/integration/device_info_helper.cc +++ b/chrome/browser/sync/test/integration/device_info_helper.cc
@@ -21,6 +21,7 @@ } bool ServerDeviceInfoMatchChecker::IsExitConditionSatisfied(std::ostream* os) { + *os << "Waiting for server DeviceInfo to match: "; std::vector<sync_pb::SyncEntity> entities = fake_server()->GetSyncEntitiesByModelType(syncer::DEVICE_INFO);
diff --git a/chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.cc b/chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.cc index bacddb3..431c7ce 100644 --- a/chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.cc +++ b/chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.cc
@@ -4,39 +4,17 @@ #include "chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.h" +#include "base/files/file_path.h" #include "base/task/sequenced_task_runner.h" -#include "base/task/single_thread_task_runner.h" -#include "base/task/task_traits.h" -#include "base/task/thread_pool.h" #include "chrome/browser/profiles/profile.h" #include "components/gcm_driver/crypto/gcm_encryption_result.h" -#include "components/gcm_driver/fake_gcm_profile_service.h" -#include "components/gcm_driver/gcm_profile_service.h" -#include "components/keyed_service/core/keyed_service.h" - -// static -std::unique_ptr<KeyedService> FakeSyncGCMDriver::Build( - content::BrowserContext* context) { - auto service = std::make_unique<gcm::FakeGCMProfileService>(); - Profile* profile = Profile::FromBrowserContext(context); - - // Allow blocking to initialize GCM client from the disk. - scoped_refptr<base::SequencedTaskRunner> blocking_task_runner( - base::ThreadPool::CreateSequencedTaskRunner( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); - service->SetDriverForTesting( - std::make_unique<FakeSyncGCMDriver>(profile, blocking_task_runner)); - return service; -} FakeSyncGCMDriver::FakeSyncGCMDriver( Profile* profile, const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) : instance_id::FakeGCMDriverForInstanceID( profile->GetPath().Append(FILE_PATH_LITERAL("gcm_test_store")), - blocking_task_runner), - profile_(profile) {} + blocking_task_runner) {} void FakeSyncGCMDriver::EncryptMessage(const std::string& app_id, const std::string& authorized_entity,
diff --git a/chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.h b/chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.h index 3bc12684..906e16b6 100644 --- a/chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.h +++ b/chrome/browser/sync/test/integration/fake_sync_gcm_driver_for_instance_id.h
@@ -8,29 +8,21 @@ #include <memory> #include <string> -#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h" +class Profile; + namespace base { class SequencedTaskRunner; } // namespace base -namespace content { -class BrowserContext; -} // namespace content - -class KeyedService; -class Profile; - class FakeSyncGCMDriver : public instance_id::FakeGCMDriverForInstanceID { public: FakeSyncGCMDriver( Profile* profile, const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner); - static std::unique_ptr<KeyedService> Build(content::BrowserContext* context); - protected: // FakeGCMDriverForInstanceID overrides: void EncryptMessage(const std::string& app_id, @@ -39,9 +31,6 @@ const std::string& auth_secret, const std::string& message, EncryptMessageCallback callback) override; - - private: - raw_ptr<Profile> profile_; }; #endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_FAKE_SYNC_GCM_DRIVER_FOR_INSTANCE_ID_H_
diff --git a/chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.cc b/chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.cc index 5d25b78..67b75954d 100644 --- a/chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.cc +++ b/chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.cc
@@ -4,21 +4,14 @@ #include "chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.h" -#include "base/containers/contains.h" +#include "base/containers/cxx20_erase.h" +#include "base/logging.h" #include "base/time/time.h" +#include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h" #include "components/sync/base/time.h" -#include "components/sync/invalidations/fcm_handler.h" namespace fake_server { -namespace { - -// This has the same value as in -// components/sync/invalidations/sync_invalidations_service_impl.cc. -const char kSyncInvalidationsAppId[] = "com.google.chrome.sync.invalidations"; - -} // namespace - FakeServerSyncInvalidationSender::FakeServerSyncInvalidationSender( FakeServer* fake_server) : fake_server_(fake_server) { @@ -28,30 +21,23 @@ FakeServerSyncInvalidationSender::~FakeServerSyncInvalidationSender() { fake_server_->RemoveObserver(this); - - // Unsubscribe from all the remaining FCM handlers. This is mostly the case - // for Android platform. - for (syncer::FCMHandler* fcm_handler : fcm_handlers_) { - fcm_handler->RemoveTokenObserver(this); + for (instance_id::FakeGCMDriverForInstanceID* fake_gcm_driver : + fake_gcm_drivers_) { + fake_gcm_driver->RemoveConnectionObserver(this); } } -void FakeServerSyncInvalidationSender::AddFCMHandler( - syncer::FCMHandler* fcm_handler) { - DCHECK(fcm_handler); - DCHECK(!base::Contains(fcm_handlers_, fcm_handler)); - - fcm_handlers_.push_back(fcm_handler); - fcm_handler->AddTokenObserver(this); +void FakeServerSyncInvalidationSender::AddFakeGCMDriver( + instance_id::FakeGCMDriverForInstanceID* fake_gcm_driver) { + // It's safe to cast since SyncTest uses FakeGCMProfileService. + fake_gcm_drivers_.push_back(fake_gcm_driver); + fake_gcm_driver->AddConnectionObserver(this); } -void FakeServerSyncInvalidationSender::RemoveFCMHandler( - syncer::FCMHandler* fcm_handler) { - DCHECK(fcm_handler); - DCHECK(base::Contains(fcm_handlers_, fcm_handler)); - - fcm_handler->RemoveTokenObserver(this); - base::Erase(fcm_handlers_, fcm_handler); +void FakeServerSyncInvalidationSender::RemoveFakeGCMDriver( + instance_id::FakeGCMDriverForInstanceID* fake_gcm_driver) { + fake_gcm_driver->RemoveConnectionObserver(this); + base::Erase(fake_gcm_drivers_, fake_gcm_driver); } void FakeServerSyncInvalidationSender::OnWillCommit() { @@ -92,18 +78,28 @@ DeliverInvalidationsToHandlers(); } -void FakeServerSyncInvalidationSender::OnFCMRegistrationTokenChanged() { +void FakeServerSyncInvalidationSender::OnConnected( + const net::IPEndPoint& ip_endpoint) { + // Try to deliver invalidations once GCMDriver is connected. + DVLOG(1) << "GCM driver connected"; DeliverInvalidationsToHandlers(); } void FakeServerSyncInvalidationSender::DeliverInvalidationsToHandlers() { - for (auto& token_and_invalidations : invalidations_to_deliver_) { + DVLOG(1) << "Trying to deliver invalidations for " + << invalidations_to_deliver_.size() + << " FCM tokens. Known target tokens from DeviceInfo: " + << token_to_interested_data_types_.size(); + std::set<std::string> processed_tokens; + for (const auto& token_and_invalidations : invalidations_to_deliver_) { const std::string& token = token_and_invalidations.first; - // Pass a message to each FCMHandler to simulate a message from the - // GCMDriver. + + // Pass a message to GCMDriver to simulate a message from the server. // TODO(crbug.com/1082115): Implement reflection blocking. - syncer::FCMHandler* fcm_handler = GetFCMHandlerByToken(token); - if (!fcm_handler) { + instance_id::FakeGCMDriverForInstanceID* fake_gcm_driver = + GetFakeGCMDriverByToken(token); + if (!fake_gcm_driver) { + DVLOG(1) << "Could not find FakeGCMDriver for token: " << token; continue; } @@ -111,18 +107,37 @@ token_and_invalidations.second) { gcm::IncomingMessage message; message.raw_data = payload.SerializeAsString(); - fcm_handler->OnMessage(kSyncInvalidationsAppId, message); + fake_gcm_driver->DispatchMessage(kSyncInvalidationsAppId, message); } - token_and_invalidations.second.clear(); + processed_tokens.insert(token); + } + + for (const std::string& token_to_remove : processed_tokens) { + invalidations_to_deliver_.erase(token_to_remove); } } -syncer::FCMHandler* FakeServerSyncInvalidationSender::GetFCMHandlerByToken( +instance_id::FakeGCMDriverForInstanceID* +FakeServerSyncInvalidationSender::GetFakeGCMDriverByToken( const std::string& fcm_registration_token) const { - for (syncer::FCMHandler* fcm_handler : fcm_handlers_) { - if (fcm_registration_token == fcm_handler->GetFCMRegistrationToken()) { - return fcm_handler; + for (instance_id::FakeGCMDriverForInstanceID* fake_gcm_driver : + fake_gcm_drivers_) { +#if !BUILDFLAG(IS_ANDROID) + // On Android platform FCM registration token is returned from Java + // implementation, so HasTokenForAppId() does not contain these tokens. + // Since Android does not support several profiles, for the simplicity just + // check for AppHandler registration. + if (!fake_gcm_driver->HasTokenForAppId(kSyncInvalidationsAppId, + fcm_registration_token)) { + continue; + } +#endif // !BUILDFLAG(IS_ANDROID) + + // AppHandler may not be registered while SyncSetup() is not called yet, the + // server should keep invalidations to deliver them later. + if (fake_gcm_driver->GetAppHandler(kSyncInvalidationsAppId)) { + return fake_gcm_driver; } } return nullptr;
diff --git a/chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.h b/chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.h index f06f61c..c9acf91 100644 --- a/chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.h +++ b/chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.h
@@ -6,24 +6,28 @@ #define CHROME_BROWSER_SYNC_TEST_INTEGRATION_INVALIDATIONS_FAKE_SERVER_SYNC_INVALIDATION_SENDER_H_ #include "base/memory/raw_ptr.h" +#include "components/gcm_driver/gcm_connection_observer.h" #include "components/sync/base/model_type.h" -#include "components/sync/invalidations/fcm_registration_token_observer.h" #include "components/sync/protocol/sync_invalidations_payload.pb.h" #include "components/sync/test/fake_server.h" -namespace syncer { -class FCMHandler; -} +namespace instance_id { +class FakeGCMDriverForInstanceID; +} // namespace instance_id namespace fake_server { // This class is observing changes to the fake server, and sends invalidations // to clients upon commits. Sent invalidation follows the same format expected // by the sync invalidations framework (i.e. SyncInvalidationsService). -class FakeServerSyncInvalidationSender - : public FakeServer::Observer, - public syncer::FCMRegistrationTokenObserver { +class FakeServerSyncInvalidationSender : public FakeServer::Observer, + public gcm::GCMConnectionObserver { public: + // This has the same value as in + // components/sync/invalidations/sync_invalidations_service_impl.cc. + static constexpr char kSyncInvalidationsAppId[] = + "com.google.chrome.sync.invalidations"; + // |fake_server| must not be nullptr, and must outlive this object. explicit FakeServerSyncInvalidationSender(FakeServer* fake_server); ~FakeServerSyncInvalidationSender() override; @@ -32,26 +36,24 @@ FakeServerSyncInvalidationSender& operator=( const FakeServerSyncInvalidationSender&) = delete; - // |fcm_handler| must not be nullptr, and must be removed using - // RemoveFCMHandler(). If the FCM handler has registered token, all the - // message for the token will be delivered immediately. - void AddFCMHandler(syncer::FCMHandler* fcm_handler); + // Add |fake_gcm_driver| to send invalidations to from the fake server. + void AddFakeGCMDriver( + instance_id::FakeGCMDriverForInstanceID* fake_gcm_driver); - // |fcm_handler| must not be nullptr, and must exist in |fcm_handlers_|. - void RemoveFCMHandler(syncer::FCMHandler* fcm_handler); + // Remove |fake_gcm_driver| to stop sending invalidations. + void RemoveFakeGCMDriver( + instance_id::FakeGCMDriverForInstanceID* fake_gcm_driver); // FakeServer::Observer implementation. void OnWillCommit() override; void OnCommit(const std::string& committer_invalidator_client_id, syncer::ModelTypeSet committed_model_types) override; - // syncer::FCMRegistrationTokenObserver implementation. - void OnFCMRegistrationTokenChanged() override; + // gcm::GCMConnectionObserver implementation. + void OnConnected(const net::IPEndPoint& ip_endpoint) override; private: - // Returns a corresponding FCM handler having the same - // |fcm_registration_token| if exists. Otherwise, returns nullptr. - syncer::FCMHandler* GetFCMHandlerByToken( + instance_id::FakeGCMDriverForInstanceID* GetFakeGCMDriverByToken( const std::string& fcm_registration_token) const; // Delivers all the incoming messages to the corresponding FCM handlers. @@ -63,7 +65,6 @@ void UpdateTokenToInterestedDataTypesMap(); raw_ptr<FakeServer> fake_server_; - std::vector<syncer::FCMHandler*> fcm_handlers_; // Cache of invalidations to be dispatched by // DeliverInvalidationsToHandlers(), keyed by FCM registration token. If no @@ -73,8 +74,11 @@ invalidations_to_deliver_; // List of tokens with a list of interested data types. Used to send - // invalidations to a corresponding FCMHandler. + // invalidations to a corresponding client. std::map<std::string, syncer::ModelTypeSet> token_to_interested_data_types_; + + std::vector<base::raw_ptr<instance_id::FakeGCMDriverForInstanceID>> + fake_gcm_drivers_; }; } // namespace fake_server
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc index d5aa602f..e705429 100644 --- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/sync/device_info_sync_service_factory.h" #include "chrome/browser/sync/sync_invalidations_service_factory.h" #include "chrome/browser/sync/test/integration/bookmarks_helper.h" +#include "chrome/browser/sync/test/integration/committed_all_nudged_changes_checker.h" #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "chrome/browser/sync/test/integration/sync_service_impl_harness.h" #include "chrome/browser/sync/test/integration/sync_test.h" @@ -29,6 +30,7 @@ #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/bookmark_node.h" #include "components/bookmarks/browser/url_and_title.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/core/keyed_service.h" #include "components/sync/base/client_tag_hash.h" #include "components/sync/base/command_line_switches.h" @@ -1607,7 +1609,8 @@ // Make sure all local commits make it to the server. ASSERT_TRUE( - UpdatedProgressMarkerChecker(GetSyncService(kSingleProfileIndex)).Wait()); + CommittedAllNudgedChangesChecker(GetSyncService(kSingleProfileIndex)) + .Wait()); // Verify that the bookmark hasn't been uploaded (no local updates issued). No // commits are expected despite the fact that the server-side bookmark is a @@ -1693,6 +1696,14 @@ ASSERT_TRUE(SetupClients()); ASSERT_TRUE(GetClient(kSingleProfileIndex)->AwaitEngineInitialization()); + ASSERT_TRUE(GetClient(kSingleProfileIndex)->AwaitSyncSetupCompletion()); + + // Run a sync cycle to trigger bookmarks reupload on browser startup. This is + // required since bookmarks get reuploaded only after the latest changes are + // downloaded to avoid uploading outdated data. + GetSyncService(kSingleProfileIndex)->TriggerRefresh(syncer::BOOKMARKS); + + // Bookmark favicon will be loaded if there are local changes. ASSERT_TRUE( BookmarkFaviconLoadedChecker(kSingleProfileIndex, GURL(kBookmarkPageUrl)) .Wait());
diff --git a/chrome/browser/sync/test/integration/single_client_device_info_sync_test.cc b/chrome/browser/sync/test/integration/single_client_device_info_sync_test.cc index 1edf3f0..ece5869 100644 --- a/chrome/browser/sync/test/integration/single_client_device_info_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_device_info_sync_test.cc
@@ -208,9 +208,6 @@ /*creation_time=*/0, /*last_modified_time=*/0)); } - // SyncTest overrides. - bool UseConfigurationRefresher() override { return false; } - private: base::test::ScopedFeatureList override_features_; };
diff --git a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc index 9cc05ce..b3fa0f86 100644 --- a/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_passwords_sync_test.cc
@@ -300,9 +300,13 @@ IN_PROC_BROWSER_TEST_F(SingleClientPasswordsSyncTest, PersistProgressMarkerOnRestart) { base::HistogramTester histogram_tester; - ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + ASSERT_TRUE(SetupClients()); ASSERT_EQ(1, GetPasswordCount(0)); - ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization()); + + // Wait for data types to be ready for sync and trigger a sync cycle. + // Otherwise, TriggerRefresh() would be no-op. + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion()); + GetSyncService(0)->TriggerRefresh(syncer::PASSWORDS); // After restart, the last sync cycle snapshot should be empty. Once a sync // request happened (e.g. by a poll), that snapshot is populated. We use the @@ -831,12 +835,10 @@ base::HistogramTester histogram_tester; ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; ASSERT_EQ(1, GetPasswordCount(0)); - ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization()); - // After restart, the last sync cycle snapshot should be empty. Once a sync - // request happened (e.g. by a poll), that snapshot is populated. We use the - // following checker to simply wait for an non-empty snapshot. - EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + // Wait for data types to be ready for sync (and hence model types are + // loaded). + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion()); // The original metric is defined in password_sync_bridge.cc. const int kNone = 0;
diff --git a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc index 838205e..d4eaa68f 100644 --- a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
@@ -11,7 +11,6 @@ #include "chrome/browser/defaults.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/test/integration/secondary_account_helper.h" -#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "chrome/browser/sync/test/integration/sync_service_impl_harness.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "chrome/common/chrome_paths.h" @@ -53,6 +52,8 @@ ~SingleClientSecondaryAccountSyncTest() override = default; void SetUpInProcessBrowserTestFixture() override { + SyncTest::SetUpInProcessBrowserTestFixture(); + test_signin_client_subscription_ = secondary_account_helper::SetUpSigninClient(&test_url_loader_factory_); }
diff --git a/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc b/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc index e651310..f8f205c 100644 --- a/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc +++ b/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
@@ -266,10 +266,6 @@ override_features_.InitWithFeatures(enabled_features, disabled_features); } - // Disable configuration refresher to make it sure that clients receive - // invalidations correctly during browser startup. - bool UseConfigurationRefresher() override { return false; } - private: base::test::ScopedFeatureList override_features_; };
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc index 3d3cd42..69036de 100644 --- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -1311,6 +1311,8 @@ ~SingleClientWalletSecondaryAccountSyncTest() override = default; void SetUpInProcessBrowserTestFixture() override { + SingleClientWalletSyncTest::SetUpInProcessBrowserTestFixture(); + test_signin_client_subscription_ = secondary_account_helper::SetUpSigninClient(&test_url_loader_factory_); }
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index 5491fa1..89771a73 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -21,6 +21,9 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/task/sequenced_task_runner.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "base/test/test_timeouts.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -36,7 +39,6 @@ #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" -#include "chrome/browser/sync/sync_invalidations_service_factory.h" #include "chrome/browser/sync/sync_service_factory.h" #include "chrome/browser/sync/test/integration/committed_all_nudged_changes_checker.h" #include "chrome/browser/sync/test/integration/device_info_helper.h" @@ -64,6 +66,7 @@ #include "components/invalidation/impl/profile_identity_provider.h" #include "components/invalidation/impl/profile_invalidation_provider.h" #include "components/invalidation/public/invalidation_service.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/core/keyed_service.h" #include "components/os_crypt/os_crypt_mocker.h" #include "components/prefs/scoped_user_pref_update.h" @@ -75,7 +78,6 @@ #include "components/sync/driver/sync_service_impl.h" #include "components/sync/driver/sync_user_settings.h" #include "components/sync/engine/sync_scheduler_impl.h" -#include "components/sync/invalidations/fcm_handler.h" #include "components/sync/invalidations/sync_invalidations_service_impl.h" #include "components/sync/test/fake_server_network_resources.h" #include "content/public/browser/navigation_entry.h" @@ -549,10 +551,6 @@ return false; } -bool SyncTest::UseConfigurationRefresher() { - return true; -} - bool SyncTest::SetupClients() { previous_profile_ = g_browser_process->profile_manager()->GetLastUsedProfile(); @@ -665,17 +663,13 @@ sync_service_impl->OverrideNetworkForTest( fake_server::CreateFakeServerHttpPostProviderFactory( GetFakeServer()->AsWeakPtr())); - // TODO(crbug.com/1331206): use GCM driver directly to deliver - // invalidations. - syncer::SyncInvalidationsServiceImpl* sync_invalidations_service = - static_cast<syncer::SyncInvalidationsServiceImpl*>( - SyncInvalidationsServiceFactory::GetForProfile(profile)); - if (sync_invalidations_service) { - profile_to_fcm_handler_map_[profile] = - sync_invalidations_service->GetFCMHandlerForTesting(); - fake_server_sync_invalidation_sender_->AddFCMHandler( - sync_invalidations_service->GetFCMHandlerForTesting()); - } + + // Make sure that an instance of GCMProfileService has been created. This is + // required for some tests which only call SetupClients(). + gcm::GCMProfileServiceFactory::GetForProfile(profile); + DCHECK(base::Contains(profile_to_fake_gcm_driver_, profile)); + fake_server_sync_invalidation_sender_->AddFakeGCMDriver( + profile_to_fake_gcm_driver_[profile]); } SyncServiceImplHarness::SigninType signin_type = @@ -687,7 +681,6 @@ clients_[index] = SyncServiceImplHarness::Create(GetProfile(index), username_, password_, signin_type); EXPECT_NE(nullptr, GetClient(index)) << "Could not create Client " << index; - InitializeConfigurationRefresher(index); } void SyncTest::DisableNotificationsForClient(int index) { @@ -747,31 +740,6 @@ } } -void SyncTest::InitializeConfigurationRefresher(int index) { - if (!UseConfigurationRefresher()) { - return; - } - - // Lazily create |configuration_refresher_| the first time we get here (or the - // first time after a previous call to StopConfigurationRefresher). - if (!configuration_refresher_) { - configuration_refresher_ = std::make_unique<ConfigurationRefresher>(); - } - - switch (server_type_) { - case EXTERNAL_LIVE_SERVER: - // DO NOTHING. External live sync servers use GCM to notify profiles of - // any invalidations in sync'ed data. In this case, to notify other - // profiles of invalidations, we use sync refresh notifications instead. - break; - case IN_PROCESS_FAKE_SERVER: { - configuration_refresher_->Observe( - SyncServiceFactory::GetForProfile(GetProfile(index))); - break; - } - } -} - void SyncTest::SetupSyncInternal(SetupSyncMode setup_mode) { // Create sync profiles and clients if they haven't already been created. if (profiles_.empty()) { @@ -828,6 +796,9 @@ } void SyncTest::ClearProfiles() { + // This method is called for only a live server, so it shouldn't use + // FakeGCMDriver. + DCHECK(profile_to_fake_gcm_driver_.empty()); profiles_.clear(); scoped_temp_dirs_.clear(); #if !BUILDFLAG(IS_ANDROID) @@ -907,14 +878,10 @@ observer : fake_server_invalidation_observers_) { fake_server_->RemoveObserver(observer.get()); } - profile_to_fcm_handler_map_.clear(); fake_server_sync_invalidation_sender_.reset(); fake_server_.reset(); } - // Delete things that unsubscribe in destructor before their targets are gone. - configuration_refresher_.reset(); - for (Profile* profile : profiles_) { // Profile could be removed earlier. if (profile) { @@ -927,6 +894,7 @@ // sure they're not used anymore. profiles_.clear(); clients_.clear(); + profile_to_fake_gcm_driver_.clear(); // TODO(crbug.com/1260897): There are various other Profile-related members // around like profile_to_*_map_ - those should probably be cleaned up too. @@ -962,19 +930,19 @@ } CheckForDataTypeFailures(/*client_index=*/index); + + // |profile_to_fake_gcm_driver_| may be empty when using an external server. + if (base::Contains(profile_to_fake_gcm_driver_, profile)) { + fake_server_sync_invalidation_sender_->RemoveFakeGCMDriver( + profile_to_fake_gcm_driver_[profile]); + profile_to_fake_gcm_driver_.erase(profile); + } profiles_[index] = nullptr; clients_[index].reset(); #if !BUILDFLAG(IS_ANDROID) DCHECK(!browsers_[index]); #endif // !BUILDFLAG(IS_ANDROID) } - - if (fake_server_sync_invalidation_sender_) { - DCHECK(base::Contains(profile_to_fcm_handler_map_, profile)); - fake_server_sync_invalidation_sender_->RemoveFCMHandler( - profile_to_fcm_handler_map_[profile]); - profile_to_fcm_handler_map_.erase(profile); - } } void SyncTest::OnWillCreateBrowserContextServices( @@ -991,7 +959,8 @@ base::BindRepeating(&SyncTest::CreateProfileInvalidationProvider, &profile_to_fcm_network_handler_map_)); gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactory( - context, base::BindRepeating(&FakeSyncGCMDriver::Build)); + context, base::BindRepeating(&SyncTest::CreateGCMProfileService, + base::Unretained(this))); } // static @@ -1032,6 +1001,24 @@ })); } +std::unique_ptr<KeyedService> SyncTest::CreateGCMProfileService( + content::BrowserContext* context) { + scoped_refptr<base::SequencedTaskRunner> blocking_task_runner( + base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); + + Profile* profile = Profile::FromBrowserContext(context); + + auto fake_gcm_driver = + std::make_unique<FakeSyncGCMDriver>(profile, blocking_task_runner); + profile_to_fake_gcm_driver_[profile] = fake_gcm_driver.get(); + fake_gcm_driver->WaitForAppIdBeforeConnection( + fake_server::FakeServerSyncInvalidationSender::kSyncInvalidationsAppId); + return std::make_unique<gcm::FakeGCMProfileService>( + std::move(fake_gcm_driver)); +} + void SyncTest::ResetSyncForPrimaryAccount() { if (server_type_ == EXTERNAL_LIVE_SERVER) { base::ScopedAllowBlockingForTesting allow_blocking; @@ -1104,12 +1091,6 @@ std::make_unique<fake_server::FakeServerSyncInvalidationSender>( fake_server_.get()); - // Subscribe to invalidations for all the profiles which were created - // before. This is mainly the case on Android platform. - for (const auto& profile_and_fcm_handler : profile_to_fcm_handler_map_) { - fake_server_sync_invalidation_sender_->AddFCMHandler( - profile_and_fcm_handler.second); - } SetupMockGaiaResponses(); SetupMockGaiaResponsesForProfile( ProfileManager::GetLastUsedProfileIfLoaded()); @@ -1210,10 +1191,6 @@ GetSyncService(index)->TriggerRefresh(model_types); } -void SyncTest::StopConfigurationRefresher() { - configuration_refresher_.reset(); -} - arc::SyncArcPackageHelper* SyncTest::sync_arc_helper() { #if BUILDFLAG(IS_CHROMEOS_ASH) return arc::SyncArcPackageHelper::GetInstance();
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h index e3f3471..2cd0dde 100644 --- a/chrome/browser/sync/test/integration/sync_test.h +++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -19,11 +19,9 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_observer.h" -#include "chrome/browser/sync/test/integration/configuration_refresher.h" #include "chrome/browser/sync/test/integration/fake_server_invalidation_sender.h" #include "chrome/browser/sync/test/integration/invalidations/fake_server_sync_invalidation_sender.h" #include "chrome/common/buildflags.h" -#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/sync/base/model_type.h" #include "components/sync/base/user_selectable_type.h" #include "components/sync/test/fake_server.h" @@ -59,6 +57,8 @@ #define E2E_ONLY(test_name) MACRO_CONCAT(DISABLED_E2ETest, test_name) #define E2E_ENABLED(test_name) MACRO_CONCAT(test_name, E2ETest) +class FakeSyncGCMDriver; +class KeyedService; class SyncServiceImplHarness; namespace arc { @@ -75,7 +75,6 @@ } // namespace fake_server namespace syncer { -class FCMHandler; class SyncServiceImpl; } // namespace syncer @@ -215,11 +214,6 @@ // tests are rewritten in a way to not use verifier. virtual bool UseVerifier(); - // Used to determine whether to use the configuration refresher. It's used to - // mitigate test flakiness due to missed invalidations and download updates - // after SetupClients(). - virtual bool UseConfigurationRefresher(); - // Initializes sync clients and profiles but does not sync any of them. [[nodiscard]] virtual bool SetupClients(); @@ -264,11 +258,6 @@ // Triggers a sync for the given |model_types| for the Profile at |index|. void TriggerSyncForModelTypes(int index, syncer::ModelTypeSet model_types); - // The configuration refresher is triggering refreshes after the configuration - // phase is done (during start-up). Call this function before SetupSync() to - // avoid its effects. - void StopConfigurationRefresher(); - arc::SyncArcPackageHelper* sync_arc_helper(); std::string GetCacheGuid(size_t profile_index) const; @@ -327,6 +316,10 @@ profile_to_fcm_network_handler_map, content::BrowserContext* context); + // Creates a fake GCMProfileService to simulate sync invalidations. + std::unique_ptr<KeyedService> CreateGCMProfileService( + content::BrowserContext* context); + #if !BUILDFLAG(IS_ANDROID) // Called when the |browser| was removed externally. This just marks the // |browser| in the |browsers_| list as nullptr to keep indexes in |browsers_| @@ -362,9 +355,6 @@ // value of |server_type_|. void SetUpInvalidations(int index); - // Initializes the configuration refresher. - void InitializeConfigurationRefresher(int index); - // Internal routine for setting up sync. void SetupSyncInternal(SetupSyncMode setup_mode); @@ -446,10 +436,10 @@ std::map<const Profile*, invalidation::FCMNetworkHandler*> profile_to_fcm_network_handler_map_; - std::map<const Profile*, syncer::FCMHandler*> profile_to_fcm_handler_map_; - - // Triggers a GetUpdates via refresh after a configuration. - std::unique_ptr<ConfigurationRefresher> configuration_refresher_; + // Used to deliver invalidations to different profiles within + // FakeSyncServerInvalidationSender. + std::map<raw_ptr<Profile>, raw_ptr<FakeSyncGCMDriver>> + profile_to_fake_gcm_driver_; base::CallbackListSubscription create_services_subscription_;
diff --git a/chrome/browser/sync/test/integration/two_client_polling_sync_test.cc b/chrome/browser/sync/test/integration/two_client_polling_sync_test.cc index 492f851..35b8543 100644 --- a/chrome/browser/sync/test/integration/two_client_polling_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_polling_sync_test.cc
@@ -99,8 +99,6 @@ // Disconnect client 1 from sync and write another change from client 0. // Disconnect the remote client from the invalidation service. DisableNotificationsForClient(1); - // Make sure no extra sync cycles get triggered by test infrastructure. - StopConfigurationRefresher(); // Note: It's important to *not* clear data here - if we clear data, then // we'll do a regular GetUpdates at the next startup, so there'd be no need // for a poll.
diff --git a/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc b/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc index 783ee64..6370d85f 100644 --- a/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc
@@ -859,7 +859,12 @@ IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTestWithoutLacrosSupport, ResetWithDuplicateMetadata) { base::HistogramTester histogram_tester; - ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // SetupSync() can't be used since it relies on an additional sync cycle (via + // UpdateProgressMarkerChecker which checks non-empty progress markers). + ASSERT_TRUE(SetupClients()); + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion()); + ASSERT_TRUE(GetClient(1)->AwaitSyncSetupCompletion()); // On startup, client 1 should reset its metadata and perform initial sync // once again. Sync one more url across the clients to be sure client 1
diff --git a/chrome/browser/sync/test/integration/updated_progress_marker_checker.cc b/chrome/browser/sync/test/integration/updated_progress_marker_checker.cc index 0cc6417..fb237fa 100644 --- a/chrome/browser/sync/test/integration/updated_progress_marker_checker.cc +++ b/chrome/browser/sync/test/integration/updated_progress_marker_checker.cc
@@ -26,9 +26,10 @@ UpdatedProgressMarkerChecker::~UpdatedProgressMarkerChecker() = default; bool UpdatedProgressMarkerChecker::IsExitConditionSatisfied(std::ostream* os) { - *os << "Waiting for progress markers"; + *os << "Waiting for progress markers... "; if (!has_unsynced_items_.has_value()) { + *os << "Unknown synced values state."; return false; } @@ -42,9 +43,22 @@ // by the test-only 'self-notify' cycle). // 3. No pending local changes (which will ultimately generate new progress // markers once submitted to the server). - return !snap.download_progress_markers().empty() && - snap.model_neutral_state().num_successful_commits == 0 && - !has_unsynced_items_.value(); + if (snap.download_progress_markers().empty()) { + *os << "Progress markers are empty."; + return false; + } + + if (snap.model_neutral_state().num_successful_commits > 0) { + *os << "Last sync cycle wasn't empty."; + return false; + } + + if (has_unsynced_items_.value()) { + *os << "Has unsynced items."; + return false; + } + + return true; } void UpdatedProgressMarkerChecker::GotHasUnsyncedItems(
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerBridge.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerBridge.java index 430bf50..8f481f0 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerBridge.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerBridge.java
@@ -31,10 +31,10 @@ } @Override - public void onDismissed() { + public void onDismissed(boolean dismissedByUser) { if (mNativeTouchToFillCreditCardViewController != 0) { TouchToFillCreditCardControllerBridgeJni.get().onDismissed( - mNativeTouchToFillCreditCardViewController); + mNativeTouchToFillCreditCardViewController, dismissedByUser); } } @@ -64,7 +64,7 @@ @NativeMethods interface Natives { - void onDismissed(long nativeTouchToFillCreditCardViewController); + void onDismissed(long nativeTouchToFillCreditCardViewController, boolean dismissedByUser); void scanCreditCard(long nativeTouchToFillCreditCardViewController); void showCreditCardSettings(long nativeTouchToFillCreditCardViewController); void suggestionSelected(long nativeTouchToFillCreditCardViewController, String uniqueId);
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardMediator.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardMediator.java index b8d5cf5..b1d87c49 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardMediator.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardMediator.java
@@ -110,8 +110,10 @@ public void onDismissed(@StateChangeReason int reason) { if (!mModel.get(VISIBLE)) return; // Dismiss only if not dismissed yet. mModel.set(VISIBLE, false); - mDelegate.onDismissed(); - if (reason == StateChangeReason.SWIPE) { + boolean dismissedByUser = + reason == StateChangeReason.SWIPE || reason == StateChangeReason.BACK_PRESS; + mDelegate.onDismissed(dismissedByUser); + if (dismissedByUser) { RecordHistogram.recordEnumeratedHistogram(TOUCH_TO_FILL_OUTCOME_HISTOGRAM, TouchToFillCreditCardOutcome.DISMISS, TouchToFillCreditCardOutcome.MAX_VALUE + 1);
diff --git a/chrome/browser/touch_to_fill/payments/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardComponent.java b/chrome/browser/touch_to_fill/payments/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardComponent.java index 77880cf5..cfdac33 100644 --- a/chrome/browser/touch_to_fill/payments/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardComponent.java +++ b/chrome/browser/touch_to_fill/payments/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardComponent.java
@@ -21,7 +21,7 @@ /** * Called whenever the sheet is dismissed (by user or native). */ - void onDismissed(); + void onDismissed(boolean dismissedByUser); /** * Called when user requests to scan a new credit card.
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.cc b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.cc index 4d13a87..9a210b63 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.cc +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.cc
@@ -51,10 +51,11 @@ } } -void TouchToFillCreditCardController::OnDismissed(JNIEnv* env) { +void TouchToFillCreditCardController::OnDismissed(JNIEnv* env, + bool dismissed_by_user) { SetShouldSuppressKeyboard(/*suppress=*/false); if (delegate_) { - delegate_->OnDismissed(); + delegate_->OnDismissed(dismissed_by_user); } view_.reset(); delegate_.reset();
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h index ef00311..2d325662 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h
@@ -45,7 +45,7 @@ void Hide(); // TouchToFillCreditCardViewController: - void OnDismissed(JNIEnv* env) override; + void OnDismissed(JNIEnv* env, bool dismissed_by_user) override; void ScanCreditCard(JNIEnv* env) override; void ShowCreditCardSettings(JNIEnv* env) override; void SuggestionSelected(
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller_unittest.cc b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller_unittest.cc index 7e196085..d70e140 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller_unittest.cc +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller_unittest.cc
@@ -75,7 +75,7 @@ MOCK_METHOD(void, OnCreditCardScanned, (const CreditCard& card), (override)); MOCK_METHOD(void, ShowCreditCardSettings, (), (override)); MOCK_METHOD(void, SuggestionSelected, (std::string unique_id), (override)); - MOCK_METHOD(void, OnDismissed, (), (override)); + MOCK_METHOD(void, OnDismissed, (bool dismissed_by_user), (override)); private: MockContentAutofillDriver driver_; @@ -135,5 +135,5 @@ mock_delegate_.GetWeakPointer(), credit_cards_); EXPECT_CALL(mock_delegate_, OnDismissed); - credit_card_controller_.OnDismissed(nullptr); + credit_card_controller_.OnDismissed(nullptr, true); }
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h index f6f8ffbb..bff9016 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h
@@ -15,7 +15,7 @@ virtual ~TouchToFillCreditCardViewController() = default; // Called whenever the surface gets hidden (regardless of the cause). - virtual void OnDismissed(JNIEnv* env) = 0; + virtual void OnDismissed(JNIEnv* env, bool dismissed_by_user) = 0; // Calls credit card scanner virtual void ScanCreditCard(JNIEnv* env) = 0; // Causes the credit cards settings page to be shown
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 0b1f80f..04eb144 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1173,8 +1173,8 @@ "omnibox/alternate_nav_infobar_delegate.h", "omnibox/chrome_omnibox_client.cc", "omnibox/chrome_omnibox_client.h", - "omnibox/chrome_omnibox_edit_controller.cc", - "omnibox/chrome_omnibox_edit_controller.h", + "omnibox/chrome_omnibox_edit_model_delegate.cc", + "omnibox/chrome_omnibox_edit_model_delegate.h", "omnibox/chrome_omnibox_navigation_observer.cc", "omnibox/chrome_omnibox_navigation_observer.h", "omnibox/clipboard_utils.cc", @@ -2252,6 +2252,8 @@ "ash/back_gesture_contextual_nudge_delegate.h", "ash/browser_data_migration_error_dialog.cc", "ash/browser_data_migration_error_dialog.h", + "ash/bruschetta_delegate.cc", + "ash/bruschetta_delegate.h", "ash/calendar/calendar_client_impl.cc", "ash/calendar/calendar_client_impl.h", "ash/calendar/calendar_keyed_service.cc", @@ -5488,8 +5490,6 @@ sources += [ "bookmarks/bookmark_bubble_sign_in_delegate.cc", "bookmarks/bookmark_bubble_sign_in_delegate.h", - "dialogs/outdated_upgrade_bubble.cc", - "dialogs/outdated_upgrade_bubble.h", "views/accessibility/accessibility_focus_highlight.cc", "views/accessibility/accessibility_focus_highlight.h", "views/policy/enterprise_startup_dialog_view.cc", @@ -5512,6 +5512,8 @@ if (!is_chromeos) { sources += [ + "dialogs/outdated_upgrade_bubble.cc", + "dialogs/outdated_upgrade_bubble.h", "idle_dialog.h", "sharing_hub/sharing_hub_bubble_controller_desktop_impl.cc", "sharing_hub/sharing_hub_bubble_controller_desktop_impl.h",
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc index efb82f4..c3a806a4 100644 --- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc +++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
@@ -6,6 +6,7 @@ #include "chrome/android/chrome_jni_headers/CardUnmaskBridge_jni.h" #include "chrome/browser/android/resource_mapper.h" +#include "chrome/browser/autofill/autofill_popup_controller_utils.h" #include "chrome/browser/ui/autofill/payments/create_card_unmask_prompt_view.h" #include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h" #include "components/autofill/core/common/autofill_payments_features.h" @@ -149,12 +150,22 @@ ScopedJavaLocalRef<jstring> instructions = base::android::ConvertUTF16ToJavaString( env, controller_->GetInstructionsMessage()); + ScopedJavaLocalRef<jstring> card_name = + base::android::ConvertUTF16ToJavaString(env, controller_->GetCardName()); + ScopedJavaLocalRef<jstring> card_last_four_digits = + base::android::ConvertUTF16ToJavaString( + env, controller_->GetCardLastFourDigits()); + ScopedJavaLocalRef<jstring> card_expiration = + base::android::ConvertUTF16ToJavaString(env, + controller_->GetCardExpiration()); ScopedJavaLocalRef<jstring> confirm = base::android::ConvertUTF16ToJavaString( env, controller_->GetOkButtonLabel()); return java_object_internal_ = Java_CardUnmaskBridge_create( env, reinterpret_cast<intptr_t>(this), dialog_title, instructions, - confirm, + ResourceMapper::MapToJavaDrawableId( + GetIconResourceID(controller_->GetCardIconString())), + card_name, card_last_four_digits, card_expiration, confirm, ResourceMapper::MapToJavaDrawableId(controller_->GetCvcImageRid()), ResourceMapper::MapToJavaDrawableId( controller_->GetGooglePayImageRid()),
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 8466ad1..e7c1ff1f 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -5413,18 +5413,21 @@ <message name="IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_MESSAGE" desc="The body text of a dialog explaining the benefits of enabling Chrome notifications."> You’ll be able to easily manage media controls, Incognito sessions, downloads and more </message> - <message name="IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_TITLE_VARIATION_2" desc="The title of a dialog shown to users before asking for notification permission."> - Manage media controls, Incognito tabs, and more with notifications - </message> - <message name="IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_MESSAGE_VARIATION_2" desc="The body text of a dialog explaining the benefits of enabling Chrome notifications."> - You can disable notifications by visiting settings - </message> <message name="IDS_NOTIFICATION_PERMISSION_RATIONALE_ACCEPT_BUTTON_TEXT" desc="The text of the positive button on the notification permission prompt dialog"> Continue </message> <message name="IDS_NOTIFICATION_PERMISSION_RATIONALE_REJECT_BUTTON_TEXT" desc="The text of the negative button on the notification permission prompt dialog"> No thanks </message> + <message name="IDS_NOTIFICATION_PERMISSION_RATIONALE_CONTENT_DESCRIPTION" desc="The content description for the notification permission rationale bottom sheet. Read as accessibility string when tapping on the bottom sheet."> + Notification permission flow + </message> + <message name="IDS_NOTIFICATION_PERMISSION_RATIONALE_OPENED_FULL" desc="The accessibility string read when the notification permission rationale bottom sheet is fully opened."> + Notification permission flow opened at full height + </message> + <message name="IDS_NOTIFICATION_PERMISSION_RATIONALE_CLOSED_DESCRIPTION" desc="The accessibility string read when the notification permission rationale bottom sheet is closed."> + Notification permission flow closed + </message> <!-- Get Image Descriptions --> <message name="IDS_IMAGE_DESCRIPTIONS_DIALOG_HEADER" desc="Header for confirmation dialog to enable image descriptions.">
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_CLOSED_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_CLOSED_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..dd05615 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_CLOSED_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +2a0594789322e45f78702fc995722dcf9abdf449 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_CONTENT_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_CONTENT_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..dd05615 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_CONTENT_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +2a0594789322e45f78702fc995722dcf9abdf449 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_MESSAGE_VARIATION_2.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_MESSAGE_VARIATION_2.png.sha1 deleted file mode 100644 index 9bc6cd4..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_MESSAGE_VARIATION_2.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -0f94ab4cd54824a86dfedbd7e84d2903152dbaed \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_TITLE_VARIATION_2.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_TITLE_VARIATION_2.png.sha1 deleted file mode 100644 index 9bc6cd4..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_DIALOG_TITLE_VARIATION_2.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -0f94ab4cd54824a86dfedbd7e84d2903152dbaed \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_OPENED_FULL.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_OPENED_FULL.png.sha1 new file mode 100644 index 0000000..dd05615 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_NOTIFICATION_PERMISSION_RATIONALE_OPENED_FULL.png.sha1
@@ -0,0 +1 @@ +2a0594789322e45f78702fc995722dcf9abdf449 \ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml b/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml index 690712e..6936222e 100644 --- a/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml +++ b/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml
@@ -20,10 +20,22 @@ android:paddingStart="@dimen/tablet_toolbar_start_padding" > <LinearLayout + android:id="@+id/toolbar_tablet_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > + <org.chromium.chrome.browser.toolbar.HomeButton + android:id="@+id/home_button" + style="@style/ToolbarButton" + android:src="@drawable/btn_toolbar_home" + android:contentDescription="@string/accessibility_toolbar_btn_home" + android:visibility="gone" + app:menuMaxWidth="@dimen/home_button_list_menu_width" + app:menuPositionedAtEnd="false" + app:menuVerticalOverlapAnchor="false" + app:tint="@color/default_icon_color_tint_list" /> + <org.chromium.ui.widget.ChromeImageButton android:id="@+id/back_button" style="@style/ToolbarButton" @@ -46,17 +58,6 @@ app:tint="@color/default_icon_color_tint_list" style="@style/ToolbarButton" /> - <org.chromium.chrome.browser.toolbar.HomeButton - android:id="@+id/home_button" - style="@style/ToolbarButton" - android:src="@drawable/btn_toolbar_home" - android:contentDescription="@string/accessibility_toolbar_btn_home" - android:visibility="gone" - app:menuMaxWidth="@dimen/home_button_list_menu_width" - app:menuPositionedAtEnd="false" - app:menuVerticalOverlapAnchor="false" - app:tint="@color/default_icon_color_tint_list" /> - <org.chromium.chrome.browser.omnibox.LocationBarTablet android:id="@+id/location_bar" android:layout_width="0dp"
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/HomeButtonCoordinatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/HomeButtonCoordinatorTest.java index 311cb21c..ec35aa5 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/HomeButtonCoordinatorTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/HomeButtonCoordinatorTest.java
@@ -40,7 +40,6 @@ import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.feature_engagement.FeatureConstants; import org.chromium.url.GURL; import org.chromium.url.JUnitTestGURLs; @@ -52,7 +51,6 @@ @RunWith(BaseRobolectricTestRunner.class) @Config(shadows = {HomeButtonCoordinatorTest.ShadowChromeFeatureList.class}) @DisableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) -@EnableFeatures(ChromeFeatureList.ENABLE_IPH) public class HomeButtonCoordinatorTest { private static final GURL NTP_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.NTP_URL); private static final GURL NOT_NTP_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinator.java index 328c34e..c287c9f 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinator.java
@@ -12,14 +12,12 @@ import org.chromium.base.CallbackController; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.OneshotSupplier; -import org.chromium.chrome.browser.flags.FeatureParamUtils; import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.tab.CurrentTabObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.R; -import org.chromium.chrome.browser.toolbar.ToolbarIntentMetadata; import org.chromium.chrome.browser.user_education.IPHCommandBuilder; import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightParams; @@ -37,17 +35,11 @@ * class. */ public class ToggleTabStackButtonCoordinator { - @VisibleForTesting - static final String MAIN_INTENT_FROM_LAUNCHER_PARAM_NAME = "isMainIntentFromLauncher"; - @VisibleForTesting - static final String INTENT_WITH_EFFECT_PARAM_NAME = "intentWithEffect"; - private final CallbackController mCallbackController = new CallbackController(); private final Context mContext; private final ToggleTabStackButton mToggleTabStackButton; private final UserEducationHelper mUserEducationHelper; private final BooleanSupplier mIsIncognitoSupplier; - private final OneshotSupplier<ToolbarIntentMetadata> mIntentMetadataOneshotSupplier; private final OneshotSupplier<Boolean> mPromoShownOneshotSupplier; private final Callback<Boolean> mSetNewTabButtonHighlightCallback; private final CurrentTabObserver mPageLoadObserver; @@ -63,7 +55,6 @@ * component. * @param userEducationHelper Helper class for showing in-product help text bubbles. * @param isIncognitoSupplier Supplier for whether the current tab is incognito. - * @param intentMetadataOneshotSupplier Potentially delayed information about launching intent. * @param promoShownOneshotSupplier Potentially delayed information about if a promo was shown. * @param layoutStateProviderSupplier Allows observing layout state. * @param setNewTabButtonHighlightCallback Delegate to highlight the new tab button. @@ -71,9 +62,7 @@ */ public ToggleTabStackButtonCoordinator(Context context, ToggleTabStackButton toggleTabStackButton, UserEducationHelper userEducationHelper, - BooleanSupplier isIncognitoSupplier, - OneshotSupplier<ToolbarIntentMetadata> intentMetadataOneshotSupplier, - OneshotSupplier<Boolean> promoShownOneshotSupplier, + BooleanSupplier isIncognitoSupplier, OneshotSupplier<Boolean> promoShownOneshotSupplier, OneshotSupplier<LayoutStateProvider> layoutStateProviderSupplier, Callback<Boolean> setNewTabButtonHighlightCallback, ObservableSupplier<Tab> activityTabSupplier) { @@ -81,7 +70,6 @@ mToggleTabStackButton = toggleTabStackButton; mUserEducationHelper = userEducationHelper; mIsIncognitoSupplier = isIncognitoSupplier; - mIntentMetadataOneshotSupplier = intentMetadataOneshotSupplier; mPromoShownOneshotSupplier = promoShownOneshotSupplier; mSetNewTabButtonHighlightCallback = setNewTabButtonHighlightCallback; @@ -142,20 +130,6 @@ if (mIsIncognitoSupplier.getAsBoolean()) return; if (mPromoShownOneshotSupplier.get() == null || mPromoShownOneshotSupplier.get()) return; - ToolbarIntentMetadata intentMetadata = mIntentMetadataOneshotSupplier.get(); - if (intentMetadata == null) return; - if (FeatureParamUtils.paramExistsAndDoesNotMatch( - FeatureConstants.TAB_SWITCHER_BUTTON_FEATURE, - MAIN_INTENT_FROM_LAUNCHER_PARAM_NAME, - intentMetadata.getIsMainIntentFromLauncher())) { - return; - } - if (FeatureParamUtils.paramExistsAndDoesNotMatch( - FeatureConstants.TAB_SWITCHER_BUTTON_FEATURE, INTENT_WITH_EFFECT_PARAM_NAME, - intentMetadata.getIsIntentWithEffect())) { - return; - } - HighlightParams params = new HighlightParams(HighlightShape.CIRCLE); params.setBoundsRespectPadding(true); mUserEducationHelper.requestShowIPH(new IPHCommandBuilder(mContext.getResources(),
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinatorTest.java index 4cddf88..1b9f2c2 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinatorTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinatorTest.java
@@ -24,9 +24,6 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; import org.robolectric.annotation.LooperMode; import org.chromium.base.Callback; @@ -36,43 +33,21 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.layouts.LayoutType; -import org.chromium.chrome.browser.toolbar.ToolbarIntentMetadata; import org.chromium.chrome.browser.user_education.IPHCommand; import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; -import org.chromium.components.feature_engagement.FeatureConstants; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; /** * Unit tests for ToggleTabStackButtonCoordinator. */ @RunWith(BaseRobolectricTestRunner.class) -@Config(shadows = {ToggleTabStackButtonCoordinatorTest.ShadowChromeFeatureList.class}) @LooperMode(LooperMode.Mode.LEGACY) @DisableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) -@EnableFeatures(ChromeFeatureList.ENABLE_IPH) public class ToggleTabStackButtonCoordinatorTest { - private static final ToolbarIntentMetadata DEFAULT_INTENT_METADATA = - new ToolbarIntentMetadata(/*isMainIntent*/ true, /*isIntentWithEffect*/ false); - - @Implements(ChromeFeatureList.class) - static class ShadowChromeFeatureList { - static Map<String, String> sParamMap; - @Implementation - public static String getFieldTrialParamByFeature(String featureName, String paramName) { - Assert.assertEquals("Wrong feature name", FeatureConstants.TAB_SWITCHER_BUTTON_FEATURE, - featureName); - if (sParamMap.containsKey(paramName)) return sParamMap.get(paramName); - return ""; - } - } - @Rule public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor(); @@ -94,8 +69,6 @@ private boolean mIsIncognito; private boolean mOverviewOpen; - private final OneshotSupplierImpl<ToolbarIntentMetadata> mIntentMetadataOneshotSupplier = - new OneshotSupplierImpl<>(); private final OneshotSupplierImpl<Boolean> mPromoShownOneshotSupplier = new OneshotSupplierImpl<>(); private Set<LayoutStateProvider.LayoutStateObserver> mLayoutStateObserverSet; @@ -128,7 +101,6 @@ // Defaults most test cases expect, can be overridden by each test though. when(mToggleTabStackButton.isShown()).thenReturn(true); - ShadowChromeFeatureList.sParamMap = new HashMap<>(); mIsIncognito = false; } @@ -136,7 +108,7 @@ ToggleTabStackButton toggleTabStackButton) { // clang-format off return new ToggleTabStackButtonCoordinator(mContext, toggleTabStackButton, - mUserEducationHelper, () -> mIsIncognito, mIntentMetadataOneshotSupplier, + mUserEducationHelper, () -> mIsIncognito, mPromoShownOneshotSupplier, mLayoutSateProviderOneshotSupplier, mSetNewTabButtonHighlightCallback, new ObservableSupplierImpl<>()); // clang-format on @@ -212,7 +184,6 @@ ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); toggleTabStackButtonCoordinator.handlePageLoadFinished(); @@ -230,7 +201,6 @@ ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); toggleTabStackButtonCoordinator.handlePageLoadFinished(); @@ -257,7 +227,6 @@ ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); toggleTabStackButtonCoordinator.handlePageLoadFinished(); @@ -285,7 +254,6 @@ ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); showOverviewMode(); @@ -302,7 +270,6 @@ ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); verifyIphNotShown(); @@ -313,7 +280,6 @@ ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ null); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); toggleTabStackButtonCoordinator.handlePageLoadFinished(); @@ -324,7 +290,6 @@ public void testIphWithNoOverviewModeBehavior() { ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); toggleTabStackButtonCoordinator.handlePageLoadFinished(); @@ -352,7 +317,6 @@ ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); mIsIncognito = true; @@ -369,7 +333,6 @@ ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(false); when(mToggleTabStackButton.isShown()).thenReturn(false); @@ -382,61 +345,10 @@ } @Test - public void testIphMainIntentFalse() { - ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = - newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); - mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set( - new ToolbarIntentMetadata(/*isMainIntent*/ false, /*isIntentWithEffect*/ false)); - mPromoShownOneshotSupplier.set(false); - - ShadowChromeFeatureList.sParamMap.put( - HomeButtonCoordinator.MAIN_INTENT_FROM_LAUNCHER_PARAM_NAME, ""); - toggleTabStackButtonCoordinator.handlePageLoadFinished(); - verifyIphShown(); - - ShadowChromeFeatureList.sParamMap.put( - HomeButtonCoordinator.MAIN_INTENT_FROM_LAUNCHER_PARAM_NAME, "false"); - toggleTabStackButtonCoordinator.handlePageLoadFinished(); - verifyIphShown(); - - ShadowChromeFeatureList.sParamMap.put( - HomeButtonCoordinator.MAIN_INTENT_FROM_LAUNCHER_PARAM_NAME, "true"); - toggleTabStackButtonCoordinator.handlePageLoadFinished(); - verifyIphNotShown(); - } - - @Test - public void testIphIntentWithEffectTrue() { - ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = - newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); - mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set( - new ToolbarIntentMetadata(/*isMainIntent*/ true, /*isIntentWithEffect*/ true)); - mPromoShownOneshotSupplier.set(false); - - ShadowChromeFeatureList.sParamMap.put( - HomeButtonCoordinator.INTENT_WITH_EFFECT_PARAM_NAME, ""); - toggleTabStackButtonCoordinator.handlePageLoadFinished(); - verifyIphShown(); - - ShadowChromeFeatureList.sParamMap.put( - HomeButtonCoordinator.INTENT_WITH_EFFECT_PARAM_NAME, "false"); - toggleTabStackButtonCoordinator.handlePageLoadFinished(); - verifyIphNotShown(); - - ShadowChromeFeatureList.sParamMap.put( - HomeButtonCoordinator.INTENT_WITH_EFFECT_PARAM_NAME, "true"); - toggleTabStackButtonCoordinator.handlePageLoadFinished(); - verifyIphShown(); - } - - @Test public void testIphShowedPromo() { ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); mPromoShownOneshotSupplier.set(true); toggleTabStackButtonCoordinator.handlePageLoadFinished(); @@ -444,26 +356,10 @@ } @Test - public void testIphDelayedIntentMetadata() { - ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = - newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); - mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mPromoShownOneshotSupplier.set(false); - - toggleTabStackButtonCoordinator.handlePageLoadFinished(); - verifyIphNotShown(); - - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); - toggleTabStackButtonCoordinator.handlePageLoadFinished(); - verifyIphShown(); - } - - @Test public void testIphDelayedPromoShown() { ToggleTabStackButtonCoordinator toggleTabStackButtonCoordinator = newToggleTabStackButtonCoordinator(/*view*/ mToggleTabStackButton); mLayoutSateProviderOneshotSupplier.set(mLayoutStateProvider); - mIntentMetadataOneshotSupplier.set(DEFAULT_INTENT_METADATA); toggleTabStackButtonCoordinator.handlePageLoadFinished(); verifyIphNotShown();
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java index eb5bfd5..531f431 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -50,7 +50,6 @@ import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate; import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.omnibox.LocationBar; import org.chromium.chrome.browser.omnibox.LocationBarCoordinator; import org.chromium.chrome.browser.omnibox.NewTabPageDelegate; @@ -270,7 +269,6 @@ private boolean mOptionalButtonAnimationRunning; private int mUrlFocusTranslationX; - private boolean mOptimizationsEnabled; private boolean mDropdownListScrolled; // The following are some properties used during animation. We use explicit property classes @@ -486,9 +484,6 @@ protected void onNativeLibraryReady() { super.onNativeLibraryReady(); - mOptimizationsEnabled = - ChromeFeatureList.isEnabled(ChromeFeatureList.TOOLBAR_PHONE_OPTIMIZATIONS); - enableTabSwitchingResources(); mHomeButton.setOnClickListener(this); @@ -575,20 +570,9 @@ if (!mDisableLocationBarRelayout) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - boolean changed; - if (mOptimizationsEnabled) { - // Without optimizations, layoutLocationBar sometimes calls - // updateLocationBarLayoutForExpansionAnimation, followed always by a second call to - // updateLocationBarLayoutForExpansionAnimation. The location bar shouldn't change - // between these two calls, so we can optimize by removing the call that is made - // sometimes. - changed = layoutLocationBarWithoutAnimationExpansion( - MeasureSpec.getSize(widthMeasureSpec)); - updateUrlExpansionAnimation(); - } else { - changed = layoutLocationBar(MeasureSpec.getSize(widthMeasureSpec)); - if (!isInTabSwitcherMode()) updateUrlExpansionAnimation(); - } + boolean changed = layoutLocationBarWithoutAnimationExpansion( + MeasureSpec.getSize(widthMeasureSpec)); + updateUrlExpansionAnimation(); if (!changed) return; } else { updateUnfocusedLocationBarLayoutParams(); @@ -1015,7 +999,7 @@ */ private void updateLocationBarLayoutForExpansionAnimation() { TraceEvent.begin("ToolbarPhone.updateLocationBarLayoutForExpansionAnimation"); - if (mOptimizationsEnabled && isInTabSwitcherMode()) return; + if (isInTabSwitcherMode()) return; boolean isLocationBarShownInNTP = isLocationBarShownInNTP(); FrameLayout.LayoutParams locationBarLayoutParams = @@ -1826,12 +1810,6 @@ // so that the final translation position is correct (since onMeasure updates // won't happen in tab switcher mode). crbug.com/518795. layoutLocationBar(getMeasuredWidth()); - if (!mOptimizationsEnabled) { - // We're in tab switcher mode here. updateUrlExpansionAnimation doesn't need to - // get called because we don't see the url bar, and that this gets called as - // soon as we exit tab switcher mode. - updateUrlExpansionAnimation(); - } } updateViewsForTabSwitcherMode();
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 1bab8f79..0df235ad 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
@@ -17,10 +17,12 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.view.ViewStub; import android.view.accessibility.AccessibilityEvent; import android.widget.ImageButton; import android.widget.ImageView; +import android.widget.LinearLayout; import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; @@ -83,6 +85,8 @@ void downloadPage(Context context, Tab tab); } + private static final int HOME_BUTTON_POSITION_FOR_TAB_STRIP_REDESIGN = 3; + private HomeButton mHomeButton; private ImageButton mBackButton; private ImageButton mForwardButton; @@ -136,10 +140,13 @@ mForwardButton = findViewById(R.id.forward_button); mReloadButton = findViewById(R.id.refresh_button); - // Disable home button reposition that aligns with desktop ordering when TSR disabled. - if (!ChromeFeatureList.sTabStripRedesign.isEnabled()) { - // Bring home button to the top when TSR is disabled. - mHomeButton.bringToFront(); + // Reposition home button to align with desktop ordering when TSR enabled. + if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { + // Remove home button view added in XML and adding back with different ordering + // programmatically. + ((ViewGroup) mHomeButton.getParent()).removeView(mHomeButton); + LinearLayout linearlayout = (LinearLayout) findViewById(R.id.toolbar_tablet_layout); + linearlayout.addView(mHomeButton, HOME_BUTTON_POSITION_FOR_TAB_STRIP_REDESIGN); } // ImageView tinting doesn't work with LevelListDrawable, use Drawable tinting instead.
diff --git a/chrome/browser/ui/ash/bruschetta_delegate.cc b/chrome/browser/ui/ash/bruschetta_delegate.cc new file mode 100644 index 0000000..7778e9f --- /dev/null +++ b/chrome/browser/ui/ash/bruschetta_delegate.cc
@@ -0,0 +1,12 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/bruschetta_delegate.h" + +#include "chrome/browser/ui/views/bruschetta/bruschetta_installer_view.h" + +void RunBruschettaInstaller(Profile* profile, + const guest_os::GuestId& guest_id) { + BruschettaInstallerView::Show(profile, guest_id); +}
diff --git a/chrome/browser/ui/ash/bruschetta_delegate.h b/chrome/browser/ui/ash/bruschetta_delegate.h new file mode 100644 index 0000000..70de5a5a --- /dev/null +++ b/chrome/browser/ui/ash/bruschetta_delegate.h
@@ -0,0 +1,15 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ASH_BRUSCHETTA_DELEGATE_H_ +#define CHROME_BROWSER_UI_ASH_BRUSCHETTA_DELEGATE_H_ + +#include "chrome/browser/ash/guest_os/guest_id.h" + +class Profile; + +void RunBruschettaInstaller(Profile* profile, + const guest_os::GuestId& guest_id); + +#endif // CHROME_BROWSER_UI_ASH_BRUSCHETTA_DELEGATE_H_
diff --git a/chrome/browser/ui/ash/media_client_impl.cc b/chrome/browser/ui/ash/media_client_impl.cc index cb02671..26ceccb7 100644 --- a/chrome/browser/ui/ash/media_client_impl.cc +++ b/chrome/browser/ui/ash/media_client_impl.cc
@@ -281,7 +281,8 @@ ash::PrivacyHubNotification::SensorSet{}, base::MakeRefCounted<ash::PrivacyHubNotificationClickDelegate>( base::BindRepeating( - ash::PrivacyHubNotificationController::OpenSupportUrl)), + ash::PrivacyHubNotificationController::OpenSupportUrl, + ash::PrivacyHubNotificationController::Sensor::kCamera)), ash::NotificationCatalogName::kCameraPrivacySwitch, IDS_ASH_LEARN_MORE) { MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index 7d4e7e0..1bd597f4 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -60,6 +60,7 @@ #include "components/autofill/core/browser/payments/credit_card_otp_authenticator.h" #include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/ui/payments/bubble_show_options.h" +#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h" #include "components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h" #include "components/autofill/core/browser/ui/popup_item_ids.h" #include "components/autofill/core/common/autofill_features.h" @@ -379,9 +380,9 @@ const CreditCard& card, const CardUnmaskPromptOptions& card_unmask_prompt_options, base::WeakPtr<CardUnmaskDelegate> delegate) { - unmask_controller_.ShowPrompt( + unmask_controller_->ShowPrompt( base::BindOnce(&CreateCardUnmaskPromptView, - base::Unretained(&unmask_controller_), + base::Unretained(unmask_controller_.get()), base::Unretained(web_contents())), card, card_unmask_prompt_options, delegate); } @@ -389,7 +390,7 @@ // TODO(crbug.com/1220990): Refactor this for both CVC and Biometrics flows. void ChromeAutofillClient::OnUnmaskVerificationResult( PaymentsRpcResult result) { - unmask_controller_.OnVerificationResult(result); + unmask_controller_->OnVerificationResult(result); #if BUILDFLAG(IS_ANDROID) // For VCN-related errors, on Android we show a new error dialog instead of // updating the CVC unmask prompt with the error message. @@ -1114,8 +1115,8 @@ LogManager::Create(AutofillLogRouterFactory::GetForBrowserContext( web_contents->GetBrowserContext()), base::NullCallback())), - unmask_controller_( - user_prefs::UserPrefs::Get(web_contents->GetBrowserContext())), + unmask_controller_(std::make_unique<CardUnmaskPromptControllerImpl>( + user_prefs::UserPrefs::Get(web_contents->GetBrowserContext()))), autofill_error_dialog_controller_(web_contents), autofill_progress_dialog_controller_( std::make_unique<AutofillProgressDialogControllerImpl>(
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h index 21b20f67..b24f3ef 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.h +++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -246,6 +246,11 @@ return popup_controller_; } void KeepPopupOpenForTesting() { keep_popup_open_for_testing_ = true; } + std::unique_ptr<CardUnmaskPromptControllerImpl> + SetCardUnmaskControllerForTesting( + std::unique_ptr<CardUnmaskPromptControllerImpl> test_controller) { + return std::exchange(unmask_controller_, std::move(test_controller)); + } #if !BUILDFLAG(IS_ANDROID) // ZoomObserver implementation. @@ -282,7 +287,7 @@ SaveUpdateAddressProfileFlowManager save_update_address_profile_flow_manager_; TouchToFillCreditCardController touch_to_fill_credit_card_controller_; #endif - CardUnmaskPromptControllerImpl unmask_controller_; + std::unique_ptr<CardUnmaskPromptControllerImpl> unmask_controller_; AutofillErrorDialogControllerImpl autofill_error_dialog_controller_; std::unique_ptr<AutofillProgressDialogControllerImpl> autofill_progress_dialog_controller_;
diff --git a/chrome/browser/ui/autofill/payments/card_unmask_prompt_view_browsertest.cc b/chrome/browser/ui/autofill/payments/card_unmask_prompt_view_browsertest.cc index a9b7172..276e83c 100644 --- a/chrome/browser/ui/autofill/payments/card_unmask_prompt_view_browsertest.cc +++ b/chrome/browser/ui/autofill/payments/card_unmask_prompt_view_browsertest.cc
@@ -185,7 +185,7 @@ controller()->set_expected_verification_failure( /*allow_retry*/ name == kExpiryValidTemporaryError); CardUnmaskPromptViewTester::For(controller()->view()) - ->EnterCVCAndAccept(); + ->EnterCVCAndAccept(u"123"); } }
diff --git a/chrome/browser/ui/autofill/payments/card_unmask_prompt_view_tester.h b/chrome/browser/ui/autofill/payments/card_unmask_prompt_view_tester.h index 7f18a74..3e39da7 100644 --- a/chrome/browser/ui/autofill/payments/card_unmask_prompt_view_tester.h +++ b/chrome/browser/ui/autofill/payments/card_unmask_prompt_view_tester.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_CARD_UNMASK_PROMPT_VIEW_TESTER_H_ #include <memory> +#include <string> namespace autofill { @@ -22,8 +23,9 @@ virtual void Close() = 0; - // Will enter a CVC value and click "Confirm" to advance to the next step. - virtual void EnterCVCAndAccept() = 0; + // Will enter a given CVC value and click "Confirm" to advance to the next + // step. + virtual void EnterCVCAndAccept(const std::u16string& cvc) = 0; }; } // namespace autofill
diff --git a/chrome/browser/ui/autofill/payments/test_card_unmask_prompt_waiter.cc b/chrome/browser/ui/autofill/payments/test_card_unmask_prompt_waiter.cc new file mode 100644 index 0000000..9c071e5 --- /dev/null +++ b/chrome/browser/ui/autofill/payments/test_card_unmask_prompt_waiter.cc
@@ -0,0 +1,89 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/autofill/payments/test_card_unmask_prompt_waiter.h" +#include "base/test/scoped_run_loop_timeout.h" +#include "chrome/browser/ui/autofill/payments/card_unmask_prompt_view_tester.h" + +namespace autofill { + +class TestCardUnmaskPromptControllerImpl + : public CardUnmaskPromptControllerImpl { + public: + explicit TestCardUnmaskPromptControllerImpl(PrefService* pref_service) + : CardUnmaskPromptControllerImpl(pref_service) {} + TestCardUnmaskPromptControllerImpl( + const TestCardUnmaskPromptControllerImpl&) = delete; + TestCardUnmaskPromptControllerImpl& operator=( + const TestCardUnmaskPromptControllerImpl&) = delete; + + void ShowPrompt(CardUnmaskPromptViewFactory view_factory, + const CreditCard& card, + const CardUnmaskPromptOptions& card_unmask_prompt_options, + base::WeakPtr<CardUnmaskDelegate> delegate) override { + CardUnmaskPromptControllerImpl::ShowPrompt( + std::move(view_factory), card, card_unmask_prompt_options, delegate); + run_loop_.Quit(); + } + + testing::AssertionResult Wait() { + bool timeout = false; + base::test::ScopedRunLoopTimeout run_loop_timeout( + FROM_HERE, base::Seconds(10), + base::BindRepeating( + [](bool* timeout) { + *timeout = new bool(true); + return std::string( + "\"Enter CVC\" dialog did not pop up within timout."); + }, + base::Unretained(&timeout))); + run_loop_.Run(); + return timeout ? testing::AssertionFailure() : testing::AssertionSuccess(); + } + + using CardUnmaskPromptControllerImpl::view; + + private: + base::RunLoop run_loop_; +}; + +TestCardUnmaskPromptWaiter::TestCardUnmaskPromptWaiter( + content::WebContents* web_contents, + PrefService* pref_service) + : client_(ChromeAutofillClient::FromWebContents(web_contents)) { + auto controller = + std::make_unique<TestCardUnmaskPromptControllerImpl>(pref_service); + injected_controller_ = controller.get(); + old_controller_ = + client_->SetCardUnmaskControllerForTesting(std::move(controller)); +} + +TestCardUnmaskPromptWaiter::~TestCardUnmaskPromptWaiter() { + if (injected_controller_) { + client_->SetCardUnmaskControllerForTesting(std::move(old_controller_)); + } +} + +testing::AssertionResult TestCardUnmaskPromptWaiter::Wait() { + DCHECK(injected_controller_); + return injected_controller_->Wait(); +} + +bool TestCardUnmaskPromptWaiter::EnterAndAcceptCvcDialog( + const std::u16string& cvc) { + // Enter CVC and accept to dismiss "Enter CVC" prompt dialog with + // TestCardUnmaskController. + DCHECK(injected_controller_); + bool success = false; + if (injected_controller_->view()) { + CardUnmaskPromptViewTester::For(injected_controller_->view()) + ->EnterCVCAndAccept(cvc); + success = true; + } + injected_controller_ = nullptr; + client_->SetCardUnmaskControllerForTesting(std::move(old_controller_)); + return success; +} + +} // namespace autofill
diff --git a/chrome/browser/ui/autofill/payments/test_card_unmask_prompt_waiter.h b/chrome/browser/ui/autofill/payments/test_card_unmask_prompt_waiter.h new file mode 100644 index 0000000..36b18c6 --- /dev/null +++ b/chrome/browser/ui/autofill/payments/test_card_unmask_prompt_waiter.h
@@ -0,0 +1,45 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_TEST_CARD_UNMASK_PROMPT_WAITER_H_ +#define CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_TEST_CARD_UNMASK_PROMPT_WAITER_H_ + +#include "chrome/browser/ui/autofill/chrome_autofill_client.h" +#include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/web_contents.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +class TestCardUnmaskPromptControllerImpl; + +// RAII type that injects a `TestCardUnmaskPromptController` with the ability to +// wait until the CVC prompt is shown. It also helps to accept the CVC prompt +// with a given CVC value. +// Example: +// TestCardUnmaskPromptWaiter test_card_unmask_prompt_waiter( +// web_contents, +// user_prefs::UserPrefs::Get(web_contents->GetBrowserContext())); +// ASSERT_TRUE(test_card_unmask_prompt_waiter.Wait()); +// test_card_unmask_prompt_waiter.EnterAndAcceptCvcDialog(cvc); +class TestCardUnmaskPromptWaiter { + public: + explicit TestCardUnmaskPromptWaiter(content::WebContents* web_contents, + PrefService* pref_service); + ~TestCardUnmaskPromptWaiter(); + + // Blocks until the prompt is shown. + testing::AssertionResult Wait(); + + bool EnterAndAcceptCvcDialog(const std::u16string& cvc); + + private: + raw_ptr<autofill::ChromeAutofillClient> client_; + raw_ptr<TestCardUnmaskPromptControllerImpl> injected_controller_; + std::unique_ptr<autofill::CardUnmaskPromptControllerImpl> old_controller_; +}; + +} // namespace autofill +#endif // CHROME_BROWSER_UI_AUTOFILL_PAYMENTS_TEST_CARD_UNMASK_PROMPT_WAITER_H_
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc index 53ef5b5..24cbc9d 100644 --- a/chrome/browser/ui/browser_focus_uitest.cc +++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -36,8 +36,8 @@ #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" #include "components/omnibox/browser/autocomplete_match_type.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" #include "components/omnibox/browser/omnibox_edit_model.h" +#include "components/omnibox/browser/omnibox_edit_model_delegate.h" #include "components/omnibox/browser/omnibox_view.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" @@ -618,15 +618,15 @@ // Focus the omnibox. chrome::FocusLocationBar(browser()); - OmniboxEditController* controller = browser() - ->window() - ->GetLocationBar() - ->GetOmniboxView() - ->model() - ->controller(); + OmniboxEditModelDelegate* edit_model_delegate = browser() + ->window() + ->GetLocationBar() + ->GetOmniboxView() + ->model() + ->delegate(); // Simulate an alt-enter. - controller->OnAutocompleteAccept( + edit_model_delegate->OnAutocompleteAccept( url2, nullptr, WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_TYPED, AutocompleteMatchType::URL_WHAT_YOU_TYPED, base::TimeTicks(), false, std::u16string(), AutocompleteMatch(),
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h index c5fc3734..a0e26721 100644 --- a/chrome/browser/ui/color/chrome_color_id.h +++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -159,7 +159,7 @@ E_CPONLY(kColorNewTabPageDialogForeground) \ E_CPONLY(kColorNewTabPageDialogSecondaryForeground) \ E_CPONLY(kColorNewTabPageFirstRunBackground) \ - E_CPONLY(kColorNewTabPageFocusShadow) \ + E_CPONLY(kColorNewTabPageFocusRing) \ E_CPONLY(kColorNewTabPageHeader) \ E_CPONLY(kColorNewTabPagePromoBackground) \ E_CPONLY(kColorNewTabPagePromoImageBackground) \
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc index b8a43b0..6fd69309 100644 --- a/chrome/browser/ui/color/chrome_color_mixer.cc +++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -93,32 +93,6 @@ std::move(frame_color_transform)); } -ui::ColorTransform PickGoogleColorTwoBackgrounds( - ui::ColorTransform fg_transform, - ui::ColorTransform bg_a_transform, - ui::ColorTransform bg_b_transform, - float contrast_threshold) { - const auto generator = - [](ui::ColorTransform fg_transform, ui::ColorTransform bg_a_transform, - ui::ColorTransform bg_b_transform, float contrast_threshold, - SkColor input_color, const ui::ColorMixer& mixer) { - const SkColor fg_color = fg_transform.Run(input_color, mixer); - const SkColor bg_a_color = bg_a_transform.Run(input_color, mixer); - const SkColor bg_b_color = bg_b_transform.Run(input_color, mixer); - const SkColor result_color = color_utils::PickGoogleColor( - fg_color, bg_a_color, bg_b_color, contrast_threshold); - DVLOG(2) << "ColorTransform PickGoogleColorTwoBackgrounds:" - << " Foreground Color: " << ui::SkColorName(fg_color) - << " Background Color A: " << ui::SkColorName(bg_a_color) - << " Background Color B: " << ui::SkColorName(bg_b_color) - << " Result Color: " << ui::SkColorName(result_color); - return result_color; - }; - return base::BindRepeating(generator, std::move(fg_transform), - std::move(bg_a_transform), - std::move(bg_b_transform), contrast_threshold); -} - // Default toolbar colors. constexpr SkColor kDarkToolbarColor = SkColorSetRGB(0x35, 0x36, 0x3A); constexpr SkColor kLightToolbarColor = SK_ColorWHITE;
diff --git a/chrome/browser/ui/color/chrome_color_provider_utils.cc b/chrome/browser/ui/color/chrome_color_provider_utils.cc index e38468b3..9b3ef34 100644 --- a/chrome/browser/ui/color/chrome_color_provider_utils.cc +++ b/chrome/browser/ui/color/chrome_color_provider_utils.cc
@@ -96,6 +96,32 @@ frame_color); } +ui::ColorTransform PickGoogleColorTwoBackgrounds( + ui::ColorTransform fg_transform, + ui::ColorTransform bg_a_transform, + ui::ColorTransform bg_b_transform, + float contrast_threshold) { + const auto generator = + [](ui::ColorTransform fg_transform, ui::ColorTransform bg_a_transform, + ui::ColorTransform bg_b_transform, float contrast_threshold, + SkColor input_color, const ui::ColorMixer& mixer) { + const SkColor fg_color = fg_transform.Run(input_color, mixer); + const SkColor bg_a_color = bg_a_transform.Run(input_color, mixer); + const SkColor bg_b_color = bg_b_transform.Run(input_color, mixer); + const SkColor result_color = color_utils::PickGoogleColor( + fg_color, bg_a_color, bg_b_color, contrast_threshold); + DVLOG(2) << "ColorTransform PickGoogleColorTwoBackgrounds:" + << " Foreground Color: " << ui::SkColorName(fg_color) + << " Background Color A: " << ui::SkColorName(bg_a_color) + << " Background Color B: " << ui::SkColorName(bg_b_color) + << " Result Color: " << ui::SkColorName(result_color); + return result_color; + }; + return base::BindRepeating(generator, std::move(fg_transform), + std::move(bg_a_transform), + std::move(bg_b_transform), contrast_threshold); +} + bool ShouldApplyHighContrastColors(const ui::ColorProviderManager::Key& key) { // Only apply custom high contrast handling on platforms where we are not // using the system theme for high contrast.
diff --git a/chrome/browser/ui/color/chrome_color_provider_utils.h b/chrome/browser/ui/color/chrome_color_provider_utils.h index dc902cc..59d5eed 100644 --- a/chrome/browser/ui/color/chrome_color_provider_utils.h +++ b/chrome/browser/ui/color/chrome_color_provider_utils.h
@@ -9,6 +9,8 @@ #include "ui/color/color_id.h" #include "ui/color/color_provider_manager.h" +#include "ui/color/color_provider_utils.h" +#include "ui/color/color_transform.h" #include "ui/gfx/color_utils.h" // Converts ColorId if |color_id| is in CHROME_COLOR_IDS. @@ -28,6 +30,12 @@ // the foreground tab is the most important). SkColor GetToolbarTopSeparatorColor(SkColor toolbar_color, SkColor frame_color); +ui::ColorTransform PickGoogleColorTwoBackgrounds( + ui::ColorTransform fg_transform, + ui::ColorTransform bg_a_transform, + ui::ColorTransform bg_b_transform, + float contrast_threshold); + // Returns true if we should apply chrome high contrast colors for the `key`. bool ShouldApplyHighContrastColors(const ui::ColorProviderManager::Key& key);
diff --git a/chrome/browser/ui/color/new_tab_page_color_mixer.cc b/chrome/browser/ui/color/new_tab_page_color_mixer.cc index 82cb572..93e13ac2 100644 --- a/chrome/browser/ui/color/new_tab_page_color_mixer.cc +++ b/chrome/browser/ui/color/new_tab_page_color_mixer.cc
@@ -129,6 +129,10 @@ /* 10% opacity */ 0.1 * SK_AlphaOPAQUE), ui::SetAlpha({gfx::kGoogleGrey900}, /* 10% opacity */ 0.1 * SK_AlphaOPAQUE)); + mixer[kColorNewTabPageFocusRing] = PickGoogleColorTwoBackgrounds( + ui::kColorFocusableBorderFocused, element_background_color, + kColorNewTabPageBackground, color_utils::kMinimumVisibleContrastRatio); + mixer[kColorNewTabPageLogo] = element_background_color; mixer[kColorNewTabPageLink] = themed_foreground_color; mixer[kColorNewTabPageFirstRunBackground] = {kColorNewTabPageBackground}; @@ -417,7 +421,7 @@ /* 10% opacity */ 0.1 * SK_AlphaOPAQUE); mixer[kColorNewTabPageFirstRunBackground] = { kColorNewTabPageBackgroundOverride}; - mixer[kColorNewTabPageFocusShadow] = + mixer[kColorNewTabPageFocusRing] = dark_mode ? ui::SetAlpha({gfx::kGoogleBlue300}, /* 50% opacity */ 0.5 * SK_AlphaOPAQUE) : ui::SetAlpha({gfx::kGoogleBlue600},
diff --git a/chrome/browser/ui/extensions/OWNERS b/chrome/browser/ui/extensions/OWNERS index e4f2c270..18911ca 100644 --- a/chrome/browser/ui/extensions/OWNERS +++ b/chrome/browser/ui/extensions/OWNERS
@@ -1,5 +1,5 @@ # App-y stuff -benwells@chromium.org +dominickn@chromium.org per-file hosted_app_*=file://chrome/browser/web_applications/UI_OWNERS # Extension-y stuff
diff --git a/chrome/browser/ui/managed_ui.cc b/chrome/browser/ui/managed_ui.cc index 0dba734..f5f4f8c 100644 --- a/chrome/browser/ui/managed_ui.cc +++ b/chrome/browser/ui/managed_ui.cc
@@ -146,6 +146,8 @@ } #endif +// TODO(crbug.com/1409028): Modify this function so it would not return +// absl::nullopt if the device is managed. absl::optional<std::string> GetDeviceManagerIdentity() { if (!policy::ManagementServiceFactory::GetForPlatform()->IsManaged()) return absl::nullopt;
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc index 8f06e75..bfd7237 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc +++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -48,7 +48,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/layout_constants.h" -#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" +#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.h" #include "chrome/browser/ui/omnibox/omnibox_tab_helper.h" #include "components/favicon/content/content_favicon_driver.h" @@ -79,9 +79,9 @@ using predictors::AutocompleteActionPredictor; ChromeOmniboxClient::ChromeOmniboxClient( - ChromeOmniboxEditController* controller, + ChromeOmniboxEditModelDelegate* edit_model_delegate, Profile* profile) - : controller_(controller), + : edit_model_delegate_(edit_model_delegate), profile_(profile), scheme_classifier_(profile), favicon_cache_(FaviconServiceFactory::GetForProfile( @@ -114,31 +114,34 @@ } bool ChromeOmniboxClient::CurrentPageExists() const { - return (controller_->GetWebContents() != nullptr); + return (edit_model_delegate_->GetWebContents() != nullptr); } const GURL& ChromeOmniboxClient::GetURL() const { - return CurrentPageExists() ? controller_->GetWebContents()->GetVisibleURL() - : GURL::EmptyGURL(); + return CurrentPageExists() + ? edit_model_delegate_->GetWebContents()->GetVisibleURL() + : GURL::EmptyGURL(); } const std::u16string& ChromeOmniboxClient::GetTitle() const { - return CurrentPageExists() ? controller_->GetWebContents()->GetTitle() - : base::EmptyString16(); + return CurrentPageExists() + ? edit_model_delegate_->GetWebContents()->GetTitle() + : base::EmptyString16(); } gfx::Image ChromeOmniboxClient::GetFavicon() const { return favicon::ContentFaviconDriver::FromWebContents( - controller_->GetWebContents()) + edit_model_delegate_->GetWebContents()) ->GetFavicon(); } bool ChromeOmniboxClient::IsLoading() const { - return controller_->GetWebContents()->IsLoading(); + return edit_model_delegate_->GetWebContents()->IsLoading(); } bool ChromeOmniboxClient::IsPasteAndGoEnabled() const { - return controller_->command_updater()->IsCommandEnabled(IDC_OPEN_CURRENT_URL); + return edit_model_delegate_->command_updater()->IsCommandEnabled( + IDC_OPEN_CURRENT_URL); } bool ChromeOmniboxClient::IsDefaultSearchProviderEnabled() const { @@ -150,7 +153,7 @@ const SessionID& ChromeOmniboxClient::GetSessionID() const { return sessions::SessionTabHelper::FromWebContents( - controller_->GetWebContents()) + edit_model_delegate_->GetWebContents()) ->session_id(); } @@ -244,7 +247,7 @@ size_t prefix_length = std::min(match.keyword.length() + 1, match.fill_into_edit.length()); extensions::ExtensionOmniboxEventRouter::OnInputEntered( - controller_->GetWebContents(), template_url->GetExtensionId(), + edit_model_delegate_->GetWebContents(), template_url->GetExtensionId(), base::UTF16ToUTF8(match.fill_into_edit.substr(prefix_length)), disposition); @@ -253,20 +256,22 @@ } void ChromeOmniboxClient::OnInputStateChanged() { - if (!controller_->GetWebContents()) + if (!edit_model_delegate_->GetWebContents()) { return; - if (auto* helper = - OmniboxTabHelper::FromWebContents(controller_->GetWebContents())) { + } + if (auto* helper = OmniboxTabHelper::FromWebContents( + edit_model_delegate_->GetWebContents())) { helper->OnInputStateChanged(); } } void ChromeOmniboxClient::OnFocusChanged(OmniboxFocusState state, OmniboxFocusChangeReason reason) { - if (!controller_->GetWebContents()) + if (!edit_model_delegate_->GetWebContents()) { return; - if (auto* helper = - OmniboxTabHelper::FromWebContents(controller_->GetWebContents())) { + } + if (auto* helper = OmniboxTabHelper::FromWebContents( + edit_model_delegate_->GetWebContents())) { helper->OnFocusChanged(state, reason); } } @@ -279,8 +284,8 @@ if (should_preload) { if (SearchPrefetchService* search_prefetch_service = SearchPrefetchServiceFactory::GetForProfile(profile_)) { - search_prefetch_service->OnResultChanged(controller_->GetWebContents(), - result); + search_prefetch_service->OnResultChanged( + edit_model_delegate_->GetWebContents(), result); } } @@ -343,7 +348,7 @@ AutocompleteActionPredictor::Action recommended_action = AutocompleteActionPredictor::ACTION_NONE; if (user_input_in_progress) { - content::WebContents* web_contents = controller_->GetWebContents(); + content::WebContents* web_contents = edit_model_delegate_->GetWebContents(); AutocompleteActionPredictor* action_predictor = predictors::AutocompleteActionPredictorFactory::GetForProfile(profile_); action_predictor->RegisterTransitionalMatches(user_text, result); @@ -388,7 +393,7 @@ // Record the value if prerender for search suggestion was not started. Other // values (kHitFinished, kUnused, kCancelled) are recorded in // PrerenderManager. - content::WebContents* web_contents = controller_->GetWebContents(); + content::WebContents* web_contents = edit_model_delegate_->GetWebContents(); if (web_contents) { if (SearchPrefetchService* search_prefetch_service = SearchPrefetchServiceFactory::GetForProfile(profile_)) { @@ -414,11 +419,13 @@ } void ChromeOmniboxClient::DiscardNonCommittedNavigations() { - controller_->GetWebContents()->GetController().DiscardNonCommittedEntries(); + edit_model_delegate_->GetWebContents() + ->GetController() + .DiscardNonCommittedEntries(); } void ChromeOmniboxClient::OpenUpdateChromeDialog() { - const content::WebContents* contents = controller_->GetWebContents(); + const content::WebContents* contents = edit_model_delegate_->GetWebContents(); if (contents) { Browser* browser = chrome::FindBrowserWithWebContents(contents); if (browser) { @@ -436,8 +443,9 @@ } void ChromeOmniboxClient::FocusWebContents() { - if (controller_->GetWebContents()) - controller_->GetWebContents()->Focus(); + if (edit_model_delegate_->GetWebContents()) { + edit_model_delegate_->GetWebContents()->Focus(); + } } void ChromeOmniboxClient::OnNavigationLikely( @@ -447,12 +455,13 @@ if (SearchPrefetchService* search_prefetch_service = SearchPrefetchServiceFactory::GetForProfile(profile_)) { search_prefetch_service->OnNavigationLikely( - index, match, navigation_predictor, controller_->GetWebContents()); + index, match, navigation_predictor, + edit_model_delegate_->GetWebContents()); } } void ChromeOmniboxClient::DoPrerender(const AutocompleteMatch& match) { - content::WebContents* web_contents = controller_->GetWebContents(); + content::WebContents* web_contents = edit_model_delegate_->GetWebContents(); // Don't prerender when DevTools is open in this tab. if (content::DevToolsAgentHost::IsDebuggerAttached(web_contents))
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.h b/chrome/browser/ui/omnibox/chrome_omnibox_client.h index ac905c5..0bf44e12 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_client.h +++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
@@ -19,13 +19,13 @@ #include "components/omnibox/browser/omnibox_client.h" #include "components/omnibox/browser/on_device_tail_model_observer.h" -class ChromeOmniboxEditController; +class ChromeOmniboxEditModelDelegate; class GURL; class Profile; class ChromeOmniboxClient : public OmniboxClient { public: - ChromeOmniboxClient(ChromeOmniboxEditController* controller, + ChromeOmniboxClient(ChromeOmniboxEditModelDelegate* edit_model_delegate, Profile* profile); ChromeOmniboxClient(const ChromeOmniboxClient&) = delete; @@ -108,7 +108,7 @@ int result_index, const SkBitmap& bitmap); - raw_ptr<ChromeOmniboxEditController> controller_; + raw_ptr<ChromeOmniboxEditModelDelegate> edit_model_delegate_; raw_ptr<Profile> profile_; ChromeAutocompleteSchemeClassifier scheme_classifier_; std::vector<BitmapFetcherService::RequestId> request_ids_;
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc b/chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.cc similarity index 83% rename from chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc rename to chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.cc index 25a18e6..d31a48f1 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc +++ b/chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" +#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.h" #include "base/trace_event/typed_macros.h" #include "build/build_config.h" @@ -25,15 +25,15 @@ #include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h" #endif -ChromeOmniboxEditController::ChromeOmniboxEditController( +ChromeOmniboxEditModelDelegate::ChromeOmniboxEditModelDelegate( Browser* browser, Profile* profile, CommandUpdater* command_updater) : browser_(browser), profile_(profile), command_updater_(command_updater) {} -ChromeOmniboxEditController::~ChromeOmniboxEditController() = default; +ChromeOmniboxEditModelDelegate::~ChromeOmniboxEditModelDelegate() = default; -void ChromeOmniboxEditController::OnAutocompleteAccept( +void ChromeOmniboxEditModelDelegate::OnAutocompleteAccept( const GURL& destination_url, TemplateURLRef::PostContent* post_content, WindowOpenDisposition disposition, @@ -45,7 +45,7 @@ const AutocompleteMatch& match, const AutocompleteMatch& alternative_nav_match, IDNA2008DeviationCharacter deviation_char_in_hostname) { - TRACE_EVENT("omnibox", "ChromeOmniboxEditController::OnAutocompleteAccept", + TRACE_EVENT("omnibox", "ChromeOmniboxEditModelDelegate::OnAutocompleteAccept", "text", text, "match", match, "alternative_nav_match", alternative_nav_match); @@ -75,11 +75,11 @@ } #if BUILDFLAG(ENABLE_EXTENSIONS) - extensions::MaybeShowExtensionControlledSearchNotification( - GetWebContents(), match_type); + extensions::MaybeShowExtensionControlledSearchNotification(GetWebContents(), + match_type); #endif } -void ChromeOmniboxEditController::OnInputInProgress(bool in_progress) { +void ChromeOmniboxEditModelDelegate::OnInputInProgress(bool in_progress) { UpdateWithoutTabRestore(); }
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h b/chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.h similarity index 62% rename from chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h rename to chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.h index 87f586cf..aeb404b 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h +++ b/chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.h
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_OMNIBOX_CHROME_OMNIBOX_EDIT_CONTROLLER_H_ -#define CHROME_BROWSER_UI_OMNIBOX_CHROME_OMNIBOX_EDIT_CONTROLLER_H_ +#ifndef CHROME_BROWSER_UI_OMNIBOX_CHROME_OMNIBOX_EDIT_MODEL_DELEGATE_H_ +#define CHROME_BROWSER_UI_OMNIBOX_CHROME_OMNIBOX_EDIT_MODEL_DELEGATE_H_ #include "base/memory/raw_ptr.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" +#include "components/omnibox/browser/omnibox_edit_model_delegate.h" class Browser; class CommandUpdater; @@ -16,18 +16,19 @@ class WebContents; } -// Chrome-specific extension of the OmniboxEditController base class. -class ChromeOmniboxEditController : public OmniboxEditController { +// Chrome-specific extension of the OmniboxEditModelDelegate base class. +class ChromeOmniboxEditModelDelegate : public OmniboxEditModelDelegate { public: - ChromeOmniboxEditController(Browser* browser, - Profile* profile, - CommandUpdater* command_updater); - ChromeOmniboxEditController(const ChromeOmniboxEditController&) = delete; - ChromeOmniboxEditController& operator=(const ChromeOmniboxEditController&) = + ChromeOmniboxEditModelDelegate(Browser* browser, + Profile* profile, + CommandUpdater* command_updater); + ChromeOmniboxEditModelDelegate(const ChromeOmniboxEditModelDelegate&) = delete; - ~ChromeOmniboxEditController() override; + ChromeOmniboxEditModelDelegate& operator=( + const ChromeOmniboxEditModelDelegate&) = delete; + ~ChromeOmniboxEditModelDelegate() override; - // OmniboxEditController: + // OmniboxEditModelDelegate: void OnAutocompleteAccept( const GURL& destination_url, TemplateURLRef::PostContent* post_content, @@ -58,4 +59,4 @@ const raw_ptr<CommandUpdater, DanglingUntriaged> command_updater_; }; -#endif // CHROME_BROWSER_UI_OMNIBOX_CHROME_OMNIBOX_EDIT_CONTROLLER_H_ +#endif // CHROME_BROWSER_UI_OMNIBOX_CHROME_OMNIBOX_EDIT_MODEL_DELEGATE_H_
diff --git a/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc b/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc index 037013e..1e83d172 100644 --- a/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc +++ b/chrome/browser/ui/omnibox/omnibox_pedal_implementations_unittest.cc
@@ -17,7 +17,7 @@ #include "components/omnibox/browser/actions/omnibox_pedal_provider.h" #include "components/omnibox/browser/mock_autocomplete_provider_client.h" #include "components/omnibox/browser/test_omnibox_client.h" -#include "components/omnibox/browser/test_omnibox_edit_controller.h" +#include "components/omnibox/browser/test_omnibox_edit_model_delegate.h" #include "components/omnibox/common/omnibox_features.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/window_open_disposition.h" @@ -25,8 +25,8 @@ class OmniboxPedalImplementationsTest : public testing::Test { protected: OmniboxPedalImplementationsTest() - : omnibox_edit_controller_( - std::make_unique<TestOmniboxEditController>()) {} + : omnibox_edit_model_delegate_( + std::make_unique<TestOmniboxEditModelDelegate>()) {} void SetUp() override { feature_list_.InitWithFeatures({}, {}); @@ -57,11 +57,11 @@ GURL ExecuteContextAndReturnResult(const OmniboxPedal* pedal) { OmniboxPedal::ExecutionContext context( autocomplete_provider_client_, - base::BindOnce(&OmniboxEditController::OnAutocompleteAccept, - omnibox_edit_controller_->AsWeakPtr()), + base::BindOnce(&OmniboxEditModelDelegate::OnAutocompleteAccept, + omnibox_edit_model_delegate_->AsWeakPtr()), {}, WindowOpenDisposition::CURRENT_TAB); pedal->Execute(context); - return omnibox_edit_controller_->destination_url(); + return omnibox_edit_model_delegate_->destination_url(); } // Exhaustive test of unordered synonym groups for concept matches; this is @@ -17953,7 +17953,7 @@ base::test::ScopedFeatureList feature_list_; base::test::TaskEnvironment task_environment_; std::unique_ptr<TestOmniboxClient> omnibox_client_; - std::unique_ptr<TestOmniboxEditController> omnibox_edit_controller_; + std::unique_ptr<TestOmniboxEditModelDelegate> omnibox_edit_model_delegate_; MockAutocompleteProviderClient autocomplete_provider_client_; };
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 index 5e93032..deebeedf 100644 --- 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
@@ -184,8 +184,8 @@ browser_owning_tab_group, web_contents); saved_tab_group_tab.SetLocalTabID(token); - saved_tab_group.AddTab(saved_tab_group.saved_tabs().size(), - std::move(saved_tab_group_tab)); + saved_tab_group.AddTab(std::move(saved_tab_group_tab), + /*update_tab_positions=*/true); } model_.Add(std::move(saved_tab_group));
diff --git a/chrome/browser/ui/tabs/tab_group.cc b/chrome/browser/ui/tabs/tab_group.cc index abcd1d94..c917f061 100644 --- a/chrome/browser/ui/tabs/tab_group.cc +++ b/chrome/browser/ui/tabs/tab_group.cc
@@ -147,22 +147,23 @@ std::vector<SavedTabGroupTab> tabs; const gfx::Range tab_range = ListTabs(); const base::GUID saved_group_guid = base::GUID::GenerateRandomV4(); + SavedTabGroup group(visual_data_->title(), visual_data_->color(), {}, + saved_group_guid, absl::nullopt, id_); + for (auto i = tab_range.start(); i < tab_range.end(); ++i) { content::WebContents* web_contents = controller_->GetWebContentsAt(i); const GURL& url = web_contents->GetVisibleURL(); const std::u16string& title = web_contents->GetTitle(); - tabs.emplace_back( - SavedTabGroupTab(url, title, saved_group_guid) - .SetFavicon(favicon::TabFaviconFromWebContents(web_contents))); + SavedTabGroupTab tab(url, title, saved_group_guid); + tab.SetFavicon(favicon::TabFaviconFromWebContents(web_contents)); + group.AddTab(tab); } SavedTabGroupKeyedService* backend = SavedTabGroupServiceFactory::GetForProfile(controller_->GetProfile()); if (!backend || !backend->model()) return; - SavedTabGroup saved_tab_group(visual_data_->title(), visual_data_->color(), - tabs, saved_group_guid, absl::nullopt, id_); - backend->model()->Add(saved_tab_group); + backend->model()->Add(std::move(group)); } void TabGroup::UnsaveGroup() {
diff --git a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.cc b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.cc index 6d03326..e83f57a 100644 --- a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.cc +++ b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.h" +#include <string> + #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.h" #include "ui/views/controls/textfield/textfield.h" @@ -28,8 +30,9 @@ view_->ClosePrompt(); } -void CardUnmaskPromptViewTesterViews::EnterCVCAndAccept() { - view_->cvc_input_->SetText(u"123"); +void CardUnmaskPromptViewTesterViews::EnterCVCAndAccept( + const std::u16string& cvc) { + view_->cvc_input_->SetText(cvc); view_->AcceptDialog(); }
diff --git a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.h b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.h index 4663bdf2..3209233 100644 --- a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.h +++ b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_CARD_UNMASK_PROMPT_VIEW_TESTER_VIEWS_H_ #define CHROME_BROWSER_UI_VIEWS_AUTOFILL_PAYMENTS_CARD_UNMASK_PROMPT_VIEW_TESTER_VIEWS_H_ +#include <string> + #include "base/memory/raw_ptr.h" #include "chrome/browser/ui/autofill/payments/card_unmask_prompt_view_tester.h" @@ -26,7 +28,7 @@ // CardUnmaskPromptViewTester: void Close() override; - void EnterCVCAndAccept() override; + void EnterCVCAndAccept(const std::u16string& cvc) override; private: raw_ptr<CardUnmaskPromptViews> view_;
diff --git a/chrome/browser/ui/views/bubble/bubble_contents_wrapper.cc b/chrome/browser/ui/views/bubble/bubble_contents_wrapper.cc index 4c53800..9162188 100644 --- a/chrome/browser/ui/views/bubble/bubble_contents_wrapper.cc +++ b/chrome/browser/ui/views/bubble/bubble_contents_wrapper.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/bubble/bubble_contents_wrapper.h" +#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" #include "content/public/browser/keyboard_event_processing_result.h" #include "content/public/browser/native_web_keyboard_event.h" @@ -96,6 +97,14 @@ return true; } +std::unique_ptr<content::EyeDropper> BubbleContentsWrapper::OpenEyeDropper( + content::RenderFrameHost* frame, + content::EyeDropperListener* listener) { + BrowserWindow* window = + BrowserWindow::FindBrowserWindowWithWebContents(web_contents_.get()); + return window->OpenEyeDropper(frame, listener); +} + void BubbleContentsWrapper::PrimaryPageChanged(content::Page& page) { content::RenderWidgetHostView* render_widget_host_view = web_contents_->GetRenderWidgetHostView();
diff --git a/chrome/browser/ui/views/bubble/bubble_contents_wrapper.h b/chrome/browser/ui/views/bubble/bubble_contents_wrapper.h index 188ef6d..5dbc69d 100644 --- a/chrome/browser/ui/views/bubble/bubble_contents_wrapper.h +++ b/chrome/browser/ui/views/bubble/bubble_contents_wrapper.h
@@ -64,6 +64,9 @@ const content::NativeWebKeyboardEvent& event) override; bool HandleContextMenu(content::RenderFrameHost& render_frame_host, const content::ContextMenuParams& params) override; + std::unique_ptr<content::EyeDropper> OpenEyeDropper( + content::RenderFrameHost* frame, + content::EyeDropperListener* listener) override; // content::WebContentsObserver: void PrimaryPageChanged(content::Page& page) override;
diff --git a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc index 9614d3a7..63c9adc 100644 --- a/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_bubble_row_view.cc
@@ -597,6 +597,7 @@ quick_actions_size.width() - insets.right(), insets.top()), quick_actions_size)); + inkdrop_container_->SetBoundsRect(GetLocalBounds()); } void DownloadBubbleRowView::OnMainButtonPressed() {
diff --git a/chrome/browser/ui/views/download/bubble/download_dialog_view.cc b/chrome/browser/ui/views/download/bubble/download_dialog_view.cc index 89c2edb..aebef8e2 100644 --- a/chrome/browser/ui/views/download/bubble/download_dialog_view.cc +++ b/chrome/browser/ui/views/download/bubble/download_dialog_view.cc
@@ -11,7 +11,7 @@ #include "chrome/browser/ui/layout_constants.h" #include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" -#include "chrome/browser/ui/views/controls/hover_button.h" +#include "chrome/browser/ui/views/controls/rich_hover_button.h" #include "chrome/browser/ui/views/download/bubble/download_bubble_row_list_view.h" #include "chrome/grit/generated_resources.h" #include "components/vector_icons/vector_icons.h" @@ -77,19 +77,17 @@ } void DownloadDialogView::AddFooter() { - // Do not display an icon in the primary position. - auto empty_primary_icon = std::make_unique<views::View>(); - auto launch_icon_view = std::make_unique<views::ImageView>(); - launch_icon_view->SetImage(ui::ImageModel::FromVectorIcon( - vector_icons::kLaunchIcon, ui::kColorIconSecondary)); - - AddChildView(std::make_unique<HoverButton>( - base::BindRepeating(&DownloadDialogView::ShowAllDownloads, - base::Unretained(this)), - std::move(empty_primary_icon), - l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_LINK), - /*subtitle=*/std::u16string(), std::move(launch_icon_view), - /*resize_row_for_secondary_view=*/false)) + AddChildView( + std::make_unique<RichHoverButton>( + base::BindRepeating(&DownloadDialogView::ShowAllDownloads, + base::Unretained(this)), + /*main_image_icon=*/ui::ImageModel(), + l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_LINK), + /*secondary_text=*/std::u16string(), + l10n_util::GetStringUTF16(IDS_DOWNLOAD_BUBBLE_FOOTER_TOOLTIP), + /*subtitle_text=*/std::u16string(), + ui::ImageModel::FromVectorIcon(vector_icons::kLaunchIcon, + ui::kColorIconSecondary))) ->SetBorder(views::CreateEmptyBorder(GetLayoutInsets(DOWNLOAD_ROW))); }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index bfcb6ea..b564bca7 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -168,7 +168,7 @@ Delegate* delegate, bool is_popup_mode) : AnimationDelegateViews(this), - ChromeOmniboxEditController(browser, profile, command_updater), + ChromeOmniboxEditModelDelegate(browser, profile, command_updater), browser_(browser), profile_(profile), delegate_(delegate),
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h index cd834f43..f7d7965 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -19,7 +19,7 @@ #include "build/build_config.h" #include "chrome/browser/extensions/extension_context_menu_model.h" #include "chrome/browser/ui/location_bar/location_bar.h" -#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" +#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.h" #include "chrome/browser/ui/page_action/page_action_icon_type.h" #include "chrome/browser/ui/views/dropdown_bar_host.h" #include "chrome/browser/ui/views/dropdown_bar_host_delegate.h" @@ -71,7 +71,7 @@ public views::View, public views::DragController, public views::AnimationDelegateViews, - public ChromeOmniboxEditController, + public ChromeOmniboxEditModelDelegate, public DropdownBarHostDelegate, public IconLabelBubbleView::Delegate, public LocationIconView::Delegate, @@ -195,7 +195,7 @@ void OnThemeChanged() override; void ChildPreferredSizeChanged(views::View* child) override; - // ChromeOmniboxEditController: + // ChromeOmniboxEditModelDelegate: void UpdateWithoutTabRestore() override; LocationBarModel* GetLocationBarModel() override; content::WebContents* GetWebContents() override; @@ -368,7 +368,7 @@ void AnimationCanceled(const gfx::Animation* animation) override; void OnChildViewRemoved(View* observed_view, View* child) override; - // ChromeOmniboxEditController: + // ChromeOmniboxEditModelDelegate: void OnChanged() override; void OnPopupVisibilityChanged() override; const LocationBarModel* GetLocationBarModel() const override;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index cb9872c8..06b3dea 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -48,8 +48,8 @@ #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/location_bar_model.h" #include "components/omnibox/browser/omnibox_client.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" #include "components/omnibox/browser/omnibox_edit_model.h" +#include "components/omnibox/browser/omnibox_edit_model_delegate.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_popup_selection.h" #include "components/omnibox/browser/omnibox_prefs.h" @@ -165,12 +165,13 @@ // OmniboxViewViews ----------------------------------------------------------- -OmniboxViewViews::OmniboxViewViews(OmniboxEditController* controller, - std::unique_ptr<OmniboxClient> client, - bool popup_window_mode, - LocationBarView* location_bar, - const gfx::FontList& font_list) - : OmniboxView(controller, std::move(client)), +OmniboxViewViews::OmniboxViewViews( + OmniboxEditModelDelegate* edit_model_delegate, + std::unique_ptr<OmniboxClient> client, + bool popup_window_mode, + LocationBarView* location_bar, + const gfx::FontList& font_list) + : OmniboxView(edit_model_delegate, std::move(client)), popup_window_mode_(popup_window_mode), location_bar_view_(location_bar), latency_histogram_state_(NOT_ACTIVE), @@ -586,15 +587,16 @@ // in about:blank URLs. Or in blob: or filesystem: URLs, which have an inner // origin, the URL is likely too syntax-y to be able to meaningfully draw // attention to any part of it. - auto* const location_bar_model = controller()->GetLocationBarModel(); + auto* const location_bar_model = edit_model_delegate()->GetLocationBarModel(); if (!location_bar_model->GetURL().SchemeIsHTTPOrHTTPS()) return; if (net::IsCertStatusError(location_bar_model->GetCertStatus())) { if (location_bar_view_) { - ApplyColor(location_bar_view_->GetSecurityChipColor( - controller()->GetLocationBarModel()->GetSecurityLevel()), - range); + ApplyColor( + location_bar_view_->GetSecurityChipColor( + edit_model_delegate()->GetLocationBarModel()->GetSecurityLevel()), + range); } ApplyStyle(gfx::TEXT_STYLE_STRIKE, true, range); } @@ -1115,7 +1117,7 @@ SelectWordAt(event.location()); std::u16string shown_url = GetText(); std::u16string full_url = - controller()->GetLocationBarModel()->GetFormattedFullURL(); + edit_model_delegate()->GetLocationBarModel()->GetFormattedFullURL(); size_t offset = full_url.find(shown_url); if (offset != std::u16string::npos) { next_double_click_selection_len_ = GetSelectedText().length(); @@ -1347,7 +1349,8 @@ // TODO(oshima): Get control key state. model()->OnSetFocus(false); - // Don't call controller()->OnSetFocus, this view has already acquired focus. + // Don't call edit_model_delegate()->OnSetFocus, this view has already + // acquired focus. // Restore the selection we saved in OnBlur() if it's still valid. if (!saved_selection_for_focus_change_.empty()) {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h index d991c84..ffe3153 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -69,7 +69,7 @@ // Max width of the gradient mask used to smooth ElideAnimation edges. static const int kSmoothingGradientMaxWidth = 15; - OmniboxViewViews(OmniboxEditController* controller, + OmniboxViewViews(OmniboxEditModelDelegate* edit_model_delegate, std::unique_ptr<OmniboxClient> client, bool popup_window_mode, LocationBarView* location_bar,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc index 46e88b7..f6ff0fa 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -32,7 +32,7 @@ #include "chrome/browser/signin/chrome_signin_client_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h" -#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" +#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_model_delegate.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/test_browser_window.h" #include "chrome/test/base/testing_profile.h" @@ -80,7 +80,7 @@ class TestingOmniboxView : public OmniboxViewViews { public: - TestingOmniboxView(OmniboxEditController* controller, + TestingOmniboxView(OmniboxEditModelDelegate* edit_model_delegate, TestLocationBarModel* location_bar_model, std::unique_ptr<OmniboxClient> client); TestingOmniboxView(const TestingOmniboxView&) = delete; @@ -156,10 +156,11 @@ bool base_text_emphasis_; }; -TestingOmniboxView::TestingOmniboxView(OmniboxEditController* controller, - TestLocationBarModel* location_bar_model, - std::unique_ptr<OmniboxClient> client) - : OmniboxViewViews(controller, +TestingOmniboxView::TestingOmniboxView( + OmniboxEditModelDelegate* edit_model_delegate, + TestLocationBarModel* location_bar_model, + std::unique_ptr<OmniboxClient> client) + : OmniboxViewViews(edit_model_delegate, std::move(client), false, nullptr, @@ -255,24 +256,25 @@ OmniboxViewViews::ApplyStyle(style, value, range); } -// TestingOmniboxEditController ----------------------------------------------- +// TestingOmniboxEditModelDelegate --------------------------------------------- -class TestingOmniboxEditController : public ChromeOmniboxEditController { +class TestingOmniboxEditModelDelegate : public ChromeOmniboxEditModelDelegate { public: - TestingOmniboxEditController(Browser* browser, - Profile* profile, - CommandUpdater* command_updater, - LocationBarModel* location_bar_model) - : ChromeOmniboxEditController(browser, profile, command_updater), + TestingOmniboxEditModelDelegate(Browser* browser, + Profile* profile, + CommandUpdater* command_updater, + LocationBarModel* location_bar_model) + : ChromeOmniboxEditModelDelegate(browser, profile, command_updater), location_bar_model_(location_bar_model) {} - TestingOmniboxEditController(const TestingOmniboxEditController&) = delete; - TestingOmniboxEditController& operator=(const TestingOmniboxEditController&) = + TestingOmniboxEditModelDelegate(const TestingOmniboxEditModelDelegate&) = delete; + TestingOmniboxEditModelDelegate& operator=( + const TestingOmniboxEditModelDelegate&) = delete; void set_omnibox_view(OmniboxViewViews* view) { omnibox_view_ = view; } private: - // ChromeOmniboxEditController: + // ChromeOmniboxEditModelDelegate: LocationBarModel* GetLocationBarModel() override { return location_bar_model_; } @@ -358,8 +360,8 @@ protected: Browser* browser() { return browser_.get(); } Profile* profile() { return profile_.get(); } - TestingOmniboxEditController* omnibox_edit_controller() { - return &omnibox_edit_controller_; + TestingOmniboxEditModelDelegate* edit_model_delegate() { + return &omnibox_edit_model_delegate_; } // Updates the models' URL and display text to |new_url|. @@ -387,7 +389,7 @@ std::unique_ptr<TemplateURLServiceFactoryTestUtil> util_; CommandUpdaterImpl command_updater_; TestLocationBarModel location_bar_model_; - TestingOmniboxEditController omnibox_edit_controller_; + TestingOmniboxEditModelDelegate omnibox_edit_model_delegate_; content::RenderViewHostTestEnabler rvh_test_enabler_; std::unique_ptr<views::Widget> widget_; @@ -406,10 +408,10 @@ disabled_features, is_rtl_ui_test), command_updater_(nullptr), - omnibox_edit_controller_(browser(), - profile(), - &command_updater_, - &location_bar_model_) {} + omnibox_edit_model_delegate_(browser(), + profile(), + &command_updater_, + &location_bar_model_) {} void OmniboxViewViewsTest::SetAndEmphasizeText(const std::string& new_text, bool accept_input) { @@ -450,8 +452,8 @@ profile_.get(), base::BindRepeating(&AutocompleteClassifierFactory::BuildInstanceFor)); auto omnibox_view = std::make_unique<TestingOmniboxView>( - &omnibox_edit_controller_, location_bar_model(), - std::make_unique<ChromeOmniboxClient>(&omnibox_edit_controller_, + &omnibox_edit_model_delegate_, location_bar_model(), + std::make_unique<ChromeOmniboxClient>(&omnibox_edit_model_delegate_, profile_.get())); test_api_ = std::make_unique<views::TextfieldTestApi>(omnibox_view.get()); omnibox_view->Init(); @@ -823,7 +825,7 @@ // Verifies |OmniboxEditModel::State::needs_revert_and_select_all|, and verifies // a recent regression in this logic (see https://crbug.com/923290). TEST_F(OmniboxViewViewsTest, SelectAllOnReactivateTabAfterDeleteAll) { - omnibox_edit_controller()->set_omnibox_view(omnibox_view()); + edit_model_delegate()->set_omnibox_view(omnibox_view()); auto web_contents1 = content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
diff --git a/chrome/browser/ui/views/payments/secure_payment_confirmation_dialog_view_browsertest.cc b/chrome/browser/ui/views/payments/secure_payment_confirmation_dialog_view_browsertest.cc index 60451f07..a320755 100644 --- a/chrome/browser/ui/views/payments/secure_payment_confirmation_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/payments/secure_payment_confirmation_dialog_view_browsertest.cc
@@ -21,10 +21,13 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/events/base_event_utils.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/link.h" #include "ui/views/controls/styled_label.h" +#include "ui/views/test/mock_input_event_activation_protector.h" +#include "ui/views/window/dialog_client_view.h" namespace payments { namespace { @@ -133,6 +136,17 @@ web_modal::WebContentsModalDialogManager::FromWebContents( web_contents); EXPECT_TRUE(web_contents_modal_dialog_manager->IsDialogActive()); + + // By default, disable the input event protector for testing purposes. + // However, see the AcceptButtonIgnoresAccidentalInputs test, which + // explicitly checks that the protector is able to block unintended inputs. + auto mock_input_protector = + std::make_unique<views::MockInputEventActivationProtector>(); + EXPECT_CALL(*mock_input_protector, IsPossiblyUnintendedInteraction) + .WillRepeatedly(testing::Return(false)); + test_delegate_->dialog_view() + ->GetDialogClientView() + ->SetInputProtectorForTesting(std::move(mock_input_protector)); } void ExpectLabelText( @@ -233,6 +247,15 @@ model_.opt_out_link_label()); } + void ClickButton(views::View* button) { + gfx::Point center(button->width() / 2, button->height() / 2); + const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, center, center, + ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON); + button->OnMousePressed(event); + button->OnMouseReleased(event); + } + void ResetEventWaiter(DialogEvent event) { event_waiter_ = std::make_unique<autofill::EventWaiter<DialogEvent>>( std::list<DialogEvent>{event}); @@ -294,7 +317,7 @@ InvokeSecurePaymentConfirmationUI(); ResetEventWaiter(DialogEvent::DIALOG_CLOSED); - test_delegate_->dialog_view()->AcceptDialog(); + ClickButton(test_delegate_->dialog_view()->GetOkButton()); event_waiter_->Wait(); EXPECT_TRUE(confirm_pressed_); @@ -311,6 +334,49 @@ SecurePaymentConfirmationAuthenticationDialogResult::kAccepted, 1); } +// Test that the 'Accept' button is protected against accidental inputs. +IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationDialogViewTest, + AcceptButtonIgnoresAccidentalInputs) { + CreateModel(); + InvokeSecurePaymentConfirmationUI(); + + // Insert a mock input protector that will ignore the first input and then + // accepts all subsequent inputs. + auto mock_input_protector = + std::make_unique<views::MockInputEventActivationProtector>(); + EXPECT_CALL(*mock_input_protector, IsPossiblyUnintendedInteraction) + .WillOnce(testing::Return(true)) + .WillRepeatedly(testing::Return(false)); + test_delegate_->dialog_view() + ->GetDialogClientView() + ->SetInputProtectorForTesting(std::move(mock_input_protector)); + + // Because of the input protector, the first press of the button should be + // ignored. + ClickButton(test_delegate_->dialog_view()->GetOkButton()); + EXPECT_FALSE(confirm_pressed_); + histogram_tester_.ExpectTotalCount( + "PaymentRequest.SecurePaymentConfirmation.Funnel." + "AuthenticationDialogResult", + 0); + histogram_tester_.ExpectBucketCount( + "PaymentRequest.SecurePaymentConfirmation.Funnel." + "AuthenticationDialogResult", + SecurePaymentConfirmationAuthenticationDialogResult::kAccepted, 0); + + // However a subsequent press should be accepted. + ClickButton(test_delegate_->dialog_view()->GetOkButton()); + EXPECT_TRUE(confirm_pressed_); + histogram_tester_.ExpectTotalCount( + "PaymentRequest.SecurePaymentConfirmation.Funnel." + "AuthenticationDialogResult", + 1); + histogram_tester_.ExpectBucketCount( + "PaymentRequest.SecurePaymentConfirmation.Funnel." + "AuthenticationDialogResult", + SecurePaymentConfirmationAuthenticationDialogResult::kAccepted, 1); +} + // Test that clicking the 'Cancel' button triggers the expected path and closes // the dialog. IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationDialogViewTest, @@ -319,7 +385,7 @@ InvokeSecurePaymentConfirmationUI(); ResetEventWaiter(DialogEvent::DIALOG_CLOSED); - test_delegate_->dialog_view()->CancelDialog(); + ClickButton(test_delegate_->dialog_view()->GetCancelButton()); event_waiter_->Wait(); EXPECT_TRUE(cancel_pressed_);
diff --git a/chrome/browser/ui/views/tabs/compound_tab_container.cc b/chrome/browser/ui/views/tabs/compound_tab_container.cc index de0ab06..b061db6 100644 --- a/chrome/browser/ui/views/tabs/compound_tab_container.cc +++ b/chrome/browser/ui/views/tabs/compound_tab_container.cc
@@ -330,7 +330,7 @@ new_unpinned_active_index); } -std::unique_ptr<Tab> CompoundTabContainer::TransferTabOut(int model_index) { +Tab* CompoundTabContainer::RemoveTabFromViewModel(int model_index) { // TODO(1395526): This only needs to be implemented in TabContainerImpl. NOTREACHED(); return nullptr; @@ -852,7 +852,7 @@ gfx::RectF( from_container.GetTabAtModelIndex(from_container_index)->bounds())); Tab* const tab = - AddChildView(from_container.TransferTabOut(from_container_index)); + AddChildView(from_container.RemoveTabFromViewModel(from_container_index)); tab->SetBoundsRect(ToEnclosingRect(initial_tab_bounds)); // Let `to_container` update its layout data structures.
diff --git a/chrome/browser/ui/views/tabs/compound_tab_container.h b/chrome/browser/ui/views/tabs/compound_tab_container.h index 983cb81..b017306 100644 --- a/chrome/browser/ui/views/tabs/compound_tab_container.h +++ b/chrome/browser/ui/views/tabs/compound_tab_container.h
@@ -43,7 +43,7 @@ void SetTabPinned(int model_index, TabPinned pinned) override; void SetActiveTab(absl::optional<size_t> prev_active_index, absl::optional<size_t> new_active_index) override; - std::unique_ptr<Tab> TransferTabOut(int model_index) override; + Tab* RemoveTabFromViewModel(int model_index) override; Tab* AddTabToViewModel(Tab* tab, int model_index, TabPinned pinned) override; void ReturnTabSlotView(TabSlotView* view) override; void ScrollTabToVisible(int model_index) override;
diff --git a/chrome/browser/ui/views/tabs/tab_container.h b/chrome/browser/ui/views/tabs/tab_container.h index bd2661ab..7f26a69 100644 --- a/chrome/browser/ui/views/tabs/tab_container.h +++ b/chrome/browser/ui/views/tabs/tab_container.h
@@ -47,11 +47,11 @@ virtual void SetActiveTab(absl::optional<size_t> prev_active_index, absl::optional<size_t> new_active_index) = 0; - // Transfer the tab at `model_index` our of this container so it can be - // parented elsewhere. Unlike RemoveTab, this method does not close the tab, - // but it does remove it from the layout viewmodel. - [[nodiscard]] virtual std::unique_ptr<Tab> TransferTabOut( - int model_index) = 0; + // Removes the tab at `model_index` from the TabContainer's data structures so + // it can be reparented elsewhere. Unlike RemoveTab, it does not animate the + // tab closed and it does not destroy the tab, so it should be used only to + // transfer the tab to another parent and not to close the tab. + [[nodiscard]] virtual Tab* RemoveTabFromViewModel(int model_index) = 0; // Adds the tab to the TabContainer's data structures, but does not transfer // ownership of the actual view `tab`.
diff --git a/chrome/browser/ui/views/tabs/tab_container_impl.cc b/chrome/browser/ui/views/tabs/tab_container_impl.cc index a12ae5d..7309a43 100644 --- a/chrome/browser/ui/views/tabs/tab_container_impl.cc +++ b/chrome/browser/ui/views/tabs/tab_container_impl.cc
@@ -172,10 +172,10 @@ void TabContainerImpl::RemoveTab(int model_index, bool was_active) { UpdateClosingModeOnRemovedTab(model_index, was_active); - Tab* tab = GetTabAtModelIndex(model_index); + Tab* const tab = GetTabAtModelIndex(model_index); tab->SetClosing(true); - RemoveTabFromViewModel(model_index); + CloseTabInViewModel(model_index); StartRemoveTabAnimation(tab, model_index); @@ -234,12 +234,12 @@ ScrollTabToVisible(new_active_index.value()); } -std::unique_ptr<Tab> TabContainerImpl::TransferTabOut(int model_index) { +Tab* TabContainerImpl::RemoveTabFromViewModel(int model_index) { Tab* const tab = GetTabAtModelIndex(model_index); tabs_view_model_.Remove(model_index); OnTabRemoved(tab); - return RemoveChildViewT(tab); + return tab; } Tab* TabContainerImpl::AddTabToViewModel(Tab* tab, @@ -1236,7 +1236,7 @@ return trailing_x; } -void TabContainerImpl::RemoveTabFromViewModel(int index) { +void TabContainerImpl::CloseTabInViewModel(int index) { Tab* tab = GetTabAtModelIndex(index); bool tab_was_active = tab->IsActive();
diff --git a/chrome/browser/ui/views/tabs/tab_container_impl.h b/chrome/browser/ui/views/tabs/tab_container_impl.h index c993a130..c9d42fd2 100644 --- a/chrome/browser/ui/views/tabs/tab_container_impl.h +++ b/chrome/browser/ui/views/tabs/tab_container_impl.h
@@ -60,7 +60,7 @@ void SetActiveTab(absl::optional<size_t> prev_active_index, absl::optional<size_t> new_active_index) override; - std::unique_ptr<Tab> TransferTabOut(int model_index) override; + Tab* RemoveTabFromViewModel(int model_index) override; Tab* AddTabToViewModel(Tab* tab, int model_index, TabPinned pinned) override; void ReturnTabSlotView(TabSlotView* view) override; @@ -247,9 +247,9 @@ absl::optional<int> GetMidAnimationTrailingX() const; - // Remove the tab from |tabs_view_model_|, but *not* from the View hierarchy, - // so it can be animated closed. - void RemoveTabFromViewModel(int index); + // Update `layout_helper_` and remove the tab from `tabs_view_model_` (but + // *not* from the View hierarchy) so it can be animated closed. + void CloseTabInViewModel(int index); // Call when `tab` is going away to remove the tab from data structures. void OnTabRemoved(Tab* tab);
diff --git a/chrome/browser/ui/views/tabs/tab_container_unittest.cc b/chrome/browser/ui/views/tabs/tab_container_unittest.cc index 1728dd8d..6ef95cd 100644 --- a/chrome/browser/ui/views/tabs/tab_container_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_container_unittest.cc
@@ -969,14 +969,15 @@ .right()); } -TEST_F(TabContainerTest, PreferredWidthNotAffectedByTransferOut) { +TEST_F(TabContainerTest, PreferredWidthNotAffectedByTransferTabTo) { // Start with two tabs. AddTab(0); AddTab(1); const int initial_pref_width = tab_container_->GetPreferredSize().width(); // Transfer one out, then pretend to animate it. - std::unique_ptr<Tab> owned_tab = tab_container_->TransferTabOut(1); + std::unique_ptr<views::View> hold_my_tab = std::make_unique<views::View>(); + hold_my_tab->AddChildView(tab_container_->RemoveTabFromViewModel(1)); tab_container_controller_->set_is_animating_outside_container(true); // Preferred width should be unchanged, even though `owned_tab` is no longer // part of `tab_container_`.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 4478e8ea..60dfed1af 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -122,6 +122,9 @@ #if !BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h" +#endif + +#if !BUILDFLAG(IS_CHROMEOS) #include "chrome/browser/ui/dialogs/outdated_upgrade_bubble.h" #endif @@ -925,7 +928,11 @@ } void ToolbarView::ShowOutdatedInstallNotification(bool auto_update_enabled) { -#if !BUILDFLAG(IS_CHROMEOS_ASH) +#if !BUILDFLAG(IS_CHROMEOS) + // The outdated upgrade notification is not relevant on ChromeOS, for either + // ash-chrome or lacros-chrome, as browser upgrades are managed via a + // different process to the rest of the desktop platforms (see + // crbug.com/1406873). // TODO(pbos): Can this move outside ToolbarView completely? ShowOutdatedUpgradeBubble(browser_, auto_update_enabled); #endif
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view.cc b/chrome/browser/ui/views/webid/account_selection_bubble_view.cc index 518050a..5644d29 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view.cc +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view.cc
@@ -458,9 +458,8 @@ void AccountSelectionBubbleView::ShowVerifyingSheet( const content::IdentityRequestAccount& account, - const IdentityProviderDisplayData& idp_data) { - const std::u16string title = - l10n_util::GetStringUTF16(IDS_VERIFY_SHEET_TITLE); + const IdentityProviderDisplayData& idp_data, + const std::u16string& title) { UpdateHeader(idp_data.idp_metadata_, title, /*show_back_button=*/false); RemoveNonHeaderChildViews(); @@ -650,7 +649,7 @@ auto button = std::make_unique<ContinueButton>( base::BindRepeating(&Observer::OnAccountSelected, base::Unretained(observer_), std::cref(account), - std::cref(idp_data)), + std::cref(idp_data), /*auto_signin=*/false), l10n_util::GetStringFUTF16(IDS_ACCOUNT_SELECTION_CONTINUE, base::UTF8ToUTF16(display_name)), this, idp_metadata.brand_background_color, idp_metadata.brand_text_color); @@ -788,7 +787,7 @@ auto row = std::make_unique<HoverButton>( base::BindRepeating(&Observer::OnAccountSelected, base::Unretained(observer_), std::cref(account), - std::cref(idp_data)), + std::cref(idp_data), /*auto_signin=*/false), std::move(image_view), base::UTF8ToUTF16(account.name), base::UTF8ToUTF16(account.email)); row->SetBorder(views::CreateEmptyBorder(
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view.h b/chrome/browser/ui/views/webid/account_selection_bubble_view.h index e0d2b31a..3f0b156 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view.h +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view.h
@@ -39,14 +39,17 @@ public: enum class LinkType { PRIVACY_POLICY, TERMS_OF_SERVICE }; - // Called when the user either selects the account from the multi-account - // chooser or clicks the "continue" button. + // Called when: + // 1. A user either selects the account from the multi-account chooser or + // clicks the "continue" button. (auto_signin == false) + // 2. Auto sign-in is triggered. (auto_signin == true) // Takes `account` as well as `idp_data` since passing `account_id` is // insufficient in the multiple IDP case. The caller should pass a cref, as // these objects are owned by the observer. virtual void OnAccountSelected( const content::IdentityRequestAccount& account, - const IdentityProviderDisplayData& idp_data) = 0; + const IdentityProviderDisplayData& idp_data, + bool auto_signin) = 0; // Called when the user clicks "privacy policy" or "terms of service" link. virtual void OnLinkClicked(LinkType link_type, const GURL& url) = 0; @@ -73,7 +76,8 @@ const std::vector<IdentityProviderDisplayData>& idp_data_list, bool show_back_button) override; void ShowVerifyingSheet(const content::IdentityRequestAccount& account, - const IdentityProviderDisplayData& idp_data) override; + const IdentityProviderDisplayData& idp_data, + const std::u16string& title) override; void ShowSingleAccountConfirmDialog( const std::u16string& rp_for_display,
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view_interface.h b/chrome/browser/ui/views/webid/account_selection_bubble_view_interface.h index 6f0a054b..76cca3f 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view_interface.h +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view_interface.h
@@ -27,7 +27,8 @@ // Updates the FedCM bubble to show the "verifying" sheet. virtual void ShowVerifyingSheet( const content::IdentityRequestAccount& account, - const IdentityProviderDisplayData& idp_data) = 0; + const IdentityProviderDisplayData& idp_data, + const std::u16string& title) = 0; // Updates to show single account plus a confirm dialog. Used when showing the // account confirmation dialog after the user picks one of multiple accounts.
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc index 2375863..3ffe48d 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/ui/views/controls/hover_button.h" #include "chrome/browser/ui/views/webid/fake_delegate.h" #include "chrome/browser/ui/views/webid/identity_provider_display_data.h" +#include "chrome/grit/generated_resources.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/views/chrome_views_test_base.h" #include "content/public/browser/web_contents.h" @@ -25,6 +26,7 @@ #include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/events/base_event_utils.h" #include "ui/views/controls/button/md_text_button.h" #include "ui/views/controls/image_view.h" @@ -43,6 +45,8 @@ u"Sign in to rp-example.com with idp-example.com"; const std::u16string kTitleSignInWithoutIdp = u"Sign in to rp-example.com"; const std::u16string kTitleSigningIn = u"Verifying…"; +const std::u16string kTitleSigningInWithAutoSignin = + u"Signing in to rp-example.com with idp-example.com"; constexpr char kIdBase[] = "id"; constexpr char kEmailBase[] = "email"; @@ -464,7 +468,8 @@ content::ClientMetadata(GURL(), GURL()), {account}); CreateAccountSelectionBubble(); - dialog_->ShowVerifyingSheet(account, idp_data); + dialog_->ShowVerifyingSheet( + account, idp_data, l10n_util::GetStringUTF16(IDS_VERIFY_SHEET_TITLE)); const std::vector<views::View*> children = dialog()->children(); ASSERT_EQ(children.size(), 3u); @@ -476,6 +481,29 @@ CheckAccountRow(row_container->children()[0], kAccountSuffix); } +TEST_F(AccountSelectionBubbleViewTest, VerifyingForAutoSignin) { + const std::string kAccountSuffix = "suffix"; + content::IdentityRequestAccount account = CreateTestIdentityRequestAccount( + kAccountSuffix, content::IdentityRequestAccount::LoginState::kSignIn); + IdentityProviderDisplayData idp_data( + kIdpETLDPlusOne, content::IdentityProviderMetadata(), + content::ClientMetadata(GURL(), GURL()), {account}); + + CreateAccountSelectionBubble(); + const auto title = l10n_util::GetStringFUTF16( + IDS_VERIFY_SHEET_TITLE_AUTO_SIGNIN, kRpETLDPlusOne, kIdpETLDPlusOne); + dialog_->ShowVerifyingSheet(account, idp_data, title); + + const std::vector<views::View*> children = dialog()->children(); + ASSERT_EQ(children.size(), 3u); + PerformHeaderChecks(children[0], kTitleSigningInWithAutoSignin, + /*expect_idp_brand_icon_in_header=*/true); + + views::View* row_container = dialog()->children()[2]; + ASSERT_EQ(row_container->children().size(), 1u); + CheckAccountRow(row_container->children()[0], kAccountSuffix); +} + class MultipleIdpAccountSelectionBubbleViewTest : public AccountSelectionBubbleViewTest { public:
diff --git a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.cc b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.cc index 866a63b..e134e13 100644 --- a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.cc +++ b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.cc
@@ -9,7 +9,9 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/grit/generated_resources.h" #include "third_party/blink/public/mojom/webid/federated_auth_request.mojom.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" using DismissReason = content::IdentityRequestDialogController::DismissReason; @@ -86,8 +88,26 @@ rp_for_display_ = base::UTF8ToUTF16(rp_etld_plus_one); bubble_widget_ = CreateBubble(browser, rp_for_display_, idp_title, rp_context) ->GetWeakPtr(); - GetBubbleView()->ShowAccountPicker(idp_data_list_, - /*show_back_button=*/false); + if (sign_in_mode == Account::SignInMode::kExplicit) { + GetBubbleView()->ShowAccountPicker(idp_data_list_, + /*show_back_button=*/false); + } else { + DCHECK_EQ(sign_in_mode, Account::SignInMode::kAuto); + + for (const auto& idp_data : idp_data_list_) { + for (const auto& account : idp_data.accounts_) { + if (account.login_state != Account::LoginState::kSignIn) { + continue; + } + // When auto sign-in UX flow is triggered, there will be one and only + // only account that's returning with LoginStatus::kSignIn. + OnAccountSelected(account, idp_data, /*auto_signin=*/true); + bubble_widget_->Show(); + bubble_widget_->AddObserver(this); + return; + } + } + } bubble_widget_->Show(); bubble_widget_->AddObserver(this); } @@ -194,7 +214,8 @@ void FedCmAccountSelectionView::OnAccountSelected( const Account& account, - const IdentityProviderDisplayData& idp_data) { + const IdentityProviderDisplayData& idp_data, + bool auto_signin) { state_ = (state_ == State::ACCOUNT_PICKER && account.login_state == Account::LoginState::kSignUp) ? State::PERMISSION @@ -210,7 +231,12 @@ if (!weak_ptr) return; - GetBubbleView()->ShowVerifyingSheet(account, idp_data); + const std::u16string title = + auto_signin ? l10n_util::GetStringFUTF16( + IDS_VERIFY_SHEET_TITLE_AUTO_SIGNIN, rp_for_display_, + idp_data.idp_etld_plus_one_) + : l10n_util::GetStringUTF16(IDS_VERIFY_SHEET_TITLE); + GetBubbleView()->ShowVerifyingSheet(account, idp_data, title); return; } GetBubbleView()->ShowSingleAccountConfirmDialog(rp_for_display_, account,
diff --git a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.h b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.h index c015993..35c8c3d 100644 --- a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.h +++ b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.h
@@ -84,7 +84,8 @@ // AccountSelectionBubbleView::Observer: void OnAccountSelected(const Account& account, - const IdentityProviderDisplayData& idp_data) override; + const IdentityProviderDisplayData& idp_data, + bool auto_signin) override; void OnLinkClicked(LinkType link_type, const GURL& url) override; void OnBackButtonClicked() override; void OnCloseButtonClicked() override;
diff --git a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc index 8fd1be9b..24fe358 100644 --- a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc +++ b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc
@@ -45,9 +45,9 @@ account_ids_.push_back(account.id); } - void ShowVerifyingSheet( - const content::IdentityRequestAccount& account, - const IdentityProviderDisplayData& idp_data) override { + void ShowVerifyingSheet(const content::IdentityRequestAccount& account, + const IdentityProviderDisplayData& idp_data, + const std::u16string& title) override { show_verifying_sheet_ = true; account_ids_ = {account.id}; } @@ -153,7 +153,8 @@ } std::unique_ptr<TestFedCmAccountSelectionView> CreateAndShow( - const std::vector<content::IdentityRequestAccount>& accounts) { + const std::vector<content::IdentityRequestAccount>& accounts, + SignInMode mode) { auto controller = std::make_unique<TestFedCmAccountSelectionView>( delegate_.get(), widget_.get(), bubble_view_.get()); controller->Show( @@ -161,7 +162,7 @@ {{kIdpEtldPlusOne, accounts, content::IdentityProviderMetadata(), content::ClientMetadata(GURL(), GURL()), blink::mojom::RpContext::kSignIn}}, - SignInMode::kExplicit); + mode); return controller; } @@ -183,7 +184,7 @@ CreateIdentityProviderDisplayData({{kAccountId, LoginState::kSignUp}}); const std::vector<Account>& accounts = idp_data.accounts_; std::unique_ptr<TestFedCmAccountSelectionView> controller = - CreateAndShow(accounts); + CreateAndShow(accounts, SignInMode::kExplicit); AccountSelectionBubbleView::Observer* observer = static_cast<AccountSelectionBubbleView::Observer*>(controller.get()); @@ -191,7 +192,7 @@ EXPECT_FALSE(bubble_view_->show_verifying_sheet_); EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId)); - observer->OnAccountSelected(accounts[0], idp_data); + observer->OnAccountSelected(accounts[0], idp_data, /*auto_signin=*/false); EXPECT_TRUE(bubble_view_->show_verifying_sheet_); EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId)); } @@ -203,7 +204,7 @@ {{kAccountId1, LoginState::kSignIn}, {kAccountId2, LoginState::kSignIn}}); const std::vector<Account>& accounts = idp_data.accounts_; std::unique_ptr<TestFedCmAccountSelectionView> controller = - CreateAndShow(accounts); + CreateAndShow(accounts, SignInMode::kExplicit); AccountSelectionBubbleView::Observer* observer = static_cast<AccountSelectionBubbleView::Observer*>(controller.get()); @@ -212,7 +213,7 @@ EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId1, kAccountId2)); - observer->OnAccountSelected(accounts[0], idp_data); + observer->OnAccountSelected(accounts[0], idp_data, /*auto_signin=*/false); EXPECT_TRUE(bubble_view_->show_verifying_sheet_); EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId1)); } @@ -226,7 +227,7 @@ }); const std::vector<Account>& accounts = idp_data.accounts_; std::unique_ptr<TestFedCmAccountSelectionView> controller = - CreateAndShow(accounts); + CreateAndShow(accounts, SignInMode::kExplicit); AccountSelectionBubbleView::Observer* observer = static_cast<AccountSelectionBubbleView::Observer*>(controller.get()); @@ -235,7 +236,7 @@ EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId1, kAccountId2)); - observer->OnAccountSelected(accounts[0], idp_data); + observer->OnAccountSelected(accounts[0], idp_data, /*auto_signin=*/false); EXPECT_TRUE(bubble_view_->show_back_button_); EXPECT_FALSE(bubble_view_->show_verifying_sheet_); EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId1)); @@ -246,16 +247,44 @@ EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId1, kAccountId2)); - observer->OnAccountSelected(accounts[1], idp_data); + observer->OnAccountSelected(accounts[1], idp_data, /*auto_signin=*/false); EXPECT_TRUE(bubble_view_->show_back_button_); EXPECT_FALSE(bubble_view_->show_verifying_sheet_); EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId2)); - observer->OnAccountSelected(accounts[1], idp_data); + observer->OnAccountSelected(accounts[1], idp_data, /*auto_signin=*/false); EXPECT_TRUE(bubble_view_->show_verifying_sheet_); EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId2)); } +TEST_F(FedCmAccountSelectionViewDesktopTest, AutoSigninSingleAccountFlow) { + const char kAccountId[] = "account_id"; + IdentityProviderDisplayData idp_data = + CreateIdentityProviderDisplayData({{kAccountId, LoginState::kSignIn}}); + const std::vector<Account>& accounts = idp_data.accounts_; + std::unique_ptr<TestFedCmAccountSelectionView> controller = + CreateAndShow(accounts, SignInMode::kAuto); + + EXPECT_FALSE(bubble_view_->show_back_button_); + EXPECT_TRUE(bubble_view_->show_verifying_sheet_); + EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId)); +} + +TEST_F(FedCmAccountSelectionViewDesktopTest, + AutoSigninMultipleAccountsOneReturning) { + const char kAccountId1[] = "account_id1"; + const char kAccountId2[] = "account_id2"; + IdentityProviderDisplayData idp_data = CreateIdentityProviderDisplayData( + {{kAccountId1, LoginState::kSignIn}, {kAccountId2, LoginState::kSignUp}}); + const std::vector<Account>& accounts = idp_data.accounts_; + std::unique_ptr<TestFedCmAccountSelectionView> controller = + CreateAndShow(accounts, SignInMode::kAuto); + + EXPECT_FALSE(bubble_view_->show_back_button_); + EXPECT_TRUE(bubble_view_->show_verifying_sheet_); + EXPECT_THAT(bubble_view_->account_ids_, testing::ElementsAre(kAccountId1)); +} + namespace { // AccountSelectionViewDelegate which deletes the FedCmAccountSelectionView in @@ -303,12 +332,12 @@ AccountSelectionBubbleView::Observer* observer = nullptr; { std::unique_ptr<TestFedCmAccountSelectionView> controller = - CreateAndShow(accounts); + CreateAndShow(accounts, SignInMode::kExplicit); observer = static_cast<AccountSelectionBubbleView::Observer*>(controller.get()); view_deleting_delegate->SetView(std::move(controller)); } // Destroys FedCmAccountSelectionView. Should not cause crash. - observer->OnAccountSelected(accounts[0], idp_data); + observer->OnAccountSelected(accounts[0], idp_data, /*auto_signin=*/false); }
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc index 8ce2107..dedc57df 100644 --- a/chrome/browser/ui/webauthn/sheet_models.cc +++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -103,7 +103,7 @@ bool AuthenticatorSheetModelBase::IsOtherMechanismButtonVisible() const { return other_mechanism_button_visibility_ == OtherMechanismButtonVisibility::kVisible && - dialog_model_->mechanisms().size() > 1; + dialog_model_ && dialog_model_->mechanisms().size() > 1; } std::u16string AuthenticatorSheetModelBase::GetCancelButtonLabel() const {
diff --git a/chrome/browser/ui/webauthn/sheet_models_unittest.cc b/chrome/browser/ui/webauthn/sheet_models_unittest.cc new file mode 100644 index 0000000..a3b2457 --- /dev/null +++ b/chrome/browser/ui/webauthn/sheet_models_unittest.cc
@@ -0,0 +1,103 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webauthn/sheet_models.h" + +#include "base/functional/callback_helpers.h" +#include "chrome/app/vector_icons/vector_icons.h" +#include "chrome/browser/webauthn/authenticator_request_dialog_model.h" +#include "chrome/browser/webauthn/authenticator_transport.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using Mechanism = AuthenticatorRequestDialogModel::Mechanism; +using MechanismVisibility = + AuthenticatorGenericErrorSheetModel::OtherMechanismButtonVisibility; + +class AuthenticatorSheetBaseTest : public testing::Test {}; + +class MockDialogModel : public AuthenticatorRequestDialogModel { + public: + MockDialogModel() : AuthenticatorRequestDialogModel(nullptr) {} + + MOCK_METHOD(base::span<const Mechanism>, mechanisms, (), (const)); +}; + +class TestAuthenticatorSheetModel : public AuthenticatorSheetModelBase { + public: + TestAuthenticatorSheetModel( + AuthenticatorRequestDialogModel* dialog_model, + OtherMechanismButtonVisibility other_mechanism_button_visibility) + : AuthenticatorSheetModelBase(dialog_model, + other_mechanism_button_visibility) {} + + const gfx::VectorIcon& GetStepIllustration( + ImageColorScheme color_scheme) const override { + return kPasskeyHeaderDarkIcon; + } + + std::u16string GetStepTitle() const override { return u"Step title"; } + + std::u16string GetStepDescription() const override { + return u"Step description"; + } + + bool IsOtherMechanismButtonVisible() const override { + return AuthenticatorSheetModelBase::IsOtherMechanismButtonVisible(); + } +}; + +TEST_F(AuthenticatorSheetBaseTest, IsOtherMechanismButtonVisible) { + MockDialogModel dialog_model; + + // No mechanisms present. + { + TestAuthenticatorSheetModel sheet_model(&dialog_model, + MechanismVisibility::kVisible); + std::vector<Mechanism> mechanisms; + EXPECT_CALL(dialog_model, mechanisms) + .WillOnce(testing::Return(base::make_span(mechanisms))); + EXPECT_FALSE(sheet_model.IsOtherMechanismButtonVisible()); + testing::Mock::VerifyAndClearExpectations(&dialog_model); + } + + // Two mechanisms present. + { + TestAuthenticatorSheetModel sheet_model(&dialog_model, + MechanismVisibility::kVisible); + std::vector<Mechanism> mechanisms; + mechanisms.emplace_back(Mechanism::Phone("phone"), u"phone", u"ph", + kPasskeyAoaIcon, base::DoNothing(), false); + mechanisms.emplace_back( + Mechanism::Transport(AuthenticatorTransport::kUsbHumanInterfaceDevice), + u"security key", u"usb", kPasskeyAoaIcon, base::DoNothing(), false); + EXPECT_CALL(dialog_model, mechanisms) + .WillOnce(testing::Return(base::make_span(mechanisms))); + EXPECT_TRUE(sheet_model.IsOtherMechanismButtonVisible()); + testing::Mock::VerifyAndClearExpectations(&dialog_model); + } + + // Hidden button. + { + TestAuthenticatorSheetModel sheet_model(&dialog_model, + MechanismVisibility::kHidden); + EXPECT_CALL(dialog_model, mechanisms).Times(0); + EXPECT_FALSE(sheet_model.IsOtherMechanismButtonVisible()); + testing::Mock::VerifyAndClearExpectations(&dialog_model); + } +} + +// Regression test for crbug.com/1408492. +TEST_F(AuthenticatorSheetBaseTest, + IsOtherMechanismButtonVisible_NoDialogModel) { + auto dialog_model = std::make_unique<MockDialogModel>(); + TestAuthenticatorSheetModel sheet_model(dialog_model.get(), + MechanismVisibility::kVisible); + dialog_model.reset(); + EXPECT_FALSE(sheet_model.IsOtherMechanismButtonVisible()); +} + +} // namespace
diff --git a/chrome/browser/ui/webui/app_home/app_home_ui.cc b/chrome/browser/ui/webui/app_home/app_home_ui.cc index a9b06c80..e6d5ac6 100644 --- a/chrome/browser/ui/webui/app_home/app_home_ui.cc +++ b/chrome/browser/ui/webui/app_home/app_home_ui.cc
@@ -11,12 +11,35 @@ #include "chrome/common/webui_url_constants.h" #include "chrome/grit/app_home_resources.h" #include "chrome/grit/app_home_resources_map.h" +#include "chrome/grit/generated_resources.h" #include "content/public/browser/web_ui_data_source.h" + namespace webapps { +namespace { + +void AddAppHomeLocalizedStrings(content::WebUIDataSource* ui_source) { + static constexpr webui::LocalizedString kAppHomeLocalizedStrings[] = { + {"appHomeTitle", IDS_APP_HOME_TITLE}, + {"appWindowOpenLabel", IDS_APP_HOME_OPEN_IN_WINDOW}, + {"appWindowOpenCheckboxLabel", + IDS_ACCNAME_APP_HOME_OPEN_IN_WINDOW_CHECKBOX}, + {"appLaunchAtStartupLabel", IDS_APP_HOME_LAUNCH_AT_STARTUP}, + {"appLaunchAtStartupCheckboxLabel", + IDS_ACCNAME_APP_HOME_LAUNCH_AT_STARTUP_CHECKBOX}, + {"createShortcutForAppLabel", IDS_APP_HOME_CREATE_SHORTCUT}, + {"uninstallAppLabel", IDS_APP_HOME_UNINSTALL_APP}, + {"appSettingsLabel", IDS_APP_HOME_APP_SETTINGS}, + }; + ui_source->AddLocalizedStrings(kAppHomeLocalizedStrings); +} + +} // namespace + AppHomeUI::AppHomeUI(content::WebUI* web_ui) : ui::MojoWebUIController(web_ui) { content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( Profile::FromWebUI(web_ui), chrome::kChromeUIAppLauncherPageHost); + AddAppHomeLocalizedStrings(source); webui::SetupWebUIDataSource( source, base::make_span(kAppHomeResources, kAppHomeResourcesSize), IDR_APP_HOME_APP_HOME_HTML);
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom index 63b6033..4998127d 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom
@@ -51,6 +51,10 @@ // The local file tasks the user can pick from to open the files. Displayed in // the `kFileHandlerDialog` dialog. array<DialogTask> tasks; + + // True if the setup flow is running for the first time. False if running + // fixup flow. + bool first_time_setup; }; // Lives in the browser process. A renderer uses this to create a page handler
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc index 4265504..8220ce1 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
@@ -10,6 +10,8 @@ #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ash/file_manager/file_tasks.h" #include "chrome/browser/ash/file_manager/open_with_browser.h" #include "chrome/browser/ash/file_system_provider/mount_path_util.h" @@ -18,7 +20,9 @@ #include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_ui.h" #include "chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.h" #include "chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.h" +#include "chrome/browser/web_applications/web_app_id_constants.h" #include "chrome/common/webui_url_constants.h" +#include "components/services/app_service/public/cpp/types_util.h" #include "extensions/browser/api/file_handlers/mime_util.h" #include "extensions/browser/entry_info.h" #include "ui/gfx/geometry/size.h" @@ -31,10 +35,13 @@ namespace { +using ash::file_system_provider::ProvidedFileSystemInfo; +using ash::file_system_provider::ProviderId; +using ash::file_system_provider::Service; using file_manager::file_tasks::kDriveTaskResultMetricName; using file_manager::file_tasks::OfficeTaskResult; -const char kOpenWebActionId[] = "OPEN_WEB"; +const char kOneDriveUrlActionId[] = "HIDDEN_ONEDRIVE_URL"; // Open a hosted MS Office file e.g. .docx, from a url hosted in // DriveFS. Check the file was successfully uploaded to DriveFS. @@ -70,7 +77,7 @@ } } -void OpenODFSUrl(const storage::FileSystemURL& url) { +void OpenODFSUrl(Profile* profile, const storage::FileSystemURL& url) { if (!url.is_valid()) { LOG(ERROR) << "Invalid uploaded file URL"; return; @@ -81,19 +88,45 @@ return; } - parser.file_system()->ExecuteAction( - {parser.file_path()}, kOpenWebActionId, - base::BindOnce([](base::File::Error result) { - if (result != base::File::Error::FILE_OK) { - LOG(ERROR) << "Error executing action: " << result; - // TODO(cassycc): Run GetUserFallbackChoice(). - } - })); + parser.file_system()->GetActions( + {parser.file_path()}, + base::BindOnce( + [](base::WeakPtr<Profile> profile_weak_ptr, + const file_system_provider::Actions& actions, + base::File::Error result) { + if (result != base::File::Error::FILE_OK) { + return; + } + Profile* profile = profile_weak_ptr.get(); + if (!profile) { + return; + } + for (const file_system_provider::Action& action : actions) { + if (action.id == kOneDriveUrlActionId) { + // Custom actions are used to pass a OneDrive URL as the "title" + // attribute to be opened using an installed web app. + GURL url(action.title); + if (!url.is_valid()) { + return; + } + + auto* proxy = + apps::AppServiceProxyFactory::GetForProfile(profile); + proxy->LaunchAppWithUrl(web_app::kMicrosoftOfficeAppId, + /*event_flags=*/ui::EF_NONE, url, + apps::LaunchSource::kFromFileManager, + /*window_info=*/nullptr); + return; + } + } + }, + profile->GetWeakPtr())); } -void OpenODFSUrls(const std::vector<storage::FileSystemURL>& file_urls) { +void OpenODFSUrls(Profile* profile, + const std::vector<storage::FileSystemURL>& file_urls) { for (const auto& file_url : file_urls) { - OpenODFSUrl(file_url); + OpenODFSUrl(profile, file_url); } } @@ -124,8 +157,18 @@ } } else if (cloud_provider == CloudProvider::kOneDrive) { for (const auto& file_url : file_urls) { - OneDriveUploadHandler::Upload(profile, file_url, - base::BindOnce(&OpenODFSUrl)); + OneDriveUploadHandler::Upload( + profile, file_url, + base::BindOnce( + [](base::WeakPtr<Profile> profile_weak_ptr, + const storage::FileSystemURL& url) { + Profile* profile = profile_weak_ptr.get(); + if (!profile) { + return; + } + OpenODFSUrl(profile, url); + }, + profile->GetWeakPtr())); } } } @@ -310,6 +353,12 @@ return CloudUploadDialog::SetUpAndShowDialog( profile, file_urls, mojom::DialogPage::kFileHandlerDialog); } + + if (ShouldFixUpOffice(profile, cloud_provider)) { + // TODO(cassycc): Use page specifically for fix up. + CloudUploadDialog::SetUpAndShowDialog(profile, file_urls, + mojom::DialogPage::kOneDriveSetup); + } OpenOrMoveFiles(profile, file_urls, cloud_provider); return true; } @@ -324,13 +373,19 @@ } else if (cloud_provider == CloudProvider::kOneDrive && FileIsOnODFS(profile, file_urls.front())) { // The files are on OneDrive already. - OpenODFSUrls(file_urls); + OpenODFSUrls(profile, file_urls); } else { // The files need to be moved. ConfirmMoveOrStartUpload(profile, file_urls, cloud_provider); } } +bool ShouldFixUpOffice(Profile* profile, const CloudProvider cloud_provider) { + return cloud_provider == CloudProvider::kOneDrive && + !(CloudUploadDialog::IsODFSMounted(profile) && + CloudUploadDialog::IsOfficeWebAppInstalled(profile)); +} + void GetEntriesFromFilePathsAndMimeTypes( const std::vector<base::FilePath>& file_paths, EntriesCallback entries_callback, @@ -438,6 +493,8 @@ args->file_names.push_back(file_url.path().BaseName().value()); } args->dialog_page = dialog_page; + args->first_time_setup = + !file_manager::file_tasks::OfficeSetupComplete(profile); // The pointer is managed by an instance of `views::WebDialogView` and // removed in `SystemWebDialogDelegate::OnDialogClosed`. @@ -463,6 +520,31 @@ return true; } +bool CloudUploadDialog::IsODFSMounted(Profile* profile) { + Service* service = Service::Get(profile); + ProviderId provider_id = ProviderId::CreateFromExtensionId( + file_manager::file_tasks::kODFSExtensionId); + std::vector<ProvidedFileSystemInfo> file_systems = + service->GetProvidedFileSystemInfoList(provider_id); + + // Assume any file system mounted by ODFS is the correct one. + return !file_systems.empty(); +} + +bool CloudUploadDialog::IsOfficeWebAppInstalled(Profile* profile) { + if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) { + return false; + } + auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile); + bool installed = false; + proxy->AppRegistryCache().ForOneApp( + web_app::kMicrosoftOfficeAppId, + [&installed](const apps::AppUpdate& update) { + installed = apps_util::IsInstalled(update.Readiness()); + }); + return installed; +} + void CloudUploadDialog::OnDialogShown(content::WebUI* webui) { DCHECK(dialog_args_); SystemWebDialogDelegate::OnDialogShown(webui);
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h index 0c96e01..2e9db34 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h
@@ -56,6 +56,10 @@ const std::vector<storage::FileSystemURL>& file_urls, const CloudProvider cloud_provider); +// Returns True if OneDrive is the selected `cloud_provider` but either ODFS +// is not mounted or the Office PWA is not installed. Returns False otherwise. +bool ShouldFixUpOffice(Profile* profile, const CloudProvider cloud_provider); + // Defines the web dialog used to help users upload Office files to the cloud. class CloudUploadDialog : public SystemWebDialogDelegate { public: @@ -87,6 +91,9 @@ const std::vector<storage::FileSystemURL>& file_urls, const mojom::DialogPage dialog_page); + static bool IsODFSMounted(Profile* profile); + static bool IsOfficeWebAppInstalled(Profile* profile); + void OnDialogShown(content::WebUI* webui) override; void OnDialogClosed(const std::string& json_retval) override;
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc index 18eb294..391202f1 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog_browsertest.cc
@@ -12,13 +12,17 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ash/file_manager/file_manager_test_util.h" #include "chrome/browser/ash/file_manager/file_tasks.h" #include "chrome/browser/ash/file_manager/fileapi_util.h" #include "chrome/browser/ash/file_manager/path_util.h" +#include "chrome/browser/ash/file_system_provider/fake_extension_provider.h" +#include "chrome/browser/ash/file_system_provider/service.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/web_app_id_constants.h" #include "chrome/browser/web_applications/web_app_install_info.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_sync_bridge.h" @@ -35,6 +39,15 @@ namespace { +// The mime type and file_extension must be matching for +// `CreateFakeWebApps()`. +const char kDocFileExtension[] = ".doc"; +const char kDocMimeType[] = "application/msword"; +const char kPptFileExtension[] = ".ppt"; +const char kPptMimeType[] = "application/vnd.ms-powerpoint"; +const char kXlsFileExtension[] = ".xls"; +const char kXlsMimeType[] = "application/vnd.ms-excel"; + // Create `n` fake web apps that open any files with the `file_extensions` and // matching `mime_types`. The apps can be identified by a unique `app_id` // and launched by file_manager::file_tasks::ExecuteFileTask() which can be @@ -94,20 +107,42 @@ return -1; } +content::WebContents* GetWebContentsFromCloudUploadDialog() { + ash::SystemWebDialogDelegate* dialog = + ash::SystemWebDialogDelegate::FindInstance( + chrome::kChromeUICloudUploadURL); + EXPECT_TRUE(dialog); + content::WebUI* webui = dialog->GetWebUIForTest(); + EXPECT_TRUE(webui); + content::WebContents* web_contents = webui->GetWebContents(); + EXPECT_TRUE(web_contents); + return web_contents; +} + +// Fill in the placeholder from `script_with_placeholder` with the JS command +// to retrieve the HTML `element`. Return the resulting JS script. +std::string ScriptFillPlaceholder(const char script_with_placeholder[], + std::string element) { + const char element_with_placeholder[] = "document.querySelectorAll('%s')[0]"; + std::string element_script = + base::StringPrintf(element_with_placeholder, element.c_str()); + return base::StringPrintf(script_with_placeholder, element_script.c_str()); +} + } // namespace // Tests the `kFileHandlerDialog` dialog page of the `CloudUploadDialog`. // Ensures that fake local file tasks are all found and passed to the JS side of // the dialog - the `FileHandlerPageElement`. Ensures that a local file task // selected on the JS side gets executed. -class CloudUploadDialogBrowserTest : public InProcessBrowserTest { +class FileHandlerDialogBrowserTest : public InProcessBrowserTest { public: - CloudUploadDialogBrowserTest() { + FileHandlerDialogBrowserTest() { feature_list_.InitAndEnableFeature(features::kUploadOfficeToCloud); } - CloudUploadDialogBrowserTest(const CloudUploadDialogBrowserTest&) = delete; - CloudUploadDialogBrowserTest& operator=(const CloudUploadDialogBrowserTest&) = + FileHandlerDialogBrowserTest(const FileHandlerDialogBrowserTest&) = delete; + FileHandlerDialogBrowserTest& operator=(const FileHandlerDialogBrowserTest&) = delete; Profile* profile() { return browser()->profile(); } @@ -118,10 +153,9 @@ int n) { // Create `n` fake web apps for office files with the Doc extension and // store the created `urls_` and `tasks_`. - CreateFakeWebApps( - profile(), &urls_, &tasks_, - {doc_file_extension_, ppt_file_extension_, xls_file_extension_}, - {doc_mime_type_, ppt_mime_type_, xls_mime_type_}, n); + CreateFakeWebApps(profile(), &urls_, &tasks_, + {kDocFileExtension, kPptFileExtension, kXlsFileExtension}, + {kDocMimeType, kPptMimeType, kXlsMimeType}, n); for (const auto& file_extension : file_extensions) { base::FilePath file = @@ -134,27 +168,7 @@ } } - // Fill in the placeholder from `script_with_placeholder` with the JS command - // to retrieve the `FileHandlerPageElement`. Return this script wrapped with - // the send command. - std::string ScriptJS(const char script_with_placeholder[]) { - const char send_command[] = "domAutomationController.send(%s)"; - const char dialog[] = - "document.querySelectorAll('file-handler-" - "page')[0]"; - std::string script = base::StringPrintf(script_with_placeholder, dialog); - return base::StringPrintf(send_command, script.c_str()); - } - protected: - // The mime type and file_extension must be matching for - // `CreateFakeWebApps()`. - std::string doc_file_extension_ = ".doc"; - std::string doc_mime_type_ = "application/msword"; - std::string ppt_file_extension_ = ".ppt"; - std::string ppt_mime_type_ = "application/vnd.ms-powerpoint"; - std::string xls_file_extension_ = ".xls"; - std::string xls_mime_type_ = "application/vnd.ms-excel"; std::vector<std::string> urls_; std::vector<file_manager::file_tasks::TaskDescriptor> tasks_; std::vector<storage::FileSystemURL> files_; @@ -167,10 +181,10 @@ // `FileHandlerPageElement`. Tests that the `FileHandlerPageElement` observes // all of the fake file tasks and that a file task can be launched by clicking // on its button before clicking the open button. -IN_PROC_BROWSER_TEST_F(CloudUploadDialogBrowserTest, OpenFileTaskFromDialog) { +IN_PROC_BROWSER_TEST_F(FileHandlerDialogBrowserTest, OpenFileTaskFromDialog) { // Create fake doc and ppt files and 3 fake local file tasks that support all // office file types. - SetUpTasksAndFiles({doc_file_extension_, ppt_file_extension_}, 3); + SetUpTasksAndFiles({kDocFileExtension, kPptFileExtension}, 3); // Install QuickOffice. file_manager::test::AddDefaultComponentExtensionsOnMainThread(profile()); @@ -195,14 +209,7 @@ // Get the web contents of the dialog to be able to query // `FileHandlerPageElement`. - ash::SystemWebDialogDelegate* dialog = - ash::SystemWebDialogDelegate::FindInstance( - chrome::kChromeUICloudUploadURL); - ASSERT_TRUE(dialog); - content::WebUI* webui = dialog->GetWebUIForTest(); - ASSERT_TRUE(webui); - content::WebContents* web_contents = webui->GetWebContents(); - ASSERT_TRUE(web_contents); + content::WebContents* web_contents = GetWebContentsFromCloudUploadDialog(); // Get the `tasks` member from the `FileHandlerPageElement` which are all of // the observed local file tasks. @@ -215,7 +222,12 @@ // been initiated yet. It is completed when the `tasks` member is non-empty. if (!content::ExecuteScriptAndExtractString( web_contents, - ScriptJS("JSON.stringify(%s.tasks.map(task => task.appId))"), + base::StringPrintf( + "domAutomationController.send(%s)", + ScriptFillPlaceholder( + "JSON.stringify(%s.tasks.map(task => task.appId))", + "file-handler-page") + .c_str()), &result)) { continue; } @@ -261,22 +273,23 @@ // Check that there is not a default task for doc files. file_manager::file_tasks::TaskDescriptor default_task; ASSERT_FALSE(file_manager::file_tasks::GetDefaultTaskFromPrefs( - *profile()->GetPrefs(), doc_mime_type_, doc_file_extension_, - &default_task)); + *profile()->GetPrefs(), kDocMimeType, kDocFileExtension, &default_task)); // Check that there is not a default task for ppt files. ASSERT_FALSE(file_manager::file_tasks::GetDefaultTaskFromPrefs( - *profile()->GetPrefs(), ppt_mime_type_, ppt_file_extension_, - &default_task)); + *profile()->GetPrefs(), kPptMimeType, kPptFileExtension, &default_task)); // Click the selected task. std::string rename_task_id = "%s.$('#id" + base::NumberToString(selected_task_position) + "').click()"; - EXPECT_TRUE(content::ExecJs(web_contents, ScriptJS(rename_task_id.c_str()))); + EXPECT_TRUE(content::ExecJs( + web_contents, + ScriptFillPlaceholder(rename_task_id.c_str(), "file-handler-page"))); // Click the open button. - EXPECT_TRUE(content::ExecJs(web_contents, - ScriptJS("%s.$('.action-button').click()"))); + EXPECT_TRUE(content::ExecJs( + web_contents, ScriptFillPlaceholder("%s.$('.action-button').click()", + "file-handler-page"))); // Wait for selected task to open. navigation_observer_task.Wait(); @@ -286,30 +299,27 @@ // Check that the selected task has been made the default for doc files. ASSERT_TRUE(file_manager::file_tasks::GetDefaultTaskFromPrefs( - *profile()->GetPrefs(), doc_mime_type_, doc_file_extension_, - &default_task)); + *profile()->GetPrefs(), kDocMimeType, kDocFileExtension, &default_task)); ASSERT_EQ(tasks_[selected_task], default_task); // Check that the selected task has been made the default for ppt files. ASSERT_TRUE(file_manager::file_tasks::GetDefaultTaskFromPrefs( - *profile()->GetPrefs(), ppt_mime_type_, ppt_file_extension_, - &default_task)); + *profile()->GetPrefs(), kPptMimeType, kPptFileExtension, &default_task)); ASSERT_EQ(tasks_[selected_task], default_task); // Check that the selected task has not been made the default for xls files // because there was not an xls file selected by the user, even though the // task supports xls files. ASSERT_FALSE(file_manager::file_tasks::GetDefaultTaskFromPrefs( - *profile()->GetPrefs(), xls_mime_type_, xls_file_extension_, - &default_task)); + *profile()->GetPrefs(), kXlsMimeType, kXlsFileExtension, &default_task)); } // Tests that OnDialogComplete() opens the specified fake file task. -IN_PROC_BROWSER_TEST_F(CloudUploadDialogBrowserTest, +IN_PROC_BROWSER_TEST_F(FileHandlerDialogBrowserTest, OnDialogCompleteOpensFileTasks) { file_manager::file_tasks::TaskDescriptor default_task; int num_tasks = 3; - SetUpTasksAndFiles({xls_file_extension_}, num_tasks); + SetUpTasksAndFiles({kXlsFileExtension}, num_tasks); for (int selected_task = 0; selected_task < num_tasks; selected_task++) { std::string user_response = base::NumberToString(selected_task); @@ -328,7 +338,7 @@ // Check that the selected task has been made the default. ASSERT_TRUE(file_manager::file_tasks::GetDefaultTaskFromPrefs( - *profile()->GetPrefs(), xls_mime_type_, xls_file_extension_, + *profile()->GetPrefs(), kXlsMimeType, kXlsFileExtension, &default_task)); ASSERT_EQ(tasks_[selected_task], default_task); } @@ -336,9 +346,9 @@ // Tests that OnDialogComplete() doesn't crash when the specified selected task // doesn't exist. -IN_PROC_BROWSER_TEST_F(CloudUploadDialogBrowserTest, OnDialogCompleteNoCrash) { +IN_PROC_BROWSER_TEST_F(FileHandlerDialogBrowserTest, OnDialogCompleteNoCrash) { int num_tasks = 3; - SetUpTasksAndFiles({ppt_file_extension_}, num_tasks); + SetUpTasksAndFiles({kPptFileExtension}, num_tasks); int out_of_range_task = 3; std::string user_response = base::NumberToString(out_of_range_task); @@ -346,4 +356,280 @@ // Simulate user selecting a nonexistent selected task. OnDialogComplete(profile(), files_, user_response, std::move(tasks_)); } + +// Tests the Fixup flow. Ensures that it is run when the conditions are met: the +// Setup flow has completed, ODFS is not mounted or the Office PWA is not +// installed and OneDrive is selected as the cloud provider. Ensures that it +// cannot change the default task set. +class FixUpFlowBrowserTest : public InProcessBrowserTest { + public: + FixUpFlowBrowserTest() { + feature_list_.InitAndEnableFeature(features::kUploadOfficeToCloud); + } + + FixUpFlowBrowserTest(const FixUpFlowBrowserTest&) = delete; + FixUpFlowBrowserTest& operator=(const FixUpFlowBrowserTest&) = delete; + + Profile* profile() { return browser()->profile(); } + + // Add a doc test file. + void SetUpFiles() { + base::FilePath file = + file_manager::util::GetMyFilesFolderForProfile(profile()).AppendASCII( + "foo.doc"); + GURL url; + CHECK(file_manager::util::ConvertAbsoluteFilePathToFileSystemUrl( + profile(), file, file_manager::util::GetFileManagerURL(), &url)); + files_.push_back(storage::FileSystemURL::CreateForTest(url)); + } + + void AddFakeODFS() { + auto fake_provider = + ash::file_system_provider::FakeExtensionProvider::Create( + file_manager::file_tasks::kODFSExtensionId); + const auto kProviderId = fake_provider->GetId(); + auto* service = file_system_provider::Service::Get(profile()); + service->RegisterProvider(std::move(fake_provider)); + service->MountFileSystem(kProviderId, + ash::file_system_provider::MountOptions( + "test-filesystem", "Test FileSystem")); + } + + void AddFakeOfficePWA() { + file_manager::test::AddFakeWebApp( + web_app::kMicrosoftOfficeAppId, kDocMimeType, kDocFileExtension, "", + true, apps::AppServiceProxyFactory::GetForProfile(profile())); + } + + protected: + std::vector<storage::FileSystemURL> files_; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Tests that the Fixup flow is entered when OneDrive is selected as the cloud +// provider but ODFS is not mounted and the Setup flow has already completed. +// Checks that the ODFS Sign In Page is reachable. +IN_PROC_BROWSER_TEST_F(FixUpFlowBrowserTest, FixUpFlowWhenODFSNotMounted) { + // Set Setup flow as complete. + file_manager::file_tasks::SetOfficeSetupComplete(profile(), true); + + SetUpFiles(); + AddFakeOfficePWA(); + + // ODFS is not mounted, expect that the Fixup flow will need to run. + ASSERT_TRUE(ShouldFixUpOffice(profile(), CloudProvider::kOneDrive)); + + // Watch for OneDrive Setup dialog URL chrome://cloud-upload. + content::TestNavigationObserver navigation_observer_dialog( + (GURL(chrome::kChromeUICloudUploadURL))); + navigation_observer_dialog.StartWatchingNewWebContents(); + + OpenFilesWithCloudProvider(profile(), files_, CloudProvider::kOneDrive); + + // Wait for Welcome Page to open at chrome://cloud-upload. + navigation_observer_dialog.Wait(); + ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded()); + + content::WebContents* web_contents = GetWebContentsFromCloudUploadDialog(); + + // Click through the Welcome Page. + while (!content::ExecJs( + web_contents, + ScriptFillPlaceholder( + "%s.$('welcome-page').querySelector('.action-button').click()", + "cloud-upload"))) { + } + + // Wait for the ODFS Sign In Page. + while (!content::ExecJs( + web_contents, ScriptFillPlaceholder( + "%s.$('sign-in-page').querySelector('.action-button')", + "cloud-upload"))) { + } +} + +// Tests that the Fixup flow is entered when OneDrive is selected as the cloud +// provider but the Office PWA is not installed and the Setup flow has already +// completed. Checks that the Office PWA Install Page is reachable. +IN_PROC_BROWSER_TEST_F(FixUpFlowBrowserTest, + FixUpFlowWhenOfficePWANotInstalled) { + // Set Setup flow as complete. + file_manager::file_tasks::SetOfficeSetupComplete(profile(), true); + + SetUpFiles(); + AddFakeODFS(); + + // Office PWA is not installed, expect that the Fixup flow will need to run. + ASSERT_TRUE(ShouldFixUpOffice(profile(), CloudProvider::kOneDrive)); + + // Watch for OneDrive Setup dialog URL chrome://cloud-upload. + content::TestNavigationObserver navigation_observer_dialog( + (GURL(chrome::kChromeUICloudUploadURL))); + navigation_observer_dialog.StartWatchingNewWebContents(); + + OpenFilesWithCloudProvider(profile(), files_, CloudProvider::kOneDrive); + + // Wait for Welcome Page to open at chrome://cloud-upload. + navigation_observer_dialog.Wait(); + ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded()); + + content::WebContents* web_contents = GetWebContentsFromCloudUploadDialog(); + + // Click through the Welcome Page. + while (!content::ExecJs( + web_contents, + ScriptFillPlaceholder( + "%s.$('welcome-page').querySelector('.action-button').click()", + "cloud-upload"))) { + } + + // Wait for the Office PWA Install Page, this script will fail until the page + // exists. + while (!content::ExecJs( + web_contents, + ScriptFillPlaceholder( + "%s.$('office-pwa-install-page').querySelector('.action-button')", + "cloud-upload"))) { + } +} + +// Tests that `ShouldFixUpOffice()` returns true when neither ODFS is mounted +// nor Office PWA is installed and OneDrive is selected as the cloud provider. +IN_PROC_BROWSER_TEST_F(FixUpFlowBrowserTest, ShouldFixUpOfficeNoODFSNoPWA) { + ASSERT_TRUE(ShouldFixUpOffice(profile(), CloudProvider::kOneDrive)); +} + +// Tests that `ShouldFixUpOffice()` returns false when neither ODFS is mounted +// nor Office PWA is installed but Drive is selected as the cloud provider. +IN_PROC_BROWSER_TEST_F(FixUpFlowBrowserTest, ShouldFixUpOfficeDrive) { + ASSERT_FALSE(ShouldFixUpOffice(profile(), CloudProvider::kGoogleDrive)); +} + +// Tests that `ShouldFixUpOffice()` returns false when both ODFS is mounted and +// Office PWA is installed and OneDrive is selected as the cloud provider. +IN_PROC_BROWSER_TEST_F(FixUpFlowBrowserTest, ShouldFixUpOfficeODFSAndPWA) { + AddFakeODFS(); + AddFakeOfficePWA(); + ASSERT_FALSE(ShouldFixUpOffice(profile(), CloudProvider::kOneDrive)); +} + +// Test that entering and completing the Setup flow from the OneDrive Set Up +// point changes the default task set when the Setup has not been run before. +IN_PROC_BROWSER_TEST_F(FixUpFlowBrowserTest, + OneDriveSetUpChangesDefaultTaskWhenSetUpIncomplete) { + // Set Setup flow as incomplete. + file_manager::file_tasks::SetOfficeSetupComplete(profile(), false); + + // Add a doc test file. + SetUpFiles(); + AddFakeODFS(); + AddFakeOfficePWA(); + + // Watch for OneDrive Setup dialog URL chrome://cloud-upload. + content::TestNavigationObserver navigation_observer_dialog( + (GURL(chrome::kChromeUICloudUploadURL))); + navigation_observer_dialog.StartWatchingNewWebContents(); + + // Check that there is not a default task for doc files. + file_manager::file_tasks::TaskDescriptor default_task; + ASSERT_FALSE(file_manager::file_tasks::GetDefaultTaskFromPrefs( + *profile()->GetPrefs(), kDocMimeType, kDocFileExtension, &default_task)); + + // Open the Welcome Page for the OneDrive set up part of the Setup flow. This + // will lead to the Office PWA being set as the default task. + CloudUploadDialog::SetUpAndShowDialog(profile(), files_, + mojom::DialogPage::kOneDriveSetup); + + // Wait for Welcome Page to open at chrome://cloud-upload. + navigation_observer_dialog.Wait(); + ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded()); + + content::WebContents* web_contents = GetWebContentsFromCloudUploadDialog(); + + // Click through the Welcome Page. + while (!content::ExecJs( + web_contents, + ScriptFillPlaceholder( + "%s.$('welcome-page').querySelector('.action-button').click()", + "cloud-upload"))) { + } + + // Click through the Upload Page. + while (!content::ExecJs( + web_contents, + ScriptFillPlaceholder( + "%s.$('upload-page').querySelector('.action-button').click()", + "cloud-upload"))) { + } + + // Check that the Office PWA has been made the default for doc files. + ASSERT_TRUE(file_manager::file_tasks::GetDefaultTaskFromPrefs( + *profile()->GetPrefs(), kDocMimeType, kDocFileExtension, &default_task)); + ASSERT_TRUE(IsOpenInOfficeTask(default_task)); +} + +// Test that entering and completing the Setup flow from the OneDrive Set Up +// point does not change the default task set when the Setup has been run +// before. This is to test that when the Fixup flow runs, the default task does +// not change. +IN_PROC_BROWSER_TEST_F(FixUpFlowBrowserTest, + OneDriveSetUpDoesNotChangeDefaultTaskWhenSetUpComplete) { + // Set Setup flow as complete. + file_manager::file_tasks::SetOfficeSetupComplete(profile(), true); + + // Add a doc test file. + SetUpFiles(); + // Note: although mounting ODFS and installing the Office PWA sets up + // conditions so that the Fixup flow does not need to be run, this test is + // just to check that entering the Setup flow from OneDrive Setup point does + // not set the default task when the Setup flow is already complete. + // Otherwise, the test would get stuck trying to set up OneDrive, unable to + // navigate through all the dialog pages. + AddFakeODFS(); + AddFakeOfficePWA(); + + // Watch for OneDrive Setup dialog URL chrome://cloud-upload. + content::TestNavigationObserver navigation_observer_dialog( + (GURL(chrome::kChromeUICloudUploadURL))); + navigation_observer_dialog.StartWatchingNewWebContents(); + + // Check that there is not a default task for doc files. + file_manager::file_tasks::TaskDescriptor default_task; + ASSERT_FALSE(file_manager::file_tasks::GetDefaultTaskFromPrefs( + *profile()->GetPrefs(), kDocMimeType, kDocFileExtension, &default_task)); + + // Open the Welcome Page for the OneDrive set up part of the Setup flow. This + // will not lead to the Office PWA being set as the default task because the + // Setup flow has already been completed. + CloudUploadDialog::SetUpAndShowDialog(profile(), files_, + mojom::DialogPage::kOneDriveSetup); + + // Wait for Welcome Page to open at chrome://cloud-upload. + navigation_observer_dialog.Wait(); + ASSERT_TRUE(navigation_observer_dialog.last_navigation_succeeded()); + + content::WebContents* web_contents = GetWebContentsFromCloudUploadDialog(); + + // Click through the Welcome Page. + while (!content::ExecJs( + web_contents, + ScriptFillPlaceholder( + "%s.$('welcome-page').querySelector('.action-button').click()", + "cloud-upload"))) { + } + + // Click through the Upload Page. + while (!content::ExecJs( + web_contents, + ScriptFillPlaceholder( + "%s.$('upload-page').querySelector('.action-button').click()", + "cloud-upload"))) { + } + + // Check that there is still not a default task for doc files. + ASSERT_FALSE(file_manager::file_tasks::GetDefaultTaskFromPrefs( + *profile()->GetPrefs(), kDocMimeType, kDocFileExtension, &default_task)); +} } // namespace ash::cloud_upload
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc index ef5472f..660517a 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc
@@ -6,7 +6,6 @@ #include "base/functional/bind.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" -#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ash/crosapi/crosapi_ash.h" #include "chrome/browser/ash/crosapi/crosapi_manager.h" #include "chrome/browser/ash/crosapi/web_app_service_ash.h" @@ -15,16 +14,13 @@ #include "chrome/browser/ash/file_system_provider/service.h" #include "chrome/browser/chromeos/office_web_app/office_web_app.h" #include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom.h" -#include "chrome/browser/web_applications/web_app_id_constants.h" +#include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h" #include "chrome/browser/web_applications/web_app_provider.h" -#include "components/services/app_service/public/cpp/app_update.h" -#include "components/services/app_service/public/cpp/types_util.h" #include "components/webapps/browser/install_result_code.h" #include "mojo/public/cpp/bindings/callback_helpers.h" namespace ash::cloud_upload { -using ash::file_system_provider::ProvidedFileSystemInfo; using ash::file_system_provider::ProviderId; using ash::file_system_provider::Service; @@ -61,19 +57,7 @@ void CloudUploadPageHandler::IsOfficeWebAppInstalled( IsOfficeWebAppInstalledCallback callback) { - if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile( - profile_)) { - std::move(callback).Run(false); - return; - } - auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile_); - bool installed = false; - proxy->AppRegistryCache().ForOneApp( - web_app::kMicrosoftOfficeAppId, - [&installed](const apps::AppUpdate& update) { - installed = apps_util::IsInstalled(update.Readiness()); - }); - std::move(callback).Run(installed); + std::move(callback).Run(CloudUploadDialog::IsOfficeWebAppInstalled(profile_)); } void CloudUploadPageHandler::InstallOfficeWebApp( @@ -105,14 +89,8 @@ } void CloudUploadPageHandler::IsODFSMounted(IsODFSMountedCallback callback) { - Service* service = Service::Get(profile_); - ProviderId provider_id = ProviderId::CreateFromExtensionId( - file_manager::file_tasks::kODFSExtensionId); - std::vector<ProvidedFileSystemInfo> file_systems = - service->GetProvidedFileSystemInfoList(provider_id); - // Assume any file system mounted by ODFS is the correct one. - std::move(callback).Run(!file_systems.empty()); + std::move(callback).Run(CloudUploadDialog::IsODFSMounted(profile_)); } void CloudUploadPageHandler::SignInToOneDrive(
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc index dccbf26..cdb6524 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
@@ -233,6 +233,8 @@ profile_, observed_relative_drive_path_); } return; + case file_manager::io_task::State::kPaused: + return; case file_manager::io_task::State::kSuccess: move_progress_ = 100; UpdateProgressNotification();
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.cc index b27e1a9d..285d785 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/one_drive_upload_handler.cc
@@ -180,6 +180,8 @@ 100 * status.bytes_transferred / status.total_bytes); } return; + case file_manager::io_task::State::kPaused: + return; case file_manager::io_task::State::kSuccess: notification_manager_->ShowUploadProgress(100); DCHECK_EQ(status.outputs.size(), 1u);
diff --git a/chrome/browser/ui/webui/intro/intro_handler.cc b/chrome/browser/ui/webui/intro/intro_handler.cc index 6f589b2..deb6c6b3 100644 --- a/chrome/browser/ui/webui/intro/intro_handler.cc +++ b/chrome/browser/ui/webui/intro/intro_handler.cc
@@ -3,9 +3,120 @@ // found in the LICENSE file. #include "chrome/browser/ui/webui/intro/intro_handler.h" +#include "base/cancelable_callback.h" +#include "base/functional/bind.h" +#include "base/scoped_observation.h" +#include "base/strings/utf_string_conversions.h" +#include "base/task/single_thread_task_runner.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/policy/chrome_browser_policy_connector.h" +#include "chrome/browser/ui/managed_ui.h" +#include "chrome/grit/generated_resources.h" +#include "components/policy/core/common/cloud/cloud_policy_store.h" +#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h" +#include "ui/base/l10n/l10n_util.h" -IntroHandler::IntroHandler(base::RepeatingCallback<void(bool sign_in)> callback) - : callback_(std::move(callback)) { +namespace { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) +policy::CloudPolicyStore* GetCloudPolicyStore() { + auto* machine_level_manager = g_browser_process->browser_policy_connector() + ->machine_level_user_cloud_policy_manager(); + + return machine_level_manager ? machine_level_manager->core()->store() + : nullptr; +} + +// PolicyStoreState will make it easier to handle all the states in a single +// callback. +enum class PolicyStoreState { + // Store has been loaded before the time delay ends. + kSuccess, + // Store did not load in time. + kTimeout, + // OnStoreError called. + kStoreError, + // Store was already loaded when we attached the observer. + kSuccessAlreadyLoaded, +}; + +class PolicyStoreObserver : public policy::CloudPolicyStore::Observer { + public: + explicit PolicyStoreObserver( + base::OnceCallback<void(std::string)> handle_policy_store_change) + : handle_policy_store_change_(std::move(handle_policy_store_change)) { + DCHECK(handle_policy_store_change_); + // Update the disclaimer directly if the policy store is already loaded. + auto* policy_store = GetCloudPolicyStore(); + if (policy_store->is_initialized()) { + HandlePolicyStoreStatusChange(PolicyStoreState::kSuccessAlreadyLoaded); + return; + } + + policy_store_observation_.Observe(policy_store); + // 2.5 is the chrome logo animation time which is 1.5s plus the maximum + // delay of 1s that we are willing to wait for. + constexpr auto kMaximumEnterpriseDisclaimerDelay = base::Seconds(2.5); + on_organization_fetch_timeout_.Reset( + base::BindOnce(&PolicyStoreObserver::OnOrganizationFetchTimeout, + base::Unretained(this))); + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, on_organization_fetch_timeout_.callback(), + kMaximumEnterpriseDisclaimerDelay); + } + + ~PolicyStoreObserver() override = default; + + // policy::CloudPolicyStore::Observer: + void OnStoreLoaded(policy::CloudPolicyStore* store) override { + on_organization_fetch_timeout_.Cancel(); + policy_store_observation_.Reset(); + HandlePolicyStoreStatusChange(PolicyStoreState::kSuccess); + } + + void OnStoreError(policy::CloudPolicyStore* store) override { + on_organization_fetch_timeout_.Cancel(); + policy_store_observation_.Reset(); + HandlePolicyStoreStatusChange(PolicyStoreState::kStoreError); + } + + // Called when the delay specified for the store to load has passed. We show a + // generic disclaimer when this happens. + void OnOrganizationFetchTimeout() { + policy_store_observation_.Reset(); + HandlePolicyStoreStatusChange(PolicyStoreState::kTimeout); + } + + void HandlePolicyStoreStatusChange(PolicyStoreState state) { + std::string managed_device_disclaimer; + if (state == PolicyStoreState::kSuccess || + state == PolicyStoreState::kSuccessAlreadyLoaded) { + absl::optional<std::string> manager = chrome::GetDeviceManagerIdentity(); + DCHECK(manager.has_value()); + managed_device_disclaimer = + manager->empty() + ? l10n_util::GetStringUTF8(IDS_FRE_MANAGED_DESCRIPTION) + : l10n_util::GetStringFUTF8(IDS_FRE_MANAGED_BY_DESCRIPTION, + base::UTF8ToUTF16(*manager)); + } else { + managed_device_disclaimer = + l10n_util::GetStringUTF8(IDS_FRE_MANAGED_DESCRIPTION); + } + std::move(handle_policy_store_change_).Run(managed_device_disclaimer); + } + + private: + base::ScopedObservation<policy::CloudPolicyStore, + policy::CloudPolicyStore::Observer> + policy_store_observation_{this}; + base::OnceCallback<void(std::string)> handle_policy_store_change_; + base::CancelableOnceCallback<void()> on_organization_fetch_timeout_; +}; +#endif +} // namespace + +IntroHandler::IntroHandler(base::RepeatingCallback<void(bool sign_in)> callback, + bool is_device_managed) + : callback_(std::move(callback)), is_device_managed_(is_device_managed) { DCHECK(callback_); } @@ -20,6 +131,20 @@ "continueWithAccount", base::BindRepeating(&IntroHandler::HandleContinueWithAccount, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "initializeMainView", + base::BindRepeating(&IntroHandler::HandleInitializeMainView, + base::Unretained(this))); +} + +void IntroHandler::OnJavascriptAllowed() { + if (!is_device_managed_) { + return; + } +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + policy_store_observer_ = std::make_unique<PolicyStoreObserver>(base::BindOnce( + &IntroHandler::FireManagedDisclaimerUpdate, base::Unretained(this))); +#endif } void IntroHandler::HandleContinueWithAccount(const base::Value::List& args) { @@ -31,3 +156,16 @@ CHECK(args.empty()); callback_.Run(/*sign_in=*/false); } + +void IntroHandler::HandleInitializeMainView(const base::Value::List& args) { + CHECK(args.empty()); + AllowJavascript(); +} + +void IntroHandler::FireManagedDisclaimerUpdate(std::string disclaimer) { + DCHECK(is_device_managed_); + if (IsJavascriptAllowed()) { + FireWebUIListener("managed-device-disclaimer-updated", + base::Value(std::move(disclaimer))); + } +}
diff --git a/chrome/browser/ui/webui/intro/intro_handler.h b/chrome/browser/ui/webui/intro/intro_handler.h index 5d8a419..d7a3720 100644 --- a/chrome/browser/ui/webui/intro/intro_handler.h +++ b/chrome/browser/ui/webui/intro/intro_handler.h
@@ -5,11 +5,15 @@ #ifndef CHROME_BROWSER_UI_WEBUI_INTRO_INTRO_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_INTRO_INTRO_HANDLER_H_ +#include "base/functional/callback_forward.h" +#include "components/policy/core/common/cloud/cloud_policy_store.h" +#include "components/signin/public/base/signin_buildflags.h" #include "content/public/browser/web_ui_message_handler.h" class IntroHandler : public content::WebUIMessageHandler { public: - explicit IntroHandler(base::RepeatingCallback<void(bool sign_in)> callback); + explicit IntroHandler(base::RepeatingCallback<void(bool sign_in)> callback, + bool is_device_managed); IntroHandler(const IntroHandler&) = delete; IntroHandler& operator=(const IntroHandler&) = delete; @@ -18,12 +22,31 @@ // content::WebUIMessageHandler: void RegisterMessages() override; + void OnJavascriptAllowed() override; private: + // Handles "continueWithAccount" message from the page. No arguments. + // This message is sent when the user confirms that they want to sign in to + // Chrome. void HandleContinueWithAccount(const base::Value::List& args); + + // Handles "continueWithoutAccount" message from the page. No arguments. + // This message is sent when the user declines signing in to Chrome. void HandleContinueWithoutAccount(const base::Value::List& args); + // Handles "initializeMainView" message from the page. No arguments. + // This message is sent when the view is created. + void HandleInitializeMainView(const base::Value::List& args); + + // Fires the `managed-device-disclaimer-updated` event with the disclaimer + // that will be caught and handled in the ts file. + void FireManagedDisclaimerUpdate(std::string disclaimer); + const base::RepeatingCallback<void(bool sign_in)> callback_; + const bool is_device_managed_ = false; +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + std::unique_ptr<policy::CloudPolicyStore::Observer> policy_store_observer_; +#endif }; #endif // CHROME_BROWSER_UI_WEBUI_INTRO_INTRO_HANDLER_H_
diff --git a/chrome/browser/ui/webui/intro/intro_ui.cc b/chrome/browser/ui/webui/intro/intro_ui.cc index dd15a53..e3d6a749 100644 --- a/chrome/browser/ui/webui/intro/intro_ui.cc +++ b/chrome/browser/ui/webui/intro/intro_ui.cc
@@ -26,7 +26,6 @@ #endif namespace { - void AddStrings(content::WebUIDataSource* html_source) { #if BUILDFLAG(ENABLE_DICE_SUPPORT) static constexpr webui::LocalizedString kLocalizedStrings[] = { @@ -45,18 +44,6 @@ html_source->AddLocalizedStrings(kLocalizedStrings); #endif } - -std::string GetEnterpriseDisclaimer(content::WebUI* web_ui) { -#if BUILDFLAG(ENABLE_DICE_SUPPORT) - int managed_id = IDS_FRE_MANAGED_DESCRIPTION; - return chrome::ShouldDisplayManagedUi(Profile::FromWebUI(web_ui)) - ? l10n_util::GetStringUTF8(managed_id) - : ""; -#else - return ""; -#endif -} - } // namespace IntroUI::IntroUI(content::WebUI* web_ui) : content::WebUIController(web_ui) { @@ -72,7 +59,11 @@ AddStrings(source); - source->AddString("managedDeviceDisclaimer", GetEnterpriseDisclaimer(web_ui)); + // TODO(crbug.com/1409028): Replace this function by a call to + // chrome::GetDeviceManagerIdentity() + bool is_device_managed = + chrome::ShouldDisplayManagedUi(Profile::FromWebUI(web_ui)); + source->AddBoolean("isDeviceManaged", is_device_managed); source->AddResourcePath("product-logo.svg", IDR_PRODUCT_LOGO_SVG); source->AddResourcePath("product-logo-animation.svg", @@ -91,8 +82,9 @@ IDR_SIGNIN_SYNC_CONFIRMATION_IMAGES_TANGIBLE_SYNC_WINDOW_RIGHT_ILLUSTRATION_DARK_SVG); // Unretained ok: `this` owns the handler. - web_ui->AddMessageHandler(std::make_unique<IntroHandler>(base::BindRepeating( - &IntroUI::HandleSigninChoice, base::Unretained(this)))); + web_ui->AddMessageHandler(std::make_unique<IntroHandler>( + base::BindRepeating(&IntroUI::HandleSigninChoice, base::Unretained(this)), + is_device_managed)); } IntroUI::~IntroUI() = default;
diff --git a/chrome/browser/ui/webui/new_tab_page/OWNERS b/chrome/browser/ui/webui/new_tab_page/OWNERS index 9154f32..2750495 100644 --- a/chrome/browser/ui/webui/new_tab_page/OWNERS +++ b/chrome/browser/ui/webui/new_tab_page/OWNERS
@@ -1,6 +1,7 @@ mahmadi@chromium.org pauladedeji@google.com romanarora@chromium.org +rtatum@google.com tiborg@chromium.org tluk@chromium.org
diff --git a/chrome/browser/ui/webui/policy/policy_ui.cc b/chrome/browser/ui/webui/policy/policy_ui.cc index d5ab74f..03265ad 100644 --- a/chrome/browser/ui/webui/policy/policy_ui.cc +++ b/chrome/browser/ui/webui/policy/policy_ui.cc
@@ -19,8 +19,47 @@ #include "services/network/public/mojom/content_security_policy.mojom.h" #include "ui/base/webui/web_ui_util.h" +#if BUILDFLAG(IS_ANDROID) +#include "base/json/json_writer.h" +#include "base/strings/stringprintf.h" +#include "base/system/sys_info.h" +#include "components/policy/core/common/policy_logger.h" +#include "components/version_info/version_info.h" +#include "components/version_ui/version_handler_helper.h" +#include "content/public/common/user_agent.h" +#endif // BUILDFLAG(IS_ANDROID) + namespace { +#if BUILDFLAG(IS_ANDROID) +// Returns the operating system information to be displayed on +// chrome://policy/logs page. +std::string GetOsInfo() { + // The base format for the OS version and build + constexpr char kOSVersionAndBuildFormat[] = "%s, Version: %s"; + return base::StringPrintf( + kOSVersionAndBuildFormat, + (content::GetAndroidOSInfo(content::IncludeAndroidBuildNumber::Include, + content::IncludeAndroidModel::Include)) + .c_str(), + (base::SysInfo::OperatingSystemVersion()).c_str()); +} + +// Returns the version information to be displayed on the chrome://policy/logs +// page. +base::Value GetVersionInfo() { + base::Value version_info(base::Value::Type::DICT); + + version_info.SetStringPath("revision", version_info::GetLastChange()); + version_info.SetStringPath("version", version_info::GetVersionNumber()); + version_info.SetStringPath("device_os", GetOsInfo()); + version_info.SetPath("variations", + base::Value(version_ui::GetVariationsList())); + + return version_info; +} +#endif + void CreateAndAddPolicyUIHtmlSource(Profile* profile) { content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( profile, chrome::kChromeUIPolicyHost); @@ -91,6 +130,22 @@ }; source->AddLocalizedStrings(kStrings); +#if BUILDFLAG(IS_ANDROID) + source->AddBoolean( + "loggingEnabled", + policy::PolicyLogger::GetInstance()->IsPolicyLoggingEnabled()); + + if (policy::PolicyLogger::GetInstance()->IsPolicyLoggingEnabled()) { + std::string variations_json_value; + base::JSONWriter::Write(GetVersionInfo(), &variations_json_value); + + source->AddString("versionInfo", variations_json_value); + } + + source->AddResourcePath("logs/", IDR_POLICY_LOGS_POLICY_LOGS_HTML); + source->AddResourcePath("logs", IDR_POLICY_LOGS_POLICY_LOGS_HTML); +#endif // BUILDFLAG(IS_ANDROID) + webui::SetupWebUIDataSource( source, base::make_span(kPolicyResources, kPolicyResourcesSize), IDR_POLICY_POLICY_HTML);
diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc index 483b86a..9add6e92 100644 --- a/chrome/browser/ui/webui/policy/policy_ui_handler.cc +++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
@@ -72,6 +72,10 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/webui/web_ui_util.h" +#if BUILDFLAG(IS_ANDROID) +#include "components/policy/core/common/policy_logger.h" +#endif // BUILDFLAG(IS_ANDROID) + #if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ash/policy/active_directory/active_directory_policy_manager.h" #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h" @@ -175,6 +179,14 @@ "copyPoliciesJSON", base::BindRepeating(&PolicyUIHandler::HandleCopyPoliciesJson, base::Unretained(this))); + +#if BUILDFLAG(IS_ANDROID) + web_ui()->RegisterMessageCallback( + "getPolicyLogs", + base::BindRepeating(&PolicyUIHandler::HandleGetPolicyLogs, + base::Unretained(this))); +#endif // BUILDFLAG(IS_ANDROID) + #if !BUILDFLAG(IS_CHROMEOS) web_ui()->RegisterMessageCallback( "uploadReport", base::BindRepeating(&PolicyUIHandler::HandleUploadReport, @@ -285,6 +297,15 @@ scw.WriteText(base::UTF8ToUTF16(policies_json)); } +#if BUILDFLAG(IS_ANDROID) +void PolicyUIHandler::HandleGetPolicyLogs(const base::Value::List& args) { + DCHECK(policy::PolicyLogger::GetInstance()->IsPolicyLoggingEnabled()); + AllowJavascript(); + ResolveJavascriptCallback(args[0], + policy::PolicyLogger::GetInstance()->GetAsValue()); +} +#endif // BUILDFLAG(IS_ANDROID) + #if !BUILDFLAG(IS_CHROMEOS) void PolicyUIHandler::HandleUploadReport(const base::Value::List& args) { DCHECK_EQ(1u, args.size());
diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.h b/chrome/browser/ui/webui/policy/policy_ui_handler.h index 14bea23..a6a320f0 100644 --- a/chrome/browser/ui/webui/policy/policy_ui_handler.h +++ b/chrome/browser/ui/webui/policy/policy_ui_handler.h
@@ -63,6 +63,11 @@ void HandleUploadReport(const base::Value::List& args); #endif +#if BUILDFLAG(IS_ANDROID) + // Handler functions for chrome://policy/logs. + void HandleGetPolicyLogs(const base::Value::List& args); +#endif // BUILDFLAG(IS_ANDROID) + // Send information about the current policy values to the UI. Information is // sent in two parts to the UI: // - A dictionary containing all available policy names
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h index 0fd6400..9cf3f90 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -30,6 +30,10 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +#if BUILDFLAG(ENABLE_OOP_PRINTING) +#include "chrome/browser/printing/print_backend_service_manager.h" +#endif + namespace base { class FilePath; class RefCountedMemory; @@ -261,7 +265,7 @@ #if BUILDFLAG(ENABLE_OOP_PRINTING) // This UI's client ID with the print backend service manager. - uint32_t service_manager_client_id_; + PrintBackendServiceManager::ClientId service_manager_client_id_; #endif // Weak pointer to the WebUI handler.
diff --git a/chrome/browser/ui/webui/settings/ash/crostini_handler.cc b/chrome/browser/ui/webui/settings/ash/crostini_handler.cc index 6909df9..ea01f28e 100644 --- a/chrome/browser/ui/webui/settings/ash/crostini_handler.cc +++ b/chrome/browser/ui/webui/settings/ash/crostini_handler.cc
@@ -10,6 +10,8 @@ #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/metrics/histogram_functions.h" +#include "chrome/browser/ash/bruschetta/bruschetta_features.h" +#include "chrome/browser/ash/bruschetta/bruschetta_util.h" #include "chrome/browser/ash/crostini/crostini_disk.h" #include "chrome/browser/ash/crostini/crostini_features.h" #include "chrome/browser/ash/crostini/crostini_installer.h" @@ -25,6 +27,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/ash/bruschetta_delegate.h" #include "chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_dialog.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" @@ -195,6 +198,13 @@ base::BindRepeating(&CrostiniHandler::HandleSetVmDeviceShared, handler_weak_ptr_factory_.GetWeakPtr())); } + if (bruschetta::BruschettaFeatures::Get()->IsEnabled()) { + web_ui()->RegisterMessageCallback( + "requestBruschettaInstallerView", + base::BindRepeating( + &CrostiniHandler::HandleRequestBruschettaInstallerView, + handler_weak_ptr_factory_.GetWeakPtr())); + } } void CrostiniHandler::OnJavascriptAllowed() { @@ -945,4 +955,11 @@ callback_weak_ptr_factory_.GetWeakPtr(), callback_id)); } +void CrostiniHandler::HandleRequestBruschettaInstallerView( + const base::Value::List& args) { + AllowJavascript(); + RunBruschettaInstaller(Profile::FromWebUI(web_ui()), + bruschetta::GetBruschettaAlphaId()); +} + } // namespace ash::settings
diff --git a/chrome/browser/ui/webui/settings/ash/crostini_handler.h b/chrome/browser/ui/webui/settings/ash/crostini_handler.h index 0a374c5..94d24fd1 100644 --- a/chrome/browser/ui/webui/settings/ash/crostini_handler.h +++ b/chrome/browser/ui/webui/settings/ash/crostini_handler.h
@@ -160,6 +160,7 @@ void HandleIsVmDeviceShared(const base::Value::List& args); // Handle a request to set the sharing status of a VmDevice void HandleSetVmDeviceShared(const base::Value::List& args); + void HandleRequestBruschettaInstallerView(const base::Value::List& args); Profile* profile_; base::CallbackListSubscription adb_sideloading_device_policy_subscription_;
diff --git a/chrome/browser/ui/webui/settings/ash/crostini_section.cc b/chrome/browser/ui/webui/settings/ash/crostini_section.cc index 5ce2b97..b9782be 100644 --- a/chrome/browser/ui/webui/settings/ash/crostini_section.cc +++ b/chrome/browser/ui/webui/settings/ash/crostini_section.cc
@@ -253,12 +253,14 @@ void CrostiniSection::AddLoadTimeData(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { {"bruschettaPageLabel", IDS_SETTINGS_BRUSCHETTA_LABEL}, + {"bruschettaEnable", IDS_SETTINGS_TURN_ON}, {"bruschettaSharedUsbDevicesDescription", IDS_SETTINGS_BRUSCHETTA_SHARED_USB_DEVICES_DESCRIPTION}, {"bruschettaSharedPathsInstructionsAdd", IDS_SETTINGS_BRUSCHETTA_SHARED_PATHS_INSTRUCTIONS_ADD}, {"bruschettaSharedPathsRemoveFailureDialogMessage", IDS_SETTINGS_BRUSCHETTA_SHARED_PATHS_REMOVE_FAILURE_DIALOG_MESSAGE}, + {"bruschettaSubtext", IDS_SETTINGS_BRUSCHETTA_SUBTEXT}, {"crostiniPageTitle", IDS_SETTINGS_CROSTINI_TITLE}, {"crostiniPageLabel", IDS_SETTINGS_CROSTINI_LABEL}, {"crostiniEnable", IDS_SETTINGS_TURN_ON}, @@ -433,13 +435,29 @@ html_source->AddBoolean( "showCrostini", crostini::CrostiniFeatures::Get()->CouldBeAllowed(profile_)); + // Should we actually enable the button to install it? html_source->AddBoolean( "allowCrostini", crostini::CrostiniFeatures::Get()->IsAllowedNow(profile_)); - // Should the Bruschetta subpage be enabled? - html_source->AddBoolean("enableBruschetta", - bruschetta::BruschettaFeatures::Get()->IsEnabled()); + + // Should Bruschetta be displayed in the settings at all? + const bool bru_feature = bruschetta::BruschettaFeatures::Get()->IsEnabled(); + const bool bru_config = + bruschetta::HasInstallableConfig(profile_, bruschetta::kBruschettaVmName); + if (bru_feature && !bru_config) { + LOG(WARNING) << "Bruschetta has no installable config."; + } + // TODO(b/266160969): After confirming that the Bruschetta policy is present + // for existing users, make showBruschetta check for both bru_feature && + // bru_config. + html_source->AddBoolean("showBruschetta", bru_feature); + + // Is Bruschetta installed? If yes, we have a subpage of settings. If not, we + // show an install button. + html_source->AddBoolean( + "isBruschettaInstalled", + bruschetta::IsInstalled(profile_, bruschetta::GetBruschettaAlphaId())); html_source->AddString( "bruschettaSharedPathsInstructionsLocate", @@ -507,7 +525,8 @@ } void CrostiniSection::AddHandlers(content::WebUI* web_ui) { - if (crostini::CrostiniFeatures::Get()->CouldBeAllowed(profile_)) { + if (crostini::CrostiniFeatures::Get()->CouldBeAllowed(profile_) || + bruschetta::BruschettaFeatures::Get()->IsEnabled()) { web_ui->AddMessageHandler(std::make_unique<GuestOsHandler>(profile_)); web_ui->AddMessageHandler(std::make_unique<CrostiniHandler>(profile_)); } @@ -615,6 +634,7 @@ mojom::SearchResultIcon::kDeveloperTags, mojom::SearchResultDefaultRank::kMedium, mojom::kBruschettaDetailsSubpagePath); + // USB preferences. generator->RegisterNestedSubpage( IDS_SETTINGS_GUEST_OS_SHARED_USB_DEVICES_LABEL, @@ -667,19 +687,22 @@ updater.AddSearchTags(GetCrostiniOptedInSearchConcepts()); - if (IsExportImportAllowed()) + if (IsExportImportAllowed()) { updater.AddSearchTags(GetCrostiniExportImportSearchConcepts()); + } if (IsAdbSideloadingAllowed() && pref_service_->GetBoolean(arc::prefs::kArcEnabled)) { updater.AddSearchTags(GetCrostiniAdbSideloadingSearchConcepts()); } - if (IsPortForwardingAllowed()) + if (IsPortForwardingAllowed()) { updater.AddSearchTags(GetCrostiniPortForwardingSearchConcepts()); + } - if (IsContainerUpgradeAllowed()) + if (IsContainerUpgradeAllowed()) { updater.AddSearchTags(GetCrostiniContainerUpgradeSearchConcepts()); + } updater.AddSearchTags(GetCrostiniDiskResizingSearchConcepts());
diff --git a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc index 6577df1..5f00fcc3 100644 --- a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.cc
@@ -576,8 +576,7 @@ OnAutoconfQueried(callback_id, PrinterQueryResult::kUnknownFailure, ::printing::PrinterStatus(), /*make_and_model=*/"", /*document_formats=*/{}, /*ipp_everywhere=*/false, - chromeos::PrinterAuthenticationInfo{}, - /*client_info_supported=*/false); + chromeos::PrinterAuthenticationInfo{}); return; } @@ -594,8 +593,7 @@ const std::string& make_and_model, const std::vector<std::string>& /*document_formats*/, bool ipp_everywhere, - const chromeos::PrinterAuthenticationInfo& /*auth_info*/, - bool /*client_info_supported*/) { + const chromeos::PrinterAuthenticationInfo& /*auth_info*/) { RecordIppQueryResult(result); const bool success = result == PrinterQueryResult::kSuccess; @@ -636,8 +634,7 @@ const std::string& make_and_model, const std::vector<std::string>& document_formats, bool ipp_everywhere, - const chromeos::PrinterAuthenticationInfo& /*auth_info*/, - bool /*client_info_supported*/) { + const chromeos::PrinterAuthenticationInfo& /*auth_info*/) { RecordIppQueryResult(result); const bool success = result == PrinterQueryResult::kSuccess;
diff --git a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h index 2212c83..317ebf7 100644 --- a/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h +++ b/chrome/browser/ui/webui/settings/ash/cups_printers_handler.h
@@ -98,19 +98,16 @@ // was successful. |printer_status| contains the current status of the // printer. |make_and_model| is the unparsed printer-make-and-model string. // |ipp_everywhere| indicates if configuration using the CUPS IPP Everywhere - // driver should be attempted. |client_info_supported| indicates whether the - // printer supports all member attributes of the IPP 'client-info' attribute. - // If |result| is not SUCCESS, the values of |printer_status|, - // |make_and_model|, |document_formats|, |ipp_everywhere|, |auth_info|, and - // |client_info_supported| are not specified. + // driver should be attempted. If |result| is not SUCCESS, the values of + // |printer_status|, |make_and_model|, |document_formats|, |ipp_everywhere| + // and |auth_info| are not specified. void OnAutoconfQueried(const std::string& callback_id, printing::PrinterQueryResult result, const printing::PrinterStatus& printer_status, const std::string& make_and_model, const std::vector<std::string>& document_formats, bool ipp_everywhere, - const chromeos::PrinterAuthenticationInfo& auth_info, - bool client_info_supported); + const chromeos::PrinterAuthenticationInfo& auth_info); // Handles the callback for HandleGetPrinterInfo for a discovered printer. void OnAutoconfQueriedDiscovered( @@ -121,8 +118,7 @@ const std::string& make_and_model, const std::vector<std::string>& document_formats, bool ipp_everywhere, - const chromeos::PrinterAuthenticationInfo& auth_info, - bool client_info_supported); + const chromeos::PrinterAuthenticationInfo& auth_info); // Callback for PPD matching attempts; void OnPpdResolved(const std::string& callback_id,
diff --git a/chrome/browser/ui/webui/settings/safety_check_handler.cc b/chrome/browser/ui/webui/settings/safety_check_handler.cc index 3231767..823be2fc 100644 --- a/chrome/browser/ui/webui/settings/safety_check_handler.cc +++ b/chrome/browser/ui/webui/settings/safety_check_handler.cc
@@ -40,12 +40,6 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/strings/grit/ui_strings.h" -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -#include "base/win/registry.h" -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h" -#include "components/chrome_cleaner/public/constants/constants.h" -#endif - #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ui/chromeos/devicetype_utils.h" #endif @@ -59,10 +53,6 @@ constexpr char kSafeBrowsingEvent[] = "safety-check-safe-browsing-status-changed"; constexpr char kExtensionsEvent[] = "safety-check-extensions-status-changed"; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -constexpr char kChromeCleanerEvent[] = - "safety-check-chrome-cleaner-status-changed"; -#endif constexpr char kPerformSafetyCheck[] = "performSafetyCheck"; constexpr char kGetParentRanDisplayString[] = "getSafetyCheckRanDisplayString"; constexpr char kNewState[] = "newState"; @@ -101,72 +91,6 @@ } } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -SafetyCheckHandler::ChromeCleanerStatus ConvertToChromeCleanerStatus( - safe_browsing::ChromeCleanerController::State state, - safe_browsing::ChromeCleanerController::IdleReason idle_reason, - bool is_allowed_by_policy, - bool is_cct_timestamp_known) { - if (!is_allowed_by_policy) { - return SafetyCheckHandler::ChromeCleanerStatus::kDisabledByAdmin; - } - switch (state) { - case safe_browsing::ChromeCleanerController::State::kIdle: - switch (idle_reason) { - case safe_browsing::ChromeCleanerController::IdleReason::kInitial: - case safe_browsing::ChromeCleanerController::IdleReason:: - kReporterFoundNothing: - case safe_browsing::ChromeCleanerController::IdleReason:: - kScanningFoundNothing: - case safe_browsing::ChromeCleanerController::IdleReason:: - kCleaningSucceeded: - return is_cct_timestamp_known - ? SafetyCheckHandler::ChromeCleanerStatus:: - kNoUwsFoundWithTimestamp - : SafetyCheckHandler::ChromeCleanerStatus:: - kNoUwsFoundWithoutTimestamp; - case safe_browsing::ChromeCleanerController::IdleReason:: - kReporterFailed: - case safe_browsing::ChromeCleanerController::IdleReason:: - kScanningFailed: - case safe_browsing::ChromeCleanerController::IdleReason:: - kCleaningFailed: - case safe_browsing::ChromeCleanerController::IdleReason:: - kCleanerDownloadFailed: - return SafetyCheckHandler::ChromeCleanerStatus::kError; - case safe_browsing::ChromeCleanerController::IdleReason:: - kConnectionLost: - case safe_browsing::ChromeCleanerController::IdleReason:: - kUserDeclinedCleanup: - return SafetyCheckHandler::ChromeCleanerStatus::kInfected; - } - case safe_browsing::ChromeCleanerController::State::kReporterRunning: - case safe_browsing::ChromeCleanerController::State::kScanning: - return SafetyCheckHandler::ChromeCleanerStatus::kScanningForUws; - case safe_browsing::ChromeCleanerController::State::kCleaning: - return SafetyCheckHandler::ChromeCleanerStatus::kRemovingUws; - case safe_browsing::ChromeCleanerController::State::kInfected: - return SafetyCheckHandler::ChromeCleanerStatus::kInfected; - case safe_browsing::ChromeCleanerController::State::kRebootRequired: - return SafetyCheckHandler::ChromeCleanerStatus::kRebootRequired; - } -} - -SafetyCheckHandler::ChromeCleanerResult fetchChromeCleanerStatus( - std::unique_ptr<TimestampDelegate>& timestamp_delegate) { - SafetyCheckHandler::ChromeCleanerResult result; - result.cct_completion_time = - timestamp_delegate->FetchChromeCleanerScanCompletionTimestamp(); - result.status = ConvertToChromeCleanerStatus( - safe_browsing::ChromeCleanerController::GetInstance()->state(), - safe_browsing::ChromeCleanerController::GetInstance()->idle_reason(), - safe_browsing::ChromeCleanerController::GetInstance() - ->IsAllowedByPolicy(), - !result.cct_completion_time.is_null()); - return result; -} -#endif - bool IsUnmutedCompromisedCredential( const extensions::api::passwords_private::PasswordUiEntry& entry) { DCHECK(entry.compromised_info); @@ -196,59 +120,9 @@ return base::Time::Now(); } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -base::Time TimestampDelegate::FetchChromeCleanerScanCompletionTimestamp() { - // TODO(crbug.com/1139806): The cleaner scan completion timestamp is not - // always written to the registry. As a workaround, it is also written to a - // pref. This ensures that the timestamp is preserved in case Chrome is still - // opened when the scan completes. Remove this workaround once the timestamp - // is written to the registry in all cases. - const base::Time end_time_from_prefs = - g_browser_process->local_state()->GetTime( - prefs::kChromeCleanerScanCompletionTime); - - // Read the scan completion timestamp from the registry, if it exists there. - base::win::RegKey reporter_key; - int64_t end_time = 0; - if (reporter_key.Open(HKEY_CURRENT_USER, - chrome_cleaner::kSoftwareRemovalToolRegistryKey, - KEY_QUERY_VALUE | KEY_SET_VALUE) != ERROR_SUCCESS || - reporter_key.ReadInt64(chrome_cleaner::kEndTimeValueName, &end_time) != - ERROR_SUCCESS) { - // TODO(crbug.com/1139806): Part of the above workaround. If the registry - // does not contain the timestamp but the pref does, then return the one - // from the pref. - if (!end_time_from_prefs.is_null()) { - return end_time_from_prefs; - } - // Reading failed. Return 'null' time. - return base::Time(); - } - - // TODO(crbug.com/1139806): Part of the above workaround. If the timestamp in - // prefs is null or older than the one from the registry, then return the one - // from the registry. Otherwise return the one from prefs. - base::Time end_time_from_registry = - base::Time::FromDeltaSinceWindowsEpoch(base::Microseconds(end_time)); - if (end_time_from_prefs.is_null() || - end_time_from_prefs < end_time_from_registry) { - return end_time_from_registry; - } else { - return end_time_from_prefs; - } -} -#endif - SafetyCheckHandler::SafetyCheckHandler() = default; -SafetyCheckHandler::~SafetyCheckHandler() { -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // It seems |OnJavascriptDisallowed| is not always called before the - // deconstructor. Remove the CCT observer (no-op if not registered) - // also here to ensure it does not stay registered. - safe_browsing::ChromeCleanerController::GetInstance()->RemoveObserver(this); -#endif -} +SafetyCheckHandler::~SafetyCheckHandler() = default; void SafetyCheckHandler::SendSafetyCheckStartedWebUiUpdates() { AllowJavascript(); @@ -266,16 +140,6 @@ passwords_status_ = PasswordsStatus::kChecking; safe_browsing_status_ = SafeBrowsingStatus::kChecking; extensions_status_ = ExtensionsStatus::kChecking; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // If the Chrome cleaner status results in the child being hidden, - // then also hide it already in the "running" state. - if (fetchChromeCleanerStatus(timestamp_delegate_).status == - SafetyCheckHandler::ChromeCleanerStatus::kHidden) { - chrome_cleaner_status_ = SafetyCheckHandler::ChromeCleanerStatus::kHidden; - } else { - chrome_cleaner_status_ = SafetyCheckHandler::ChromeCleanerStatus::kChecking; - } -#endif // Update WebUi. FireBasicSafetyCheckWebUiListener(kUpdatesEvent, @@ -292,13 +156,6 @@ kExtensionsEvent, static_cast<int>(extensions_status_), GetStringForExtensions(extensions_status_, Blocklisted(0), ReenabledUser(0), ReenabledAdmin(0))); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Construct string without timestamp, using "null time" via |base::Time()|. - FireBasicSafetyCheckWebUiListener( - kChromeCleanerEvent, static_cast<int>(chrome_cleaner_status_), - GetStringForChromeCleaner(chrome_cleaner_status_, base::Time(), - base::Time())); -#endif // Parent update is last as it reveals the children elements. FireBasicSafetyCheckWebUiListener(kParentEvent, static_cast<int>(parent_status_), @@ -361,10 +218,6 @@ } DCHECK(extension_service_); CheckExtensions(); - -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - CheckChromeCleaner(); -#endif } SafetyCheckHandler::SafetyCheckHandler( @@ -401,21 +254,6 @@ const base::Value::List& args) { const base::Value& callback_id = args[0]; - // Send updated timestamp-based display strings to all SC children who have - // such strings. -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // String update for Chrome Cleaner. - base::Value::Dict event; - event.Set(kNewState, static_cast<int>(chrome_cleaner_status_)); - event.Set( - kDisplayString, - GetStringForChromeCleaner( - chrome_cleaner_status_, - timestamp_delegate_->FetchChromeCleanerScanCompletionTimestamp(), - timestamp_delegate_->GetSystemTime())); - FireWebUIListener(kChromeCleanerEvent, event); -#endif - // String update for the parent. ResolveJavascriptCallback( callback_id, @@ -494,27 +332,6 @@ } } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -void SafetyCheckHandler::CheckChromeCleaner() { - if (safe_browsing::ChromeCleanerController::GetInstance()->HasObserver( - this)) { - // Observer already registered. Just fetch the current CCT status. - OnChromeCleanerCheckResult(fetchChromeCleanerStatus(timestamp_delegate_)); - } else { - // Registering the observer immediately triggers a callback with the - // current state. - safe_browsing::ChromeCleanerController::GetInstance()->AddObserver(this); - } - // Log the current status into metrics. - if (chrome_cleaner_status_ != ChromeCleanerStatus::kHidden && - chrome_cleaner_status_ != ChromeCleanerStatus::kChecking) { - base::UmaHistogramEnumeration("Settings.SafetyCheck.ChromeCleanerResult", - chrome_cleaner_status_); - } - CompleteParentIfChildrenCompleted(); -} -#endif - void SafetyCheckHandler::OnUpdateCheckResult(UpdateStatus status) { update_status_ = status; if (update_status_ != UpdateStatus::kChecking) { @@ -569,19 +386,6 @@ CompleteParentIfChildrenCompleted(); } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -void SafetyCheckHandler::OnChromeCleanerCheckResult( - SafetyCheckHandler::ChromeCleanerResult result) { - base::Value::Dict event; - event.Set(kNewState, static_cast<int>(result.status)); - event.Set(kDisplayString, - GetStringForChromeCleaner(result.status, result.cct_completion_time, - timestamp_delegate_->GetSystemTime())); - FireWebUIListener(kChromeCleanerEvent, event); - chrome_cleaner_status_ = result.status; -} -#endif - std::u16string SafetyCheckHandler::GetStringForParent(ParentStatus status) { switch (status) { case ParentStatus::kBefore: @@ -753,44 +557,6 @@ } } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -std::u16string SafetyCheckHandler::GetStringForChromeCleaner( - ChromeCleanerStatus status, - base::Time cct_completion_time, - base::Time system_time) { - switch (status) { - case ChromeCleanerStatus::kHidden: - case ChromeCleanerStatus::kChecking: - return u""; - case ChromeCleanerStatus::kInfected: - return l10n_util::GetStringUTF16( - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_INFECTED); - case ChromeCleanerStatus::kRebootRequired: - return l10n_util::GetStringUTF16( - IDS_SETTINGS_RESET_CLEANUP_TITLE_RESTART); - case ChromeCleanerStatus::kScanningForUws: - return l10n_util::GetStringUTF16( - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_SCANNING); - case ChromeCleanerStatus::kRemovingUws: - return l10n_util::GetStringUTF16( - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_REMOVING); - case ChromeCleanerStatus::kDisabledByAdmin: - return l10n_util::GetStringFUTF16( - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_DISABLED_BY_ADMIN, - base::ASCIIToUTF16(chrome::kWhoIsMyAdministratorHelpURL)); - case ChromeCleanerStatus::kError: - return l10n_util::GetStringUTF16( - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_ERROR); - case ChromeCleanerStatus::kNoUwsFoundWithTimestamp: - return SafetyCheckHandler::GetStringForChromeCleanerRan( - cct_completion_time, system_time); - case ChromeCleanerStatus::kNoUwsFoundWithoutTimestamp: - return l10n_util::GetStringUTF16( - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITHOUT_TIMESTAMP); - } -} -#endif - std::u16string SafetyCheckHandler::GetStringForTimePassed( base::Time completion_timestamp, base::Time system_time, @@ -860,24 +626,6 @@ base::Time::Now()); } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -std::u16string SafetyCheckHandler::GetStringForChromeCleanerRan( - base::Time cct_completion_time, - base::Time system_time) { - if (cct_completion_time.is_null()) { - return l10n_util::GetStringUTF16( - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITHOUT_TIMESTAMP); - } - return SafetyCheckHandler::GetStringForTimePassed( - cct_completion_time, system_time, - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_SECONDS, - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_MINUTES, - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_HOURS, - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_YESTERDAY, - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_NO_UWS_WITH_TIMESTAMP_AFTER_DAYS); -} -#endif - void SafetyCheckHandler::DetermineIfOfflineOrError(bool connected) { OnUpdateCheckResult(connected ? UpdateStatus::kFailed : UpdateStatus::kFailedOffline); @@ -1015,41 +763,6 @@ observed_insecure_credentials_manager_.Reset(); } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -void SafetyCheckHandler::OnIdle( - safe_browsing::ChromeCleanerController::IdleReason idle_reason) { - OnChromeCleanerCheckResult(fetchChromeCleanerStatus(timestamp_delegate_)); -} - -void SafetyCheckHandler::OnReporterRunning() { - OnChromeCleanerCheckResult(fetchChromeCleanerStatus(timestamp_delegate_)); -} - -void SafetyCheckHandler::OnScanning() { - OnChromeCleanerCheckResult(fetchChromeCleanerStatus(timestamp_delegate_)); -} - -void SafetyCheckHandler::OnInfected( - bool is_powered_by_partner, - const safe_browsing::ChromeCleanerScannerResults& scanner_results) { - OnChromeCleanerCheckResult(fetchChromeCleanerStatus(timestamp_delegate_)); -} - -void SafetyCheckHandler::OnCleaning( - bool is_powered_by_partner, - const safe_browsing::ChromeCleanerScannerResults& scanner_results) { - OnChromeCleanerCheckResult(fetchChromeCleanerStatus(timestamp_delegate_)); -} - -void SafetyCheckHandler::OnRebootRequired() { - OnChromeCleanerCheckResult(fetchChromeCleanerStatus(timestamp_delegate_)); -} - -void SafetyCheckHandler::OnRebootFailed() { - OnChromeCleanerCheckResult(fetchChromeCleanerStatus(timestamp_delegate_)); -} -#endif - void SafetyCheckHandler::OnJavascriptAllowed() {} void SafetyCheckHandler::OnJavascriptDisallowed() { @@ -1069,10 +782,6 @@ // Destroy the version updater to prevent getting a callback and firing a // WebUI event, which would cause a crash. version_updater_.reset(); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Remove |this| as an observer for the Chrome cleaner. - safe_browsing::ChromeCleanerController::GetInstance()->RemoveObserver(this); -#endif } void SafetyCheckHandler::RegisterMessages() { @@ -1095,11 +804,6 @@ extensions_status_ == ExtensionsStatus::kChecking) { return; } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - if (chrome_cleaner_status_ == ChromeCleanerStatus::kChecking) { - return; - } -#endif // All children checks completed. parent_status_ = ParentStatus::kAfter;
diff --git a/chrome/browser/ui/webui/settings/safety_check_handler.h b/chrome/browser/ui/webui/settings/safety_check_handler.h index 152906cf..ba30a9d11 100644 --- a/chrome/browser/ui/webui/settings/safety_check_handler.h +++ b/chrome/browser/ui/webui/settings/safety_check_handler.h
@@ -29,19 +29,11 @@ #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h" -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_scanner_results_win.h" -#endif - // Delegate for accessing external timestamps, overridden for tests. class TimestampDelegate { public: virtual ~TimestampDelegate() = default; virtual base::Time GetSystemTime(); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - virtual base::Time FetchChromeCleanerScanCompletionTimestamp(); -#endif }; // Settings page UI handler that checks four areas of browser safety: @@ -49,9 +41,6 @@ // software. class SafetyCheckHandler : public settings::SettingsPageUIHandler, -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - public safe_browsing::ChromeCleanerController::Observer, -#endif public password_manager::BulkLeakCheckServiceInterface::Observer, public password_manager::InsecureCredentialsManager::Observer { public: @@ -134,28 +123,6 @@ std::u16string GetStringForParentRan(base::Time safety_check_completion_time, base::Time system_time); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Constructs the string for the Chrome cleaner 'safe' state which depicts - // how long ago its last check ran. - std::u16string GetStringForChromeCleanerRan(); - std::u16string GetStringForChromeCleanerRan(base::Time cct_completion_time, - base::Time system_time); - - // safe_browsing::ChromeCleanerController::Observer overrides. - void OnIdle( - safe_browsing::ChromeCleanerController::IdleReason idle_reason) override; - void OnReporterRunning() override; - void OnScanning() override; - void OnInfected(bool is_powered_by_partner, - const safe_browsing::ChromeCleanerScannerResults& - scanner_results) override; - void OnCleaning(bool is_powered_by_partner, - const safe_browsing::ChromeCleanerScannerResults& - scanner_results) override; - void OnRebootRequired() override; - void OnRebootFailed() override; -#endif - protected: SafetyCheckHandler( std::unique_ptr<safety_check::UpdateCheckHelper> update_helper, @@ -207,11 +174,6 @@ // that case, if any of those were re-enabled. void CheckExtensions(); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Checks for unwanted software via the Chrome Cleanup Tool. Only on Windows. - void CheckChromeCleaner(); -#endif - // Callbacks that get triggered when each check completes. void OnUpdateCheckResult(UpdateStatus status); void OnPasswordsCheckResult(PasswordsStatus status, @@ -223,9 +185,6 @@ Blocklisted blocklisted, ReenabledUser reenabled_user, ReenabledAdmin reenabled_admin); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - void OnChromeCleanerCheckResult(ChromeCleanerResult result); -#endif // Methods for building user-visible strings based on the safety check // state. @@ -241,11 +200,6 @@ Blocklisted blocklisted, ReenabledUser reenabled_user, ReenabledAdmin reenabled_admin); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - std::u16string GetStringForChromeCleaner(ChromeCleanerStatus status, - base::Time cct_completion_time, - base::Time system_time); -#endif // A generic error state often includes the offline state. This method is used // as a callback for |UpdateCheckHelper| to check connectivity.
diff --git a/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc b/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc index e92aec8..47de06f 100644 --- a/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc
@@ -53,10 +53,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h" -#endif - #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ui/chromeos/devicetype_utils.h" #endif @@ -71,9 +67,6 @@ constexpr char kPasswords[] = "passwords"; constexpr char kSafeBrowsing[] = "safe-browsing"; constexpr char kExtensions[] = "extensions"; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -constexpr char kChromeCleaner[] = "chrome-cleaner"; -#endif namespace { using Enabled = base::StrongAlias<class EnabledTag, bool>; @@ -136,13 +129,6 @@ return base::Time::FromDoubleT(1609459199).LocalMidnight() - base::Seconds(1); } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - base::Time FetchChromeCleanerScanCompletionTimestamp() override { - // 2 seconds before midnight Dec 31st 2020. - return base::Time::FromDoubleT(1609459199).LocalMidnight() - - base::Seconds(2); - } -#endif }; bool TestDestructionVersionUpdater::destructor_invoked_ = false; @@ -304,14 +290,6 @@ std::unordered_map<std::string, ExtensionState> state_map_; }; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -class TestChromeCleanerControllerDelegate - : public safe_browsing::ChromeCleanerControllerDelegate { - public: - bool IsAllowedByPolicy() override { return false; } -}; -#endif - } // namespace class SafetyCheckHandlerTest : public testing::Test { @@ -352,9 +330,6 @@ std::unique_ptr<TestingSafetyCheckHandler> safety_check_; base::HistogramTester histogram_tester_; base::test::ScopedFeatureList feature_list_; -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - TestChromeCleanerControllerDelegate test_chrome_cleaner_controller_delegate_; -#endif }; void SafetyCheckHandlerTest::SetUp() { @@ -1425,270 +1400,6 @@ SafetyCheckHandler::ExtensionsStatus::kBlocklistedReenabledSomeByUser, 1); } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -class SafetyCheckHandlerChromeCleanerIdleTest - : public SafetyCheckHandlerTest, - public testing::WithParamInterface< - std::tuple<safe_browsing::ChromeCleanerController::IdleReason, - SafetyCheckHandler::ChromeCleanerStatus, - std::u16string>> { - protected: - void SetUp() override { - SafetyCheckHandlerTest::SetUp(); - idle_reason_ = testing::get<0>(GetParam()); - expected_cct_status_ = testing::get<1>(GetParam()); - expected_display_string_ = testing::get<2>(GetParam()); - } - - safe_browsing::ChromeCleanerController::IdleReason idle_reason_; - SafetyCheckHandler::ChromeCleanerStatus expected_cct_status_; - std::u16string expected_display_string_; -}; - -TEST_P(SafetyCheckHandlerChromeCleanerIdleTest, CheckChromeCleanerIdleStates) { - safe_browsing::ChromeCleanerControllerImpl::ResetInstanceForTesting(); - safe_browsing::ChromeCleanerControllerImpl::GetInstance()->SetIdleForTesting( - idle_reason_); - safety_check_->PerformSafetyCheck(); - // Ensure WebUI event is sent. - const base::Value::Dict* event = GetSafetyCheckStatusChangedWithDataIfExists( - kChromeCleaner, static_cast<int>(expected_cct_status_)); - ASSERT_TRUE(event); - VerifyDisplayString(event, expected_display_string_); - // Ensure UMA is logged. - if (expected_cct_status_ == - SafetyCheckHandler::ChromeCleanerStatus::kHidden || - expected_cct_status_ == - SafetyCheckHandler::ChromeCleanerStatus::kChecking) { - // Hidden and checking state should not get recorded. - histogram_tester_.ExpectTotalCount( - "Settings.SafetyCheck.ChromeCleanerResult", 0); - } else { - histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.ChromeCleanerResult", expected_cct_status_, 1); - } -} - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_Initial, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::IdleReason::kInitial, - SafetyCheckHandler::ChromeCleanerStatus::kNoUwsFoundWithTimestamp, - u"Browser didn't find harmful software on your computer • Checked just " - u"now"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_ReporterFoundNothing, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::IdleReason:: - kReporterFoundNothing, - SafetyCheckHandler::ChromeCleanerStatus::kNoUwsFoundWithTimestamp, - u"Browser didn't find harmful software on your computer • Checked just " - u"now"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_ReporterFailed, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::IdleReason::kReporterFailed, - SafetyCheckHandler::ChromeCleanerStatus::kError, - u"Something went wrong. Click for more details."))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_ScanningFoundNothing, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::IdleReason:: - kScanningFoundNothing, - SafetyCheckHandler::ChromeCleanerStatus::kNoUwsFoundWithTimestamp, - u"Browser didn't find harmful software on your computer • Checked just " - u"now"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_ScanningFailed, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::IdleReason::kScanningFailed, - SafetyCheckHandler::ChromeCleanerStatus::kError, - u"Something went wrong. Click for more details."))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_ConnectionLost, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::IdleReason::kConnectionLost, - SafetyCheckHandler::ChromeCleanerStatus::kInfected, - u"Browser found harmful software on your computer"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_UserDeclinedCleanup, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values( - std::make_tuple(safe_browsing::ChromeCleanerController::IdleReason:: - kUserDeclinedCleanup, - SafetyCheckHandler::ChromeCleanerStatus::kInfected, - u"Browser found harmful software on your computer"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_CleaningFailed, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::IdleReason::kCleaningFailed, - SafetyCheckHandler::ChromeCleanerStatus::kError, - u"Something went wrong. Click for more details."))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_CleaningSucceed, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::IdleReason::kCleaningSucceeded, - SafetyCheckHandler::ChromeCleanerStatus::kNoUwsFoundWithTimestamp, - u"Browser didn't find harmful software on your computer • Checked just " - u"now"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_CleanerDownloadFailed, - SafetyCheckHandlerChromeCleanerIdleTest, - ::testing::Values( - std::make_tuple(safe_browsing::ChromeCleanerController::IdleReason:: - kCleanerDownloadFailed, - SafetyCheckHandler::ChromeCleanerStatus::kError, - u"Something went wrong. Click for more details."))); - -class SafetyCheckHandlerChromeCleanerNonIdleTest - : public SafetyCheckHandlerTest, - public testing::WithParamInterface< - std::tuple<safe_browsing::ChromeCleanerController::State, - SafetyCheckHandler::ChromeCleanerStatus, - std::u16string>> { - protected: - void SetUp() override { - SafetyCheckHandlerTest::SetUp(); - state_ = testing::get<0>(GetParam()); - expected_cct_status_ = testing::get<1>(GetParam()); - expected_display_string_ = testing::get<2>(GetParam()); - } - - safe_browsing::ChromeCleanerController::State state_; - SafetyCheckHandler::ChromeCleanerStatus expected_cct_status_; - std::u16string expected_display_string_; -}; - -TEST_P(SafetyCheckHandlerChromeCleanerNonIdleTest, - CheckChromeCleanerNonIdleStates) { - safe_browsing::ChromeCleanerControllerImpl::ResetInstanceForTesting(); - safe_browsing::ChromeCleanerControllerImpl::GetInstance()->SetStateForTesting( - state_); - safety_check_->PerformSafetyCheck(); - const base::Value::Dict* event = GetSafetyCheckStatusChangedWithDataIfExists( - kChromeCleaner, static_cast<int>(expected_cct_status_)); - ASSERT_TRUE(event); - VerifyDisplayString(event, expected_display_string_); - // Ensure UMA is logged. - if (expected_cct_status_ == - SafetyCheckHandler::ChromeCleanerStatus::kHidden || - expected_cct_status_ == - SafetyCheckHandler::ChromeCleanerStatus::kChecking) { - // Hidden and checking state should not get recorded. - histogram_tester_.ExpectTotalCount( - "Settings.SafetyCheck.ChromeCleanerResult", 0); - } else { - histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.ChromeCleanerResult", expected_cct_status_, 1); - } -} - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_ReporterRunning, - SafetyCheckHandlerChromeCleanerNonIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::State::kReporterRunning, - SafetyCheckHandler::ChromeCleanerStatus::kScanningForUws, - u"Browser is checking your computer for harmful software…"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_Scanning, - SafetyCheckHandlerChromeCleanerNonIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::State::kScanning, - SafetyCheckHandler::ChromeCleanerStatus::kScanningForUws, - u"Browser is checking your computer for harmful software…"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_Cleaning, - SafetyCheckHandlerChromeCleanerNonIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::State::kCleaning, - SafetyCheckHandler::ChromeCleanerStatus::kRemovingUws, - u"Browser is removing harmful software from your computer…"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_Infected, - SafetyCheckHandlerChromeCleanerNonIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::State::kInfected, - SafetyCheckHandler::ChromeCleanerStatus::kInfected, - u"Browser found harmful software on your computer"))); - -INSTANTIATE_TEST_SUITE_P( - CheckChromeCleaner_RebootRequired, - SafetyCheckHandlerChromeCleanerNonIdleTest, - ::testing::Values(std::make_tuple( - safe_browsing::ChromeCleanerController::State::kRebootRequired, - SafetyCheckHandler::ChromeCleanerStatus::kRebootRequired, - u"To finish removing harmful software, restart your computer"))); - -TEST_F(SafetyCheckHandlerTest, CheckChromeCleaner_DisabledByAdmin) { - safe_browsing::ChromeCleanerControllerImpl::ResetInstanceForTesting(); - safe_browsing::ChromeCleanerControllerImpl::GetInstance() - ->SetDelegateForTesting(&test_chrome_cleaner_controller_delegate_); - - safety_check_->PerformSafetyCheck(); - const base::Value::Dict* event = GetSafetyCheckStatusChangedWithDataIfExists( - kChromeCleaner, - static_cast<int>( - SafetyCheckHandler::ChromeCleanerStatus::kDisabledByAdmin)); - ASSERT_TRUE(event); - VerifyDisplayString( - event, - "<a target=\"_blank\" " - "href=\"https://support.google.com/chrome?p=your_administrator\">Your " - "administrator</a> has turned off checking for harmful software"); -} - -TEST_F(SafetyCheckHandlerTest, CheckChromeCleaner_ObserverUpdateLogging) { - safe_browsing::ChromeCleanerControllerImpl::ResetInstanceForTesting(); - safe_browsing::ChromeCleanerControllerImpl::GetInstance()->SetIdleForTesting( - safe_browsing::ChromeCleanerController::IdleReason:: - kReporterFoundNothing); - // We expect a user triggering a safety check to log the Chrome cleaner - // result. - safety_check_->PerformSafetyCheck(); - histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.ChromeCleanerResult", - SafetyCheckHandler::ChromeCleanerStatus::kNoUwsFoundWithTimestamp, 1); - // Subsequent Chrome cleaner status updates without the user running safety - // check again should not trigger logging. - safety_check_->OnIdle(safe_browsing::ChromeCleanerController::IdleReason:: - kReporterFoundNothing); - safety_check_->OnReporterRunning(); - safety_check_->OnScanning(); - safety_check_->OnRebootRequired(); - safety_check_->OnRebootFailed(); - histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.ChromeCleanerResult", - SafetyCheckHandler::ChromeCleanerStatus::kNoUwsFoundWithTimestamp, 1); - histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.ChromeCleanerResult", - SafetyCheckHandler::ChromeCleanerStatus::kRebootRequired, 0); - histogram_tester_.ExpectBucketCount( - "Settings.SafetyCheck.ChromeCleanerResult", - SafetyCheckHandler::ChromeCleanerStatus::kScanningForUws, 0); -} -#endif - TEST_F(SafetyCheckHandlerTest, CheckParentRanDisplayString) { // 1 second before midnight Dec 31st 2020, so that -(24h-1s) is still on the // same day. This test time is hard coded to prevent DST flakiness, see @@ -1721,51 +1432,6 @@ } } -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -TEST_F(SafetyCheckHandlerTest, CheckChromeCleanerRanDisplayString) { - // Test string without timestamp. - base::Time null_time; - std::u16string display_string = - safety_check_->GetStringForChromeCleanerRan(null_time, null_time); - ReplaceBrowserName(&display_string); - EXPECT_EQ(display_string, - u"Browser can check your computer for harmful software"); - // Test strings with timestamp. - // 1 second before midnight Dec 31st 2020, so that -(24h-1s) is still on the - // same day. This test time is hard coded to prevent DST flakiness, see - // crbug.com/1066576. - const base::Time system_time = - base::Time::FromDoubleT(1609459199).LocalMidnight() - base::Seconds(1); - // Display strings for given time deltas in seconds. - std::vector<std::tuple<std::u16string, int>> tuples{ - std::make_tuple(u"just now", 1), - std::make_tuple(u"just now", 59), - std::make_tuple(u"1 minute ago", 60), - std::make_tuple(u"2 minutes ago", 60 * 2), - std::make_tuple(u"59 minutes ago", 60 * 60 - 1), - std::make_tuple(u"1 hour ago", 60 * 60), - std::make_tuple(u"2 hours ago", 60 * 60 * 2), - std::make_tuple(u"23 hours ago", 60 * 60 * 23), - std::make_tuple(u"yesterday", 60 * 60 * 24), - std::make_tuple(u"yesterday", 60 * 60 * 24 * 2 - 1), - std::make_tuple(u"2 days ago", 60 * 60 * 24 * 2), - std::make_tuple(u"2 days ago", 60 * 60 * 24 * 3 - 1), - std::make_tuple(u"3 days ago", 60 * 60 * 24 * 3), - std::make_tuple(u"3 days ago", 60 * 60 * 24 * 4 - 1)}; - // Test that above time deltas produce the corresponding display strings. - for (auto tuple : tuples) { - const base::Time time = system_time - base::Seconds(std::get<1>(tuple)); - display_string = - safety_check_->GetStringForChromeCleanerRan(time, system_time); - ReplaceBrowserName(&display_string); - EXPECT_EQ(base::StrCat({u"Browser didn't find harmful software on your " - u"computer • Checked ", - std::get<0>(tuple)}), - display_string); - } -} -#endif - TEST_F(SafetyCheckHandlerTest, CheckSafetyCheckStartedWebUiEvents) { safety_check_->SendSafetyCheckStartedWebUiUpdates(); @@ -1810,13 +1476,6 @@ test_leak_service_->set_state_and_notify( password_manager::BulkLeakCheckService::State::kSignedOut); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Set the Chrome cleaner mock response. - safe_browsing::ChromeCleanerControllerImpl::ResetInstanceForTesting(); - safe_browsing::ChromeCleanerControllerImpl::GetInstance()->SetStateForTesting( - safe_browsing::ChromeCleanerController::State::kInfected); -#endif - // Check that the parent update is sent after all children checks completed. const base::Value::Dict* event_parent = GetSafetyCheckStatusChangedWithDataIfExists( @@ -1824,17 +1483,6 @@ ASSERT_TRUE(event_parent); VerifyDisplayString(event_parent, u"Safety check ran a moment ago"); -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - // Subsequent Chrome cleaner status updates without the user running safety - // check again should not trigger further parent element completion events. - safety_check_->OnIdle(safe_browsing::ChromeCleanerController::IdleReason:: - kReporterFoundNothing); - safety_check_->OnReporterRunning(); - safety_check_->OnScanning(); - safety_check_->OnRebootRequired(); - safety_check_->OnRebootFailed(); -#endif - // Check that there is no new parent completion event. const base::Value::Dict* event_parent2 = GetSafetyCheckStatusChangedWithDataIfExists(
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index bce457d..ea0b112 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -646,32 +646,24 @@ void AddResetStrings(content::WebUIDataSource* html_source, Profile* profile) { static constexpr webui::LocalizedString kLocalizedStrings[] = { -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - {"resetPageTitle", IDS_SETTINGS_RESET_AND_CLEANUP}, -#else - {"resetPageTitle", IDS_SETTINGS_RESET}, -#endif - {"resetTrigger", IDS_SETTINGS_RESET_SETTINGS_TRIGGER}, - {"resetPageExplanation", IDS_RESET_PROFILE_SETTINGS_EXPLANATION}, - {"resetPageExplanationBulletPoints", - IDS_RESET_PROFILE_SETTINGS_EXPLANATION_IN_BULLET_POINTS}, - {"triggeredResetPageExplanation", - IDS_TRIGGERED_RESET_PROFILE_SETTINGS_EXPLANATION}, - {"triggeredResetPageTitle", IDS_TRIGGERED_RESET_PROFILE_SETTINGS_TITLE}, - {"resetDialogTitle", IDS_SETTINGS_RESET_PROMPT_TITLE}, - {"resetDialogCommit", IDS_SETTINGS_RESET}, - {"resetPageFeedback", IDS_SETTINGS_RESET_PROFILE_FEEDBACK}, + {"resetPageTitle", IDS_SETTINGS_RESET}, + {"resetTrigger", IDS_SETTINGS_RESET_SETTINGS_TRIGGER}, + {"resetPageExplanation", IDS_RESET_PROFILE_SETTINGS_EXPLANATION}, + {"resetPageExplanationBulletPoints", + IDS_RESET_PROFILE_SETTINGS_EXPLANATION_IN_BULLET_POINTS}, + {"triggeredResetPageExplanation", + IDS_TRIGGERED_RESET_PROFILE_SETTINGS_EXPLANATION}, + {"triggeredResetPageTitle", IDS_TRIGGERED_RESET_PROFILE_SETTINGS_TITLE}, + {"resetDialogTitle", IDS_SETTINGS_RESET_PROMPT_TITLE}, + {"resetDialogCommit", IDS_SETTINGS_RESET}, + {"resetPageFeedback", IDS_SETTINGS_RESET_PROFILE_FEEDBACK}, - // Automatic reset banner (now a dialog). - {"resetAutomatedDialogTitle", IDS_SETTINGS_RESET_AUTOMATED_DIALOG_TITLE}, - {"resetProfileBannerButton", IDS_SETTINGS_RESET_BANNER_RESET_BUTTON_TEXT}, - {"resetProfileBannerDescription", IDS_SETTINGS_RESET_BANNER_TEXT}, - {"resetLearnMoreAccessibilityText", - IDS_SETTINGS_RESET_LEARN_MORE_ACCESSIBILITY_TEXT}, -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - {"resetCleanupComputerTrigger", - IDS_SETTINGS_RESET_CLEAN_UP_COMPUTER_TRIGGER}, -#endif + // Automatic reset banner (now a dialog). + {"resetAutomatedDialogTitle", IDS_SETTINGS_RESET_AUTOMATED_DIALOG_TITLE}, + {"resetProfileBannerButton", IDS_SETTINGS_RESET_BANNER_RESET_BUTTON_TEXT}, + {"resetProfileBannerDescription", IDS_SETTINGS_RESET_BANNER_TEXT}, + {"resetLearnMoreAccessibilityText", + IDS_SETTINGS_RESET_LEARN_MORE_ACCESSIBILITY_TEXT}, }; html_source->AddLocalizedStrings(kLocalizedStrings); @@ -1020,6 +1012,11 @@ {"addIbanTitle", IDS_SETTINGS_ADD_IBAN_TITLE}, {"editIbanTitle", IDS_SETTINGS_EDIT_IBAN_TITLE}, {"ibanNickname", IDS_IBAN_NICKNAME}, + {"moreActionsForIban", IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN}, + {"moreActionsForIbanDescription", + IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_IBAN_DESCRIPTION}, + {"editIban", IDS_SETTINGS_IBAN_EDIT}, + {"removeIban", IDS_SETTINGS_IBAN_REMOVE}, {"migrateCreditCardsLabel", IDS_SETTINGS_MIGRATABLE_CARDS_LABEL}, {"migratableCardsInfoSingle", IDS_SETTINGS_SINGLE_MIGRATABLE_CARD_INFO}, {"migratableCardsInfoMultiple", @@ -2246,96 +2243,92 @@ void AddSafetyCheckStrings(content::WebUIDataSource* html_source) { static constexpr webui::LocalizedString kLocalizedStrings[] = { - {"safetyCheckSectionTitle", IDS_SETTINGS_SAFETY_CHECK_SECTION_TITLE}, - {"safetyCheckParentPrimaryLabelBefore", - IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_BEFORE}, - {"safetyCheckRunning", IDS_SETTINGS_SAFETY_CHECK_RUNNING}, - {"safetyCheckParentPrimaryLabelAfter", - IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER}, - {"safetyCheckAriaLiveRunning", IDS_SETTINGS_SAFETY_CHECK_ARIA_LIVE_RUNNING}, - {"safetyCheckAriaLiveAfter", IDS_SETTINGS_SAFETY_CHECK_ARIA_LIVE_AFTER}, - {"safetyCheckParentButton", IDS_SETTINGS_SAFETY_CHECK_PARENT_BUTTON}, - {"safetyCheckParentButtonAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_PARENT_BUTTON_ARIA_LABEL}, - {"safetyCheckParentRunAgainButtonAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_PARENT_RUN_AGAIN_BUTTON_ARIA_LABEL}, - {"safetyCheckIconRunningAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_ICON_RUNNING_ARIA_LABEL}, - {"safetyCheckIconSafeAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_ICON_SAFE_ARIA_LABEL}, - {"safetyCheckIconInfoAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_ICON_INFO_ARIA_LABEL}, - {"safetyCheckIconWarningAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_ICON_WARNING_ARIA_LABEL}, - {"safetyCheckReview", IDS_SETTINGS_SAFETY_CHECK_REVIEW}, - {"safetyCheckUpdatesPrimaryLabel", - IDS_SETTINGS_SAFETY_CHECK_UPDATES_PRIMARY_LABEL}, - {"safetyCheckUpdatesButtonAriaLabel", IDS_UPDATE_RECOMMENDED_DIALOG_TITLE}, - {"safetyCheckPasswordsButtonAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_BUTTON_ARIA_LABEL}, - {"safetyCheckSafeBrowsingButton", - IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_BUTTON}, - {"safetyCheckSafeBrowsingButtonAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_BUTTON_ARIA_LABEL}, - {"safetyCheckExtensionsPrimaryLabel", - IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_PRIMARY_LABEL}, - {"safetyCheckExtensionsButtonAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BUTTON_ARIA_LABEL}, - {"safetyCheckNotificationPermissionReviewIgnoredToastLabel", - IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_IGNORED_TOAST_LABEL}, - {"safetyCheckNotificationPermissionReviewBlockedToastLabel", - IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_BLOCKED_TOAST_LABEL}, - {"safetyCheckNotificationPermissionReviewResetToastLabel", - IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_RESET_TOAST_LABEL}, - {"safetyCheckNotificationPermissionReviewDontAllowLabel", - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_DONT_ALLOW_LABEL}, - {"safetyCheckNotificationPermissionReviewDontAllowAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_DONT_ALLOW_ARIA_LABEL}, - {"safetyCheckNotificationPermissionReviewIgnoreLabel", - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_IGNORE_LABEL}, - {"safetyCheckNotificationPermissionReviewIgnoreAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_IGNORE_ARIA_LABEL}, - {"safetyCheckNotificationPermissionReviewResetLabel", - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_RESET_LABEL}, - {"safetyCheckNotificationPermissionReviewResetAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_RESET_ARIA_LABEL}, - {"safetyCheckNotificationPermissionReviewMoreActionsAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_MORE_ACTIONS_ARIA_LABEL}, - {"safetyCheckNotificationPermissionReviewUndo", - IDS_SETTINGS_SAFETY_CHECK_TOAST_UNDO_BUTTON_LABEL}, - {"safetyCheckNotificationPermissionReviewDoneLabel", - IDS_SETTINGS_SAFETY_CHECK_SITE_PERMISSIONS_REVIEW_DONE_LABEL}, - {"safetyCheckNotificationPermissionReviewBlockAllLabel", - IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_BLOCK_ALL_LABEL}, - {"safetyCheckUnusedSitePermissionsHeaderAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_HEADER_ARIA_LABEL}, - {"safetyCheckNotificationPermissionReviewButtonAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSIONS_REVIEW_BUTTON_ARIA_LABEL}, - {"safetyCheckUnusedSitePermissionsAllowAgainAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_ALLOW_AGAIN_ARIA_LABEL}, - {"safetyCheckUnusedSitePermissionsAllowAgainLabel", - IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_ALLOW_AGAIN_LABEL}, - {"safetyCheckUnusedSitePermissionsDoneLabel", - IDS_SETTINGS_SAFETY_CHECK_SITE_PERMISSIONS_REVIEW_DONE_LABEL}, - {"safetyCheckUnusedSitePermissionsGotItLabel", IDS_SETTINGS_GOT_IT}, - {"safetyCheckUnusedSitePermissionsRemovedOnePermissionLabel", - IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_REMOVED_ONE_PERMISSION_LABEL}, - {"safetyCheckUnusedSitePermissionsRemovedTwoPermissionsLabel", - IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_REMOVED_TWO_PERMISSIONS_LABEL}, - {"safetyCheckUnusedSitePermissionsRemovedThreePermissionsLabel", - IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_REMOVED_THREE_PERMISSIONS_LABEL}, - {"safetyCheckUnusedSitePermissionsRemovedFourOrMorePermissionsLabel", - IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_REMOVED_FOUR_OR_MORE_PERMISSIONS_LABEL}, - {"safetyCheckUnusedSitePermissionsToastLabel", - IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_TOAST_LABEL}, - {"safetyCheckUnusedSitePermissionsUndoLabel", - IDS_SETTINGS_SAFETY_CHECK_TOAST_UNDO_BUTTON_LABEL}, -#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) - {"safetyCheckChromeCleanerPrimaryLabel", - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_PRIMARY_LABEL}, - {"safetyCheckChromeCleanerButtonAriaLabel", - IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_BUTTON_ARIA_LABEL}, -#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) + {"safetyCheckSectionTitle", IDS_SETTINGS_SAFETY_CHECK_SECTION_TITLE}, + {"safetyCheckParentPrimaryLabelBefore", + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_BEFORE}, + {"safetyCheckRunning", IDS_SETTINGS_SAFETY_CHECK_RUNNING}, + {"safetyCheckParentPrimaryLabelAfter", + IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER}, + {"safetyCheckAriaLiveRunning", + IDS_SETTINGS_SAFETY_CHECK_ARIA_LIVE_RUNNING}, + {"safetyCheckAriaLiveAfter", IDS_SETTINGS_SAFETY_CHECK_ARIA_LIVE_AFTER}, + {"safetyCheckParentButton", IDS_SETTINGS_SAFETY_CHECK_PARENT_BUTTON}, + {"safetyCheckParentButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_PARENT_BUTTON_ARIA_LABEL}, + {"safetyCheckParentRunAgainButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_PARENT_RUN_AGAIN_BUTTON_ARIA_LABEL}, + {"safetyCheckIconRunningAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_ICON_RUNNING_ARIA_LABEL}, + {"safetyCheckIconSafeAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_ICON_SAFE_ARIA_LABEL}, + {"safetyCheckIconInfoAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_ICON_INFO_ARIA_LABEL}, + {"safetyCheckIconWarningAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_ICON_WARNING_ARIA_LABEL}, + {"safetyCheckReview", IDS_SETTINGS_SAFETY_CHECK_REVIEW}, + {"safetyCheckUpdatesPrimaryLabel", + IDS_SETTINGS_SAFETY_CHECK_UPDATES_PRIMARY_LABEL}, + {"safetyCheckUpdatesButtonAriaLabel", + IDS_UPDATE_RECOMMENDED_DIALOG_TITLE}, + {"safetyCheckPasswordsButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_BUTTON_ARIA_LABEL}, + {"safetyCheckSafeBrowsingButton", + IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_BUTTON}, + {"safetyCheckSafeBrowsingButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_BUTTON_ARIA_LABEL}, + {"safetyCheckExtensionsPrimaryLabel", + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_PRIMARY_LABEL}, + {"safetyCheckExtensionsButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BUTTON_ARIA_LABEL}, + {"safetyCheckNotificationPermissionReviewIgnoredToastLabel", + IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_IGNORED_TOAST_LABEL}, + {"safetyCheckNotificationPermissionReviewBlockedToastLabel", + IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_BLOCKED_TOAST_LABEL}, + {"safetyCheckNotificationPermissionReviewResetToastLabel", + IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_RESET_TOAST_LABEL}, + {"safetyCheckNotificationPermissionReviewDontAllowLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_DONT_ALLOW_LABEL}, + {"safetyCheckNotificationPermissionReviewDontAllowAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_DONT_ALLOW_ARIA_LABEL}, + {"safetyCheckNotificationPermissionReviewIgnoreLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_IGNORE_LABEL}, + {"safetyCheckNotificationPermissionReviewIgnoreAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_IGNORE_ARIA_LABEL}, + {"safetyCheckNotificationPermissionReviewResetLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_RESET_LABEL}, + {"safetyCheckNotificationPermissionReviewResetAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_RESET_ARIA_LABEL}, + {"safetyCheckNotificationPermissionReviewMoreActionsAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_MORE_ACTIONS_ARIA_LABEL}, + {"safetyCheckNotificationPermissionReviewUndo", + IDS_SETTINGS_SAFETY_CHECK_TOAST_UNDO_BUTTON_LABEL}, + {"safetyCheckNotificationPermissionReviewDoneLabel", + IDS_SETTINGS_SAFETY_CHECK_SITE_PERMISSIONS_REVIEW_DONE_LABEL}, + {"safetyCheckNotificationPermissionReviewBlockAllLabel", + IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_BLOCK_ALL_LABEL}, + {"safetyCheckUnusedSitePermissionsHeaderAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_HEADER_ARIA_LABEL}, + {"safetyCheckNotificationPermissionReviewButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSIONS_REVIEW_BUTTON_ARIA_LABEL}, + {"safetyCheckUnusedSitePermissionsAllowAgainAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_ALLOW_AGAIN_ARIA_LABEL}, + {"safetyCheckUnusedSitePermissionsAllowAgainLabel", + IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_ALLOW_AGAIN_LABEL}, + {"safetyCheckUnusedSitePermissionsDoneLabel", + IDS_SETTINGS_SAFETY_CHECK_SITE_PERMISSIONS_REVIEW_DONE_LABEL}, + {"safetyCheckUnusedSitePermissionsGotItLabel", IDS_SETTINGS_GOT_IT}, + {"safetyCheckUnusedSitePermissionsRemovedOnePermissionLabel", + IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_REMOVED_ONE_PERMISSION_LABEL}, + {"safetyCheckUnusedSitePermissionsRemovedTwoPermissionsLabel", + IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_REMOVED_TWO_PERMISSIONS_LABEL}, + {"safetyCheckUnusedSitePermissionsRemovedThreePermissionsLabel", + IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_REMOVED_THREE_PERMISSIONS_LABEL}, + {"safetyCheckUnusedSitePermissionsRemovedFourOrMorePermissionsLabel", + IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_REMOVED_FOUR_OR_MORE_PERMISSIONS_LABEL}, + {"safetyCheckUnusedSitePermissionsToastLabel", + IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_TOAST_LABEL}, + {"safetyCheckUnusedSitePermissionsUndoLabel", + IDS_SETTINGS_SAFETY_CHECK_TOAST_UNDO_BUTTON_LABEL}, }; html_source->AddLocalizedStrings(kLocalizedStrings); }
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom index 0ecb94b..39b3836 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome.mojom
@@ -110,7 +110,10 @@ // Triggers a call to |CustomizeChromePage.SetPageMostVisitedSettings|. UpdateMostVisitedSettings(); - // Returns the chrome colors used in the customize chrome side panel. + // Returns the chrome colors used in the customize chrome side panel overview. + GetOverviewChromeColors() => (array<ChromeColor> colors); + + // Returns the chrome colors used in the customize chrome side panel themes. GetChromeColors() => (array<ChromeColor> colors); // Returns the collections of background images.
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc index 2daa8c96..3c12159e 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.cc
@@ -8,6 +8,7 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_factory.h" +#include "chrome/browser/new_tab_page/chrome_colors/generated_colors_info.h" #include "chrome/browser/new_tab_page/chrome_colors/selected_colors_info.h" #include "chrome/browser/new_tab_page/modules/new_tab_page_modules.h" #include "chrome/browser/new_tab_page/new_tab_page_util.h" @@ -35,6 +36,19 @@ #include "ui/color/color_provider.h" #include "ui/native_theme/native_theme.h" +namespace { +side_panel::mojom::ChromeColorPtr CreateChromeColor( + chrome_colors::ColorInfo color_info) { + auto theme_colors = GetAutogeneratedThemeColors(color_info.color); + auto color = side_panel::mojom::ChromeColor::New(); + color->name = l10n_util::GetStringUTF8(color_info.label_id); + color->seed = color_info.color; + color->background = theme_colors.active_tab_color; + color->foreground = theme_colors.frame_color; + return color; +} +} // namespace + CustomizeChromePageHandler::CustomizeChromePageHandler( mojo::PendingReceiver<side_panel::mojom::CustomizeChromePageHandler> pending_page_handler, @@ -103,17 +117,20 @@ theme_service_->BuildAutogeneratedThemeFromColor(seed_color); } +void CustomizeChromePageHandler::GetOverviewChromeColors( + GetOverviewChromeColorsCallback callback) { + std::vector<side_panel::mojom::ChromeColorPtr> colors; + for (const auto& color_info : kCustomizeChromeColors) { + colors.push_back(CreateChromeColor(color_info)); + } + std::move(callback).Run(std::move(colors)); +} + void CustomizeChromePageHandler::GetChromeColors( GetChromeColorsCallback callback) { std::vector<side_panel::mojom::ChromeColorPtr> colors; - for (const auto& color_info : kCustomizeChromeColors) { - auto theme_colors = GetAutogeneratedThemeColors(color_info.color); - auto color = side_panel::mojom::ChromeColor::New(); - color->name = l10n_util::GetStringUTF8(color_info.label_id); - color->seed = color_info.color; - color->background = theme_colors.active_tab_color; - color->foreground = theme_colors.frame_color; - colors.push_back(std::move(color)); + for (const auto& color_info : chrome_colors::kGeneratedColorsInfo) { + colors.push_back(CreateChromeColor(color_info)); } std::move(callback).Run(std::move(colors)); }
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h index 559b779..53939522 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler.h
@@ -54,6 +54,8 @@ // side_panel::mojom::CustomizeChromePageHandler: void SetDefaultColor() override; void SetSeedColor(SkColor seed_color) override; + void GetOverviewChromeColors( + GetOverviewChromeColorsCallback callback) override; void GetChromeColors(GetChromeColorsCallback callback) override; void SetBackgroundImage(const std::string& attribution_1, const std::string& attribution_2,
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc index c9b93b0..9eb9f6b 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_page_handler_unittest.cc
@@ -16,6 +16,7 @@ #include "base/test/scoped_feature_list.h" #include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_factory.h" #include "chrome/browser/new_tab_page/chrome_colors/chrome_colors_service.h" +#include "chrome/browser/new_tab_page/chrome_colors/generated_colors_info.h" #include "chrome/browser/new_tab_page/chrome_colors/selected_colors_info.h" #include "chrome/browser/search/background/ntp_background_data.h" #include "chrome/browser/search/background/ntp_background_service_factory.h" @@ -349,6 +350,32 @@ histogram_tester().ExpectTotalCount("NewTabPage.CustomizeShortcutAction", 2); } +TEST_F(CustomizeChromePageHandlerTest, GetOverviewChromeColors) { + std::vector<side_panel::mojom::ChromeColorPtr> colors; + base::MockCallback<CustomizeChromePageHandler::GetChromeColorsCallback> + callback; + EXPECT_CALL(callback, Run(testing::_)) + .Times(1) + .WillOnce(testing::Invoke( + [&colors](std::vector<side_panel::mojom::ChromeColorPtr> colors_arg) { + colors = std::move(colors_arg); + })); + handler().GetOverviewChromeColors(callback.Get()); + + ASSERT_EQ(kCustomizeChromeColors.size(), colors.size()); + for (size_t i = 0; i < kCustomizeChromeColors.size(); i++) { + EXPECT_EQ(l10n_util::GetStringUTF8(kCustomizeChromeColors[i].label_id), + colors[i]->name); + EXPECT_EQ(kCustomizeChromeColors[i].color, colors[i]->seed); + EXPECT_EQ(GetAutogeneratedThemeColors(kCustomizeChromeColors[i].color) + .active_tab_color, + colors[i]->background); + EXPECT_EQ(GetAutogeneratedThemeColors(kCustomizeChromeColors[i].color) + .frame_color, + colors[i]->foreground); + } +} + TEST_F(CustomizeChromePageHandlerTest, GetChromeColors) { std::vector<side_panel::mojom::ChromeColorPtr> colors; base::MockCallback<CustomizeChromePageHandler::GetChromeColorsCallback> @@ -361,15 +388,20 @@ })); handler().GetChromeColors(callback.Get()); - ASSERT_EQ(kCustomizeChromeColors.size(), colors.size()); - for (size_t i = 0; i < kCustomizeChromeColors.size(); i++) { - EXPECT_EQ(l10n_util::GetStringUTF8(kCustomizeChromeColors[i].label_id), + auto num_colors = sizeof(chrome_colors::kGeneratedColorsInfo) / + sizeof(chrome_colors::kGeneratedColorsInfo[0]); + ASSERT_EQ(num_colors, colors.size()); + for (size_t i = 0; i < num_colors; i++) { + EXPECT_EQ(l10n_util::GetStringUTF8( + chrome_colors::kGeneratedColorsInfo[i].label_id), colors[i]->name); - EXPECT_EQ(kCustomizeChromeColors[i].color, colors[i]->seed); - EXPECT_EQ(GetAutogeneratedThemeColors(kCustomizeChromeColors[i].color) + EXPECT_EQ(chrome_colors::kGeneratedColorsInfo[i].color, colors[i]->seed); + EXPECT_EQ(GetAutogeneratedThemeColors( + chrome_colors::kGeneratedColorsInfo[i].color) .active_tab_color, colors[i]->background); - EXPECT_EQ(GetAutogeneratedThemeColors(kCustomizeChromeColors[i].color) + EXPECT_EQ(GetAutogeneratedThemeColors( + chrome_colors::kGeneratedColorsInfo[i].color) .frame_color, colors[i]->foreground); }
diff --git a/chrome/browser/ui/webui/side_panel/user_notes/user_notes.mojom b/chrome/browser/ui/webui/side_panel/user_notes/user_notes.mojom index 246e0b6..4ad6e66e 100644 --- a/chrome/browser/ui/webui/side_panel/user_notes/user_notes.mojom +++ b/chrome/browser/ui/webui/side_panel/user_notes/user_notes.mojom
@@ -87,4 +87,9 @@ // If the WebUI is in the background we can delay reloading until it is // foregrounded. NotesChanged(); + + // Called when the URL of the current tab has changed. + // This could be triggered by either switching tab or navigating to + // a new URL. + CurrentTabUrlChanged(); };
diff --git a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler.cc b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler.cc index 0234514..22a1c9d 100644 --- a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler.cc +++ b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler.cc
@@ -106,11 +106,7 @@ DCHECK(browser_); browser_->tab_strip_model()->AddObserver(this); Observe(browser_->tab_strip_model()->GetActiveWebContents()); - if (browser_->tab_strip_model()->GetActiveWebContents()) { - current_tab_url_ = browser_->tab_strip_model() - ->GetActiveWebContents() - ->GetLastCommittedURL(); - } + UpdateCurrentTabUrl(); } UserNotesPageHandler::~UserNotesPageHandler() { @@ -221,13 +217,18 @@ return; } Observe(selection.new_contents); - current_tab_url_ = selection.new_contents - ? selection.new_contents->GetLastCommittedURL() - : GURL(); + UpdateCurrentTabUrl(); } void UserNotesPageHandler::PrimaryPageChanged(content::Page& page) { - current_tab_url_ = browser_->tab_strip_model() - ->GetActiveWebContents() - ->GetLastCommittedURL(); + UpdateCurrentTabUrl(); +} + +void UserNotesPageHandler::UpdateCurrentTabUrl() { + content::WebContents* web_contents = + browser_->tab_strip_model()->GetActiveWebContents(); + if (web_contents && current_tab_url_ != web_contents->GetLastCommittedURL()) { + current_tab_url_ = web_contents->GetLastCommittedURL(); + page_->CurrentTabUrlChanged(); + } }
diff --git a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler.h b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler.h index d222ae26..0bd4b1e 100644 --- a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler.h +++ b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler.h
@@ -70,6 +70,8 @@ // WebContentsObserver: void PrimaryPageChanged(content::Page& page) override; + void UpdateCurrentTabUrl(); + mojo::Receiver<side_panel::mojom::UserNotesPageHandler> receiver_; mojo::Remote<side_panel::mojom::UserNotesPage> page_; const raw_ptr<Profile> profile_;
diff --git a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler_unittest.cc b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler_unittest.cc index 878b407..28ff01b4 100644 --- a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_page_handler_unittest.cc
@@ -43,6 +43,7 @@ mojo::Receiver<side_panel::mojom::UserNotesPage> receiver_{this}; MOCK_METHOD0(NotesChanged, void()); + MOCK_METHOD0(CurrentTabUrlChanged, void()); }; struct Note {
diff --git a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_side_panel_ui.cc b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_side_panel_ui.cc index 97f3795..0dddf0f 100644 --- a/chrome/browser/ui/webui/side_panel/user_notes/user_notes_side_panel_ui.cc +++ b/chrome/browser/ui/webui/side_panel/user_notes/user_notes_side_panel_ui.cc
@@ -17,6 +17,7 @@ #include "components/strings/grit/components_strings.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" +#include "ui/base/ui_base_features.h" UserNotesSidePanelUI::UserNotesSidePanelUI(content::WebUI* web_ui) : ui::MojoBubbleWebUIController(web_ui) { @@ -36,6 +37,10 @@ webui::AddLocalizedString(source, str.name, str.id); } + source->AddString( + "chromeRefresh2023Attribute", + features::IsChromeRefresh2023() ? "chrome-refresh-2023" : ""); + webui::SetupWebUIDataSource(source, base::make_span(kSidePanelUserNotesResources, kSidePanelUserNotesResourcesSize),
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.cc b/chrome/browser/ui/webui/signin/inline_login_handler.cc index 5824d59e..c18e86a 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler.cc
@@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "base/check_deref.h" #include "base/functional/bind.h" #include "base/metrics/user_metrics.h" #include "base/strings/string_number_conversions.h" @@ -182,27 +183,28 @@ const base::Value::List& args, const net::CookieAccessResultList& cookies, const net::CookieAccessResultList& excluded_cookies) { - const base::Value& dict = args[0]; + CHECK_EQ(args.size(), 1u); + const base::Value::Dict& dict = args[0].GetDict(); CompleteLoginParams params; - params.email = dict.FindKey("email")->GetString(); - params.password = dict.FindKey("password")->GetString(); - params.gaia_id = dict.FindKey("gaiaId")->GetString(); + params.email = CHECK_DEREF(dict.FindString("email")); + params.password = CHECK_DEREF(dict.FindString("password")); + params.gaia_id = CHECK_DEREF(dict.FindString("gaiaId")); for (const auto& cookie_with_access_result : cookies) { if (cookie_with_access_result.cookie.Name() == "oauth_code") params.auth_code = cookie_with_access_result.cookie.Value(); } - params.skip_for_now = dict.FindBoolKey("skipForNow").value_or(false); - absl::optional<bool> trusted = dict.FindBoolKey("trusted"); + params.skip_for_now = dict.FindBool("skipForNow").value_or(false); + absl::optional<bool> trusted = dict.FindBool("trusted"); params.trusted_value = trusted.value_or(false); params.trusted_found = trusted.has_value(); params.choose_what_to_sync = - dict.FindBoolKey("chooseWhatToSync").value_or(false); + dict.FindBool("chooseWhatToSync").value_or(false); params.is_available_in_arc = - dict.FindBoolKey("isAvailableInArc").value_or(false); + dict.FindBool("isAvailableInArc").value_or(false); CompleteLogin(params); }
diff --git a/chrome/browser/unexpire_flags.cc b/chrome/browser/unexpire_flags.cc index fa2641b..8e65848 100644 --- a/chrome/browser/unexpire_flags.cc +++ b/chrome/browser/unexpire_flags.cc
@@ -102,19 +102,14 @@ // This still has a problem: during browser startup, if the unexpire feature // will be configured by some other mechanism (group policy, etc), that // feature's value won't apply in time here and the bug described will happen. - // TODO(ellyjones): Figure out how to fix that. + // In fact, that is a design behavior of the feature system, since flag + // unexpiry happens during FeatureList initialization. + // TODO(ellyjones): what might we do about that? std::set<int> unexpired_milestones = UnexpiredMilestonesFromStorage(storage); if (base::Contains(unexpired_milestones, mstone)) { return false; } - // If there's an unexpiry feature, and the unexpiry feature is *disabled*, - // then the flag is expired. The double-negative is very unfortunate. - const base::Feature* expiry_feature = GetUnexpireFeatureForMilestone(mstone); - if (expiry_feature) { - return !base::FeatureList::IsEnabled(*expiry_feature); - } - // Otherwise, the flag is expired if its expiration mstone is less than the // mstone of this copy of Chromium. return mstone < CHROME_VERSION_MAJOR;
diff --git a/chrome/browser/user_education/BUILD.gn b/chrome/browser/user_education/BUILD.gn index d4aa0d4..cd946a0e 100644 --- a/chrome/browser/user_education/BUILD.gn +++ b/chrome/browser/user_education/BUILD.gn
@@ -30,28 +30,6 @@ resources_package = "org.chromium.chrome.browser.user_education" } -android_library("unit_device_javatests") { - testonly = true - sources = [ "java/src/org/chromium/chrome/browser/user_education/UserEducationHelperTest.java" ] - deps = [ - "//base:base_java", - "//base:base_java_test_support", - "//chrome/browser/feature_engagement:java", - "//chrome/browser/flags:java", - "//chrome/browser/profiles/android:java", - "//chrome/browser/user_education:java", - "//components/browser_ui/widget/android:java", - "//components/feature_engagement/public:public_java", - "//content/public/test/android:content_java_test_support", - "//third_party/android_deps:espresso_java", - "//third_party/androidx:androidx_test_runner_java", - "//third_party/hamcrest:hamcrest_library_java", - "//third_party/junit", - "//third_party/mockito:mockito_java", - "//ui/android:ui_java_test_support", - ] -} - android_resources("java_resources") { sources = [ "java/res/values/dimens.xml" ] }
diff --git a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommandBuilder.java b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommandBuilder.java index 36fbfb3..c5565cd 100644 --- a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommandBuilder.java +++ b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommandBuilder.java
@@ -233,10 +233,6 @@ * @return an (@see IPHCommand) containing the accumulated state of this builder. */ public IPHCommand build() { - if (!ChromeFeatureList.isEnabled(ChromeFeatureList.ENABLE_IPH)) { - return null; - } - if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS)) { return buildLazy(); }
diff --git a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java index 0fd35a7..961a2cb 100644 --- a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java +++ b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java
@@ -16,7 +16,6 @@ import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter; import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightParams; import org.chromium.components.browser_ui.widget.textbubble.TextBubble; -import org.chromium.components.feature_engagement.SnoozeAction; import org.chromium.components.feature_engagement.Tracker; import org.chromium.components.feature_engagement.TriggerDetails; import org.chromium.ui.widget.RectProvider; @@ -92,10 +91,8 @@ HighlightParams highlightParams = iphCommand.highlightParams; TextBubble textBubble = null; - TriggerDetails triggerDetails = ChromeFeatureList.isEnabled(ChromeFeatureList.SNOOZABLE_IPH) - ? tracker.shouldTriggerHelpUIWithSnooze(featureName) - : new TriggerDetails( - tracker.shouldTriggerHelpUI(featureName), /*shouldShowSnooze=*/false); + TriggerDetails triggerDetails = new TriggerDetails( + tracker.shouldTriggerHelpUI(featureName), /*shouldShowSnooze=*/false); assert (triggerDetails != null); if (!triggerDetails.shouldTriggerIph) { @@ -114,32 +111,10 @@ assert (!contentString.isEmpty()); assert (!accessibilityString.isEmpty()); - // Automatic snoozes are handled separately. If automatic snoozing is enabled, we won't show - // snooze UI in the IPH, but we will treat the dismiss as an implicit snooze action. - boolean shouldShowSnoozeButton = triggerDetails.shouldShowSnooze; - if (shouldShowSnoozeButton) { - // TODO(crbug.com/1243973): Implement explicit dismiss. - boolean showExplicitDismiss = false; - Runnable snoozeRunnable = showExplicitDismiss - ? null - : () -> tracker.dismissedWithSnooze(featureName, SnoozeAction.SNOOZED); - Runnable snoozeDismissRunnable = showExplicitDismiss ? () - -> tracker.dismissedWithSnooze(featureName, SnoozeAction.DISMISSED) - : null; - - textBubble = new TextBubble(mActivity, anchorView, contentString, accessibilityString, - iphCommand.removeArrow ? false : true, - viewRectProvider != null ? viewRectProvider : rectProvider, null, false, false, - ChromeAccessibilityUtil.get().isAccessibilityEnabled(), snoozeRunnable, - snoozeDismissRunnable); - - } else { - textBubble = new TextBubble(mActivity, anchorView, contentString, accessibilityString, - iphCommand.removeArrow ? false : true, - viewRectProvider != null ? viewRectProvider : rectProvider, - ChromeAccessibilityUtil.get().isAccessibilityEnabled()); - } - + textBubble = new TextBubble(mActivity, anchorView, contentString, accessibilityString, + iphCommand.removeArrow ? false : true, + viewRectProvider != null ? viewRectProvider : rectProvider, + ChromeAccessibilityUtil.get().isAccessibilityEnabled()); textBubble.setPreferredVerticalOrientation(iphCommand.preferredVerticalOrientation); textBubble.setDismissOnTouchInteraction(iphCommand.dismissOnTouch); textBubble.addOnDismissListener(() -> mHandler.postDelayed(() -> {
diff --git a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelperTest.java b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelperTest.java deleted file mode 100644 index 6332a1a..0000000 --- a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelperTest.java +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.user_education; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.matcher.RootMatchers.withDecorView; -import static androidx.test.espresso.matcher.ViewMatchers.withId; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.Activity; -import android.os.Handler; -import android.view.View; -import android.widget.Button; -import android.widget.FrameLayout; - -import androidx.test.espresso.action.ViewActions; -import androidx.test.filters.MediumTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.Callback; -import org.chromium.base.FeatureList; -import org.chromium.base.FeatureList.TestValues; -import org.chromium.base.test.BaseActivityTestRule; -import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.components.browser_ui.widget.R; -import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightParams; -import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightShape; -import org.chromium.components.feature_engagement.FeatureConstants; -import org.chromium.components.feature_engagement.SnoozeAction; -import org.chromium.components.feature_engagement.Tracker; -import org.chromium.components.feature_engagement.TriggerDetails; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.test.util.BlankUiTestActivity; - -/** Integration tests for UserEducationHelper. */ -@RunWith(BaseJUnit4ClassRunner.class) -public final class UserEducationHelperTest { - @ClassRule - public static BaseActivityTestRule<BlankUiTestActivity> activityTestRule = - new BaseActivityTestRule<>(BlankUiTestActivity.class); - - @Mock - private Tracker mTracker; - - @Mock - private Profile mProfile; - - private static Activity sActivity; - private FrameLayout mContentView; - private TestValues mTestValues = new TestValues(); - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - // Pretend the feature engagement feature is already initialized. Otherwise - // UserEducationHelper#requestShowIPH() calls get dropped during test. - doAnswer(invocation -> { - invocation.<Callback<Boolean>>getArgument(0).onResult(true); - return null; - }) - .when(mTracker) - .addOnInitializedCallback(any()); - TrackerFactory.setTrackerForTests(mTracker); - - // When snoozing is enabled, do not show any unwanted IPH bubbles. - when(mTracker.shouldTriggerHelpUIWithSnooze(any())) - .thenReturn(new TriggerDetails(false, false)); - - activityTestRule.launchActivity(null); - Profile.setLastUsedProfileForTesting(mProfile); - TestThreadUtils.runOnUiThreadBlocking(() -> { - sActivity = activityTestRule.getActivity(); - mContentView = new FrameLayout(sActivity); - ; - sActivity.setContentView(mContentView); - Button button = new Button(sActivity); - button.setLayoutParams(new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT)); - button.setText("Dummy"); - button.setTag("Dummy"); - mContentView.addView(button); - }); - } - - @After - public void tearDown() { - TrackerFactory.setTrackerForTests(null); - FeatureList.setTestValues(null); - } - - @Test - @MediumTest - public void testShowIPHWithSnooze() throws Throwable { - mTestValues.addFeatureFlagOverride(ChromeFeatureList.SNOOZABLE_IPH, true); - mTestValues.addFeatureFlagOverride(ChromeFeatureList.ENABLE_IPH, true); - mTestValues.addFeatureFlagOverride(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); - FeatureList.setTestValues(mTestValues); - TestThreadUtils.runOnUiThreadBlocking(() -> { - when(mTracker.shouldTriggerHelpUIWithSnooze(FeatureConstants.DOWNLOAD_HOME_FEATURE)) - .thenReturn(new TriggerDetails(true, true)); - UserEducationHelper userEducationHelper = - new UserEducationHelper(sActivity, new Handler()); - View homeButton = mContentView.findViewWithTag("Dummy"); - userEducationHelper.requestShowIPH( - new IPHCommandBuilder(sActivity.getResources(), - FeatureConstants.DOWNLOAD_HOME_FEATURE, R.id.promo_description, - R.id.promo_description) - .setAnchorView(homeButton) - .setHighlightParams(new HighlightParams(HighlightShape.CIRCLE)) - .build()); - }); - onView(withId(R.id.button_snooze)) - .inRoot(withDecorView(not(is(sActivity.getWindow().getDecorView())))) - .perform(ViewActions.click()); - - verify(mTracker, times(1)) - .dismissedWithSnooze(FeatureConstants.DOWNLOAD_HOME_FEATURE, SnoozeAction.SNOOZED); - } -} \ No newline at end of file
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index cffb65c97..ea2d99f 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -114,6 +114,8 @@ "manifest_update_manager.h", "manifest_update_utils.cc", "manifest_update_utils.h", + "os_integration/file_handling_sub_manager.cc", + "os_integration/file_handling_sub_manager.h", "os_integration/os_integration_manager.cc", "os_integration/os_integration_manager.h", "os_integration/os_integration_sub_manager.h", @@ -608,6 +610,7 @@ "isolated_web_apps/pending_install_info_unittest.cc", "isolated_web_apps/signed_web_bundle_reader_unittest.cc", "isolation_prefs_utils_unittest.cc", + "os_integration/file_handling_sub_manager_unittest.cc", "os_integration/os_integration_manager_unittest.cc", "os_integration/protocol_handling_sub_manager_unittest.cc", "os_integration/run_on_os_login_sub_manager_unittest.cc",
diff --git a/chrome/browser/web_applications/chromeos_web_app_experiments.cc b/chrome/browser/web_applications/chromeos_web_app_experiments.cc index bd3b4b6..1dbdc53a 100644 --- a/chrome/browser/web_applications/chromeos_web_app_experiments.cc +++ b/chrome/browser/web_applications/chromeos_web_app_experiments.cc
@@ -114,16 +114,6 @@ return absl::nullopt; } -bool ChromeOsWebAppExperiments::ShouldOverrideUrlLoading( - const GURL& previous_url, - const GURL& current_url) { - // We expect |previous_url| to be empty, because the navigations we care about - // are caused by chrome.browser.openTab(), which does not set an - // initiator_origin on the navigation. - return previous_url.is_empty() && current_url.is_valid() && - GetExtendedScopeScore(kMicrosoftOfficeAppId, current_url.spec()) > 0; -} - void ChromeOsWebAppExperiments::SetAlwaysEnabledForTesting() { g_always_enabled_for_testing = true; }
diff --git a/chrome/browser/web_applications/chromeos_web_app_experiments.h b/chrome/browser/web_applications/chromeos_web_app_experiments.h index 4d53189..0ed1f1d0 100644 --- a/chrome/browser/web_applications/chromeos_web_app_experiments.h +++ b/chrome/browser/web_applications/chromeos_web_app_experiments.h
@@ -51,13 +51,6 @@ const AppId& app_id, content::WebContents* web_contents); - // Whether the navigation from |previous_url| to |current_url| should override - // the default decision for opening URLs in a web app, based on whether the - // experimental behavior is enabled and whether |current_url| is in the - // extended scope of the experiment. - static bool ShouldOverrideUrlLoading(const GURL& previous_url, - const GURL& current_url); - static void SetAlwaysEnabledForTesting(); static void SetScopeExtensionsForTesting( std::vector<const char* const> scope_extensions_override);
diff --git a/chrome/browser/web_applications/chromeos_web_app_experiments_browsertest.cc b/chrome/browser/web_applications/chromeos_web_app_experiments_browsertest.cc index ecaff55..92324257 100644 --- a/chrome/browser/web_applications/chromeos_web_app_experiments_browsertest.cc +++ b/chrome/browser/web_applications/chromeos_web_app_experiments_browsertest.cc
@@ -113,28 +113,4 @@ #endif // !BUILDFLAG(IS_CHROMEOS_LACROS) -IN_PROC_BROWSER_TEST_F(ChromeOsWebAppExperimentsBrowserTest, - OverrideLoadingForNonEmptyPreviousUrl) { - EXPECT_FALSE(ChromeOsWebAppExperiments::ShouldOverrideUrlLoading( - extended_scope_page_, extended_scope_.Resolve("app3.html"))); -} - -IN_PROC_BROWSER_TEST_F(ChromeOsWebAppExperimentsBrowserTest, - OverrideLoadingForInvalidUrl) { - EXPECT_FALSE( - ChromeOsWebAppExperiments::ShouldOverrideUrlLoading(GURL(), GURL("a"))); -} - -IN_PROC_BROWSER_TEST_F(ChromeOsWebAppExperimentsBrowserTest, - OverrideLoadingForOutOfScopeUrl) { - EXPECT_FALSE(ChromeOsWebAppExperiments::ShouldOverrideUrlLoading( - GURL(), GURL("https://google.com"))); -} - -IN_PROC_BROWSER_TEST_F(ChromeOsWebAppExperimentsBrowserTest, - OverrideLoadingForExtendedScopeUrl) { - EXPECT_TRUE(ChromeOsWebAppExperiments::ShouldOverrideUrlLoading( - GURL(), extended_scope_page_)); -} - } // namespace web_app
diff --git a/chrome/browser/web_applications/commands/install_from_manifest_command.cc b/chrome/browser/web_applications/commands/install_from_manifest_command.cc index b400d10..ea90a8e 100644 --- a/chrome/browser/web_applications/commands/install_from_manifest_command.cc +++ b/chrome/browser/web_applications/commands/install_from_manifest_command.cc
@@ -7,7 +7,11 @@ #include <memory> #include <utility> +#include "base/containers/contains.h" +#include "base/containers/flat_set.h" +#include "base/containers/flat_tree.h" #include "base/functional/bind.h" +#include "base/strings/string_util.h" #include "chrome/browser/web_applications/locks/shared_web_contents_lock.h" #include "chrome/browser/web_applications/locks/shared_web_contents_with_app_lock.h" #include "chrome/browser/web_applications/locks/web_app_lock_manager.h" @@ -22,6 +26,7 @@ #include "components/webapps/browser/installable/installable_metrics.h" #include "content/public/browser/web_contents.h" #include "mojo/public/cpp/bindings/remote.h" +#include "net/base/url_util.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/common/manifest/manifest_util.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom.h" @@ -36,6 +41,7 @@ GURL manifest_url, std::string manifest_contents, AppId expected_id, + base::flat_set<std::string> host_allowlist, OnceInstallCallback callback) : WebAppCommandTemplate<SharedWebContentsLock>( "InstallFromManifestCommand"), @@ -44,9 +50,11 @@ manifest_url_(std::move(manifest_url)), manifest_contents_(std::move(manifest_contents)), expected_id_(std::move(expected_id)), + host_allowlist_(std::move(host_allowlist)), install_callback_(std::move(callback)), web_contents_lock_description_( - std::make_unique<SharedWebContentsLockDescription>()) {} + std::make_unique<SharedWebContentsLockDescription>()), + data_retriever_(std::make_unique<WebAppDataRetriever>()) {} InstallFromManifestCommand::~InstallFromManifestCommand() = default; @@ -117,9 +125,44 @@ UpdateWebAppInfoFromManifest(*manifest, manifest_url_, web_app_info_.get()); - // Generates a fallback icon for the app. - // TODO(crbug.com/1402583): Download and use real icons. - PopulateProductIcons(web_app_info_.get(), nullptr); + base::flat_set<GURL> icon_urls = GetValidIconUrlsToDownload(*web_app_info_); + base::EraseIf(icon_urls, [this](const GURL& url) { + return !base::Contains(host_allowlist_, url.host()); + }); + + if (icon_urls.empty()) { + // Abort as "not a valid manifest" if there are no icons to download, so we + // can distinguish this case from having icons but failing to download + // them. + Abort(CommandResult::kFailure, + webapps::InstallResultCode::kNotValidManifestForWebApp); + return; + } + + data_retriever_->GetIcons( + &web_contents_lock_->shared_web_contents(), std::move(icon_urls), + /*skip_page_favicons=*/true, + base::BindOnce(&InstallFromManifestCommand::OnIconsRetrieved, + weak_ptr_factory_.GetWeakPtr())); +} + +void InstallFromManifestCommand::OnIconsRetrieved( + IconsDownloadedResult result, + IconsMap icons_map, + DownloadedIconsHttpResults icons_http_results) { + DCHECK(web_app_info_); + + PopulateProductIcons(web_app_info_.get(), &icons_map); + if (web_app_info_->is_generated_icon) { + // PopulateProductIcons sets is_generated_icon if it had to generate a + // product icon due a lack of successfully downloaded product icons. In + // this case, abort the installation and report the error. + Abort(CommandResult::kFailure, + webapps::InstallResultCode::kIconDownloadingFailed); + return; + } + + PopulateOtherIcons(web_app_info_.get(), icons_map); AppId app_id = GenerateAppId(web_app_info_->manifest_id, web_app_info_->start_url);
diff --git a/chrome/browser/web_applications/commands/install_from_manifest_command.h b/chrome/browser/web_applications/commands/install_from_manifest_command.h index 19a4848b..5d4ccbf 100644 --- a/chrome/browser/web_applications/commands/install_from_manifest_command.h +++ b/chrome/browser/web_applications/commands/install_from_manifest_command.h
@@ -8,9 +8,11 @@ #include <memory> #include <string> +#include "base/containers/flat_set.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/web_applications/commands/web_app_command.h" #include "chrome/browser/web_applications/os_integration/os_integration_manager.h" +#include "chrome/browser/web_applications/web_app_data_retriever.h" #include "chrome/browser/web_applications/web_app_install_info.h" #include "chrome/browser/web_applications/web_app_install_params.h" #include "components/webapps/browser/install_result_code.h" @@ -18,8 +20,7 @@ #include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom-forward.h" #include "third_party/blink/public/mojom/manifest/manifest_manager.mojom.h" - -class GURL; +#include "url/gurl.h" namespace web_app { @@ -31,11 +32,18 @@ // Installs a web app using a raw manifest JSON string, which is interpreted as // if it was loaded from the renderer for a given URL. This does not attempt to -// verify all the installability criteria of the manifest: the manifest is -// treated as valid if it parses successfully and contains a start URL. +// verify all the normal installability criteria of the manifest, instead it +// just checks limited criteria needed to successfully install the app: +// - The manifest must be valid JSON +// - The manifest must have a valid start URL +// - The manifest must have a valid icon from an allowlisted host (see +// `host_allowlist` parameter). // -// The web app can be simultaneously installed from multiple sources. If the web -// app already exists, the manifest contents will be ignored. +// Installation will fail if any of these criteria are not met, or if icons fail +// to download (that is, placeholder icons will never be generated). +// +// The web app can be simultaneously installed from multiple sources. If the +// web app already exists, the manifest contents will be ignored. class InstallFromManifestCommand : public WebAppCommandTemplate<SharedWebContentsLock> { public: @@ -49,12 +57,16 @@ // `manifest_contents`: JSON string of a web app manifest to install. // `expected_id`: Expected hashed App ID for the installed app. If the ID does // not match, installation will abort with an error. + // `host_allowlist`: Allowlist of hosts which icon data can be downloaded + // from. Icon URLs whose host does not exactly match a host from this set are + // ignored. // `callback`: Called when installation completes. InstallFromManifestCommand(webapps::WebappInstallSource install_source, GURL document_url, GURL manifest_url, std::string manifest_contents, AppId expected_id, + base::flat_set<std::string> host_allowlist, OnceInstallCallback callback); ~InstallFromManifestCommand() override; @@ -68,6 +80,9 @@ private: void OnManifestParsed(blink::mojom::ManifestPtr manifest); + void OnIconsRetrieved(IconsDownloadedResult result, + IconsMap icons_map, + DownloadedIconsHttpResults icons_http_results); void OnAppLockAcquired( std::unique_ptr<SharedWebContentsWithAppLock> app_lock); void OnInstallFinalized(const AppId& app_id, @@ -81,6 +96,7 @@ GURL manifest_url_; std::string manifest_contents_; AppId expected_id_; + base::flat_set<std::string> host_allowlist_; OnceInstallCallback install_callback_; // SharedWebContentsLock is held while parsing the manifest. @@ -93,6 +109,8 @@ std::unique_ptr<SharedWebContentsWithAppLockDescription> app_lock_description_; + std::unique_ptr<WebAppDataRetriever> data_retriever_; + bool manifest_parsed_ = false; std::unique_ptr<WebAppInstallInfo> web_app_info_;
diff --git a/chrome/browser/web_applications/commands/install_from_manifest_command_browsertest.cc b/chrome/browser/web_applications/commands/install_from_manifest_command_browsertest.cc index 98c9234..9df352ff 100644 --- a/chrome/browser/web_applications/commands/install_from_manifest_command_browsertest.cc +++ b/chrome/browser/web_applications/commands/install_from_manifest_command_browsertest.cc
@@ -4,21 +4,27 @@ #include <memory> +#include "base/containers/flat_set.h" #include "base/files/file_util.h" +#include "base/strings/string_util.h" #include "base/test/test_future.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h" #include "chrome/browser/web_applications/commands/install_from_manifest_command.h" #include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/test/web_app_icon_test_utils.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/browser/web_applications/web_app_command_manager.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_id.h" +#include "chrome/browser/web_applications/web_app_install_info.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "components/webapps/browser/install_result_code.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "content/public/test/browser_test.h" +#include "third_party/skia/include/core/SkColor.h" #include "url/gurl.h" namespace web_app { @@ -26,6 +32,8 @@ class InstallFromManifestCommandTest : public WebAppControllerBrowserTest { public: void SetUpOnMainThread() override { + WebAppControllerBrowserTest::SetUpOnMainThread(); + os_hooks_suppress_.reset(); { base::ScopedAllowBlockingForTesting allow_blocking; @@ -54,6 +62,12 @@ #endif } + std::string GetIconUrl() { + return https_server()->GetURL("/web_apps/blue-192.png").spec(); + } + + base::flat_set<std::string> GetHostAllowlist() { return {"127.0.0.1"}; } + private: std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> test_override_; @@ -63,20 +77,29 @@ const GURL kDocumentUrl("https://www.app.com/"); const GURL kStartUrl("https://www.app.com/home"); const GURL kManifestUrl("https://www.app.com/manifest.json"); - const char kManifest[] = R"json({ + const char kManifestTemplate[] = R"json({ "start_url": "/home", "name": "Test app", "launch_handler": { "client_mode": "focus-existing" - } + }, + "icons": [{ + "src": "$1", + "sizes": "192x192", + "type": "image/png" + }] })json"; + std::string manifest = base::ReplaceStringPlaceholders( + kManifestTemplate, {GetIconUrl()}, nullptr); + AppId expected_id = GenerateAppId(/*manifest_id=*/absl::nullopt, kStartUrl); base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; provider().command_manager().ScheduleCommand( std::make_unique<InstallFromManifestCommand>( webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, - kManifestUrl, kManifest, expected_id, result.GetCallback())); + kManifestUrl, manifest, expected_id, GetHostAllowlist(), + result.GetCallback())); AppId result_id = result.Get<0>(); EXPECT_EQ(result_id, expected_id); @@ -90,6 +113,10 @@ ->launch_handler() ->client_mode, blink::Manifest::LaunchHandler::ClientMode::kFocusExisting); + SkColor icon_color = + IconManagerReadAppIconPixel(provider().icon_manager(), result_id, 96); + EXPECT_EQ(icon_color, SK_ColorBLUE); + EXPECT_TRUE(IsShortcutCreated(result_id, "Test app")); } @@ -97,11 +124,19 @@ SuccessCrossOriginManifest) { const GURL kDocumentUrl("https://www.app.com/"); const GURL kManifestUrl("https://www.cdn.com/app/manifest.json"); - const char kManifest[] = R"json({ + const char kManifestTemplate[] = R"json({ "start_url": "https://www.app.com/", - "name": "Test app" + "name": "Test app", + "icons": [{ + "src": "$1", + "sizes": "192x192", + "type": "image/png" + }] })json"; + std::string manifest = base::ReplaceStringPlaceholders( + kManifestTemplate, {GetIconUrl()}, nullptr); + AppId expected_id = GenerateAppId(/*manifest_id=*/absl::nullopt, kDocumentUrl); @@ -109,7 +144,8 @@ provider().command_manager().ScheduleCommand( std::make_unique<InstallFromManifestCommand>( webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, - kManifestUrl, kManifest, expected_id, result.GetCallback())); + kManifestUrl, manifest, expected_id, GetHostAllowlist(), + result.GetCallback())); AppId result_id = result.Get<0>(); EXPECT_EQ(result_id, expected_id); @@ -120,18 +156,27 @@ IN_PROC_BROWSER_TEST_F(InstallFromManifestCommandTest, SuccessWithManifestId) { const GURL kDocumentUrl("https://www.app.com/"); const GURL kManifestUrl("https://www.app.com/manifest.json"); - const char kManifest[] = R"json({ + const char kManifestTemplate[] = R"json({ "start_url": "/", "id": "/appid", - "name": "Test app" + "name": "Test app", + "icons": [{ + "src": "$1", + "sizes": "192x192", + "type": "image/png" + }] })json"; + std::string manifest = base::ReplaceStringPlaceholders( + kManifestTemplate, {GetIconUrl()}, nullptr); + AppId expected_id = GenerateAppId("appid", kDocumentUrl); base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; provider().command_manager().ScheduleCommand( std::make_unique<InstallFromManifestCommand>( webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, - kManifestUrl, kManifest, expected_id, result.GetCallback())); + kManifestUrl, manifest, expected_id, GetHostAllowlist(), + result.GetCallback())); AppId result_id = result.Get<0>(); EXPECT_EQ(result_id, expected_id); @@ -145,10 +190,17 @@ IN_PROC_BROWSER_TEST_F(InstallFromManifestCommandTest, SuccessWithExistingApp) { const GURL kDocumentUrl("https://www.app.com/"); const GURL kManifestUrl("https://www.app.com/manifest.json"); - const char kManifest[] = R"json({ + const char kManifestTemplate[] = R"json({ "start_url": "/", - "name": "Manifest installed app" + "name": "Manifest installed app", + "icons": [{ + "src": "$1", + "sizes": "192x192", + "type": "image/png" + }] })json"; + std::string manifest = base::ReplaceStringPlaceholders( + kManifestTemplate, {GetIconUrl()}, nullptr); AppId existing_id = test::InstallDummyWebApp(profile(), "User installed app", kDocumentUrl); @@ -157,7 +209,8 @@ provider().command_manager().ScheduleCommand( std::make_unique<InstallFromManifestCommand>( webapps::WebappInstallSource::INTERNAL_DEFAULT, kDocumentUrl, - kManifestUrl, kManifest, existing_id, result.GetCallback())); + kManifestUrl, manifest, existing_id, GetHostAllowlist(), + result.GetCallback())); AppId result_id = result.Get<0>(); EXPECT_EQ(result_id, existing_id); @@ -171,6 +224,76 @@ provider().registrar_unsafe().GetAppById(result_id)->IsPreinstalledApp()); } +IN_PROC_BROWSER_TEST_F(InstallFromManifestCommandTest, + SuccessWithMultipleIcons) { + const GURL kDocumentUrl("https://www.app.com/"); + const GURL kManifestUrl("https://www.app.com/manifest.json"); + const char kManifestTemplate[] = R"json({ + "start_url": "/ ", + "name": "Test app", + "icons": [ + { + "src": "$1", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "$2", + "sizes": "192x192", + "type": "image/png" + } + ], + "shortcuts": [ + { + "name": "Shortcut", + "url": "/shortcut", + "icons": [{ + "src": "$3", + "sizes": "192x192", + "type": "image/png" + }] + } + ] + })json"; + + std::string manifest = base::ReplaceStringPlaceholders( + kManifestTemplate, + {https_server()->GetURL("/banners/96x96-red.png").spec(), + https_server()->GetURL("/banners/192x192-green.png").spec(), + https_server()->GetURL("/web_apps/blue-192.png").spec() + + }, + nullptr); + AppId expected_id = + GenerateAppId(/*manifest_id=*/absl::nullopt, kDocumentUrl); + + base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; + provider().command_manager().ScheduleCommand( + std::make_unique<InstallFromManifestCommand>( + webapps::WebappInstallSource::INTERNAL_DEFAULT, kDocumentUrl, + kManifestUrl, manifest, expected_id, GetHostAllowlist(), + result.GetCallback())); + + AppId result_id = result.Get<0>(); + EXPECT_TRUE(webapps::IsSuccess(result.Get<1>())); + + SkColor small_icon_color = + IconManagerReadAppIconPixel(provider().icon_manager(), result_id, 96); + EXPECT_EQ(small_icon_color, SK_ColorRED); + + SkColor large_icon_color = + IconManagerReadAppIconPixel(provider().icon_manager(), result_id, 192); + EXPECT_EQ(large_icon_color, SK_ColorGREEN); + + base::test::TestFuture<ShortcutsMenuIconBitmaps> shortcut_future; + provider().icon_manager().ReadAllShortcutsMenuIcons( + result_id, shortcut_future.GetCallback()); + + SkColor shortcut_icon_color = + shortcut_future.Get()[0].any.at(192).getColor(0, 0); + EXPECT_EQ(shortcut_icon_color, SK_ColorBLUE); +} + IN_PROC_BROWSER_TEST_F(InstallFromManifestCommandTest, FailureInvalidManifest) { const GURL kDocumentUrl("https://www.app.com/"); const GURL kManifestUrl("https://www.app.com/manifest.json"); @@ -181,7 +304,7 @@ std::make_unique<InstallFromManifestCommand>( webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, kManifestUrl, kManifest, - /*expected_id=*/"", result.GetCallback())); + /*expected_id=*/"", GetHostAllowlist(), result.GetCallback())); EXPECT_EQ(result.Get<1>(), webapps::InstallResultCode::kNotValidManifestForWebApp); @@ -200,7 +323,7 @@ std::make_unique<InstallFromManifestCommand>( webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, kManifestUrl, kManifest, - /*expected_id=*/"", result.GetCallback())); + /*expected_id=*/"", GetHostAllowlist(), result.GetCallback())); EXPECT_EQ(result.Get<1>(), webapps::InstallResultCode::kNotValidManifestForWebApp); @@ -214,7 +337,12 @@ const GURL kManifestUrl("https://www.app.com/manifest.json"); const char kManifest[] = R"json({ "start_url": "https://www.not-app.com/", - "name": "Test app 2" + "name": "Test app 2", + "icons": [{ + "src": "/icon/96.png", + "sizes": "96x96", + "type": "image/png" + }] })json"; base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; @@ -222,7 +350,7 @@ std::make_unique<InstallFromManifestCommand>( webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, kManifestUrl, kManifest, - /*expected_id=*/"", result.GetCallback())); + /*expected_id=*/"", GetHostAllowlist(), result.GetCallback())); EXPECT_EQ(result.Get<1>(), webapps::InstallResultCode::kNotValidManifestForWebApp); @@ -230,25 +358,113 @@ IN_PROC_BROWSER_TEST_F(InstallFromManifestCommandTest, FailureExpectedIdMismatch) { - // Installation will fail because the start URL is a different origin to the - // document URL. + // Installation will fail because the expected ID doesn't match the ID in the + // manifest. const GURL kDocumentUrl("https://www.app.com/"); const GURL kManifestUrl("https://www.app.com/manifest.json"); - const char kManifest[] = R"json({ + const AppId kExpectedId = GenerateAppId("/two", kDocumentUrl); + const char kManifestTemplate[] = R"json({ "start_url": "/", "id": "/one", - "name": "Test app 2" + "name": "Test app 2", + "icons": [{ + "src": "$1", + "sizes": "192x192", + "type": "image/png" + }] })json"; + std::string manifest = base::ReplaceStringPlaceholders( + kManifestTemplate, {GetIconUrl()}, nullptr); base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; provider().command_manager().ScheduleCommand( std::make_unique<InstallFromManifestCommand>( webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, - kManifestUrl, kManifest, GenerateAppId("/two", kDocumentUrl), + kManifestUrl, manifest, kExpectedId, GetHostAllowlist(), result.GetCallback())); EXPECT_EQ(result.Get<1>(), webapps::InstallResultCode::kExpectedAppIdCheckFailed); } +IN_PROC_BROWSER_TEST_F(InstallFromManifestCommandTest, FailureNoValidIcons) { + // Installation will fail because there are no icons that match the allowlist. + const GURL kDocumentUrl("https://www.app.com/"); + const GURL kManifestUrl("https://www.app.com/manifest.json"); + const AppId kExpectedId = GenerateAppId("/two", kDocumentUrl); + const char kManifestTemplate[] = R"json({ + "start_url": "/", + "name": "Test app", + "icons": [ + { + "src": "/icons/96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "https://www.somesite.com/icons/48.png", + "sizes": "48x48", + "type": "image/png" + }, + { + "src": "https://notcdn.com/icons/192.png", + "sizes": "192x192", + "type": "image/png" + }, + ] + })json"; + std::string manifest = base::ReplaceStringPlaceholders( + kManifestTemplate, {GetIconUrl()}, nullptr); + base::flat_set<std::string> host_allowlist = {"cdn.com", "subdomain.app.com"}; + + base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; + provider().command_manager().ScheduleCommand( + std::make_unique<InstallFromManifestCommand>( + webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, + kManifestUrl, manifest, kExpectedId, host_allowlist, + result.GetCallback())); + + EXPECT_EQ(result.Get<1>(), + webapps::InstallResultCode::kNotValidManifestForWebApp); +} + +IN_PROC_BROWSER_TEST_F(InstallFromManifestCommandTest, FailureAllIconsError) { + // Installation will fail because all icons error when downloaded. + const GURL kDocumentUrl("https://www.app.com/"); + const GURL kManifestUrl("https://www.app.com/manifest.json"); + const AppId kExpectedId = GenerateAppId("/two", kDocumentUrl); + const char kManifestTemplate[] = R"json({ + "start_url": "/", + "id": "/one", + "name": "Test app 2", + "icons": [ + { + "src": "$1", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "$2", + "sizes": "48x48", + "type": "image/png" + } + ] + })json"; + std::string manifest = base::ReplaceStringPlaceholders( + kManifestTemplate, + {https_server()->GetURL("/404").spec(), + https_server()->GetURL("/nocontent").spec()}, + nullptr); + + base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; + provider().command_manager().ScheduleCommand( + std::make_unique<InstallFromManifestCommand>( + webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, kDocumentUrl, + kManifestUrl, manifest, kExpectedId, GetHostAllowlist(), + result.GetCallback())); + + EXPECT_EQ(result.Get<1>(), + webapps::InstallResultCode::kIconDownloadingFailed); +} + } // namespace web_app
diff --git a/chrome/browser/web_applications/commands/manifest_update_data_fetch_command.cc b/chrome/browser/web_applications/commands/manifest_update_data_fetch_command.cc index 4559f23c..649eab12 100644 --- a/chrome/browser/web_applications/commands/manifest_update_data_fetch_command.cc +++ b/chrome/browser/web_applications/commands/manifest_update_data_fetch_command.cc
@@ -555,71 +555,33 @@ return false; } -bool ManifestUpdateDataFetchCommand::IsUpdateNeededForWebAppOriginAssociations() - const { - // Web app origin association update is tied to the manifest update process. - // If there are url handlers for the current app, associations need to be - // revalidated. - DCHECK(install_info_.has_value()); - return !install_info_->url_handlers.empty(); -} - void ManifestUpdateDataFetchCommand::NoManifestUpdateRequired() { if (IsWebContentsDestroyed()) { CompleteCommand(ManifestUpdateResult::kWebContentsDestroyed); return; } DCHECK_EQ(stage_, ManifestUpdateStage::kPendingAppIdentityCheck); - stage_ = ManifestUpdateStage::kPendingAssociationsUpdate; - - if (!IsUpdateNeededForWebAppOriginAssociations()) { - CompleteCommand(ManifestUpdateResult::kAppUpToDate); - return; - } - - auto manifest_update_origin_update_callback = base::BindOnce( - &ManifestUpdateDataFetchCommand::OnWebAppOriginAssociationsUpdated, - AsWeakPtr()); - auto synchronize_callback = base::BarrierCallback<bool>( - /*num_callbacks = */ 2, - base::BindOnce( - [&](base::OnceCallback<void(bool)> final_callback, - std::vector<bool> final_results) { - DCHECK_EQ(2u, final_results.size()); - bool final_result = final_results[0] && final_results[1]; - std::move(final_callback).Run(final_result); - }, - std::move(manifest_update_origin_update_callback))); - - // TODO(crbug.com/1401125): Remove UpdateUrlHandlers() once OS integration - // sub managers have been implemented. - lock_->os_integration_manager().UpdateUrlHandlers(app_id_, - synchronize_callback); - lock_->os_integration_manager().Synchronize( - app_id_, base::BindOnce(synchronize_callback, true)); -} - -void ManifestUpdateDataFetchCommand::OnWebAppOriginAssociationsUpdated( - bool success) { - DCHECK_EQ(stage_, ManifestUpdateStage::kPendingAssociationsUpdate); - success ? CompleteCommand(ManifestUpdateResult::kAppAssociationsUpdated) - : CompleteCommand(ManifestUpdateResult::kAppAssociationsUpdateFailed); + CompleteCommand(ManifestUpdateResult::kAppUpToDate); } void ManifestUpdateDataFetchCommand::CompleteCommand( - absl::optional<ManifestUpdateResult> result) { - if (result.has_value()) - debug_log_.Set("result", base::StreamableToString(result.value())); - else + absl::optional<ManifestUpdateResult> early_exit_result) { + if (early_exit_result.has_value()) { + debug_log_.Set("result", + base::StreamableToString(early_exit_result.value())); + } else { debug_log_.Set("result", "pending_manifest_data_write"); + } + // TODO(crbug.com/1409710): Does success/failure make sense here? It should + // probably be based on the exact result rather than if we early exit. CommandResult command_result = CommandResult::kSuccess; - if (result.has_value() && - result.value() != ManifestUpdateResult::kAppAssociationsUpdated) + if (early_exit_result.has_value()) { command_result = CommandResult::kFailure; + } SignalCompletionAndSelfDestruct( command_result, - base::BindOnce(std::move(fetch_callback_), result, + base::BindOnce(std::move(fetch_callback_), early_exit_result, std::move(install_info_), app_identity_update_allowed_)); }
diff --git a/chrome/browser/web_applications/commands/manifest_update_data_fetch_command.h b/chrome/browser/web_applications/commands/manifest_update_data_fetch_command.h index 4600878..63f26251 100644 --- a/chrome/browser/web_applications/commands/manifest_update_data_fetch_command.h +++ b/chrome/browser/web_applications/commands/manifest_update_data_fetch_command.h
@@ -129,10 +129,15 @@ // - Require user confirmation for changes to the app name. class ManifestUpdateDataFetchCommand : public WebAppCommandTemplate<AppLock> { public: - using ManifestFetchCallback = - base::OnceCallback<void(absl::optional<ManifestUpdateResult> result, - absl::optional<WebAppInstallInfo> install_info_, - bool app_identity_update_allowed)>; + // If no `early_exit_result` is provided then the manifest should be updated + // with `install_info`. + // TODO(crbug.com/1409710): Merge ManifestUpdateDataFetchCommand and + // ManifestUpdateFinalizeCommand into one so we don't have to return optional + // early exit results to the caller. + using ManifestFetchCallback = base::OnceCallback<void( + absl::optional<ManifestUpdateResult> early_exit_result, + absl::optional<WebAppInstallInfo> install_info, + bool app_identity_update_allowed)>; ManifestUpdateDataFetchCommand( const GURL& url, @@ -173,18 +178,9 @@ ShortcutsMenuIconBitmaps disk_shortcuts_menu_icons); bool IsUpdateNeededForShortcutsMenuIconsContents( const ShortcutsMenuIconBitmaps& disk_shortcuts_menu_icons) const; - bool IsUpdateNeededForWebAppOriginAssociations() const; void NoManifestUpdateRequired(); - void OnWebAppOriginAssociationsUpdated(bool success); void OnExistingIconsRead(IconBitmaps icon_bitmaps); - // Having an absl::nullopt as a result means that the data fetch - // was successful and no error results were thrown, apart from - // kAppAssociationsUpdated which is meant to be treated as a success. - // The manifest update process however is still not over, and would - // require the ManifestUpdateManager to wait till the app windows - // are closed to actually finalize the update and write the values - // to the DB. - void CompleteCommand(absl::optional<ManifestUpdateResult> result); + void CompleteCommand(absl::optional<ManifestUpdateResult> early_exit_result); std::unique_ptr<AppLockDescription> lock_description_; std::unique_ptr<AppLock> lock_;
diff --git a/chrome/browser/web_applications/manifest_update_manager.cc b/chrome/browser/web_applications/manifest_update_manager.cc index 6799465..136dd04 100644 --- a/chrome/browser/web_applications/manifest_update_manager.cc +++ b/chrome/browser/web_applications/manifest_update_manager.cc
@@ -251,7 +251,7 @@ base::WeakPtr<content::WebContents> contents, const GURL& url, const AppId& app_id, - absl::optional<ManifestUpdateResult> result, + absl::optional<ManifestUpdateResult> early_exit_result, absl::optional<WebAppInstallInfo> install_info, bool app_identity_update_allowed) { auto update_stage_it = update_stages_.find(app_id); @@ -265,11 +265,8 @@ DCHECK_EQ(update_stage.stage, UpdateStage::Stage::kFetchingManifestData); update_stage.stage = UpdateStage::Stage::kPendingAppWindowClose; - if (result.has_value()) { - // Stop the manifest update process if there already is a result, which - // means that there were issues during the manifest fetching and can - // early exit. - OnUpdateStopped(url, app_id, result.value()); + if (early_exit_result.has_value()) { + OnUpdateStopped(url, app_id, early_exit_result.value()); return; }
diff --git a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc index a916ec77..53582fd 100644 --- a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc +++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -78,7 +78,6 @@ #include "components/services/app_service/public/cpp/icon_info.h" #include "components/services/app_service/public/cpp/protocol_handler_info.h" #include "components/services/app_service/public/cpp/share_target.h" -#include "components/services/app_service/public/cpp/url_handler_info.h" #include "components/webapps/browser/install_result_code.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "components/webapps/browser/uninstall_result_code.h" @@ -112,12 +111,6 @@ #include "base/mac/mac_util.h" #endif -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) -#include "base/command_line.h" -#include "chrome/browser/web_applications/os_integration/url_handler_manager_impl.h" -#include "chrome/browser/web_applications/test/fake_web_app_origin_association_manager.h" -#endif - #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/constants/ash_features.h" #include "chrome/browser/ash/system_web_apps/test_support/test_system_web_app_installation.h" @@ -3370,240 +3363,6 @@ EXPECT_EQ(ReadAppIconPixel(app_id, /*size=*/192), SK_ColorBLACK); } -class ManifestUpdateManagerBrowserTest_UrlHandlers - : public ManifestUpdateManagerBrowserTest { - public: -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) - void SetUpUrlHandlerManager() { - auto url_handler_manager = - std::make_unique<UrlHandlerManagerImpl>(browser()->profile()); - - // Set up web app origin association manager and expected data. - auto association_manager = - std::make_unique<FakeWebAppOriginAssociationManager>(); - url::Origin foo_origin = url::Origin::Create(GURL("https://foo.com")); - url::Origin bar_origin = url::Origin::Create(GURL("https://bar.com")); - std::map<apps::UrlHandlerInfo, apps::UrlHandlerInfo> data = { - {apps::UrlHandlerInfo(foo_origin), - apps::UrlHandlerInfo(foo_origin, false, /*paths*/ {}, - /*exclude_paths*/ {"/exclude"})}, - {apps::UrlHandlerInfo(bar_origin), - apps::UrlHandlerInfo(bar_origin, false, /*paths*/ {}, - /*exclude_paths*/ {"/exclude"})}, - }; - association_manager->SetData(std::move(data)); - - url_handler_manager->SetAssociationManagerForTesting( - std::move(association_manager)); - url_handler_manager->SetSubsystems(&(GetProvider().registrar_unsafe())); - GetProvider().os_integration_manager().set_url_handler_manager( - std::move(url_handler_manager)); - } -#endif - - base::test::ScopedFeatureList scoped_feature_list_{ - blink::features::kWebAppEnableUrlHandlers}; -}; - -IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest_UrlHandlers, - UpdateWithDifferentUrlHandlers) { - constexpr char kManifestTemplate[] = R"( - { - "name": "Test app name", - "start_url": ".", - "scope": "/", - "display": "standalone", - "icons": $1, - "url_handlers": [$2] - } - )"; - - OverrideManifest(kManifestTemplate, { - kInstallableIconList, - R"({"origin": "https://foo.com"})", - }); - AppId app_id = InstallWebApp(); - ASSERT_EQ(1u, - GetProvider().registrar_unsafe().GetAppUrlHandlers(app_id).size()); - - OverrideManifest( - kManifestTemplate, - {kInstallableIconList, - R"({"origin": "https://foo.com"}, {"origin": "https://bar.com"})"}); - EXPECT_EQ(GetResultAfterPageLoad(GetAppURL()), - ManifestUpdateResult::kAppUpdated); - - apps::UrlHandlers url_handlers = - GetProvider().registrar_unsafe().GetAppUrlHandlers(app_id); - ASSERT_EQ(2u, url_handlers.size()); - EXPECT_TRUE(base::Contains( - url_handlers, - apps::UrlHandlerInfo(url::Origin::Create(GURL("https://foo.com"))))); - EXPECT_TRUE(base::Contains( - url_handlers, - apps::UrlHandlerInfo(url::Origin::Create(GURL("https://bar.com"))))); -} - -IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest_UrlHandlers, - UpdateFromNoUrlHandlersToHaveUrlHandlers) { - constexpr char kManifestTemplate[] = R"( - { - "name": "Test app name", - "start_url": ".", - "scope": "/", - "display": "standalone", - "icons": $1 - $2 - } - )"; - - OverrideManifest(kManifestTemplate, { - kInstallableIconList, - R"()", - }); - AppId app_id = InstallWebApp(); - ASSERT_EQ(0u, - GetProvider().registrar_unsafe().GetAppUrlHandlers(app_id).size()); - - OverrideManifest(kManifestTemplate, - {kInstallableIconList, - R"(,"url_handlers": [{"origin": "https://foo.com"}])"}); - EXPECT_EQ(GetResultAfterPageLoad(GetAppURL()), - ManifestUpdateResult::kAppUpdated); - - apps::UrlHandlers url_handlers = - GetProvider().registrar_unsafe().GetAppUrlHandlers(app_id); - ASSERT_EQ(1u, url_handlers.size()); - EXPECT_TRUE(base::Contains( - url_handlers, - apps::UrlHandlerInfo(url::Origin::Create(GURL("https://foo.com"))))); -} - -IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest_UrlHandlers, - UpdateFromUrlHandlersToNoUrlHandlers) { - constexpr char kManifestTemplate[] = R"( - { - "name": "Test app name", - "start_url": ".", - "scope": "/", - "display": "standalone", - "icons": $1 - $2 - } - )"; - - OverrideManifest(kManifestTemplate, - { - kInstallableIconList, - R"(,"url_handlers": [{"origin": "https://foo.com"}])", - }); - AppId app_id = InstallWebApp(); - apps::UrlHandlers url_handlers = - GetProvider().registrar_unsafe().GetAppUrlHandlers(app_id); - ASSERT_EQ(1u, url_handlers.size()); - EXPECT_TRUE(base::Contains( - url_handlers, - apps::UrlHandlerInfo(url::Origin::Create(GURL("https://foo.com"))))); - - OverrideManifest(kManifestTemplate, {kInstallableIconList, R"()"}); - EXPECT_EQ(GetResultAfterPageLoad(GetAppURL()), - ManifestUpdateResult::kAppUpdated); - - url_handlers = GetProvider().registrar_unsafe().GetAppUrlHandlers(app_id); - ASSERT_EQ(0u, url_handlers.size()); -} - -#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) -class ManifestUpdateBrowserTestUrlHandlerSynchronize - : public ManifestUpdateManagerBrowserTest_UrlHandlers, - public ::testing::WithParamInterface<OsIntegrationSubManagersState> { - public: - ManifestUpdateBrowserTestUrlHandlerSynchronize() { - if (GetParam() == OsIntegrationSubManagersState::kSaveStateToDB) { - scoped_feature_list_.InitWithFeaturesAndParameters( - {{features::kOsIntegrationSubManagers, {{"stage", "write_config"}}}}, - /*disabled_features=*/{}); - } else { - scoped_feature_list_.InitWithFeatures( - {}, {features::kOsIntegrationSubManagers}); - } - } - - ~ManifestUpdateBrowserTestUrlHandlerSynchronize() override = default; - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -IN_PROC_BROWSER_TEST_P(ManifestUpdateBrowserTestUrlHandlerSynchronize, - NoHandlersChangeUpdateAssociations) { - constexpr char kManifestTemplate[] = R"( - { - "name": "Test app name", - "start_url": ".", - "scope": "/", - "display": "standalone", - "icons": $1, - "url_handlers": [ - { - "origin": "https://foo.com" - }, - { - "origin": "https://bar.com" - } - ] - } - )"; - - OverrideManifest(kManifestTemplate, {kInstallableIconList}); - AppId app_id = InstallWebApp(); - apps::UrlHandlers url_handlers = - GetProvider().registrar_unsafe().GetAppUrlHandlers(app_id); - ASSERT_EQ(2u, url_handlers.size()); - EXPECT_TRUE(base::Contains( - url_handlers, - apps::UrlHandlerInfo(url::Origin::Create(GURL("https://foo.com"))))); - EXPECT_TRUE(base::Contains( - url_handlers, - apps::UrlHandlerInfo(url::Origin::Create(GURL("https://bar.com"))))); - - // Prepare for association fetching at manifest update. - SetUpUrlHandlerManager(); - OverrideManifest(kManifestTemplate, {kInstallableIconList}); - EXPECT_EQ(GetResultAfterPageLoad(GetAppURL()), - ManifestUpdateResult::kAppAssociationsUpdated); - - // Verify url handlers are saved to prefs. - base::CommandLine cmd = base::CommandLine(base::CommandLine::NO_PROGRAM); - cmd.AppendArg("https://foo.com/ok"); - std::vector<UrlHandlerLaunchParams> matches = - UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd); - ASSERT_EQ(matches.size(), 1u); - // Check exclude paths came through. - cmd = base::CommandLine(base::CommandLine::NO_PROGRAM); - cmd.AppendArg("https://foo.com/exclude"); - matches = UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd); - ASSERT_EQ(matches.size(), 0u); - - cmd = base::CommandLine(base::CommandLine::NO_PROGRAM); - cmd.AppendArg("https://bar.com/ok"); - matches = UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd); - ASSERT_EQ(matches.size(), 1u); - // Check exclude paths came through. - cmd = base::CommandLine(base::CommandLine::NO_PROGRAM); - cmd.AppendArg("https://bar.com/exclude"); - matches = UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd); - ASSERT_EQ(matches.size(), 0u); -} - -INSTANTIATE_TEST_SUITE_P( - All, - ManifestUpdateBrowserTestUrlHandlerSynchronize, - ::testing::Values(OsIntegrationSubManagersState::kSaveStateToDB, - OsIntegrationSubManagersState::kDisabled), - test::GetOsIntegrationSubManagersTestName); -#endif - IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest, CheckFindsAddedProtocolHandler) { constexpr char kManifestTemplate[] = R"(
diff --git a/chrome/browser/web_applications/manifest_update_utils.cc b/chrome/browser/web_applications/manifest_update_utils.cc index 5e8753c..731aabf0 100644 --- a/chrome/browser/web_applications/manifest_update_utils.cc +++ b/chrome/browser/web_applications/manifest_update_utils.cc
@@ -62,10 +62,6 @@ return os << "kIconReadFromDiskFailed"; case ManifestUpdateResult::kAppIdMismatch: return os << "kAppIdMismatch"; - case ManifestUpdateResult::kAppAssociationsUpdateFailed: - return os << "kAppAssociationsUpdateFailed"; - case ManifestUpdateResult::kAppAssociationsUpdated: - return os << "kAppAssociationsUpdated"; } } @@ -79,8 +75,6 @@ return os << "kPendingIconReadFromDisk"; case ManifestUpdateStage::kPendingAppIdentityCheck: return os << "kPendingAppIdentityCheck"; - case ManifestUpdateStage::kPendingAssociationsUpdate: - return os << "kPendingAssociationsUpdate"; case ManifestUpdateStage::kAppWindowsClosed: return os << "kAppWindowsClosed"; case ManifestUpdateStage::kPendingFinalizerUpdate:
diff --git a/chrome/browser/web_applications/manifest_update_utils.h b/chrome/browser/web_applications/manifest_update_utils.h index 01ad6974..6c9ddc2 100644 --- a/chrome/browser/web_applications/manifest_update_utils.h +++ b/chrome/browser/web_applications/manifest_update_utils.h
@@ -30,9 +30,9 @@ kIconDownloadFailed = 10, kIconReadFromDiskFailed = 11, kAppIdMismatch = 12, - kAppAssociationsUpdateFailed = 13, - kAppAssociationsUpdated = 14, - kMaxValue = kAppAssociationsUpdated, + // kAppAssociationsUpdateFailed = 13, + // kAppAssociationsUpdated = 14, + kMaxValue = kAppIdMismatch, }; std::ostream& operator<<(std::ostream& os, ManifestUpdateResult result); @@ -42,7 +42,6 @@ kPendingIconDownload, kPendingIconReadFromDisk, kPendingAppIdentityCheck, - kPendingAssociationsUpdate, kAppWindowsClosed, kPendingFinalizerUpdate, };
diff --git a/chrome/browser/web_applications/os_integration/file_handling_sub_manager.cc b/chrome/browser/web_applications/os_integration/file_handling_sub_manager.cc new file mode 100644 index 0000000..5a772443 --- /dev/null +++ b/chrome/browser/web_applications/os_integration/file_handling_sub_manager.cc
@@ -0,0 +1,73 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/os_integration/file_handling_sub_manager.h" + +#include <utility> + +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/web_app_registrar.h" + +namespace web_app { + +FileHandlingSubManager::FileHandlingSubManager(WebAppRegistrar& registrar) + : registrar_(registrar) {} + +FileHandlingSubManager::~FileHandlingSubManager() = default; + +void FileHandlingSubManager::Configure( + const AppId& app_id, + proto::WebAppOsIntegrationState& desired_state, + base::OnceClosure configure_done) { + DCHECK(!desired_state.has_file_handling()); + + if (!registrar_->IsLocallyInstalled(app_id) || + registrar_->GetAppFileHandlerApprovalState(app_id) == + ApiApprovalState::kDisallowed) { + std::move(configure_done).Run(); + return; + } + + proto::FileHandling* os_file_handling = desired_state.mutable_file_handling(); + + // GetAppFileHandlers should never return a nullptr because of the registrar + // checks above. + for (const auto& file_handler : *registrar_->GetAppFileHandlers(app_id)) { + proto::FileHandling::FileHandler* file_handler_proto = + os_file_handling->add_file_handlers(); + DCHECK(file_handler.action.is_valid()); + file_handler_proto->set_action(file_handler.action.spec()); + file_handler_proto->set_display_name( + base::UTF16ToUTF8(file_handler.display_name)); + + for (const auto& accept_entry : file_handler.accept) { + auto* accept_entry_proto = file_handler_proto->add_accept(); + accept_entry_proto->set_mimetype(accept_entry.mime_type); + + for (const auto& file_extension : accept_entry.file_extensions) { + accept_entry_proto->add_file_extensions(file_extension); + } + } + } + + std::move(configure_done).Run(); +} + +void FileHandlingSubManager::Start() {} + +void FileHandlingSubManager::Shutdown() {} + +void FileHandlingSubManager::Execute( + const AppId& app_id, + const absl::optional<SynchronizeOsOptions>& synchronize_options, + const proto::WebAppOsIntegrationState& desired_state, + const proto::WebAppOsIntegrationState& current_state, + base::OnceClosure callback) { + // Not implemented yet. + std::move(callback).Run(); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/os_integration/file_handling_sub_manager.h b/chrome/browser/web_applications/os_integration/file_handling_sub_manager.h new file mode 100644 index 0000000..880cb56 --- /dev/null +++ b/chrome/browser/web_applications/os_integration/file_handling_sub_manager.h
@@ -0,0 +1,41 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_FILE_HANDLING_SUB_MANAGER_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_FILE_HANDLING_SUB_MANAGER_H_ + +#include "base/functional/callback_forward.h" +#include "base/memory/raw_ref.h" +#include "chrome/browser/web_applications/os_integration/os_integration_sub_manager.h" +#include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" +#include "chrome/browser/web_applications/web_app_id.h" + +namespace web_app { + +class WebAppRegistrar; + +// Used to track updates to the file handlers for a web app. +class FileHandlingSubManager : public OsIntegrationSubManager { + public: + explicit FileHandlingSubManager(WebAppRegistrar& registrar); + ~FileHandlingSubManager() override; + void Start() override; + void Shutdown() override; + + void Configure(const AppId& app_id, + proto::WebAppOsIntegrationState& desired_state, + base::OnceClosure configure_done) override; + void Execute(const AppId& app_id, + const absl::optional<SynchronizeOsOptions>& synchronize_options, + const proto::WebAppOsIntegrationState& desired_state, + const proto::WebAppOsIntegrationState& current_state, + base::OnceClosure callback) override; + + private: + const raw_ref<WebAppRegistrar> registrar_; +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_OS_INTEGRATION_FILE_HANDLING_SUB_MANAGER_H_
diff --git a/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc b/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc new file mode 100644 index 0000000..10ca0bd1 --- /dev/null +++ b/chrome/browser/web_applications/os_integration/file_handling_sub_manager_unittest.cc
@@ -0,0 +1,271 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <utility> +#include <vector> + +#include "base/files/file_util.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/test_future.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/os_integration/os_integration_manager.h" +#include "chrome/browser/web_applications/os_integration/os_integration_test_override.h" +#include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" +#include "chrome/browser/web_applications/test/fake_web_app_provider.h" +#include "chrome/browser/web_applications/test/web_app_install_test_utils.h" +#include "chrome/browser/web_applications/test/web_app_test.h" +#include "chrome/browser/web_applications/test/web_app_test_utils.h" +#include "chrome/browser/web_applications/web_app_command_scheduler.h" +#include "chrome/browser/web_applications/web_app_install_info.h" +#include "chrome/browser/web_applications/web_app_install_params.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/common/chrome_features.h" +#include "components/webapps/browser/install_result_code.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace web_app { + +namespace { + +class FileHandlingSubManagerTest + : public WebAppTest, + public ::testing::WithParamInterface<OsIntegrationSubManagersState> { + public: + const GURL kWebAppUrl = GURL("https://example.com/path/index.html"); + + FileHandlingSubManagerTest() = default; + ~FileHandlingSubManagerTest() override = default; + + void SetUp() override { + WebAppTest::SetUp(); + { + base::ScopedAllowBlockingForTesting allow_blocking; + test_override_ = + OsIntegrationTestOverride::OverrideForTesting(base::GetHomeDir()); + } + if (GetParam() == OsIntegrationSubManagersState::kSaveStateToDB) { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + features::kOsIntegrationSubManagers, {{"stage", "write_config"}}); + } else { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kOsIntegrationSubManagers}); + } + + provider_ = FakeWebAppProvider::Get(profile()); + + auto file_handler_manager = + std::make_unique<WebAppFileHandlerManager>(profile()); + auto protocol_handler_manager = + std::make_unique<WebAppProtocolHandlerManager>(profile()); + auto shortcut_manager = std::make_unique<WebAppShortcutManager>( + profile(), /*icon_manager=*/nullptr, file_handler_manager.get(), + protocol_handler_manager.get()); + auto os_integration_manager = std::make_unique<OsIntegrationManager>( + profile(), std::move(shortcut_manager), std::move(file_handler_manager), + std::move(protocol_handler_manager), /*url_handler_manager=*/nullptr); + + provider_->SetOsIntegrationManager(std::move(os_integration_manager)); + test::AwaitStartWebAppProviderAndSubsystems(profile()); + } + + void TearDown() override { + // Blocking required due to file operations in the shortcut override + // destructor. + test::UninstallAllWebApps(profile()); + { + base::ScopedAllowBlockingForTesting allow_blocking; + test_override_.reset(); + } + WebAppTest::TearDown(); + } + + web_app::AppId InstallWebAppWithFileHandlers( + apps::FileHandlers file_handlers) { + std::unique_ptr<WebAppInstallInfo> info = + std::make_unique<WebAppInstallInfo>(); + info->start_url = kWebAppUrl; + info->title = u"Test App"; + info->user_display_mode = web_app::mojom::UserDisplayMode::kStandalone; + info->file_handlers = file_handlers; + base::test::TestFuture<const AppId&, webapps::InstallResultCode> result; + // InstallFromInfoWithParams is used instead of InstallFromInfo, because + // InstallFromInfo doesn't register OS integration. + provider().scheduler().InstallFromInfoWithParams( + std::move(info), /*overwrite_existing_manifest_fields=*/true, + webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, + result.GetCallback(), WebAppInstallParams()); + bool success = result.Wait(); + EXPECT_TRUE(success); + if (!success) { + return AppId(); + } + EXPECT_EQ(result.Get<webapps::InstallResultCode>(), + webapps::InstallResultCode::kSuccessNewInstall); + return result.Get<AppId>(); + } + + protected: + WebAppProvider& provider() { return *provider_; } + + private: + raw_ptr<FakeWebAppProvider> provider_; + base::test::ScopedFeatureList scoped_feature_list_; + std::unique_ptr<OsIntegrationTestOverride::BlockingRegistration> + test_override_; +}; + +TEST_P(FileHandlingSubManagerTest, InstallWithFilehandlers) { + apps::FileHandlers file_handlers; + + { + apps::FileHandler file_handler; + file_handler.action = GURL("https://app.site/open-foo"); + file_handler.display_name = u"Foo opener"; + { + apps::FileHandler::AcceptEntry accept_entry; + accept_entry.mime_type = "application/foo"; + accept_entry.file_extensions.insert(".foo"); + file_handler.accept.push_back(accept_entry); + } + { + apps::FileHandler::AcceptEntry accept_entry; + accept_entry.mime_type = "application/foobar"; + accept_entry.file_extensions.insert(".foobar"); + file_handler.accept.push_back(accept_entry); + } + file_handlers.push_back(file_handler); + } + + { + apps::FileHandler file_handler; + file_handler.action = GURL("https://app.site/open-bar"); + file_handler.display_name = u"Bar opener"; + { + apps::FileHandler::AcceptEntry accept_entry; + accept_entry.mime_type = "application/bar"; + accept_entry.file_extensions.insert(".bar"); + accept_entry.file_extensions.insert(".baz"); + file_handler.accept.push_back(accept_entry); + } + file_handlers.push_back(file_handler); + } + + const AppId& app_id = InstallWebAppWithFileHandlers(file_handlers); + + auto state = + provider().registrar_unsafe().GetAppCurrentOsIntegrationState(app_id); + ASSERT_TRUE(state.has_value()); + const proto::WebAppOsIntegrationState& os_integration_state = state.value(); + if (AreOsIntegrationSubManagersEnabled()) { + ASSERT_TRUE(os_integration_state.has_file_handling()); + auto file_handling = os_integration_state.file_handling(); + + ASSERT_EQ(file_handling.file_handlers_size(), 2); + + EXPECT_EQ(file_handling.file_handlers(0).accept_size(), 2); + EXPECT_EQ(file_handling.file_handlers(0).display_name(), "Foo opener"); + EXPECT_EQ(file_handling.file_handlers(0).action(), + "https://app.site/open-foo"); + EXPECT_EQ(file_handling.file_handlers(0).accept(0).mimetype(), + "application/foo"); + EXPECT_EQ(file_handling.file_handlers(0).accept(0).file_extensions_size(), + 1); + EXPECT_EQ(file_handling.file_handlers(0).accept(0).file_extensions(0), + ".foo"); + EXPECT_EQ(file_handling.file_handlers(0).accept(1).mimetype(), + "application/foobar"); + EXPECT_EQ(file_handling.file_handlers(0).accept(1).file_extensions_size(), + 1); + EXPECT_EQ(file_handling.file_handlers(0).accept(1).file_extensions(0), + ".foobar"); + + EXPECT_EQ(file_handling.file_handlers(1).accept_size(), 1); + EXPECT_EQ(file_handling.file_handlers(1).display_name(), "Bar opener"); + EXPECT_EQ(file_handling.file_handlers(1).action(), + "https://app.site/open-bar"); + EXPECT_EQ(file_handling.file_handlers(1).accept(0).mimetype(), + "application/bar"); + EXPECT_EQ(file_handling.file_handlers(1).accept(0).file_extensions_size(), + 2); + EXPECT_EQ(file_handling.file_handlers(1).accept(0).file_extensions(0), + ".bar"); + EXPECT_EQ(file_handling.file_handlers(1).accept(0).file_extensions(1), + ".baz"); + } else { + ASSERT_FALSE(os_integration_state.has_file_handling()); + } +} + +TEST_P(FileHandlingSubManagerTest, UpdateUserChoiceDisallowed) { + apps::FileHandlers file_handlers; + + { + apps::FileHandler file_handler; + file_handler.action = GURL("https://app.site/open-foo"); + file_handler.display_name = u"Foo opener"; + { + apps::FileHandler::AcceptEntry accept_entry; + accept_entry.mime_type = "application/foo"; + accept_entry.file_extensions.insert(".foo"); + file_handler.accept.push_back(accept_entry); + } + file_handlers.push_back(file_handler); + } + + const AppId& app_id = InstallWebAppWithFileHandlers(file_handlers); + + base::test::TestFuture<void> future; + provider().scheduler().PersistFileHandlersUserChoice( + app_id, /*allowed=*/false, future.GetCallback()); + + ASSERT_TRUE(future.Wait()); + + auto state = + provider().registrar_unsafe().GetAppCurrentOsIntegrationState(app_id); + ASSERT_TRUE(state.has_value()); + const proto::WebAppOsIntegrationState& os_integration_state = state.value(); + if (AreOsIntegrationSubManagersEnabled()) { + ASSERT_FALSE(os_integration_state.has_file_handling()); + } else { + ASSERT_FALSE(os_integration_state.has_file_handling()); + } +} + +TEST_P(FileHandlingSubManagerTest, Uninstall) { + apps::FileHandlers file_handlers; + + { + apps::FileHandler file_handler; + file_handler.action = GURL("https://app.site/open-foo"); + file_handler.display_name = u"Foo opener"; + { + apps::FileHandler::AcceptEntry accept_entry; + accept_entry.mime_type = "application/foo"; + accept_entry.file_extensions.insert(".foo"); + file_handler.accept.push_back(accept_entry); + } + file_handlers.push_back(file_handler); + } + + const AppId& app_id = InstallWebAppWithFileHandlers(file_handlers); + + test::UninstallAllWebApps(profile()); + auto state = + provider().registrar_unsafe().GetAppCurrentOsIntegrationState(app_id); + ASSERT_FALSE(state.has_value()); +} + +INSTANTIATE_TEST_SUITE_P( + All, + FileHandlingSubManagerTest, + ::testing::Values(OsIntegrationSubManagersState::kSaveStateToDB, + OsIntegrationSubManagersState::kDisabled), + test::GetOsIntegrationSubManagersTestName); + +} // namespace + +} // namespace web_app
diff --git a/chrome/browser/web_applications/os_integration/os_integration_manager.cc b/chrome/browser/web_applications/os_integration/os_integration_manager.cc index fd1789d2..f2e0c2b 100644 --- a/chrome/browser/web_applications/os_integration/os_integration_manager.cc +++ b/chrome/browser/web_applications/os_integration/os_integration_manager.cc
@@ -24,6 +24,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/os_integration/file_handling_sub_manager.h" #include "chrome/browser/web_applications/os_integration/os_integration_sub_manager.h" #include "chrome/browser/web_applications/os_integration/protocol_handling_sub_manager.h" #include "chrome/browser/web_applications/os_integration/run_on_os_login_sub_manager.h" @@ -184,6 +185,8 @@ auto shortcut_sub_manager = std::make_unique<ShortcutSubManager>( *profile_, *icon_manager, *registrar); + auto file_handling_sub_manager = + std::make_unique<FileHandlingSubManager>(*registrar); auto protocol_handling_sub_manager = std::make_unique<ProtocolHandlingSubManager>(profile_, *registrar); auto shortcut_menu_handling_sub_manager = @@ -194,6 +197,7 @@ auto uninstallation_via_os_settings_sub_manager = std::make_unique<UninstallationViaOsSettingsSubManager>(*registrar); sub_managers_.push_back(std::move(shortcut_sub_manager)); + sub_managers_.push_back(std::move(file_handling_sub_manager)); sub_managers_.push_back(std::move(protocol_handling_sub_manager)); sub_managers_.push_back(std::move(shortcut_menu_handling_sub_manager)); sub_managers_.push_back(std::move(run_on_os_login_sub_manager));
diff --git a/chrome/browser/web_applications/proto/web_app_os_integration_state.proto b/chrome/browser/web_applications/proto/web_app_os_integration_state.proto index 3841dc0..5dd1d89 100644 --- a/chrome/browser/web_applications/proto/web_app_os_integration_state.proto +++ b/chrome/browser/web_applications/proto/web_app_os_integration_state.proto
@@ -59,6 +59,23 @@ optional bool registered_with_os = 1; } +message FileHandling { + // A mapping between a MIME type and a set of file extensions for a file + // handler "accept" entry. See chrome/browser/web_applications/web_app.h for + // details. + message FileHandler { + message FileHandlerAccept { + optional string mimetype = 1; + repeated string file_extensions = 2; + } + optional string action = 1; + repeated FileHandlerAccept accept = 2; + optional string display_name = 3; + } + + repeated FileHandler file_handlers = 1; +} + // Represents all the common OS Integration states to be stored in the web_app // DB that matches the values in the OS. message WebAppOsIntegrationState { @@ -68,6 +85,7 @@ optional RunOnOsLogin run_on_os_login = 4; optional OsUninstallRegistration uninstall_registration = 5; optional ShortcutMenus shortcut_menus = 6; + optional FileHandling file_handling = 7; // Add data states for other OS integration hooks here. // New fields added to this message must also be added to: // OsStatesDebugValue()
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 10da49f..274f666 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -15,6 +15,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/values.h" #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h" #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.h" #include "chrome/browser/web_applications/user_display_mode.h" @@ -115,6 +116,7 @@ } if (current_states.has_shortcut_menus()) { + base::Value::List shortcut_menus_list; for (const auto& shortcut_menu : current_states.shortcut_menus().shortcut_menu_info()) { base::Value::Dict icon_data_any_dict; @@ -147,9 +149,34 @@ base::Value(std::move(icon_data_maskable_dict))); shortcut_menu_dict.Set("icon_data_monochrome", base::Value(std::move(icon_data_monochrome_dict))); - debug_dict.Set("shortcut_menus", - base::Value(std::move(shortcut_menu_dict))); + shortcut_menus_list.Append(std::move(shortcut_menu_dict)); } + debug_dict.Set("shortcut_menus", + base::Value(std::move(shortcut_menus_list))); + } + + if (current_states.has_file_handling()) { + base::Value::List file_handlers_list; + for (const auto& file_handler : + current_states.file_handling().file_handlers()) { + base::Value::Dict file_handler_dict; + file_handler_dict.Set("action", base::Value(file_handler.action())); + file_handler_dict.Set("display_name", file_handler.display_name()); + base::Value::List accept_list; + for (const auto& accept : file_handler.accept()) { + base::Value::Dict accept_dict; + accept_dict.Set("mimetype", accept.mimetype()); + base::Value::List file_extensions_list; + for (const auto& file_extension : accept.file_extensions()) { + file_extensions_list.Append(file_extension); + } + accept_dict.Set("file_extensions", std::move(file_extensions_list)); + accept_list.Append(std::move(accept_dict)); + } + file_handler_dict.Set("accept", std::move(accept_list)); + file_handlers_list.Append(std::move(file_handler_dict)); + } + debug_dict.Set("file_handling", std::move(file_handlers_list)); } return base::Value(std::move(debug_dict));
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index e93ff82..c018ae9 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -472,6 +472,7 @@ std::vector<apps::ProtocolHandlerInfo> protocol_handlers_; base::flat_set<std::string> allowed_launch_protocols_; base::flat_set<std::string> disallowed_launch_protocols_; + // TODO(crbug.com/1072058): No longer aiming to ship, remove. apps::UrlHandlers url_handlers_; GURL lock_screen_start_url_; GURL note_taking_new_note_url_;
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h index 4c6704a..396faa77 100644 --- a/chrome/browser/webauthn/authenticator_request_dialog_model.h +++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -248,7 +248,7 @@ AuthenticatorRequestDialogModel& operator=( const AuthenticatorRequestDialogModel&) = delete; - ~AuthenticatorRequestDialogModel(); + virtual ~AuthenticatorRequestDialogModel(); Step current_step() const { return current_step_; } @@ -512,7 +512,7 @@ void SetSelectedAuthenticatorForTesting(AuthenticatorReference authenticator); - base::span<const Mechanism> mechanisms() const; + virtual base::span<const Mechanism> mechanisms() const; // current_mechanism returns the index into |mechanisms| of the most recently // activated mechanism, or nullopt if there isn't one.
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index ae48ca74..c2d72f4 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1674475200-e498ba800953a7eed586317423d0d187692d6313.profdata +chrome-linux-main-1674539934-ca7827028b5253d87c7498c3f51b303df5a56aca.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 2167d4cd..28e3667 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1674475200-3d20295ad223daebe66b8dabfb3592056cafe3fb.profdata +chrome-mac-arm-main-1674539934-2482c366e5b92f50f7b668d196402c8ddb3cbd83.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index ea76ea5..12f2f332 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1674475200-b889e73b0d244ee979b0d9cd05fbea8dddce0f63.profdata +chrome-mac-main-1674539934-bc79d193251784ed51a16f2dde1e12bc67e29239.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index ec15b51..bc5457a 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1674442478-3e6bcf93d075e2d11475e54b64c03465e4dca39f.profdata +chrome-win32-main-1674539934-9eaed176fd4bdb8c7d1d3a73cb43300f42cf79b9.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index a30f533d..878b960 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1674464242-24768750bcc93df37fb851a20b34445b7926f40c.profdata +chrome-win64-main-1674539934-f4fa67d02fccf998715da323cd473892dc4947a5.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 3c7ae130..7114c1a 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -365,13 +365,6 @@ const base::FeatureParam<std::string> kDnsOverHttpsTemplatesParam{ &kDnsOverHttps, "Templates", ""}; -#if BUILDFLAG(IS_CHROMEOS_ASH) -// Enables the DNS-Over-HTTPS in the DNS proxy. -BASE_FEATURE(kDnsProxyEnableDOH, - "DnsProxyEnableDOH", - base::FEATURE_ENABLED_BY_DEFAULT); -#endif - #if BUILDFLAG(IS_ANDROID) // Enable loading native libraries earlier in startup on Android. BASE_FEATURE(kEarlyLibraryLoad,
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 0b35ada..d403abc 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -196,10 +196,6 @@ extern const base::FeatureParam<std::string> kDnsOverHttpsTemplatesParam; COMPONENT_EXPORT(CHROME_FEATURES) -#if BUILDFLAG(IS_CHROMEOS_ASH) -COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kDnsProxyEnableDOH); -#endif - #if BUILDFLAG(IS_ANDROID) COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kEarlyLibraryLoad); #endif
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index eeea8e6..428378f 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -306,6 +306,7 @@ queued, scanning, in_progress, + paused, success, error, need_password,
diff --git a/chrome/renderer/accessibility/ax_tree_distiller.cc b/chrome/renderer/accessibility/ax_tree_distiller.cc index 3929c20..979f651 100644 --- a/chrome/renderer/accessibility/ax_tree_distiller.cc +++ b/chrome/renderer/accessibility/ax_tree_distiller.cc
@@ -123,7 +123,7 @@ for (const ui::AXNode* content_root_node : content_root_nodes) { AddContentNodesToVector(content_root_node, &content_node_ids); } - on_ax_tree_distilled_callback_.Run(content_node_ids); + on_ax_tree_distilled_callback_.Run(tree.GetAXTreeID(), content_node_ids); } #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) @@ -141,7 +141,7 @@ const std::vector<ui::AXNodeID>& content_node_ids) { // If content nodes were identified, run callback. if (!content_node_ids.empty()) { - on_ax_tree_distilled_callback_.Run(content_node_ids); + on_ax_tree_distilled_callback_.Run(tree.GetAXTreeID(), content_node_ids); return; } @@ -154,6 +154,7 @@ } void AXTreeDistiller::OnMainContentExtractorDisconnected() { - on_ax_tree_distilled_callback_.Run(std::vector<ui::AXNodeID>()); + on_ax_tree_distilled_callback_.Run(ui::AXTreeIDUnknown(), + std::vector<ui::AXNodeID>()); } #endif
diff --git a/chrome/renderer/accessibility/ax_tree_distiller.h b/chrome/renderer/accessibility/ax_tree_distiller.h index a11e28c..68f6e0e 100644 --- a/chrome/renderer/accessibility/ax_tree_distiller.h +++ b/chrome/renderer/accessibility/ax_tree_distiller.h
@@ -11,6 +11,7 @@ #include "base/functional/callback.h" #include "components/services/screen_ai/buildflags/buildflags.h" #include "ui/accessibility/ax_node_id_forward.h" +#include "ui/accessibility/ax_tree_id.h" #include "ui/accessibility/ax_tree_update_forward.h" #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) @@ -39,6 +40,7 @@ // class AXTreeDistiller { using OnAXTreeDistilledCallback = base::RepeatingCallback<void( + const ui::AXTreeID& tree_id, const std::vector<ui::AXNodeID>& content_node_ids)>; public:
diff --git a/chrome/renderer/accessibility/ax_tree_distiller_browsertest.cc b/chrome/renderer/accessibility/ax_tree_distiller_browsertest.cc index 2814f1a..f967b69 100644 --- a/chrome/renderer/accessibility/ax_tree_distiller_browsertest.cc +++ b/chrome/renderer/accessibility/ax_tree_distiller_browsertest.cc
@@ -44,10 +44,12 @@ } void OnAXTreeDistilled(ui::AXTree* tree, + const ui::AXTreeID& tree_id, const std::vector<int32_t>& content_node_ids) { // Content node IDs list should be the same length as // |expected_node_contents_|. EXPECT_EQ(content_node_ids.size(), expected_node_contents_.size()); + EXPECT_EQ(tree_id, tree->GetAXTreeID()); // Iterate through each content node ID from distiller and check that the // text value equals the passed-in string from |expected_node_contents_|.
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything_app_controller.cc index 364b8f73..c16fb55 100644 --- a/chrome/renderer/accessibility/read_anything_app_controller.cc +++ b/chrome/renderer/accessibility/read_anything_app_controller.cc
@@ -25,6 +25,7 @@ #include "third_party/blink/public/web/blink.h" #include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/public/web/web_script_source.h" +#include "ui/accessibility/ax_enum_util.h" #include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_selection.h" #include "ui/accessibility/ax_serializable_tree.h" @@ -124,6 +125,27 @@ direction); } +void SetAXNodeDataTextStyle(v8::Isolate* isolate, + gin::Dictionary* v8_dict, + ui::AXNodeData* ax_node_data) { + v8::Local<v8::Value> v8_text_style; + v8_dict->Get("textStyle", &v8_text_style); + std::string text_style; + gin::ConvertFromV8(isolate, v8_text_style, &text_style); + if (text_style.find("underline") != std::string::npos) { + ax_node_data->AddTextStyle(ax::mojom::TextStyle::kUnderline); + } + if (text_style.find("overline") != std::string::npos) { + ax_node_data->AddTextStyle(ax::mojom::TextStyle::kOverline); + } + if (text_style.find("italic") != std::string::npos) { + ax_node_data->AddTextStyle(ax::mojom::TextStyle::kItalic); + } + if (text_style.find("bold") != std::string::npos) { + ax_node_data->AddTextStyle(ax::mojom::TextStyle::kBold); + } +} + void SetAXNodeDataUrl(v8::Isolate* isolate, gin::Dictionary* v8_dict, ui::AXNodeData* ax_node_data) { @@ -216,6 +238,7 @@ SetAXNodeDataHtmlTag(isolate, &v8_node_dict, &ax_node_data); SetAXNodeDataLanguage(isolate, &v8_node_dict, &ax_node_data); SetAXNodeDataTextDirection(isolate, &v8_node_dict, &ax_node_data); + SetAXNodeDataTextStyle(isolate, &v8_node_dict, &ax_node_data); SetAXNodeDataUrl(isolate, &v8_node_dict, &ax_node_data); snapshot.nodes.push_back(ax_node_data); } @@ -424,6 +447,7 @@ } void ReadAnythingAppController::OnAXTreeDistilled( + const ui::AXTreeID& tree_id, const std::vector<ui::AXNodeID>& content_node_ids) { // Reset state. display_node_ids_.clear(); @@ -434,12 +458,18 @@ content_node_ids_ = content_node_ids; distillation_in_progress_ = false; - // This callback could be called after the AXTree was destroyed. In that case, - // return early. - if (active_tree_id_ == ui::AXTreeIDUnknown()) { + // Return early if any of the following scenarios occurred while waiting for + // distillation to complete: + // 1. tree_id != active_tree_id_: The active tree was changed. + // 2. active_tree_id_ == ui::AXTreeIDUnknown(): The active tree was change to + // an unknown tree id. + // 3. !base::Contains(trees_, tree_id): The distilled tree was destroyed. + // 4. tree_id == ui::AXTreeIDUnknown(): The distiller sent back an unknown + // tree id which occurs when there was an error. + if (tree_id != active_tree_id_ || active_tree_id_ == ui::AXTreeIDUnknown() || + !base::Contains(trees_, tree_id) || tree_id == ui::AXTreeIDUnknown()) { return; } - DCHECK(base::Contains(trees_, active_tree_id_)); ui::AXSelection selection = trees_[active_tree_id_]->GetUnignoredSelection(); has_selection_ = selection.anchor_object_id != ui::kInvalidAXNodeID && selection.focus_object_id != ui::kInvalidAXNodeID; @@ -604,6 +634,8 @@ .SetMethod("getLanguage", &ReadAnythingAppController::GetLanguage) .SetMethod("getTextContent", &ReadAnythingAppController::GetTextContent) .SetMethod("getUrl", &ReadAnythingAppController::GetUrl) + .SetMethod("shouldBold", &ReadAnythingAppController::ShouldBold) + .SetMethod("isOverline", &ReadAnythingAppController::IsOverline) .SetMethod("onConnected", &ReadAnythingAppController::OnConnected) .SetMethod("onLinkClicked", &ReadAnythingAppController::OnLinkClicked) .SetMethod("setContentForTesting", @@ -660,7 +692,11 @@ ui::AXNodeID ax_node_id) const { ui::AXNode* ax_node = GetAXNode(ax_node_id); DCHECK(ax_node); - return ax_node->GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag); + + // Replace mark element with bold element for readability + std::string html_tag = + ax_node->GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag); + return html_tag == ui::ToString(ax::mojom::Role::kMark) ? "b" : html_tag; } std::string ReadAnythingAppController::GetLanguage( @@ -718,6 +754,21 @@ return ax_node->GetStringAttribute(ax::mojom::StringAttribute::kUrl); } +bool ReadAnythingAppController::ShouldBold(ui::AXNodeID ax_node_id) const { + ui::AXNode* ax_node = GetAXNode(ax_node_id); + DCHECK(ax_node); + bool isBold = ax_node->HasTextStyle(ax::mojom::TextStyle::kBold); + bool isItalic = ax_node->HasTextStyle(ax::mojom::TextStyle::kItalic); + bool isUnderline = ax_node->HasTextStyle(ax::mojom::TextStyle::kUnderline); + return isBold || isItalic || isUnderline; +} + +bool ReadAnythingAppController::IsOverline(ui::AXNodeID ax_node_id) const { + ui::AXNode* ax_node = GetAXNode(ax_node_id); + DCHECK(ax_node); + return ax_node->HasTextStyle(ax::mojom::TextStyle::kOverline); +} + void ReadAnythingAppController::OnConnected() { mojo::PendingReceiver<read_anything::mojom::PageHandlerFactory> page_handler_factory_receiver = @@ -764,7 +815,7 @@ GetSnapshotFromV8SnapshotLite(isolate, v8_snapshot_lite); AccessibilityEventReceived(snapshot.tree_data.tree_id, {snapshot}, {}); OnActiveAXTreeIDChanged(snapshot.tree_data.tree_id); - OnAXTreeDistilled(content_node_ids); + OnAXTreeDistilled(snapshot.tree_data.tree_id, content_node_ids); } AXTreeDistiller* ReadAnythingAppController::SetDistillerForTesting(
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.h b/chrome/renderer/accessibility/read_anything_app_controller.h index b8f0acf..d676ac0c 100644 --- a/chrome/renderer/accessibility/read_anything_app_controller.h +++ b/chrome/renderer/accessibility/read_anything_app_controller.h
@@ -109,6 +109,8 @@ std::string GetTextContent(ui::AXNodeID ax_node_id) const; std::string GetTextDirection(ui::AXNodeID ax_node_id) const; std::string GetUrl(ui::AXNodeID ax_node_id) const; + bool ShouldBold(ui::AXNodeID ax_node_id) const; + bool IsOverline(ui::AXNodeID ax_node_id) const; void OnConnected(); void OnLinkClicked(ui::AXNodeID ax_node_id) const; @@ -119,7 +121,8 @@ const ui::AXTreeID& tree_id); // Called when distillation has completed. - void OnAXTreeDistilled(const std::vector<ui::AXNodeID>& content_node_ids); + void OnAXTreeDistilled(const ui::AXTreeID& tree_id, + const std::vector<ui::AXNodeID>& content_node_ids); // Helper functions for the rendering algorithm. Post-process the AXTree and // cache values before sending an `updateContent` notification to the Read
diff --git a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc index 35c5216..c50d1c2a 100644 --- a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc +++ b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
@@ -97,7 +97,12 @@ } void OnAXTreeDistilled(const std::vector<ui::AXNodeID>& content_node_ids) { - controller_->OnAXTreeDistilled(content_node_ids); + OnAXTreeDistilled(tree_id_, content_node_ids); + } + + void OnAXTreeDistilled(const ui::AXTreeID& tree_id, + const std::vector<ui::AXNodeID>& content_node_ids) { + controller_->OnAXTreeDistilled(tree_id, content_node_ids); } void OnAXTreeDestroyed(const ui::AXTreeID& tree_id) { @@ -138,6 +143,14 @@ return controller_->GetUrl(ax_node_id); } + bool ShouldBold(ui::AXNodeID ax_node_id) { + return controller_->ShouldBold(ax_node_id); + } + + bool IsOverline(ui::AXNodeID ax_node_id) { + return controller_->IsOverline(ax_node_id); + } + size_t GetNumTrees() { return controller_->trees_.size(); } size_t GetNumPendingUpdates() { return controller_->pending_updates_.size(); } @@ -421,6 +434,37 @@ EXPECT_EQ(missing_url, GetUrl(4)); } +TEST_F(ReadAnythingAppControllerTest, ShouldBold) { + ui::AXTreeUpdate update; + SetUpdateTreeID(&update); + update.nodes.resize(3); + update.nodes[0].id = 2; + update.nodes[1].id = 3; + update.nodes[2].id = 4; + update.nodes[0].AddTextStyle(ax::mojom::TextStyle::kOverline); + update.nodes[1].AddTextStyle(ax::mojom::TextStyle::kUnderline); + update.nodes[2].AddTextStyle(ax::mojom::TextStyle::kItalic); + AccessibilityEventReceived({update}); + OnAXTreeDistilled({}); + EXPECT_EQ(false, ShouldBold(2)); + EXPECT_EQ(true, ShouldBold(3)); + EXPECT_EQ(true, ShouldBold(4)); +} + +TEST_F(ReadAnythingAppControllerTest, IsOverline) { + ui::AXTreeUpdate update; + SetUpdateTreeID(&update); + update.nodes.resize(2); + update.nodes[0].id = 2; + update.nodes[1].id = 3; + update.nodes[0].AddTextStyle(ax::mojom::TextStyle::kOverline); + update.nodes[1].AddTextStyle(ax::mojom::TextStyle::kUnderline); + AccessibilityEventReceived({update}); + OnAXTreeDistilled({}); + EXPECT_EQ(true, IsOverline(2)); + EXPECT_EQ(false, IsOverline(3)); +} + TEST_F(ReadAnythingAppControllerTest, DisplayNodeIdsContains_Selection) { ui::AXTreeUpdate update; SetUpdateTreeID(&update); @@ -792,3 +836,30 @@ OnActiveAXTreeIDChanged(tree_id_); EXPECT_EQ("567", GetTextContent(1)); } + +TEST_F(ReadAnythingAppControllerTest, + OnAXTreeDistilledCalledWithInactiveTreeId) { + OnActiveAXTreeIDChanged(ui::AXTreeID::CreateNewAXTreeID()); + // Should not crash. + OnAXTreeDistilled({}); +} + +TEST_F(ReadAnythingAppControllerTest, + OnAXTreeDistilledCalledWithDestroyedTreeId) { + OnAXTreeDestroyed(tree_id_); + // Should not crash. + OnAXTreeDistilled({}); +} + +TEST_F(ReadAnythingAppControllerTest, + OnAXTreeDistilledCalledWithUnknownActiveTreeId) { + OnActiveAXTreeIDChanged(ui::AXTreeIDUnknown()); + // Should not crash. + OnAXTreeDistilled({}); +} + +TEST_F(ReadAnythingAppControllerTest, + OnAXTreeDistilledCalledWithUnknownTreeId) { + // Should not crash. + OnAXTreeDistilled(ui::AXTreeIDUnknown(), {}); +}
diff --git a/chrome/renderer/net/available_offline_content_helper.cc b/chrome/renderer/net/available_offline_content_helper.cc index 7d59164..bc40df8e 100644 --- a/chrome/renderer/net/available_offline_content_helper.cc +++ b/chrome/renderer/net/available_offline_content_helper.cc
@@ -71,11 +71,11 @@ base::Value AvailableContentListToValue( const std::vector<AvailableOfflineContentPtr>& content_list) { - base::Value value(base::Value::Type::LIST); + base::Value::List value; for (const auto& content : content_list) { value.Append(AvailableContentToValue(content)); } - return value; + return base::Value(std::move(value)); } void RecordSuggestionPresented(
diff --git a/chrome/services/keymaster/public/mojom/cert_store.mojom b/chrome/services/keymaster/public/mojom/cert_store.mojom index 98fc48c4..6a65fba6 100644 --- a/chrome/services/keymaster/public/mojom/cert_store.mojom +++ b/chrome/services/keymaster/public/mojom/cert_store.mojom
@@ -9,30 +9,6 @@ module arc.keymaster.mojom; -// Enumerates the crypto algorithms supported by Host. -[Extensible] -enum Algorithm { - kRsaPkcs1, -}; - -// Enumerates the digests supported by Host. -[Extensible] -enum Digest { - kSha1, - kSha256, - kSha384, - kSha512, -}; - -// Enumerates the result codes of signature operation. -[Extensible] -enum SignatureResult { - kOk, - // Failed with net or internal error on chrome side. - kFailed, - kUnsupportedAlgorithm, -}; - // The possible chaps slots relevant for arc-keymaster. Note this does NOT map // to the PKCS#11 CK_SLOT_ID, but rather to an abstract representation of the // value. The corresponding CK_SLOT_ID must be queried from cryptohome. @@ -74,19 +50,3 @@ // Updates info about the latest set of keys owned by Chrome OS. UpdatePlaceholderKeys@1(array<ChromeOsKey> keys) => (bool success); }; - -// Implemented in Chrome. -// Nothing is using this interface. It is only kept to avoid changing -// CertStoreHost. -// Deprecated method IDs: 0 -// Next method ID: 1 -interface SecurityTokenOperation { - // Signs input |data| pre-hashed with the given |digest|. - // Retrieves a |signature| signed by a certificate identified by - // |subject_public_key_info| by |algorithm| (currently, only RSA is - // supported). - // In case of any error, |signature| is null. - SignDigest@0(string subject_public_key_info, Algorithm algorithm, - Digest digest, array<uint8> data) => (SignatureResult result, - array<uint8>? signature); -};
diff --git a/chrome/services/sharing/nearby/platform/wifi_lan_medium_unittest.cc b/chrome/services/sharing/nearby/platform/wifi_lan_medium_unittest.cc index b7537e1..d16a4811 100644 --- a/chrome/services/sharing/nearby/platform/wifi_lan_medium_unittest.cc +++ b/chrome/services/sharing/nearby/platform/wifi_lan_medium_unittest.cc
@@ -261,7 +261,7 @@ ipv4.Set(shill::kMethodProperty, shill::kTypeIPv4); cros_network_config_helper_->network_state_helper() .ip_config_test() - ->AddIPConfig(kIPv4ConfigPath, base::Value(std::move(ipv4))); + ->AddIPConfig(kIPv4ConfigPath, std::move(ipv4)); base::RunLoop().RunUntilIdle(); }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 21022c81..66d691c 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2209,7 +2209,6 @@ "../browser/ui/ask_google_for_suggestions_dialog_browsertest.cc", "../browser/ui/autofill/edit_address_profile_dialog_controller_impl_browsertest.cc", "../browser/ui/autofill/payments/card_unmask_prompt_view_browsertest.cc", - "../browser/ui/autofill/payments/card_unmask_prompt_view_tester.h", "../browser/ui/autofill/payments/save_card_bubble_controller_impl_browsertest.cc", "../browser/ui/autofill/payments/save_upi_bubble_controller_impl_browsertest.cc", "../browser/ui/autofill/save_update_address_profile_bubble_controller_impl_browsertest.cc", @@ -3418,8 +3417,6 @@ "../browser/ui/views/autofill/payments/autofill_progress_dialog_views_browsertest.cc", "../browser/ui/views/autofill/payments/card_unmask_authentication_selection_dialog_browsertest.cc", "../browser/ui/views/autofill/payments/card_unmask_otp_input_dialog_browsertest.cc", - "../browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.cc", - "../browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.h", "../browser/ui/views/autofill/payments/credit_card_access_manager_browsertest.cc", "../browser/ui/views/autofill/payments/offer_notification_bubble_views_browsertest.cc", "../browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc", @@ -7018,6 +7015,7 @@ "../browser/ui/views/webid/fake_delegate.cc", "../browser/ui/views/webid/fake_delegate.h", "../browser/ui/views/webid/fedcm_account_selection_view_desktop_unittest.cc", + "../browser/ui/webauthn/sheet_models_unittest.cc", "../browser/ui/webui/access_code_cast/access_code_cast_handler_unittest.cc", "../browser/ui/webui/browser_command/browser_command_handler_unittest.cc", "../browser/ui/webui/commerce/shopping_list_context_menu_controller_unittest.cc", @@ -7265,6 +7263,7 @@ "//components/commerce/core:coupon_db_content_proto", "//components/commerce/core:shopping_service_test_support", "//components/endpoint_fetcher:endpoint_fetcher", + "//components/endpoint_fetcher:test_support", "//components/enterprise", "//components/enterprise:test_support", "//components/feature_engagement/test:test_support", @@ -8514,6 +8513,7 @@ "../browser/safe_browsing/extension_telemetry/cookies_get_all_signal_unittest.cc", "../browser/safe_browsing/extension_telemetry/cookies_get_signal_processor_unittest.cc", "../browser/safe_browsing/extension_telemetry/cookies_get_signal_unittest.cc", + "../browser/safe_browsing/extension_telemetry/extension_telemetry_config_manager_unittest.cc", "../browser/safe_browsing/extension_telemetry/extension_telemetry_file_processor_unittest.cc", "../browser/safe_browsing/extension_telemetry/extension_telemetry_persister_unittest.cc", "../browser/safe_browsing/extension_telemetry/extension_telemetry_service_unittest.cc", @@ -9201,8 +9201,13 @@ "../browser/ssl/cert_verifier_browser_test.h", "../browser/ssl/cert_verifier_platform_browser_test.cc", "../browser/ssl/cert_verifier_platform_browser_test.h", + "../browser/ui/autofill/payments/card_unmask_prompt_view_tester.h", + "../browser/ui/autofill/payments/test_card_unmask_prompt_waiter.cc", + "../browser/ui/autofill/payments/test_card_unmask_prompt_waiter.h", "../browser/ui/search/ntp_test_utils.cc", "../browser/ui/search/ntp_test_utils.h", + "../browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.cc", + "../browser/ui/views/autofill/payments/card_unmask_prompt_view_tester_views.h", "../browser/ui/views/autofill/payments/offer_notification_bubble_views_test_base.cc", "../browser/ui/views/autofill/payments/offer_notification_bubble_views_test_base.h", "../browser/ui/views/tabs/tab_hover_card_test_util.cc", @@ -10283,8 +10288,6 @@ "../browser/sync/test/integration/bookmarks_helper.h", "../browser/sync/test/integration/committed_all_nudged_changes_checker.cc", "../browser/sync/test/integration/committed_all_nudged_changes_checker.h", - "../browser/sync/test/integration/configuration_refresher.cc", - "../browser/sync/test/integration/configuration_refresher.h", "../browser/sync/test/integration/contact_info_helper.cc", "../browser/sync/test/integration/contact_info_helper.h", "../browser/sync/test/integration/device_info_helper.cc",
diff --git a/chrome/test/base/chrome_unit_test_suite.cc b/chrome/test/base/chrome_unit_test_suite.cc index b356b796..2a71ca640 100644 --- a/chrome/test/base/chrome_unit_test_suite.cc +++ b/chrome/test/base/chrome_unit_test_suite.cc
@@ -30,6 +30,7 @@ #include "extensions/buildflags/buildflags.h" #include "gpu/ipc/service/image_transport_surface.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/accessibility/ax_mode.h" #include "ui/accessibility/platform/ax_platform_node.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_handle.h" @@ -83,7 +84,16 @@ TestingBrowserProcess::DeleteInstance(); // Some tests cause ChildThreadImpl to initialize a PowerMonitor. base::PowerMonitor::ShutdownForTesting(); - DCHECK(ui::AXPlatformNode::GetAccessibilityMode() == ui::AXMode::kNone) +#if BUILDFLAG(IS_WIN) + // Running tests locally on Windows machines with some degree of + // accessibility enabled can cause this flag to become implicitly set. + constexpr uint32_t kAllowedFlags = ui::AXMode::kNativeAPIs; +#else + constexpr uint32_t kAllowedFlags = ui::AXMode::kNone; +#endif + DCHECK_EQ( + kAllowedFlags, + ui::AXPlatformNode::GetAccessibilityMode().flags() | kAllowedFlags) << "Please use ScopedAXModeSetter, or add a call to " "AXPlatformNode::SetAXMode(ui::AXMode::kNone) at the end of your " "test.";
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index b776ba6..9dff2cc 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -21860,5 +21860,17 @@ } } ] + }, + "ScreensaverEnabled" : { + "reason_for_missing_test": "TODO(b/175142676): Feature not yet implemented" + }, + "ScreensaverIdleTimeoutSeconds" : { + "reason_for_missing_test": "TODO(b/175142676): Feature not yet implemented" + }, + "ScreensaverImageDisplayIntervalSeconds" : { + "reason_for_missing_test": "TODO(b/175142676): Feature not yet implemented" + }, + "ScreensaverImages" : { + "reason_for_missing_test": "TODO(b/175142676): Feature not yet implemented" } }
diff --git a/chrome/test/data/printing/on_before_after_events.html b/chrome/test/data/printing/on_before_after_events.html new file mode 100644 index 0000000..0d3ecb9 --- /dev/null +++ b/chrome/test/data/printing/on_before_after_events.html
@@ -0,0 +1,13 @@ +<!doctype html> +<html> +<script> +let firedBeforePrint = false; +let firedAfterPrint = false; +window.addEventListener('beforeprint', function (_) { + firedBeforePrint = true; +}); +window.addEventListener('afterprint', function (_) { + firedAfterPrint = true; +}); +</script> +</html>
diff --git a/chrome/test/data/webrtc/peerconnection_getstats.js b/chrome/test/data/webrtc/peerconnection_getstats.js index 135ddf29..7a6e66fb 100644 --- a/chrome/test/data/webrtc/peerconnection_getstats.js +++ b/chrome/test/data/webrtc/peerconnection_getstats.js
@@ -147,6 +147,7 @@ estimatedPlayoutTimestamp: 'number', fractionLost: 'number', // Obsolete, moved to RTCRemoteInboundRtpStreamStats. decoderImplementation: 'string', + playoutId: 'string', powerEfficientDecoder: 'boolean', framesAssembledFromMultiplePackets: 'number', totalAssemblyTime: 'number', @@ -494,6 +495,20 @@ }); addRTCStatsToAllowlist(Presence.MANDATORY, 'certificate', kRTCCertificateStats); +/* + * RTCAudioPlayoutStats + * https://w3c.github.io/webrtc-stats/#playoutstats-dict* + * @private + */ +let kRTCAudioPlayoutStats = new RTCStats(null, { + synthesizedSamplesDuration: 'number', + synthesizedSamplesEvents: 'number', + totalSamplesDuration: 'number', + totalPlayoutDelay: 'number', + totalSamplesCount: 'number', +}); +addRTCStatsToAllowlist(Presence.OPTIONAL, 'audio-playout', kRTCAudioPlayoutStats); + // Public interface to tests. These are expected to be called with // ExecuteJavascript invocations from the browser tests and will return answers // through the DOM automation controller.
diff --git a/chrome/test/data/webui/bookmarks/BUILD.gn b/chrome/test/data/webui/bookmarks/BUILD.gn index 4a0f615c..693cd23 100644 --- a/chrome/test/data/webui/bookmarks/BUILD.gn +++ b/chrome/test/data/webui/bookmarks/BUILD.gn
@@ -31,7 +31,7 @@ "test_browser_proxy.ts", "test_command_manager.ts", "test_store.ts", - "test_timer_proxy.js", + "test_timer_proxy.ts", "test_util.ts", "toolbar_test.ts", "util_test.ts",
diff --git a/chrome/test/data/webui/bookmarks/dnd_manager_test.ts b/chrome/test/data/webui/bookmarks/dnd_manager_test.ts index 747d123..d8a4229 100644 --- a/chrome/test/data/webui/bookmarks/dnd_manager_test.ts +++ b/chrome/test/data/webui/bookmarks/dnd_manager_test.ts
@@ -3,10 +3,9 @@ // found in the LICENSE file. import {BookmarkElement, BookmarkManagerApiProxyImpl, BookmarksAppElement, BookmarksFolderNodeElement, BookmarksItemElement, BookmarksListElement, BrowserProxyImpl, DndManager, DragInfo, overrideFolderOpenerTimeoutDelay, setDebouncerForTesting} from 'chrome://bookmarks/bookmarks.js'; -import {assertNotReached} from 'chrome://resources/js/assert_ts.js'; import {middleOfNode, topLeftOfNode} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {assertDeepEquals, assertEquals, assertFalse, assertNotReached, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; import {TestBookmarkManagerApiProxy} from './test_bookmark_manager_api_proxy.js';
diff --git a/chrome/test/data/webui/bookmarks/test_timer_proxy.js b/chrome/test/data/webui/bookmarks/test_timer_proxy.js deleted file mode 100644 index 4173e3513..0000000 --- a/chrome/test/data/webui/bookmarks/test_timer_proxy.js +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// TODO(calamity): Remove TestTimerProxy in favor of MockTimer. -export class TestTimerProxy { - constructor() { - this.immediatelyResolveTimeouts = true; - - /** @private {number} */ - this.nextTimeoutId_ = 0; - - /** @private {!Map<number, !Function>} */ - this.activeTimeouts_ = new Map(); - } - - /** - * @param {Function} fn - * @param {number=} delay - * @return {number} - * @override - */ - setTimeout(fn, delay) { - if (this.immediatelyResolveTimeouts) { - fn(); - } else { - this.activeTimeouts_.set(this.nextTimeoutId_, fn); - } - - return this.nextTimeoutId_++; - } - - /** - * @param {number} id - * @override - */ - clearTimeout(id) { - this.activeTimeouts_.delete(id); - } - - /** - * Run the function associated with a timeout id and clear it from the - * active timeouts. - * @param {number} id - */ - runTimeoutFn(id) { - this.activeTimeouts_.get(id)(); - this.clearTimeout(id); - } - - /** - * Returns true if a given timeout id has not been run or cleared. - * @param {number} id - * @return {boolean} Whether a given timeout id has not been run or - * cleared. - */ - hasTimeout(id) { - return this.activeTimeouts_.has(id); - } -}
diff --git a/chrome/test/data/webui/bookmarks/test_timer_proxy.ts b/chrome/test/data/webui/bookmarks/test_timer_proxy.ts new file mode 100644 index 0000000..0de69c1 --- /dev/null +++ b/chrome/test/data/webui/bookmarks/test_timer_proxy.ts
@@ -0,0 +1,44 @@ +// Copyright 2017 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {assert} from 'chrome://resources/js/assert_ts.js'; + +// TODO(calamity): Remove TestTimerProxy in favor of MockTimer. +export class TestTimerProxy { + immediatelyResolveTimeouts: boolean = true; + private nextTimeoutId_: number = 0; + private activeTimeouts_: Map<number, Function> = new Map(); + + setTimeout(fn: Function, _delay: number): number { + if (this.immediatelyResolveTimeouts) { + fn(); + } else { + this.activeTimeouts_.set(this.nextTimeoutId_, fn); + } + + return this.nextTimeoutId_++; + } + + clearTimeout(id: number) { + this.activeTimeouts_.delete(id); + } + + /** + * Run the function associated with a timeout id and clear it from the + * active timeouts. + */ + runTimeoutFn(id: number) { + const fn = this.activeTimeouts_.get(id); + assert(fn); + fn(); + this.clearTimeout(id); + } + + /** + * Returns true if a given timeout id has not been run or cleared. + */ + hasTimeout(id: number): boolean { + return this.activeTimeouts_.has(id); + } +}
diff --git a/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_dialog_test.ts b/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_dialog_test.ts index d3d4fa88..365959b 100644 --- a/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_dialog_test.ts +++ b/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_dialog_test.ts
@@ -308,4 +308,58 @@ [UserAction.kCancel], testProxy.handler.getArgs('respondWithUserActionAndClose')); })); + + /** + * Test that completing the Setup flow from the OneDrive Upload Page triggers + * the `setOfficeAsDefaultHandler` mojo request when this is the first time + * the Setup flow is running. + */ + test( + 'Office PWA set as default handler when the Setup flow is running', + async () => { + await setUp({ + officeWebAppInstalled: false, + installOfficeWebAppResult: true, + odfsMounted: true, + dialogPage: DialogPage.kOneDriveSetup, + firstTimeSetup: true, + }); + // Go to the OneDrive upload page. + await doWelcomePage(); + await doPWAInstallPage(); + checkIsOneDriveUploadPage(); + + // Click the open file button. + cloudUploadApp.$('.action-button').click(); + + assertEquals( + 1, testProxy.handler.getCallCount('setOfficeAsDefaultHandler')); + }); + + /** + * Test that completing the Setup flow from the OneDrive Upload Page does not + * trigger the `setOfficeAsDefaultHandler` mojo request when this is not the + * first time the Setup flow is not running, i.e. the Fixup flow is running. + */ + test( + 'Office PWA not set as default handler when the Fixup flow is running', + async () => { + await setUp({ + officeWebAppInstalled: false, + installOfficeWebAppResult: true, + odfsMounted: true, + dialogPage: DialogPage.kOneDriveSetup, + firstTimeSetup: false, + }); + // Go to the OneDrive upload page. + await doWelcomePage(); + await doPWAInstallPage(); + checkIsOneDriveUploadPage(); + + // Click the open file button. + cloudUploadApp.$('.action-button').click(); + + assertEquals( + 0, testProxy.handler.getCallCount('setOfficeAsDefaultHandler')); + }); }); \ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_test_browser_proxy.ts b/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_test_browser_proxy.ts index 9b20048..eee3d5b 100644 --- a/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_test_browser_proxy.ts +++ b/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_test_browser_proxy.ts
@@ -13,6 +13,7 @@ odfsMounted: boolean; dialogPage: DialogPage; tasks?: DialogTask[]|null; + firstTimeSetup?: boolean|null; } /** @@ -28,6 +29,7 @@ fileNames: [], dialogPage: options.dialogPage, tasks: [], + firstTimeSetup: true, }; if (options.fileName != null) { args.fileNames.push(options.fileName); @@ -35,6 +37,9 @@ if (options.tasks != null) { args.tasks = options.tasks; } + if (options.firstTimeSetup != null) { + args.firstTimeSetup = options.firstTimeSetup; + } this.handler.setResultFor('getDialogArgs', {args: args}); this.handler.setResultFor( 'isOfficeWebAppInstalled', {installed: options.officeWebAppInstalled});
diff --git a/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn b/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn index d7362447..0a24c5f 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn +++ b/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
@@ -20,7 +20,8 @@ target_gen_dir), ] in_files = [ - "ambient_preview_element_test.ts", + "ambient_preview_large_element_test.ts", + "ambient_preview_small_element_test.ts", "ambient_subpage_element_test.ts", "avatar_camera_element_test.ts", "avatar_list_element_test.ts",
diff --git a/chrome/test/data/webui/chromeos/personalization_app/ambient_preview_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/ambient_preview_large_element_test.ts similarity index 80% rename from chrome/test/data/webui/chromeos/personalization_app/ambient_preview_element_test.ts rename to chrome/test/data/webui/chromeos/personalization_app/ambient_preview_large_element_test.ts index a184aa0..457cb55 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/ambient_preview_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/ambient_preview_large_element_test.ts
@@ -1,11 +1,11 @@ -// Copyright 2022 The Chromium Authors +// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'chrome://personalization/strings.m.js'; import 'chrome://webui-test/mojo_webui_test_support.js'; -import {AmbientObserver, AmbientPreview, Paths, PersonalizationRouter, TopicSource} from 'chrome://personalization/js/personalization_app.js'; +import {AmbientObserver, AmbientPreviewLarge, Paths, PersonalizationRouter, TopicSource} from 'chrome://personalization/js/personalization_app.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; @@ -16,8 +16,8 @@ import {TestPersonalizationStore} from './test_personalization_store.js'; -suite('AmbientPreviewTest', function() { - let ambientPreviewElement: AmbientPreview|null; +suite('AmbientPreviewLargeTest', function() { + let ambientPreviewLargeElement: AmbientPreviewLarge|null; let ambientProvider: TestAmbientProvider; let personalizationStore: TestPersonalizationStore; const routerOriginal = PersonalizationRouter.instance; @@ -32,8 +32,8 @@ }); teardown(async () => { - await teardownElement(ambientPreviewElement); - ambientPreviewElement = null; + await teardownElement(ambientPreviewLargeElement); + ambientPreviewLargeElement = null; AmbientObserver.shutdown(); PersonalizationRouter.instance = routerOriginal; }); @@ -45,19 +45,20 @@ personalizationStore.data.ambient.ambientModeEnabled = false; personalizationStore.data.ambient.googlePhotosAlbumsPreviews = ambientProvider.googlePhotosAlbumsPreviews; - ambientPreviewElement = initElement(AmbientPreview); + ambientPreviewLargeElement = initElement(AmbientPreviewLarge); personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientPreviewElement); + await waitAfterNextRender(ambientPreviewLargeElement); const messageContainer = - ambientPreviewElement.shadowRoot!.getElementById( + ambientPreviewLargeElement.shadowRoot!.getElementById( 'messageContainer'); assertTrue(!!messageContainer); const textSpan = messageContainer.querySelector<HTMLSpanElement>( '#turnOnDescription'); assertTrue(!!textSpan); assertEquals( - ambientPreviewElement.i18n('ambientModeMainPageZeroStateMessageV2'), + ambientPreviewLargeElement.i18n( + 'ambientModeMainPageZeroStateMessageV2'), textSpan.innerText.trim()); }); @@ -69,12 +70,12 @@ personalizationStore.data.ambient.ambientModeEnabled = false; personalizationStore.data.ambient.googlePhotosAlbumsPreviews = ambientProvider.googlePhotosAlbumsPreviews; - ambientPreviewElement = initElement(AmbientPreview); + ambientPreviewLargeElement = initElement(AmbientPreviewLarge); personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientPreviewElement); + await waitAfterNextRender(ambientPreviewLargeElement); const messageContainer = - ambientPreviewElement.shadowRoot!.getElementById( + ambientPreviewLargeElement.shadowRoot!.getElementById( 'messageContainer'); assertTrue(!!messageContainer); const button = messageContainer.querySelector('cr-button'); @@ -108,9 +109,9 @@ ambientModeEnabled: true, googlePhotosAlbumsPreviews: ambientProvider.googlePhotosAlbumsPreviews, }; - ambientPreviewElement = initElement(AmbientPreview, {clickable: true}); + ambientPreviewLargeElement = initElement(AmbientPreviewLarge); personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientPreviewElement); + await waitAfterNextRender(ambientPreviewLargeElement); const original = PersonalizationRouter.instance; const goToRoutePromise = new Promise<[Paths, Object]>(resolve => { @@ -124,7 +125,7 @@ }; }); - ambientPreviewElement.shadowRoot! + ambientPreviewLargeElement.shadowRoot! .querySelector<HTMLImageElement>('.preview-image.clickable')!.click(); const [path, queryParams] = await goToRoutePromise; @@ -144,9 +145,9 @@ ambientModeEnabled: true, googlePhotosAlbumsPreviews: ambientProvider.googlePhotosAlbumsPreviews, }; - ambientPreviewElement = initElement(AmbientPreview, {clickable: true}); + ambientPreviewLargeElement = initElement(AmbientPreviewLarge); personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientPreviewElement); + await waitAfterNextRender(ambientPreviewLargeElement); function setFakeRouter() { const original = PersonalizationRouter.instance; @@ -164,8 +165,8 @@ const artGalleryPromise = setFakeRouter(); - ambientPreviewElement.shadowRoot!.getElementById( - 'collageContainer')!.click(); + ambientPreviewLargeElement.shadowRoot!.getElementById( + 'collageContainer')!.click(); let topicSource = await artGalleryPromise; assertEquals( @@ -178,8 +179,8 @@ personalizationStore.notifyObservers(); const googlePhotosPromise = setFakeRouter(); - ambientPreviewElement.shadowRoot!.getElementById( - 'collageContainer')!.click(); + ambientPreviewLargeElement.shadowRoot!.getElementById( + 'collageContainer')!.click(); topicSource = await googlePhotosPromise; assertEquals( @@ -197,9 +198,9 @@ ambientModeEnabled: true, googlePhotosAlbumsPreviews: ambientProvider.googlePhotosAlbumsPreviews, }; - ambientPreviewElement = initElement(AmbientPreview, {clickable: true}); + ambientPreviewLargeElement = initElement(AmbientPreviewLarge); personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientPreviewElement); + await waitAfterNextRender(ambientPreviewLargeElement); function setFakeRouter() { const original = PersonalizationRouter.instance; @@ -217,8 +218,8 @@ const artGalleryPromise = setFakeRouter(); - ambientPreviewElement.shadowRoot!.getElementById( - 'thumbnailContainer')!.click(); + ambientPreviewLargeElement.shadowRoot!.getElementById( + 'thumbnailContainer')!.click(); let topicSource = await artGalleryPromise; assertEquals( @@ -231,8 +232,8 @@ personalizationStore.notifyObservers(); const googlePhotosPromise = setFakeRouter(); - ambientPreviewElement.shadowRoot!.getElementById( - 'thumbnailContainer')!.click(); + ambientPreviewLargeElement.shadowRoot!.getElementById( + 'thumbnailContainer')!.click(); topicSource = await googlePhotosPromise; assertEquals( @@ -249,18 +250,19 @@ personalizationStore.data.ambient.ambientModeEnabled = false; personalizationStore.data.ambient.googlePhotosAlbumsPreviews = ambientProvider.googlePhotosAlbumsPreviews; - ambientPreviewElement = initElement(AmbientPreview); + ambientPreviewLargeElement = initElement(AmbientPreviewLarge); personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientPreviewElement); + await waitAfterNextRender(ambientPreviewLargeElement); const messageContainer = - ambientPreviewElement.shadowRoot!.getElementById('messageContainer'); + ambientPreviewLargeElement.shadowRoot!.getElementById( + 'messageContainer'); assertTrue(!!messageContainer); const textSpan = messageContainer.querySelector<HTMLSpanElement>('#turnOnDescription'); assertTrue(!!textSpan); assertEquals( - ambientPreviewElement.i18n('ambientModeMainPageZeroStateMessage'), + ambientPreviewLargeElement.i18n('ambientModeMainPageZeroStateMessage'), textSpan.innerText.trim()); }); @@ -278,19 +280,19 @@ personalizationStore.data.ambient.ambientModeEnabled = false; personalizationStore.data.ambient.googlePhotosAlbumsPreviews = ambientProvider.googlePhotosAlbumsPreviews; - ambientPreviewElement = initElement(AmbientPreview); + ambientPreviewLargeElement = initElement(AmbientPreviewLarge); personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientPreviewElement); + await waitAfterNextRender(ambientPreviewLargeElement); const messageContainer = - ambientPreviewElement.shadowRoot!.getElementById( + ambientPreviewLargeElement.shadowRoot!.getElementById( 'messageContainer'); assertTrue(!!messageContainer); const textSpan = messageContainer.querySelector<HTMLSpanElement>( '#turnOnDescription'); assertTrue(!!textSpan); assertEquals( - ambientPreviewElement.i18n( + ambientPreviewLargeElement.i18n( 'ambientModeMainPageEnterpriseUserMessage'), textSpan.innerText.trim()); });
diff --git a/chrome/test/data/webui/chromeos/personalization_app/ambient_preview_small_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/ambient_preview_small_element_test.ts new file mode 100644 index 0000000..3cb6e4db --- /dev/null +++ b/chrome/test/data/webui/chromeos/personalization_app/ambient_preview_small_element_test.ts
@@ -0,0 +1,103 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'chrome://personalization/strings.m.js'; +import 'chrome://webui-test/mojo_webui_test_support.js'; + +import {AmbientObserver, AmbientPreviewSmall, PersonalizationRouter, TopicSource} from 'chrome://personalization/js/personalization_app.js'; +import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; +import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; + +import {baseSetup, initElement, teardownElement} from './personalization_app_test_utils.js'; +import {TestAmbientProvider} from './test_ambient_interface_provider.js'; +import {TestPersonalizationStore} from './test_personalization_store.js'; + + +suite('AmbientPreviewSmallTest', function() { + let ambientPreviewSmallElement: AmbientPreviewSmall|null; + let ambientProvider: TestAmbientProvider; + let personalizationStore: TestPersonalizationStore; + const routerOriginal = PersonalizationRouter.instance; + const routerMock = TestBrowserProxy.fromClass(PersonalizationRouter); + + setup(() => { + const mocks = baseSetup(); + ambientProvider = mocks.ambientProvider; + personalizationStore = mocks.personalizationStore; + AmbientObserver.initAmbientObserverIfNeeded(); + PersonalizationRouter.instance = () => routerMock; + }); + + teardown(async () => { + await teardownElement(ambientPreviewSmallElement); + ambientPreviewSmallElement = null; + AmbientObserver.shutdown(); + PersonalizationRouter.instance = routerOriginal; + }); + + test( + 'displays zero state message when ambient mode is disabled', async () => { + personalizationStore.data.ambient.albums = ambientProvider.albums; + personalizationStore.data.ambient.topicSource = TopicSource.kArtGallery; + personalizationStore.data.ambient.ambientModeEnabled = false; + personalizationStore.data.ambient.googlePhotosAlbumsPreviews = + ambientProvider.googlePhotosAlbumsPreviews; + ambientPreviewSmallElement = initElement(AmbientPreviewSmall); + personalizationStore.notifyObservers(); + await waitAfterNextRender(ambientPreviewSmallElement); + + const zeroStateTextContainer = + ambientPreviewSmallElement.shadowRoot!.getElementById( + 'zeroStateTextContainer'); + assertTrue(!!zeroStateTextContainer); + const textSpan = + zeroStateTextContainer.firstElementChild as HTMLSpanElement; + assertTrue(!!textSpan); + assertEquals('span', textSpan.tagName.toLowerCase()); + assertEquals( + ambientPreviewSmallElement.i18n( + 'ambientModeMainPageZeroStateMessage'), + textSpan.innerText.trim()); + }); + + test('shows placeholders while loading', async () => { + // Null indicates that this value has not yet loaded. + personalizationStore.data.ambient.ambientModeEnabled = null; + ambientPreviewSmallElement = initElement(AmbientPreviewSmall); + personalizationStore.notifyObservers(); + await waitAfterNextRender(ambientPreviewSmallElement); + + const container = ambientPreviewSmallElement.$.container; + assertEquals('imagePlaceholder', container.firstElementChild?.id); + + const textPlaceholder = container.querySelector('#textPlaceholder'); + assertTrue(!!textPlaceholder, 'textPlaceholder element exists'); + for (const child of textPlaceholder.children) { + assertTrue( + child.classList.contains('placeholder'), + 'every element has placeholder class'); + } + + assertEquals(null, container.querySelector('#imageContainer')); + }); + + test('shows image when loaded', async () => { + personalizationStore.data.ambient.albums = ambientProvider.albums; + personalizationStore.data.ambient.topicSource = TopicSource.kArtGallery; + personalizationStore.data.ambient.ambientModeEnabled = true; + personalizationStore.data.ambient.googlePhotosAlbumsPreviews = + ambientProvider.googlePhotosAlbumsPreviews; + ambientPreviewSmallElement = initElement(AmbientPreviewSmall); + personalizationStore.notifyObservers(); + await waitAfterNextRender(ambientPreviewSmallElement); + + const imageContainer = + ambientPreviewSmallElement.shadowRoot?.getElementById('imageContainer'); + assertTrue(!!imageContainer, 'imageContainer exists'); + assertEquals( + 1, imageContainer.getElementsByTagName('img').length, + '1 img element displayed'); + }); +});
diff --git a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts index 1ada327..63d00a9e 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
@@ -101,22 +101,10 @@ // Preview element should show placeholders for preview images, preview // album info and preview album collage. - const ambientPreview = - ambientSubpageElement.shadowRoot!.querySelector('ambient-preview'); + const ambientPreview = ambientSubpageElement.shadowRoot!.querySelector( + 'ambient-preview-small'); assertTrue(!!ambientPreview, 'ambient-preview element exists'); - const previewImagePlaceholder = - ambientPreview.shadowRoot!.querySelector('#imagePlaceholder'); - assertTrue(!!previewImagePlaceholder); - - const previewTextPlaceholder = - ambientPreview.shadowRoot!.querySelector('#textPlaceholder'); - assertTrue(!!previewTextPlaceholder); - - const previewItemPlaceholders = - ambientPreview.shadowRoot!.querySelectorAll('.placeholder'); - assertEquals(6, previewItemPlaceholders!.length); - // Should show image placeholders for the 3 theme items. const animationThemePlaceholder = ambientSubpageElement.shadowRoot!.querySelector( @@ -157,22 +145,22 @@ personalizationStore.notifyObservers(); await waitAfterNextRender(ambientSubpageElement); - // Placeholders will be hidden for preview, animation theme, topic source + // Placeholders will be hidden for animation theme, topic source // and temperature unit elements. - assertTrue(!!previewImagePlaceholder); - assertEquals(getComputedStyle(previewImagePlaceholder).display, 'none'); - - assertTrue(!!previewTextPlaceholder); - assertEquals(getComputedStyle(previewTextPlaceholder).display, 'none'); - assertTrue(!!animationThemePlaceholder); - assertEquals(getComputedStyle(animationThemePlaceholder).display, 'none'); + assertEquals( + 'none', getComputedStyle(animationThemePlaceholder).display, + 'animation theme placeholder is hidden'); assertTrue(!!topicSourcePlaceholder); - assertEquals(getComputedStyle(topicSourcePlaceholder).display, 'none'); + assertEquals( + 'none', getComputedStyle(topicSourcePlaceholder).display, + 'topic source placeholder is hidden'); assertTrue(!!weatherUnitPlaceholder); - assertEquals(getComputedStyle(weatherUnitPlaceholder).display, 'none'); + assertEquals( + 'none', getComputedStyle(weatherUnitPlaceholder).display, + 'weather unit placeholder is hidden'); }); test('sets ambient mode enabled in store on first load', async () => { @@ -683,8 +671,8 @@ const action = await personalizationStore.waitForAction( AmbientActionName.SET_ALBUMS) as SetAlbumsAction; assertEquals(4, action.albums.length); - const ambientPreview = - ambientSubpageElement.shadowRoot!.querySelector('ambient-preview'); + const ambientPreview = ambientSubpageElement.shadowRoot!.querySelector( + 'ambient-preview-small'); assertTrue(!!ambientPreview); const previewImage = @@ -699,86 +687,6 @@ assertEquals('2', previewAlbumTitle.innerText.replace(/\s/g, '')); }); - test( - 'displays 4 image collage when there are enough photos in Google photos album', - async () => { - // Disables `isAmbientSubpageUiChangeEnabled` to show the previous UI. - loadTimeData.overrideValues( - {['isAmbientSubpageUiChangeEnabled']: false}); - - ambientSubpageElement = await displayMainSettings( - TopicSource.kGooglePhotos, TemperatureUnit.kFahrenheit, - /*ambientModeEnabled=*/ true); - personalizationStore.data.ambient.googlePhotosAlbumsPreviews = - ambientProvider.googlePhotosAlbumsPreviews; - personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientSubpageElement); - - const ambientPreview = - ambientSubpageElement.shadowRoot!.querySelector('ambient-preview'); - assertTrue(!!ambientPreview); - - const collageImages = - ambientPreview.shadowRoot!.querySelectorAll<HTMLImageElement>( - '.collage-item'); - assertTrue(!!collageImages); - assertEquals(4, collageImages.length); - }); - - test( - 'displays 1 image collage when there are not enough photos in Google photos album', - async () => { - // Disables `isAmbientSubpageUiChangeEnabled` to show the previous UI. - loadTimeData.overrideValues( - {['isAmbientSubpageUiChangeEnabled']: false}); - - ambientSubpageElement = await displayMainSettings( - TopicSource.kGooglePhotos, TemperatureUnit.kFahrenheit, - /*ambientModeEnabled=*/ true); - personalizationStore.data.ambient.googlePhotosAlbumsPreviews = [ - ambientProvider.googlePhotosAlbumsPreviews[0], - ambientProvider.googlePhotosAlbumsPreviews[1], - ]; - personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientSubpageElement); - - const ambientPreview = - ambientSubpageElement.shadowRoot!.querySelector('ambient-preview'); - assertTrue(!!ambientPreview); - - const collageImages = - ambientPreview.shadowRoot!.querySelectorAll<HTMLImageElement>( - '.collage-item'); - assertTrue(!!collageImages); - assertEquals(1, collageImages.length); - }); - - test( - 'displays preview urls from selected albums when there are zero preview photos in Google photos album', - async () => { - // Disables `isAmbientSubpageUiChangeEnabled` to show the previous UI. - loadTimeData.overrideValues( - {['isAmbientSubpageUiChangeEnabled']: false}); - - ambientSubpageElement = await displayMainSettings( - TopicSource.kGooglePhotos, TemperatureUnit.kFahrenheit, - /*ambientModeEnabled=*/ true); - personalizationStore.data.ambient.googlePhotosAlbumsPreviews = []; - personalizationStore.notifyObservers(); - await waitAfterNextRender(ambientSubpageElement); - - const ambientPreview = - ambientSubpageElement.shadowRoot!.querySelector('ambient-preview'); - assertTrue(!!ambientPreview); - - const collageImages = - ambientPreview.shadowRoot!.querySelectorAll<HTMLImageElement>( - '.collage-item'); - assertTrue(!!collageImages); - assertEquals(1, collageImages.length); - assertTrue(collageImages[0]!.src.includes('test_url3')); - }); - test('displays zero state when ambient mode is disabled', async () => { // Disables `isAmbientSubpageUiChangeEnabled` to show the previous UI. loadTimeData.overrideValues({['isAmbientSubpageUiChangeEnabled']: false}); @@ -787,28 +695,27 @@ TopicSource.kArtGallery, TemperatureUnit.kFahrenheit, /*ambientModeEnabled=*/ false); - // Main settings should be present. const mainSettings = ambientSubpageElement.shadowRoot!.querySelector('#mainSettings'); - assertTrue(!!mainSettings); + assertTrue(!!mainSettings, 'main settings should be present'); - // Preview image should be absent. - assertEquals(mainSettings.querySelector('ambient-preview'), null); - - // Topic source list should be absent. assertEquals( + null, mainSettings.querySelector('ambient-preview'), + 'preview image should be absent'); + + assertEquals( + null, ambientSubpageElement.shadowRoot!.querySelector('topic-source-list'), - null); + 'topic source list should be absent'); - // Weather unit should be absent. assertEquals( + null, ambientSubpageElement.shadowRoot!.querySelector('ambient-weather-unit'), - null); + 'weather unit should be absent'); - // Zero state should be present. const zeroState = ambientSubpageElement.shadowRoot!.querySelector('ambient-zero-state'); - assertTrue(!!zeroState); + assertTrue(!!zeroState, 'zero state should be present'); }); test('displays ambient preview when ambient mode is disabled', async () => { @@ -816,24 +723,23 @@ TopicSource.kArtGallery, TemperatureUnit.kFahrenheit, /*ambientModeEnabled=*/ false); - // Preview image should be present. - const ambientPreview = - ambientSubpageElement.shadowRoot!.querySelector('ambient-preview'); - assertTrue(!!ambientPreview); + const ambientPreview = ambientSubpageElement.shadowRoot!.querySelector( + 'ambient-preview-small'); + assertTrue(!!ambientPreview, 'preview image should be present'); - // Topic source list should be absent. assertEquals( + null, ambientSubpageElement.shadowRoot!.querySelector('topic-source-list'), - null); + 'topic source list should be absent'); - // Weather unit should be absent. assertEquals( + null, ambientSubpageElement.shadowRoot!.querySelector('ambient-weather-unit'), - null); + 'weather unit should be absent'); - // Zero state should not be present. assertEquals( + null, ambientSubpageElement.shadowRoot!.querySelector('ambient-zero-state'), - null); + 'zero state should not be present'); }); });
diff --git a/chrome/test/data/webui/chromeos/personalization_app/google_photos_albums_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/google_photos_albums_element_test.ts index 4fe98a4..b9cfb33 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/google_photos_albums_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/google_photos_albums_element_test.ts
@@ -56,6 +56,7 @@ preview: { url: createSvgDataUrl('svg-0'), }, + timestamp: {internalValue: BigInt(`13318040939308000`)}, }, { id: '0ec40478-9712-42e1-b5bf-3e75870ca042', @@ -64,6 +65,7 @@ preview: { url: createSvgDataUrl('svg-1'), }, + timestamp: {internalValue: BigInt(`13318040939307000`)}, }, { id: '0a268a37-877a-4936-81d4-38cc84b0f596', @@ -72,6 +74,7 @@ preview: { url: createSvgDataUrl('svg-2'), }, + timestamp: {internalValue: BigInt(`13318040939306000`)}, }, ]; @@ -168,12 +171,14 @@ // Prepare Google Photos data. const photosCount = 5; const albums: GooglePhotosAlbum[] = Array.from( - {length: photosCount}, (_, i) => ({ - id: `id-${i}`, - title: `title-${i}`, - photoCount: 1, - preview: {url: createSvgDataUrl(`svg-${i}`)}, - })); + {length: photosCount}, + (_, i) => ({ + id: `id-${i}`, + title: `title-${i}`, + photoCount: 1, + preview: {url: createSvgDataUrl(`svg-${i}`)}, + timestamp: {internalValue: BigInt(`${photosCount - i}`)}, + })); // Initialize |googlePhotosAlbumsElement|. googlePhotosAlbumsElement = @@ -254,6 +259,7 @@ title: `title-${nextAlbumId}`, photoCount: 1, preview: {url: `url-${nextAlbumId++}`}, + timestamp: {internalValue: BigInt(`${nextAlbumId}`)}, }; })); @@ -280,6 +286,7 @@ title: `title-${nextAlbumId}`, photoCount: 1, preview: {url: `url-${nextAlbumId++}`}, + timestamp: {internalValue: BigInt(`${nextAlbumId}`)}, }; }));
diff --git a/chrome/test/data/webui/chromeos/personalization_app/google_photos_collection_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/google_photos_collection_element_test.ts index 5072c5f8..f8fd708 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/google_photos_collection_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/google_photos_collection_element_test.ts
@@ -83,6 +83,7 @@ title: '', photoCount: 0, preview: {url: ''}, + timestamp: {internalValue: BigInt('1')}, }]); // Initialize |googlePhotosCollectionElement|. @@ -145,6 +146,7 @@ title: 'Album 0', photoCount: 1, preview: {url: 'foo.com'}, + timestamp: {internalValue: BigInt(`13318040939308000`)}, }]; wallpaperProvider.setGooglePhotosAlbums(albums); wallpaperProvider.setGooglePhotosPhotos([{
diff --git a/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_by_album_id_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_by_album_id_element_test.ts index 675e568b..68c2c235 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_by_album_id_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/google_photos_photos_by_album_id_element_test.ts
@@ -56,6 +56,7 @@ title: 'foo', photoCount: 1, preview: {url: 'foo.com'}, + timestamp: {internalValue: BigInt('1')}, }; // Set values returned by |wallpaperProvider|. @@ -122,6 +123,7 @@ // Use svg data urls so that img on-load event fires and removes the // placeholder attribute. preview: {url: createSvgDataUrl('svg-1')}, + timestamp: {internalValue: BigInt('1')}, }; const otherAlbum: GooglePhotosAlbum = { @@ -129,6 +131,7 @@ title: 'bar', photoCount: 1, preview: {url: createSvgDataUrl('svg-2')}, + timestamp: {internalValue: BigInt('2')}, }; const photosByAlbumId: Record<string, GooglePhotosPhoto[]> = { @@ -267,8 +270,13 @@ test('displays photo selected', async () => { personalizationStore.setReducersEnabled(true); - const album: GooglePhotosAlbum = - {id: '1', title: '', photoCount: 2, preview: {url: ''}}; + const album: GooglePhotosAlbum = { + id: '1', + title: '', + photoCount: 2, + preview: {url: ''}, + timestamp: {internalValue: BigInt('1')}, + }; const photo: GooglePhotosPhoto = { id: '9bd1d7a3-f995-4445-be47-53c5b58ce1cb', @@ -434,8 +442,13 @@ test('displays placeholders until photos are present', async () => { // Prepare Google Photos data. const photosCount = 5; - const album: GooglePhotosAlbum = - {id: '1', title: '', photoCount: photosCount, preview: {url: ''}}; + const album: GooglePhotosAlbum = { + id: '1', + title: '', + photoCount: photosCount, + preview: {url: ''}, + timestamp: {internalValue: BigInt('1')}, + }; const photos: GooglePhotosPhoto[] = Array.from( {length: photosCount}, (_, i) => ({ id: `id-${i}`, @@ -527,8 +540,13 @@ personalizationStore.setReducersEnabled(true); const photosCount = 200; - const album: GooglePhotosAlbum = - {id: '1', title: '', photoCount: photosCount, preview: {url: ''}}; + const album: GooglePhotosAlbum = { + id: '1', + title: '', + photoCount: photosCount, + preview: {url: ''}, + timestamp: {internalValue: BigInt('1')}, + }; // Set albums returned by |wallpaperProvider|. wallpaperProvider.setGooglePhotosAlbums([album]); @@ -677,6 +695,7 @@ title: 'foo', photoCount: 1, preview: {url: 'foo.com'}, + timestamp: {internalValue: BigInt('1')}, }; const photo: GooglePhotosPhoto = {
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js index d9d06948..d2d5647 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js +++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_component_browsertest.js
@@ -43,7 +43,8 @@ }; [['AmbientObserverTest', 'ambient_observer_test.js'], - ['AmbientPreviewTest', 'ambient_preview_element_test.js'], + ['AmbientPreviewLargeTest', 'ambient_preview_large_element_test.js'], + ['AmbientPreviewSmallTest', 'ambient_preview_small_element_test.js'], ['AmbientSubpageTest', 'ambient_subpage_element_test.js'], ['AvatarCameraTest', 'avatar_list_element_test.js'], ['AvatarListTest', 'avatar_list_element_test.js'],
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts index 24780b00..61198f6f 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_main_element_test.ts
@@ -4,9 +4,9 @@ import 'chrome://personalization/strings.m.js'; import 'chrome://webui-test/mojo_webui_test_support.js'; -import {Paths, PersonalizationMain, PersonalizationRouter} from 'chrome://personalization/js/personalization_app.js'; +import {PersonalizationMain} from 'chrome://personalization/js/personalization_app.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; import {baseSetup, initElement, teardownElement} from './personalization_app_test_utils.js'; @@ -23,57 +23,24 @@ personalizationMainElement = null; }); - test('links to ambient subpage', async () => { - loadTimeData.overrideValues({'isAmbientModeAllowed': true}); - personalizationMainElement = initElement(PersonalizationMain); - const original = PersonalizationRouter.instance; - const goToRoutePromise = new Promise<[Paths, Object]>(resolve => { - PersonalizationRouter.instance = () => { - return { - goToRoute(path: Paths, queryParams: Object = {}) { - resolve([path, queryParams]); - PersonalizationRouter.instance = original; - }, - } as PersonalizationRouter; - }; - }); - const ambientSubpageLink = - personalizationMainElement!.shadowRoot!.getElementById( - 'ambientSubpageLink')!; - ambientSubpageLink.click(); - const [path, queryParams] = await goToRoutePromise; - assertEquals(Paths.AMBIENT, path); - assertDeepEquals({}, queryParams); - }); - - test('no links to ambient subpage', async () => { - loadTimeData.overrideValues({'isAmbientModeAllowed': false}); - personalizationMainElement = initElement(PersonalizationMain); - - const ambientSubpageLink = - personalizationMainElement!.shadowRoot!.getElementById( - 'ambientSubpageLink')!; - assertFalse(!!ambientSubpageLink); - }); - - test('has ambient preview', async () => { - loadTimeData.overrideValues({'isAmbientModeAllowed': true}); + test('has large ambient preview when ambient allowed', async () => { + loadTimeData.overrideValues({isAmbientModeAllowed: true}); personalizationMainElement = initElement(PersonalizationMain); await waitAfterNextRender(personalizationMainElement); const preview = personalizationMainElement!.shadowRoot!.querySelector( - 'ambient-preview')!; - assertTrue(!!preview); + 'ambient-preview-large')!; + assertTrue(!!preview, 'ambient preview exists'); }); - test('has no ambient preview', async () => { - loadTimeData.overrideValues({'isAmbientModeAllowed': false}); + test('has no ambient preview when ambient disallowed', async () => { + loadTimeData.overrideValues({isAmbientModeAllowed: false}); personalizationMainElement = initElement(PersonalizationMain); await waitAfterNextRender(personalizationMainElement); const preview = personalizationMainElement!.shadowRoot!.querySelector( - 'ambient-preview')!; - assertFalse(!!preview); + 'ambient-preview-large')!; + assertFalse(!!preview, 'ambient preview does not exist'); }); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/apn_list_item_test.js b/chrome/test/data/webui/cr_components/chromeos/network/apn_list_item_test.js index 225f682b..c649707 100644 --- a/chrome/test/data/webui/cr_components/chromeos/network/apn_list_item_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/network/apn_list_item_test.js
@@ -79,20 +79,6 @@ apnListItem.i18n('NetworkHealthStateConnected'), subLabel.innerText); }); - test('Check if auto detected label is shown', async function() { - apnListItem.isAutoDetected = false; - await flushTasks(); - - const subLabel = apnListItem.shadowRoot.querySelector('#autoDetected'); - assertTrue(!!subLabel); - assertTrue(subLabel.hasAttribute('hidden')); - apnListItem.isAutoDetected = true; - await flushTasks(); - - assertFalse(subLabel.hasAttribute('hidden')); - assertEquals(apnListItem.i18n('apnAutoDetected'), subLabel.innerText); - }); - test('Check if APN three dot menu shows', async function() { await openThreeDotMenu(); assertTrue(apnListItem.$.dotsMenu.open); @@ -214,7 +200,12 @@ async function() { apnListItem.apn = TEST_APN_EVENT_DATA.apn; apnListItem.guid = TEST_APN_EVENT_DATA.guid; - apnListItem.isAutoDetected = true; + + const subLabel = apnListItem.shadowRoot.querySelector('#autoDetected'); + assertTrue(!!subLabel); + assertFalse(subLabel.hasAttribute('hidden')); + assertEquals(apnListItem.i18n('apnAutoDetected'), subLabel.innerText); + let apnDetailsClickedEvent = eventToPromise('show-apn-detail-dialog', window); assertTrue(!!apnListItem.$.detailsButton); @@ -225,9 +216,14 @@ assertEquals(TEST_APN_EVENT_DATA.mode, eventData.detail.mode); // Case: the apn list item is not auto detected + apnListItem.apn = { + name: TEST_APN_EVENT_DATA.apn.name, + id: '1', + }; + assertTrue(subLabel.hasAttribute('hidden')); + apnDetailsClickedEvent = eventToPromise('show-apn-detail-dialog', window); - apnListItem.isAutoDetected = false; apnListItem.$.detailsButton.click(); eventData = await apnDetailsClickedEvent; assertEquals(TEST_APN_EVENT_DATA.apn.name, eventData.detail.apn.name);
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/apn_list_test.js b/chrome/test/data/webui/cr_components/chromeos/network/apn_list_test.js index bfc24f5e..f606841e 100644 --- a/chrome/test/data/webui/cr_components/chromeos/network/apn_list_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/network/apn_list_test.js
@@ -145,7 +145,6 @@ assertTrue(OncMojo.apnMatch(apns[0].apn, customApn1)); assertTrue(OncMojo.apnMatch(apns[1].apn, customApn2)); assertFalse(apns[0].isConnected); - assertFalse(apns[0].isAutoDetected); }); test( @@ -162,7 +161,6 @@ assertEquals(apns.length, 1); assertTrue(OncMojo.apnMatch(apns[0].apn, connectedApn)); assertTrue(apns[0].isConnected); - assertTrue(apns[0].isAutoDetected); }); test( @@ -182,7 +180,6 @@ assertTrue(OncMojo.apnMatch(apns[1].apn, customApn1)); assertTrue(OncMojo.apnMatch(apns[2].apn, customApn2)); assertTrue(apns[0].isConnected); - assertTrue(apns[0].isAutoDetected); }); test('Connected APN is inside custom APN list.', async function() { @@ -201,7 +198,6 @@ assertTrue(OncMojo.apnMatch(apns[2].apn, customApn2)); assertTrue(OncMojo.apnMatch(apns[3].apn, customApn3)); assertTrue(apns[0].isConnected); - assertFalse(apns[0].isAutoDetected); }); test('Connected APN is the only apn in custom APN list.', async function() { @@ -214,7 +210,6 @@ assertEquals(apns.length, 1); assertTrue(OncMojo.apnMatch(apns[0].apn, connectedApn)); assertTrue(apns[0].isConnected); - assertFalse(apns[0].isAutoDetected); }); test(
diff --git a/chrome/test/data/webui/intro/test_intro_browser_proxy.ts b/chrome/test/data/webui/intro/test_intro_browser_proxy.ts index 273e19a6..db84b822 100644 --- a/chrome/test/data/webui/intro/test_intro_browser_proxy.ts +++ b/chrome/test/data/webui/intro/test_intro_browser_proxy.ts
@@ -11,6 +11,7 @@ super([ 'continueWithAccount', 'continueWithoutAccount', + 'initializeMainView', ]); } @@ -21,4 +22,8 @@ continueWithoutAccount() { this.methodCalled('continueWithoutAccount'); } -} \ No newline at end of file + + initializeMainView() { + this.methodCalled('initializeMainView'); + } +}
diff --git a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts index fbe7b6f..6b96b7b 100644 --- a/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts +++ b/chrome/test/data/webui/new_tab_page/realbox/realbox_test.ts
@@ -268,7 +268,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Left click does not query autocomplete when matches are showing. @@ -323,7 +323,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Tabbing into input does not query autocomplete when matches are showing. @@ -389,7 +389,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Arrow up/down keys do not query autocomplete when matches are showing. @@ -444,7 +444,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Arrow up/down keys do not query autocomplete when matches are showing. @@ -622,7 +622,7 @@ assertEquals('listbox', realbox.$.matches.getAttribute('role')); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); verifyMatch(matches[0]!, matchEls[0]!); verifyMatch(matches[1]!, matchEls[1]!); @@ -660,7 +660,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(1, matchEls.length); verifyMatch(matches[0]!, matchEls[0]!); @@ -747,7 +747,7 @@ assertFalse(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(0, matchEls.length); }); @@ -765,7 +765,7 @@ assertTrue(areMatchesShowing()); let matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); realbox.$.input.value += 'll'; @@ -780,7 +780,7 @@ assertFalse(areMatchesShowing()); matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(0, matchEls.length); realbox.$.input.value += 'o'; @@ -795,7 +795,7 @@ assertTrue(areMatchesShowing()); matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); }); @@ -919,7 +919,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // First match is selected. @@ -966,7 +966,7 @@ assertTrue(areMatchesShowing()); let matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Select the first match. @@ -996,7 +996,7 @@ // First match is still selected. matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); assertTrue(matchEls[0]!.classList.contains(Classes.SELECTED)); // Input is not cleared. @@ -1044,7 +1044,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // First match is not selected. @@ -1081,7 +1081,7 @@ assertTrue(areMatchesShowing()); let matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Select the first match. @@ -1111,7 +1111,7 @@ // Matches are cleared. matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(0, matchEls.length); // Input is cleared (zero-prefix case). assertEquals('', realbox.$.input.value); @@ -1155,7 +1155,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // First match is selected. @@ -1224,7 +1224,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // First match is selected. @@ -1268,7 +1268,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Right clicks are ignored. @@ -1342,7 +1342,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); assertEquals( @@ -1366,7 +1366,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Select the second match. @@ -1429,7 +1429,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // First match is selected. assertTrue(matchEls[0]!.classList.contains(Classes.SELECTED)); @@ -1493,7 +1493,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // By pressing 'Enter' on the button. @@ -1540,7 +1540,7 @@ assertTrue(areMatchesShowing()); let matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(1, matchEls.length); // First match is not selected. @@ -1566,7 +1566,7 @@ assertTrue(areMatchesShowing()); matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(1, matchEls.length); // First match is not selected. @@ -1611,7 +1611,7 @@ assertTrue(areMatchesShowing()); matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(1, matchEls.length); // First match is selected. @@ -1637,7 +1637,7 @@ assertTrue(areMatchesShowing()); let matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Select the second match. @@ -1679,7 +1679,7 @@ // Matches are cleared. matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(0, matchEls.length); // Input is cleared. assertEquals('', realbox.$.input.value); @@ -1695,7 +1695,7 @@ assertTrue(areMatchesShowing()); matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Pressing 'Escape' when no matches are selected closes the dropdown. @@ -1713,7 +1713,7 @@ // Matches are cleared. matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(0, matchEls.length); }); @@ -1732,7 +1732,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); let arrowDownEvent = new KeyboardEvent('keydown', { @@ -1834,7 +1834,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); const focusIndicator = matchEls[0]!.$['focus-indicator']; @@ -2062,7 +2062,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); assertIconMaskImageUrl(matchEls[0]!.$.icon, 'clock.svg'); assertFavicon(matchEls[1]!.$.icon, matches[1]!.destinationUrl.url); @@ -2172,7 +2172,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); assertFavicon(matchEls[0]!.$.icon, matches[0]!.destinationUrl.url); assertIconMaskImageUrl(matchEls[1]!.$.icon, 'clock.svg'); @@ -2280,7 +2280,7 @@ // The first match is showing. The second match is initially hidden. let matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(1, matchEls.length); // The suggestion group header and the toggle button are visible. @@ -2318,7 +2318,7 @@ // Second match is visible. matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Hide the second match by clicking the toggle button. @@ -2333,7 +2333,7 @@ // Second match is hidden. matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(1, matchEls.length); testProxy.handler.reset(); @@ -2348,7 +2348,7 @@ 1, testProxy.handler.getCallCount('toggleSuggestionGroupIdVisibility')); // Second match is visible again. matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); }); @@ -2377,7 +2377,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(2, matchEls.length); // Select the first match. @@ -2427,7 +2427,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); assertEquals(1, matchEls.length); verifyMatch(matches[0]!, matchEls[0]!); @@ -2476,7 +2476,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); verifyMatch(matches[0]!, matchEls[0]!); // Separator is not displayed @@ -2520,10 +2520,10 @@ await testProxy.callbackRouterRemote.$.flushForTesting(); assertTrue(areMatchesShowing()); - const matchEl = $$(realbox.$.matches, 'ntp-realbox-match')!; + const matchEl = $$(realbox.$.matches, 'cr-realbox-match')!; verifyMatch(matches[0]!, matchEl); - const pedalEl = $$($$(matchEl, 'ntp-realbox-action')!, '.contents')!; + const pedalEl = $$($$(matchEl, 'cr-realbox-action')!, '.contents')!; assertEquals( pedalEl.querySelector<HTMLImageElement>('#action-icon')!.src, @@ -2572,11 +2572,11 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); verifyMatch(matches[0]!, matchEls[0]!); verifyMatch(matches[1]!, matchEls[1]!); - const pedalEl = $$($$(matchEls[1]!, 'ntp-realbox-action')!, '.contents')!; + const pedalEl = $$($$(matchEls[1]!, 'cr-realbox-action')!, '.contents')!; assertEquals( pedalEl.querySelector<HTMLImageElement>('#action-icon')!.src, @@ -2646,7 +2646,7 @@ assertTrue(areMatchesShowing()); const matchEls = - realbox.$.matches.shadowRoot!.querySelectorAll('ntp-realbox-match'); + realbox.$.matches.shadowRoot!.querySelectorAll('cr-realbox-match'); const mouseDown = new MouseEvent('mousedown', { bubbles: true,
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn index 515e76c..a80cbc1 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -183,12 +183,7 @@ } if (is_win && is_chrome_branded) { - files += [ - "chrome_cleanup_page_test.ts", - "incompatible_applications_page_test.ts", - "safety_check_chrome_cleaner_test.ts", - "test_chrome_cleanup_proxy.ts", - ] + files += [ "incompatible_applications_page_test.ts" ] } ts_path_mappings = [
diff --git a/chrome/test/data/webui/settings/chrome_cleanup_page_test.ts b/chrome/test/data/webui/settings/chrome_cleanup_page_test.ts deleted file mode 100644 index b8ce29cf..0000000 --- a/chrome/test/data/webui/settings/chrome_cleanup_page_test.ts +++ /dev/null
@@ -1,505 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// clang-format off -import {webUIListenerCallback} from 'chrome://resources/js/cr.js'; -import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW, ChromeCleanerScannerResults, ChromeCleanupFilePath, ChromeCleanupIdleReason, ChromeCleanupProxyImpl, ItemsToRemoveListElement, SettingsCheckboxElement, SettingsChromeCleanupPageElement} from 'chrome://settings/lazy_load.js'; -import {CrButtonElement} from 'chrome://settings/settings.js'; -import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; - -import {TestChromeCleanupProxy} from './test_chrome_cleanup_proxy.js'; - -// clang-format on - -let chromeCleanupPage: SettingsChromeCleanupPageElement; -let chromeCleanupProxy: TestChromeCleanupProxy; - -const shortFileList: ChromeCleanupFilePath[] = [ - {'dirname': 'C:\\', 'basename': 'file 1'}, - {'dirname': 'C:\\', 'basename': 'file 2'}, - {'dirname': 'C:\\', 'basename': 'file 3'}, -]; -const exactSizeFileList = - shortFileList.concat([{'dirname': 'C:\\', 'basename': 'file 4'}]); -const longFileList = - exactSizeFileList.concat([{'dirname': 'C:\\', 'basename': 'file 5'}]); -const shortRegistryKeysList = ['key 1', 'key 2']; -const exactSizeRegistryKeysList = ['key 1', 'key 2', 'key 3', 'key 4']; -const longRegistryKeysList = - ['key 1', 'key 2', 'key 3', 'key 4', 'key 5', 'key 6']; - -const fileLists = [[], shortFileList, exactSizeFileList, longFileList]; -const registryKeysLists = [ - [], - shortRegistryKeysList, - exactSizeRegistryKeysList, - longRegistryKeysList, -]; -const descriptors = ['No', 'Few', 'ExactSize', 'Many']; - -const defaultScannerResults: ChromeCleanerScannerResults = { - files: shortFileList, - registryKeys: shortRegistryKeysList, -}; - -function validateVisibleItemsList( - originalItems: Array<string|ChromeCleanupFilePath>, - visibleItems: ItemsToRemoveListElement) { - let visibleItemsList = - visibleItems.shadowRoot!.querySelectorAll('.visible-item'); - const moreItemsLink = - visibleItems.shadowRoot!.querySelector<HTMLElement>('#more-items-link')!; - - if (originalItems.length <= CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW) { - assertEquals(visibleItemsList.length, originalItems.length); - assertTrue(moreItemsLink.hidden); - } else { - assertEquals( - visibleItemsList.length, CHROME_CLEANUP_DEFAULT_ITEMS_TO_SHOW - 1); - assertFalse(moreItemsLink.hidden); - - // Tapping on the "show more" link should expand the list. - moreItemsLink.click(); - flush(); - - visibleItemsList = - visibleItems.shadowRoot!.querySelectorAll('.visible-item'); - assertEquals(visibleItemsList.length, originalItems.length); - assertTrue(moreItemsLink.hidden); - } -} - -/** - * @param expectSuffix Whether a highlight suffix should exist. - */ -function validateHighlightSuffix( - originalItems: Array<string|ChromeCleanupFilePath>, - container: ItemsToRemoveListElement, expectSuffix: boolean) { - const itemList = - container.shadowRoot!.querySelectorAll('li:not(#more-items-link)'); - assertEquals(originalItems.length, itemList.length); - for (const item of itemList) { - const suffixes = item.querySelectorAll<HTMLElement>('.highlight-suffix'); - assertEquals(suffixes.length, 1); - assertEquals(expectSuffix, !suffixes[0]!.hidden); - } -} - -/** - * @param files The list of files to be cleaned. - * @param registryKeys The list of registry entries to be cleaned. - */ -async function startCleanupFromInfected( - files: ChromeCleanupFilePath[], registryKeys: string[]) { - const scannerResults: ChromeCleanerScannerResults = {files, registryKeys}; - - updateReportingEnabledPref(false); - webUIListenerCallback( - 'chrome-cleanup-on-infected', true /* isPoweredByPartner */, - scannerResults); - flush(); - - const showItemsButton = - chromeCleanupPage.shadowRoot!.querySelector<HTMLElement>( - '#show-items-button')!; - assertTrue(!!showItemsButton); - showItemsButton.click(); - - const filesToRemoveList = - chromeCleanupPage.shadowRoot!.querySelector<ItemsToRemoveListElement>( - '#files-to-remove-list')!; - assertTrue(!!filesToRemoveList); - validateVisibleItemsList(files, filesToRemoveList); - validateHighlightSuffix(files, filesToRemoveList, true /* expectSuffix */); - - const registryKeysListContainer = - chromeCleanupPage.shadowRoot!.querySelector<ItemsToRemoveListElement>( - '#registry-keys-list')!; - assertTrue(!!registryKeysListContainer); - if (registryKeys.length > 0) { - assertFalse(registryKeysListContainer.hidden); - assertTrue(!!registryKeysListContainer); - validateVisibleItemsList(registryKeys, registryKeysListContainer); - validateHighlightSuffix( - registryKeys, registryKeysListContainer, false /* expectSuffix */); - } else { - assertTrue(registryKeysListContainer.hidden); - } - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector<CrButtonElement>( - '#action-button'); - assertTrue(!!actionButton); - actionButton!.click(); - const logsUploadEnabled = await chromeCleanupProxy.whenCalled('startCleanup'); - assertFalse(logsUploadEnabled); - webUIListenerCallback( - 'chrome-cleanup-on-cleaning', true /* isPoweredByPartner */, - defaultScannerResults); - flush(); - - const spinner = - chromeCleanupPage.shadowRoot!.querySelector('paper-spinner-lite')!; - assertTrue(spinner.active); -} - -/** - * @param newValue The new value to set to - * prefs.software_reporter.reporting. - */ -function updateReportingEnabledPref(newValue: boolean) { - chromeCleanupPage.prefs = { - software_reporter: { - reporting: { - type: chrome.settingsPrivate.PrefType.BOOLEAN, - value: newValue, - key: '', - }, - }, - }; -} - -/** - * @param testingScanOffered Whether to test the case where scanning - * is offered to the user. - */ -function testLogsUploading(testingScanOffered: boolean) { - if (testingScanOffered) { - webUIListenerCallback( - 'chrome-cleanup-on-infected', true /* isPoweredByPartner */, - defaultScannerResults); - } else { - webUIListenerCallback( - 'chrome-cleanup-on-idle', ChromeCleanupIdleReason.INITIAL); - } - flush(); - - const logsControl = - chromeCleanupPage.shadowRoot!.querySelector<SettingsCheckboxElement>( - '#chromeCleanupLogsUploadControl'); - - updateReportingEnabledPref(true); - assertTrue(!!logsControl); - assertTrue(logsControl!.checked); - - logsControl!.$.checkbox.click(); - assertFalse(logsControl!.checked); - assertFalse(chromeCleanupPage.prefs.software_reporter.reporting.value); - - logsControl!.$.checkbox.click(); - assertTrue(logsControl!.checked); - assertTrue(chromeCleanupPage.prefs.software_reporter.reporting.value); - - updateReportingEnabledPref(false); - assertFalse(logsControl!.checked); -} - -/** - * @param onInfected Whether to test the case where current state is - * INFECTED, as opposed to CLEANING. - * @param isPoweredByPartner Whether to test the case when scan - * results are provided by a partner. - */ -function testPartnerLogoShown( - onInfected: boolean, isPoweredByPartner: boolean) { - webUIListenerCallback( - onInfected ? 'chrome-cleanup-on-infected' : 'chrome-cleanup-on-cleaning', - isPoweredByPartner, defaultScannerResults); - flush(); - - const poweredByContainerControl = - chromeCleanupPage.shadowRoot!.querySelector<HTMLElement>('#powered-by'); - assertTrue(!!poweredByContainerControl); - assertNotEquals(poweredByContainerControl!.hidden, isPoweredByPartner); -} - -suite('ChromeCleanupHandler', function() { - setup(function() { - chromeCleanupProxy = new TestChromeCleanupProxy(); - ChromeCleanupProxyImpl.setInstance(chromeCleanupProxy); - - document.body.innerHTML = window.trustedTypes!.emptyHTML; - - chromeCleanupPage = document.createElement('settings-chrome-cleanup-page'); - chromeCleanupPage.prefs = { - software_reporter: { - reporting: { - type: chrome.settingsPrivate.PrefType.BOOLEAN, - value: true, - key: '', - }, - }, - }; - document.body.appendChild(chromeCleanupPage); - }); - - function scanOfferedOnInitiallyIdle(idleReason: ChromeCleanupIdleReason) { - webUIListenerCallback('chrome-cleanup-on-idle', idleReason); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector('#action-button'); - assertTrue(!!actionButton); - } - - test('scanOfferedOnInitiallyIdle_ReporterFoundNothing', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.REPORTER_FOUND_NOTHING); - }); - - test('scanOfferedOnInitiallyIdle_ReporterFailed', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.REPORTER_FAILED); - }); - - test('scanOfferedOnInitiallyIdle_ScanningFoundNothing', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.SCANNING_FOUND_NOTHING); - }); - - test('scanOfferedOnInitiallyIdle_ScanningFailed', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.SCANNING_FAILED); - }); - - test('scanOfferedOnInitiallyIdle_ConnectionLost', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.CONNECTION_LOST); - }); - - test('scanOfferedOnInitiallyIdle_UserDeclinedCleanup', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.USER_DECLINED_CLEANUP); - }); - - test('scanOfferedOnInitiallyIdle_CleaningFailed', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.CLEANING_FAILED); - }); - - test('scanOfferedOnInitiallyIdle_CleaningSucceeded', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.CLEANING_SUCCEEDED); - }); - - test('scanOfferedOnInitiallyIdle_CleanerDownloadFailed', function() { - scanOfferedOnInitiallyIdle(ChromeCleanupIdleReason.CLEANER_DOWNLOAD_FAILED); - }); - - test('cleanerDownloadFailure', function() { - webUIListenerCallback('chrome-cleanup-on-reporter-running'); - webUIListenerCallback( - 'chrome-cleanup-on-idle', - ChromeCleanupIdleReason.CLEANER_DOWNLOAD_FAILED); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector<CrButtonElement>( - '#action-button'); - assertTrue(!!actionButton); - actionButton!.click(); - return chromeCleanupProxy.whenCalled('startScanning'); - }); - - test('reporterFoundNothing', function() { - webUIListenerCallback('chrome-cleanup-on-reporter-running'); - webUIListenerCallback( - 'chrome-cleanup-on-idle', - ChromeCleanupIdleReason.REPORTER_FOUND_NOTHING); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector('#action-button'); - assertFalse(!!actionButton); - }); - - test('reporterFoundNothing', function() { - webUIListenerCallback('chrome-cleanup-on-reporter-running'); - webUIListenerCallback( - 'chrome-cleanup-on-idle', - ChromeCleanupIdleReason.REPORTER_FOUND_NOTHING); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector('#action-button'); - assertFalse(!!actionButton); - }); - - test('startScanFromIdle', async function() { - updateReportingEnabledPref(false); - webUIListenerCallback( - 'chrome-cleanup-on-idle', ChromeCleanupIdleReason.INITIAL); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector<CrButtonElement>( - '#action-button'); - assertTrue(!!actionButton); - actionButton!.click(); - const logsUploadEnabled = - await chromeCleanupProxy.whenCalled('startScanning'); - assertFalse(logsUploadEnabled); - webUIListenerCallback('chrome-cleanup-on-scanning', false); - flush(); - - const spinner = - chromeCleanupPage.shadowRoot!.querySelector('paper-spinner-lite')!; - assertTrue(spinner.active); - }); - - test('scanFoundNothing', function() { - webUIListenerCallback('chrome-cleanup-on-scanning', false); - webUIListenerCallback( - 'chrome-cleanup-on-idle', - ChromeCleanupIdleReason.SCANNING_FOUND_NOTHING); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector('#action-button'); - assertFalse(!!actionButton); - }); - - test('scanFailure', function() { - webUIListenerCallback('chrome-cleanup-on-scanning', false); - webUIListenerCallback( - 'chrome-cleanup-on-idle', ChromeCleanupIdleReason.SCANNING_FAILED); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector('#action-button'); - assertFalse(!!actionButton); - }); - - // Test all combinations of item list sizes. - for (let file_index = 0; file_index < fileLists.length; file_index++) { - for (let registry_index = 0; registry_index < registryKeysLists.length; - registry_index++) { - const testName = 'startCleanupFromInfected_' + descriptors[file_index] + - 'Files' + descriptors[registry_index] + 'RegistryKeys'; - const fileList = fileLists[file_index]!; - const registryKeysList = registryKeysLists[registry_index]!; - - test(testName, async function() { - await startCleanupFromInfected(fileList, registryKeysList); - }); - } - } - - test('rebootFromRebootRequired', function() { - webUIListenerCallback('chrome-cleanup-on-reboot-required'); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector<CrButtonElement>( - '#action-button'); - assertTrue(!!actionButton); - actionButton!.click(); - return chromeCleanupProxy.whenCalled('restartComputer'); - }); - - test('cleanupFailure', function() { - updateReportingEnabledPref(false); - webUIListenerCallback( - 'chrome-cleanup-on-cleaning', true /* isPoweredByPartner */, - defaultScannerResults); - webUIListenerCallback( - 'chrome-cleanup-on-idle', ChromeCleanupIdleReason.CLEANING_FAILED); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector('#action-button'); - assertFalse(!!actionButton); - }); - - test('cleanupSuccess', function() { - webUIListenerCallback( - 'chrome-cleanup-on-cleaning', true /* isPoweredByPartner */, - defaultScannerResults); - webUIListenerCallback( - 'chrome-cleanup-on-idle', ChromeCleanupIdleReason.CLEANING_SUCCEEDED); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector('#action-button'); - assertFalse(!!actionButton); - - const title = chromeCleanupPage.shadowRoot!.querySelector('#status-title'); - assertTrue(!!title); - assertTrue(!!title!.querySelector('a')); - }); - - test('logsUploadingOnScanOffered', function() { - return testLogsUploading(true /* testingScanOffered */); - }); - - test('logsUploadingOnInfected', function() { - return testLogsUploading(false /* testingScanOffered */); - }); - - test('onInfectedResultsProvidedByPartner_True', function() { - return testPartnerLogoShown( - true /* onInfected */, true /* isPoweredByPartner */); - }); - - test('onInfectedResultsProvidedByPartner_False', function() { - return testPartnerLogoShown( - true /* onInfected */, false /* isPoweredByPartner */); - }); - - test('onCleaningResultsProvidedByPartner_True', function() { - return testPartnerLogoShown( - false /* onInfected */, true /* isPoweredByPartner */); - }); - - test('onCleaningResultsProvidedByPartner_False', function() { - return testPartnerLogoShown( - false /* onInfected */, false /* isPoweredByPartner */); - }); - - test('logsUploadingState_reporterPolicyDisabled', function() { - webUIListenerCallback( - 'chrome-cleanup-on-idle', ChromeCleanupIdleReason.INITIAL); - // prefs.software_reporter.enabled is not a real preference as it can't be - // set by the user. ChromeCleanupHandler can notify the JS of changes to the - // policy enforcement. - webUIListenerCallback('chrome-cleanup-enabled-change', false); - flush(); - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector<CrButtonElement>( - '#action-button'); - assertTrue(!!actionButton); - assertTrue(actionButton!.disabled); - - const logsControl = - chromeCleanupPage.shadowRoot!.querySelector<SettingsCheckboxElement>( - '#chromeCleanupLogsUploadControl'); - assertTrue(!!logsControl); - assertTrue(logsControl!.disabled); - }); - - test('logsUploadingState_reporterReportingPolicyDisabled', function() { - webUIListenerCallback( - 'chrome-cleanup-on-idle', ChromeCleanupIdleReason.INITIAL); - flush(); - - chromeCleanupPage.prefs = { - software_reporter: { - reporting: { - type: chrome.settingsPrivate.PrefType.BOOLEAN, - enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, - controlledBy: chrome.settingsPrivate.ControlledBy.USER_POLICY, - value: false, - key: '', - }, - }, - }; - - const actionButton = - chromeCleanupPage.shadowRoot!.querySelector<CrButtonElement>( - '#action-button'); - assertTrue(!!actionButton); - assertFalse(actionButton!.disabled); - - const logsControl = - chromeCleanupPage.shadowRoot!.querySelector<SettingsCheckboxElement>( - '#chromeCleanupLogsUploadControl'); - assertTrue(!!logsControl); - assertFalse(logsControl!.disabled); - assertTrue(logsControl!.$.checkbox.disabled); - }); -});
diff --git a/chrome/test/data/webui/settings/chromeos/device_page_tests.js b/chrome/test/data/webui/settings/chromeos/device_page_tests.js index f476599..8f5b9a7 100644 --- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -697,18 +697,18 @@ const sectionHeader = audioPage.shadowRoot.querySelector('#audioInputTitle'); assertTrue(isVisible(sectionHeader)); - assertEquals('Input', sectionHeader.textContent); + assertEquals('Input', sectionHeader.textContent.trim()); const deviceSubsectionHeader = audioPage.shadowRoot.querySelector('#audioInputDeviceLabel'); assertTrue(isVisible(deviceSubsectionHeader)); - assertEquals('Device', deviceSubsectionHeader.textContent); + assertEquals('Device', deviceSubsectionHeader.textContent.trim()); const deviceSubsectionDropdown = audioPage.shadowRoot.querySelector('#audioInputDeviceDropdown'); assertTrue(isVisible(deviceSubsectionDropdown)); const inputGainSubsectionHeader = audioPage.shadowRoot.querySelector('#audioInputGainLabel'); assertTrue(isVisible(inputGainSubsectionHeader), 'audioInputGainLabel'); - assertEquals('Volume', inputGainSubsectionHeader.textContent); + assertEquals('Volume', inputGainSubsectionHeader.textContent.trim()); const inputVolumeButton = audioPage.shadowRoot.querySelector('#audioInputGainMuteButton'); assertTrue(isVisible(inputVolumeButton), 'audioInputGainMuteButton'); @@ -720,7 +720,8 @@ '#audioInputNoiseCancellationLabel'); assertTrue(isVisible(noiseCancellationSubsectionHeader)); assertEquals( - 'Noise Cancellation', noiseCancellationSubsectionHeader.textContent); + 'Noise Cancellation', + noiseCancellationSubsectionHeader.textContent.trim()); const noiseCancellationToggle = audioPage.shadowRoot.querySelector( '#audioInputNoiseCancellationToggle'); assertTrue(isVisible(noiseCancellationToggle)); @@ -893,6 +894,25 @@ outputDevices: [], /** @type {!Array<!AudioDevice>} */ + inputDevices: [ + fakeCrosAudioConfig.fakeInternalMicActive, + ], + }; + + /** @type {!AudioSystemProperties} */ + const emptyInputDevicesFakeAudioSystemProperties = { + outputVolumePercent: 75, + + /** @type {!MuteState} */ + outputMuteState: crosAudioConfigMojomWebui.MuteState.kNotMuted, + + /** @type {!Array<!AudioDevice>} */ + outputDevices: [ + fakeCrosAudioConfig.fakeSpeakerActive, + fakeCrosAudioConfig.fakeMicJackInactive, + ], + + /** @type {!Array<!AudioDevice>} */ inputDevices: [], }; @@ -1103,6 +1123,12 @@ emptyOutputDevicesFakeAudioSystemProperties.outputDevices.length, outputDeviceDropdown.length); + // If the output devices are empty, the output section should be hidden. + const outputDeviceSection = audioPage.shadowRoot.querySelector('#output'); + assertFalse(isVisible(outputDeviceSection)); + const inputDeviceSection = audioPage.shadowRoot.querySelector('#input'); + assertTrue(isVisible(inputDeviceSection)); + // Test active speaker case. crosAudioConfig.setAudioSystemProperties( activeSpeakerFakeAudioSystemProperties); @@ -1157,6 +1183,21 @@ fakeCrosAudioConfig.defaultFakeAudioSystemProperties.inputDevices .length, inputDeviceDropdown.length); + + // Test empty input devices case. + crosAudioConfig.setAudioSystemProperties( + emptyInputDevicesFakeAudioSystemProperties); + await flushTasks(); + assertTrue(!inputDeviceDropdown.value); + assertEquals( + emptyInputDevicesFakeAudioSystemProperties.inputDevices.length, + inputDeviceDropdown.length); + + // If the input devices are empty, the input section should be hidden. + const inputDeviceSection = audioPage.shadowRoot.querySelector('#input'); + assertFalse(isVisible(inputDeviceSection)); + const outputDeviceSection = audioPage.shadowRoot.querySelector('#output'); + assertTrue(isVisible(outputDeviceSection)); }); test('simulate setting active input device', async function() {
diff --git a/chrome/test/data/webui/settings/chromeos/os_bluetooth_device_detail_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/os_bluetooth_device_detail_subpage_tests.js index 2796e28..175823a 100644 --- a/chrome/test/data/webui/settings/chromeos/os_bluetooth_device_detail_subpage_tests.js +++ b/chrome/test/data/webui/settings/chromeos/os_bluetooth_device_detail_subpage_tests.js
@@ -755,6 +755,15 @@ // Disconnect device and check that connection error is not shown. getBluetoothConnectDisconnectBtn().click(); + + // Disconnecting. + assertUIState( + /*isShowingConnectionFailed=*/ false, + /*isConnectDisconnectBtnDisabled=*/ true, + /*bluetoothStateText=*/ + bluetoothDeviceDetailPage.i18n('bluetoothDeviceDetailConnected'), + /*connectDisconnectBtnText=*/ + bluetoothDeviceDetailPage.i18n('bluetoothDisconnect')); await flushAsync(); bluetoothConfig.completeDisconnect(/*success=*/ true); await flushAsync();
diff --git a/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js index 9caddc4..f96f182 100644 --- a/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js
@@ -42,6 +42,7 @@ 'requestSharedVmDevices', 'isVmDeviceShared', 'setVmDeviceShared', + 'requestBruschettaInstallerView', ]); this.crostiniMicSharingEnabled = false; this.crostiniIsRunning = true; @@ -263,4 +264,9 @@ this.methodCalled('setVmDeviceShared', id, device, shared); return this.getNewPromiseFor('setVmDeviceShared'); } + + /** @override */ + requestBruschettaInstallerView() { + this.methodCalled('requestBruschettaInstallerView'); + } }
diff --git a/chrome/test/data/webui/settings/chromeos/test_os_languages_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_os_languages_browser_proxy.js index fd0ea573..fccc57bb 100644 --- a/chrome/test/data/webui/settings/chromeos/test_os_languages_browser_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_os_languages_browser_proxy.js
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {LanguagesBrowserProxy} from 'chrome://os-settings/chromeos/lazy_load.js'; import {FakeInputMethodPrivate} from './fake_input_method_private.js'; import {FakeLanguageSettingsPrivate} from './fake_language_settings_private.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; -/** @implements {LanguagesBrowserProxy} */ +// This class implements LanguagesBrowserProxy from +// c/b/r/settings/chromeos/os_languages_page/languages_browser_proxy.ts. export class TestLanguagesBrowserProxy extends TestBrowserProxy { constructor() { const methodNames = [];
diff --git a/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.js b/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.js index f69ecc5..d6d1090 100644 --- a/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.js +++ b/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.js
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {LanguagesMetricsProxy} from 'chrome://os-settings/chromeos/lazy_load.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; /** * A test version of LanguagesMetricsProxy. - * @implements {LanguagesMetricsProxy} */ +// This class implements LanguagesMetricsProxy from +// c/b/r/settings/chromeos/os_languages_page/languages_metrics_proxy.ts. export class TestLanguagesMetricsProxy extends TestBrowserProxy { constructor() { super([
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index 9267854..09e5bd9 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -351,20 +351,6 @@ mocha.run(); }); -GEN('#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)'); -var CrSettingsSafetyCheckChromeCleanerTest = - class extends CrSettingsBrowserTest { - /** @override */ - get browsePreload() { - return 'chrome://settings/test_loader.html?module=settings/safety_check_chrome_cleaner_test.js'; - } -}; - -TEST_F('CrSettingsSafetyCheckChromeCleanerTest', 'All', function() { - mocha.run(); -}); -GEN('#endif'); - var CrSettingsSiteListTest = class extends CrSettingsBrowserTest { /** @override */ get browsePreload() { @@ -683,7 +669,8 @@ } }; -TEST_F('CrSettingsCookiesPageTest', 'CookiesPageTest', function() { +// TODO(crbug.com/1409653): fix flakiness and re-enable. +TEST_F('CrSettingsCookiesPageTest', 'DISABLED_CookiesPageTest', function() { runMochaSuite('CrSettingsCookiesPageTest'); }); @@ -697,8 +684,10 @@ }); GEN('#endif'); +// TODO(crbug.com/1409653): fix flakiness and re-enable. TEST_F( - 'CrSettingsCookiesPageTest', 'PrivacySandboxSettings4Disabled', function() { + 'CrSettingsCookiesPageTest', 'DISABLED_PrivacySandboxSettings4Disabled', + function() { runMochaSuite( 'CrSettingsCookiesPageTest_PrivacySandboxSettings4Disabled'); }); @@ -983,12 +972,6 @@ ].forEach(test => registerTest(...test)); GEN('#endif'); -GEN('#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)'); -[['ChromeCleanupPage', 'chrome_cleanup_page_test.js'], - ['IncompatibleApplicationsPage', 'incompatible_applications_page_test.js'], -].forEach(test => registerTest(...test)); -GEN('#endif'); - GEN('#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS_ASH)'); registerTest('MetricsReporting', 'metrics_reporting_tests.js'); GEN('#endif');
diff --git a/chrome/test/data/webui/settings/passwords_and_autofill_fake_data.ts b/chrome/test/data/webui/settings/passwords_and_autofill_fake_data.ts index 2d7df01..56fce9df 100644 --- a/chrome/test/data/webui/settings/passwords_and_autofill_fake_data.ts +++ b/chrome/test/data/webui/settings/passwords_and_autofill_fake_data.ts
@@ -171,11 +171,13 @@ /** * Creates a new valid IBAN entry for testing. + * If `value` is not empty, set guid when creating the IBAN entry, otherwise, + * leave it undefined, as it is an empty IBAN. */ export function createIbanEntry( value?: string, nickname?: string): chrome.autofillPrivate.IbanEntry { return { - guid: makeGuid(), + guid: value ? makeGuid() : undefined, value: (value || value === '') ? value : 'CR99 0000 0000 0000 8888 88', nickname: (nickname || nickname === '') ? nickname : 'My doctor\'s IBAN', metadata: { @@ -492,6 +494,7 @@ clearedCachedCreditCards: number = 0; addedVirtualCards: number = 0; requestedIbans: number = 0; + removedIbans: number = 0; } /** @@ -519,6 +522,7 @@ 'getUpiIdList', 'clearCachedCreditCard', 'removeCreditCard', + 'removeIban', 'addVirtualCard', ]); @@ -578,6 +582,10 @@ saveIban(_iban: chrome.autofillPrivate.IbanEntry) {} + removeIban(_guid: string) { + this.methodCalled('removeIban'); + } + getIbanList() { this.methodCalled('getIbanList'); return Promise.resolve(this.data.ibans); @@ -610,5 +618,6 @@ assertEquals( expected.addedVirtualCards, this.getCallCount('addVirtualCard')); assertEquals(expected.requestedIbans, this.getCallCount('getIbanList')); + assertEquals(expected.removedIbans, this.getCallCount('removeIban')); } }
diff --git a/chrome/test/data/webui/settings/payments_section_interactive_test.ts b/chrome/test/data/webui/settings/payments_section_interactive_test.ts index 1b9bb548..dab4e7d 100644 --- a/chrome/test/data/webui/settings/payments_section_interactive_test.ts +++ b/chrome/test/data/webui/settings/payments_section_interactive_test.ts
@@ -12,7 +12,7 @@ import {eventToPromise, isVisible, whenAttributeIs} from 'chrome://webui-test/test_util.js'; import {flushTasks} from 'chrome://webui-test/polymer_test_util.js'; -import {createCreditCardEntry, TestPaymentsManager} from './passwords_and_autofill_fake_data.js'; +import {createCreditCardEntry, createIbanEntry, TestPaymentsManager} from './passwords_and_autofill_fake_data.js'; // clang-format on /** @@ -163,6 +163,37 @@ return creditCardDialog; } + /** + * Creates the Edit IBAN dialog for existing local IBANs by simulating + * clicking the three-dots menu button then clicking the edit button of the + * first IBAN in the list. + */ + async function createEditIbanDialog( + ibans: chrome.autofillPrivate.IbanEntry[]): + Promise<SettingsIbanEditDialogElement> { + const section = await createPaymentsSection( + /*creditCards=*/[], /*ibans=*/ ibans); + // Simulate clicking three-dots menu button for the first IBAN in the list. + const firstEntry = section.$.paymentsList.shadowRoot!.querySelector( + 'settings-iban-list-entry'); + assertTrue(!!firstEntry); + const menuButton = firstEntry.$.ibanMenu; + assertTrue(!!menuButton); + menuButton.click(); + flush(); + + // Simulate clicking the 'Edit' button in the menu. + const menuEditIban = + section.shadowRoot!.querySelector<HTMLElement>('#menuEditIban'); + assertTrue(!!menuEditIban); + menuEditIban.click(); + flush(); + const ibanDialog = + section.shadowRoot!.querySelector('settings-iban-edit-dialog'); + assertTrue(!!ibanDialog); + return ibanDialog; + } + function nextYear(): string { return (new Date().getFullYear() + 1).toString(); } @@ -644,4 +675,33 @@ assertEquals(saveEvent.detail.nickname, 'My doctor\'s IBAN'); }); + test('update local IBAN value', async function() { + loadTimeData.overrideValues({ + showIbansSettings: true, + }); + const iban = + createIbanEntry('IE64 IRCE 9205 0112 3456 78', 'My teacher\'s IBAN'); + const ibanDialog = await createEditIbanDialog([iban]); + + // Wait for the dialog to open. + await whenAttributeIs(ibanDialog.$.dialog, 'open', ''); + + // Update IBAN value and nickname, and trigger the on-input handler. + const nicknameInput = ibanDialog.$.nicknameInput; + const valueInput = ibanDialog.$.valueInput; + valueInput.value = 'DE75 5121 0800 1245 1261 99'; + nicknameInput.value = 'My brother\'s IBAN'; + flush(); + + const savedPromise = eventToPromise('save-iban', ibanDialog); + const saveButton = ibanDialog.$.saveButton; + saveButton.click(); + const saveEvent = await savedPromise; + + // Verify the updated values are correctly passed to save-iban. + assertEquals(saveEvent.detail.guid, iban.guid); + assertEquals(saveEvent.detail.value, 'DE75 5121 0800 1245 1261 99'); + assertEquals(saveEvent.detail.nickname, 'My brother\'s IBAN'); + }); + });
diff --git a/chrome/test/data/webui/settings/payments_section_test.ts b/chrome/test/data/webui/settings/payments_section_test.ts index 56857a07..5426829 100644 --- a/chrome/test/data/webui/settings/payments_section_test.ts +++ b/chrome/test/data/webui/settings/payments_section_test.ts
@@ -181,6 +181,7 @@ expected.clearedCachedCreditCards = 0; expected.addedVirtualCards = 0; expected.requestedIbans = 1; + expected.removedIbans = 0; return expected; } @@ -1364,4 +1365,79 @@ assertEquals('', event.detail.nickname); }); + test('verifyIbanEntryIsNotEditedAfterCancel', async function() { + const iban = createIbanEntry('FI1410093000123458', 'NickName'); + let ibanDialog = createIbanDialog(iban); + + await whenAttributeIs(ibanDialog.$.dialog, 'open', ''); + + // Edit the value and nickname of the IBAN. + const nicknameInput = ibanDialog.$.nicknameInput; + nicknameInput.value = 'Updated NickName'; + + const valueInput = ibanDialog.$.valueInput; + valueInput.value = 'FI1410093000123412'; + flush(); + + const cancelButton = ibanDialog.$.cancelButton; + cancelButton.click(); + await eventToPromise('close', ibanDialog); + + ibanDialog = createIbanDialog(iban); + await whenAttributeIs(ibanDialog.$.dialog, 'open', ''); + + assertEquals(ibanDialog.get('nickname_'), iban.nickname); + assertEquals(ibanDialog.get('value_'), iban.value); + }); + + test('verifyLocalIbanMenu', async function() { + const iban = createIbanEntry(); + const section = await createPaymentsSection( + /*creditCards=*/[], [iban], /*upiIds=*/[], + /*prefValues=*/ {}); + assertEquals(1, getLocalIbanListItems().length); + + // Local IBANs will show the 3-dot overflow menu. + section.$.ibanSharedActionMenu.get(); + const menuEditIban = + section.shadowRoot!.querySelector<HTMLElement>('#menuEditIban'); + const menuRemoveIban = + section.shadowRoot!.querySelector<HTMLElement>('#menuRemoveIban'); + + // Menu should have 2 options. + assertTrue(!!menuEditIban); + assertTrue(!!menuRemoveIban); + assertFalse(menuEditIban.hidden); + assertFalse(menuRemoveIban!.hidden); + + flush(); + }); + + test('verifyRemoveIbanClicked', async function() { + const iban = createIbanEntry(); + + const section = await createPaymentsSection( + /*creditCards=*/[], [iban], /*upiIds=*/[], /*prefValues=*/ {}); + assertEquals(1, getLocalIbanListItems().length); + + const rowShadowRoot = getIbanRowShadowRoot(section.$.paymentsList); + assertTrue(!!rowShadowRoot); + const menuButton = rowShadowRoot.querySelector<HTMLElement>('#ibanMenu'); + assertTrue(!!menuButton); + menuButton.click(); + flush(); + + const menuRemoveIban = + section.shadowRoot!.querySelector<HTMLElement>('#menuRemoveIban'); + assertTrue(!!menuRemoveIban); + menuRemoveIban.click(); + flush(); + + const paymentsManager = + PaymentsManagerImpl.getInstance() as TestPaymentsManager; + const expectations = getDefaultExpectations(); + expectations.removedIbans = 1; + paymentsManager.assertExpectations(expectations); + }); + });
diff --git a/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.ts b/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.ts deleted file mode 100644 index b9d55f6..0000000 --- a/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.ts +++ /dev/null
@@ -1,291 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// clang-format off -import {webUIListenerCallback} from 'chrome://resources/js/cr.js'; -import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {ChromeCleanupProxyImpl} from 'chrome://settings/lazy_load.js'; -import {MetricsBrowserProxyImpl, Router, routes, SafetyCheckCallbackConstants, SafetyCheckChromeCleanerStatus, SafetyCheckIconStatus, SafetyCheckInteractions, SettingsSafetyCheckChromeCleanerChildElement} from 'chrome://settings/settings.js'; - -import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; - -import {TestChromeCleanupProxy} from './test_chrome_cleanup_proxy.js'; -import {TestMetricsBrowserProxy} from './test_metrics_browser_proxy.js'; - -// clang-format on - -const testDisplayString = 'Test display string'; - -/** - * Fire a safety check Chrome cleaner event. - */ -function fireSafetyCheckChromeCleanerEvent( - state: SafetyCheckChromeCleanerStatus) { - const event = { - newState: state, - displayString: testDisplayString, - }; - webUIListenerCallback( - SafetyCheckCallbackConstants.CHROME_CLEANER_CHANGED, event); -} - -interface AssertSafetyCheckChildParams { - page: HTMLElement; - iconStatus: SafetyCheckIconStatus; - label: string; - buttonLabel?: string; - buttonAriaLabel?: string; - buttonClass?: string; - managedIcon?: boolean; - rowClickable?: boolean; -} - -/** - * Verify that the safety check child inside the page has been configured as - * specified. - */ -function assertSafetyCheckChild({ - page, - iconStatus, - label, - buttonLabel, - buttonAriaLabel, - buttonClass, - managedIcon, - rowClickable, -}: AssertSafetyCheckChildParams) { - const safetyCheckChild = - page.shadowRoot!.querySelector('settings-safety-check-child'); - assertTrue(!!safetyCheckChild, 'safetyCheckChild is null'); - assertTrue( - safetyCheckChild.iconStatus === iconStatus, - 'unexpected iconStatus: ' + safetyCheckChild.iconStatus); - assertTrue( - safetyCheckChild.label === label, - 'unexpected label: ' + safetyCheckChild.label); - assertTrue( - safetyCheckChild.subLabel === testDisplayString, - 'unexpected subLabel: ' + safetyCheckChild.subLabel); - assertTrue( - !buttonLabel || safetyCheckChild.buttonLabel === buttonLabel, - 'unexpected buttonLabel: ' + safetyCheckChild.buttonLabel); - assertTrue( - !buttonAriaLabel || safetyCheckChild.buttonAriaLabel === buttonAriaLabel, - 'unexpected buttonAriaLabel: ' + safetyCheckChild.buttonAriaLabel); - assertTrue( - !buttonClass || safetyCheckChild.buttonClass === buttonClass, - 'unexpected buttonClass: ' + safetyCheckChild.buttonClass); - assertTrue( - !!managedIcon === !!safetyCheckChild.managedIcon, - 'unexpected managedIcon: ' + safetyCheckChild.managedIcon); - assertTrue( - !!rowClickable === !!safetyCheckChild.rowClickable, - 'unexpected rowClickable: ' + safetyCheckChild.rowClickable); -} - -suite('SafetyCheckChromeCleanerUiTests', function() { - let chromeCleanupBrowserProxy: TestChromeCleanupProxy; - let metricsBrowserProxy: TestMetricsBrowserProxy; - let page: SettingsSafetyCheckChromeCleanerChildElement; - - setup(function() { - chromeCleanupBrowserProxy = new TestChromeCleanupProxy(); - ChromeCleanupProxyImpl.setInstance(chromeCleanupBrowserProxy); - - metricsBrowserProxy = new TestMetricsBrowserProxy(); - MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy); - - document.body.innerHTML = window.trustedTypes!.emptyHTML; - page = document.createElement('settings-safety-check-chrome-cleaner-child'); - document.body.appendChild(page); - flush(); - }); - - teardown(function() { - page.remove(); - Router.getInstance().navigateTo(routes.BASIC); - }); - - async function expectLogging( - safetyCheckInteraction: SafetyCheckInteractions, userAction: string) { - assertEquals( - safetyCheckInteraction, - await metricsBrowserProxy.whenCalled( - 'recordSafetyCheckInteractionHistogram')); - assertEquals( - userAction, await metricsBrowserProxy.whenCalled('recordAction')); - } - - test('chromeCleanerHiddenUiTest', function() { - fireSafetyCheckChromeCleanerEvent(SafetyCheckChromeCleanerStatus.HIDDEN); - flush(); - // There is no Chrome cleaner child in safety check. - assertFalse( - !!page.shadowRoot!.querySelector('settings-safety-check-child')); - }); - - test('chromeCleanerCheckingUiTest', function() { - fireSafetyCheckChromeCleanerEvent(SafetyCheckChromeCleanerStatus.CHECKING); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.RUNNING, - label: 'Device software', - }); - }); - - test('chromeCleanerInfectedTest', async function() { - fireSafetyCheckChromeCleanerEvent(SafetyCheckChromeCleanerStatus.INFECTED); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.WARNING, - label: 'Device software', - buttonLabel: 'Review', - buttonAriaLabel: 'Review device software', - buttonClass: 'action-button', - }); - // User clicks the button. - page.shadowRoot!.querySelector('settings-safety-check-child')!.shadowRoot! - .querySelector<HTMLElement>('#button')!.click(); - await expectLogging( - SafetyCheckInteractions.CHROME_CLEANER_REVIEW_INFECTED_STATE, - 'Settings.SafetyCheck.ChromeCleanerReviewInfectedState'); - // Ensure the correct Settings page is shown. - assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute()); - }); - - test('chromeCleanerRebootRequiredUiTest', async function() { - fireSafetyCheckChromeCleanerEvent( - SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.INFO, - label: 'Device software', - buttonLabel: 'Restart computer', - buttonAriaLabel: 'Restart computer', - buttonClass: 'action-button', - }); - // User clicks the button. - page.shadowRoot!.querySelector('settings-safety-check-child')!.shadowRoot! - .querySelector<HTMLElement>('#button')!.click(); - await expectLogging( - SafetyCheckInteractions.CHROME_CLEANER_REBOOT, - 'Settings.SafetyCheck.ChromeCleanerReboot'); - // Ensure the browser proxy call is done. - return chromeCleanupBrowserProxy.whenCalled('restartComputer'); - }); - - test('chromeCleanerScanningForUwsUiTest', async function() { - fireSafetyCheckChromeCleanerEvent( - SafetyCheckChromeCleanerStatus.SCANNING_FOR_UWS); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.RUNNING, - label: 'Device software', - rowClickable: true, - }); - // User clicks the row. - page.shadowRoot!.querySelector('settings-safety-check-child')!.click(); - // Ensure UMA is logged. - await expectLogging( - SafetyCheckInteractions.CHROME_CLEANER_CARET_NAVIGATION, - 'Settings.SafetyCheck.ChromeCleanerCaretNavigation'); - // Ensure the correct Settings page is shown. - assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute()); - }); - - test('chromeCleanerRemovingUwsUiTest', async function() { - fireSafetyCheckChromeCleanerEvent( - SafetyCheckChromeCleanerStatus.REMOVING_UWS); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.RUNNING, - label: 'Device software', - rowClickable: true, - }); - // User clicks the row. - page.shadowRoot!.querySelector('settings-safety-check-child')!.click(); - // Ensure UMA is logged. - await expectLogging( - SafetyCheckInteractions.CHROME_CLEANER_CARET_NAVIGATION, - 'Settings.SafetyCheck.ChromeCleanerCaretNavigation'); - // Ensure the correct Settings page is shown. - assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute()); - }); - - test('chromeCleanerDisabledByAdminUiTest', function() { - fireSafetyCheckChromeCleanerEvent( - SafetyCheckChromeCleanerStatus.DISABLED_BY_ADMIN); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.INFO, - label: 'Device software', - managedIcon: true, - }); - }); - - test('chromeCleanerErrorUiTest', async function() { - fireSafetyCheckChromeCleanerEvent(SafetyCheckChromeCleanerStatus.ERROR); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.INFO, - label: 'Device software', - rowClickable: true, - }); - // User clicks the row. - page.shadowRoot!.querySelector('settings-safety-check-child')!.click(); - // Ensure UMA is logged. - await expectLogging( - SafetyCheckInteractions.CHROME_CLEANER_CARET_NAVIGATION, - 'Settings.SafetyCheck.ChromeCleanerCaretNavigation'); - // Ensure the correct Settings page is shown. - assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute()); - }); - - test('chromeCleanerNoUwsFoundWithTimestampUiTest', async function() { - fireSafetyCheckChromeCleanerEvent( - SafetyCheckChromeCleanerStatus.NO_UWS_FOUND_WITH_TIMESTAMP); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.SAFE, - label: 'Device software', - rowClickable: true, - }); - // User clicks the row. - page.shadowRoot!.querySelector('settings-safety-check-child')!.click(); - // Ensure UMA is logged. - await expectLogging( - SafetyCheckInteractions.CHROME_CLEANER_CARET_NAVIGATION, - 'Settings.SafetyCheck.ChromeCleanerCaretNavigation'); - // Ensure the correct Settings page is shown. - assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute()); - }); - - test('chromeCleanerNoUwsFoundWithoutTimestampUiTest', async function() { - fireSafetyCheckChromeCleanerEvent( - SafetyCheckChromeCleanerStatus.NO_UWS_FOUND_WITHOUT_TIMESTAMP); - flush(); - assertSafetyCheckChild({ - page: page, - iconStatus: SafetyCheckIconStatus.INFO, - label: 'Device software', - rowClickable: true, - }); - // User clicks the row. - page.shadowRoot!.querySelector('settings-safety-check-child')!.click(); - // Ensure UMA is logged. - await expectLogging( - SafetyCheckInteractions.CHROME_CLEANER_CARET_NAVIGATION, - 'Settings.SafetyCheck.ChromeCleanerCaretNavigation'); - // Ensure the correct Settings page is shown. - assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute()); - }); -});
diff --git a/chrome/test/data/webui/settings/safety_check_page_test.ts b/chrome/test/data/webui/settings/safety_check_page_test.ts index 81fe06a..fee6a9e 100644 --- a/chrome/test/data/webui/settings/safety_check_page_test.ts +++ b/chrome/test/data/webui/settings/safety_check_page_test.ts
@@ -5,7 +5,7 @@ // clang-format off import {webUIListenerCallback} from 'chrome://resources/js/cr.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {HatsBrowserProxyImpl, LifetimeBrowserProxyImpl, MetricsBrowserProxyImpl, OpenWindowProxyImpl, PasswordCheckReferrer, PasswordManagerImpl, Router, routes, SafetyCheckBrowserProxy, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckChromeCleanerStatus, SafetyCheckExtensionsStatus, SafetyCheckIconStatus, SafetyCheckInteractions, SafetyCheckParentStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus, SettingsSafetyCheckChildElement, SettingsSafetyCheckExtensionsChildElement, SettingsSafetyCheckPageElement, SettingsSafetyCheckPasswordsChildElement, SettingsSafetyCheckSafeBrowsingChildElement ,SettingsSafetyCheckUpdatesChildElement, TrustSafetyInteraction} from 'chrome://settings/settings.js'; +import {HatsBrowserProxyImpl, LifetimeBrowserProxyImpl, MetricsBrowserProxyImpl, OpenWindowProxyImpl, PasswordCheckReferrer, PasswordManagerImpl, Router, routes, SafetyCheckBrowserProxy, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckExtensionsStatus, SafetyCheckIconStatus, SafetyCheckInteractions, SafetyCheckParentStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus, SettingsSafetyCheckChildElement, SettingsSafetyCheckExtensionsChildElement, SettingsSafetyCheckPageElement, SettingsSafetyCheckPasswordsChildElement, SettingsSafetyCheckSafeBrowsingChildElement ,SettingsSafetyCheckUpdatesChildElement, TrustSafetyInteraction} from 'chrome://settings/settings.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; @@ -79,19 +79,6 @@ webUIListenerCallback(SafetyCheckCallbackConstants.EXTENSIONS_CHANGED, event); } -/** - * Fire a safety check Chrome cleaner event. - */ -function fireSafetyCheckChromeCleanerEvent( - state: SafetyCheckChromeCleanerStatus) { - const event = { - newState: state, - displayString: testDisplayString, - }; - webUIListenerCallback( - SafetyCheckCallbackConstants.CHROME_CLEANER_CHANGED, event); -} - class TestSafetyCheckBrowserProxy extends TestBrowserProxy implements SafetyCheckBrowserProxy { private parentRanDisplayString_ = ''; @@ -168,7 +155,6 @@ fireSafetyCheckPasswordsEvent(SafetyCheckPasswordsStatus.CHECKING); fireSafetyCheckSafeBrowsingEvent(SafetyCheckSafeBrowsingStatus.CHECKING); fireSafetyCheckExtensionsEvent(SafetyCheckExtensionsStatus.CHECKING); - fireSafetyCheckChromeCleanerEvent(SafetyCheckChromeCleanerStatus.CHECKING); fireSafetyCheckParentEvent(SafetyCheckParentStatus.CHECKING); flush(); @@ -185,7 +171,6 @@ SafetyCheckSafeBrowsingStatus.ENABLED_STANDARD); fireSafetyCheckExtensionsEvent( SafetyCheckExtensionsStatus.NO_BLOCKLISTED_EXTENSIONS); - fireSafetyCheckChromeCleanerEvent(SafetyCheckChromeCleanerStatus.INFECTED); fireSafetyCheckParentEvent(SafetyCheckParentStatus.AFTER); flush();
diff --git a/chrome/test/data/webui/settings/test_chrome_cleanup_proxy.ts b/chrome/test/data/webui/settings/test_chrome_cleanup_proxy.ts deleted file mode 100644 index 4af2b46..0000000 --- a/chrome/test/data/webui/settings/test_chrome_cleanup_proxy.ts +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {ChromeCleanupProxy} from 'chrome://settings/lazy_load.js'; -import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; - -export class TestChromeCleanupProxy extends TestBrowserProxy implements - ChromeCleanupProxy { - constructor() { - super([ - 'registerChromeCleanerObserver', - 'restartComputer', - 'startCleanup', - 'startScanning', - 'notifyShowDetails', - 'notifyLearnMoreClicked', - 'getMoreItemsPluralString', - 'getItemsToRemovePluralString', - ]); - } - - registerChromeCleanerObserver() { - this.methodCalled('registerChromeCleanerObserver'); - } - - restartComputer() { - this.methodCalled('restartComputer'); - } - - startCleanup(logsUploadEnabled: boolean) { - this.methodCalled('startCleanup', logsUploadEnabled); - } - - startScanning(logsUploadEnabled: boolean) { - this.methodCalled('startScanning', logsUploadEnabled); - } - - notifyShowDetails(enabled: boolean) { - this.methodCalled('notifyShowDetails', enabled); - } - - notifyLearnMoreClicked() { - this.methodCalled('notifyLearnMoreClicked'); - } - - getMoreItemsPluralString(numHiddenItems: number) { - this.methodCalled('getMoreItemsPluralString', numHiddenItems); - return Promise.resolve(''); - } - - getItemsToRemovePluralString(numItems: number) { - this.methodCalled('getItemsToRemovePluralString', numItems); - return Promise.resolve(''); - } -}
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn b/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn index f79f8ae..a126034b 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn +++ b/chrome/test/data/webui/side_panel/customize_chrome/BUILD.gn
@@ -24,6 +24,7 @@ "cards_test.ts", "categories_test.ts", "check_mark_wrapper_test.ts", + "chrome_colors_test.ts", "color_test.ts", "colors_test.ts", "colors_focus_test.ts",
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts index f978431..5ed8c69a 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/app_test.ts
@@ -57,9 +57,25 @@ assertTrue( customizeChromeApp.$.overviewPage.classList.contains('iron-selected')); - // Set page back to categories and go back a page. + // Set page back to categories. customizeChromeApp.$.appearanceElement.dispatchEvent( new Event('edit-theme-click')); + + // Send event for chrome colors select. + customizeChromeApp.$.categoriesPage.dispatchEvent( + new Event('chrome-colors-select')); + // Current page should now be chrome colors. + assertTrue(customizeChromeApp.$.chromeColorsPage.classList.contains( + 'iron-selected')); + + // Send event for back click. + customizeChromeApp.$.chromeColorsPage.dispatchEvent( + new Event('back-click')); + // Current page should now be categories. + assertTrue(customizeChromeApp.$.categoriesPage.classList.contains( + 'iron-selected')); + + // Send event for back click. customizeChromeApp.$.categoriesPage.dispatchEvent(new Event('back-click')); // Current page should now be overview. assertTrue(
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts index fc6736ba..0760b21 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/appearance_test.ts
@@ -28,13 +28,13 @@ mock, new CustomizeChromePageCallbackRouter())); callbackRouterRemote = CustomizeChromeApiProxy.getInstance() .callbackRouter.$.bindNewPipeAndPassRemote(); - // Set result for getChromeColors for the mock handler. Otherwise, it - // crashes since colors is a child of appearance and needs a Promise - // from getChromeColors. - handler.setResultFor('getChromeColors', Promise.resolve([])); + // Set result for getOverviewChromeColors for the mock handler. Otherwise, + // it crashes since colors is a child of appearance and needs a Promise from + // getOverviewChromeColors. + handler.setResultFor('getOverviewChromeColors', Promise.resolve({})); appearanceElement = document.createElement('customize-chrome-appearance'); document.body.appendChild(appearanceElement); - await handler.whenCalled('getChromeColors'); + await handler.whenCalled('getOverviewChromeColors'); }); test('appearance edit button creates event', async () => {
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/categories_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/categories_test.ts index b9200e1e..3ea06a9 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/categories_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/categories_test.ts
@@ -114,4 +114,12 @@ categoriesElement.$.chromeWebStoreTile.click(); assertEquals(1, handler.getCallCount('openChromeWebStore')); }); + + test('clicking chrome colors sends event', async () => { + const eventPromise = + eventToPromise('chrome-colors-select', categoriesElement); + categoriesElement.$.chromeColorsTile.click(); + const event = await eventPromise; + assertTrue(!!event); + }); });
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/chrome_colors_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/chrome_colors_test.ts new file mode 100644 index 0000000..e3a0477 --- /dev/null +++ b/chrome/test/data/webui/side_panel/customize_chrome/chrome_colors_test.ts
@@ -0,0 +1,71 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'chrome://webui-test/mojo_webui_test_support.js'; +import 'chrome://customize-chrome-side-panel.top-chrome/chrome_colors.js'; + +import {ChromeColorsElement} from 'chrome://customize-chrome-side-panel.top-chrome/chrome_colors.js'; +import {ColorElement} from 'chrome://customize-chrome-side-panel.top-chrome/color.js'; +import {ChromeColor, CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerRemote} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; +import {CustomizeChromeApiProxy} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome_api_proxy.js'; +import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; +import {eventToPromise} from 'chrome://webui-test/test_util.js'; + +import {installMock} from './test_support.js'; + +suite('ChromeColorsTest', () => { + let chromeColorsElement: ChromeColorsElement; + let handler: TestBrowserProxy<CustomizeChromePageHandlerRemote>; + + setup(async () => { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + handler = installMock( + CustomizeChromePageHandlerRemote, + (mock: CustomizeChromePageHandlerRemote) => + CustomizeChromeApiProxy.setInstance( + mock, new CustomizeChromePageCallbackRouter())); + }); + + async function setInitialSettings(numColors: number): Promise<void> { + const colors: ChromeColor[] = []; + for (let i = 0; i < numColors; i++) { + colors.push({ + name: `color_${i}`, + seed: {value: i}, + background: {value: i + 1}, + foreground: {value: i + 2}, + }); + } + handler.setResultFor('getChromeColors', Promise.resolve({colors})); + chromeColorsElement = + document.createElement('customize-chrome-chrome-colors'); + document.body.appendChild(chromeColorsElement); + await handler.whenCalled('getChromeColors'); + } + + test('back button create event', async () => { + await setInitialSettings(0); + + const eventPromise = eventToPromise('back-click', chromeColorsElement); + chromeColorsElement.$.backButton.click(); + const event = await eventPromise; + assertTrue(!!event); + }); + + test('get chrome colors', async () => { + await setInitialSettings(2); + + const colors = + chromeColorsElement.shadowRoot!.querySelectorAll<ColorElement>( + '.chrome-color'); + assertEquals(colors.length, 2); + assertDeepEquals({value: 1}, colors[0]!.backgroundColor); + assertDeepEquals({value: 2}, colors[0]!.foregroundColor); + assertEquals('color_0', colors[0]!.title); + assertDeepEquals({value: 2}, colors[1]!.backgroundColor); + assertDeepEquals({value: 3}, colors[1]!.foregroundColor); + assertEquals('color_1', colors[1]!.title); + }); +});
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/color_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/color_test.ts index a14a201..bf21a9d 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/color_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/color_test.ts
@@ -37,8 +37,7 @@ const svg = colorElement.shadowRoot!.querySelector('svg')!; assertStyle(svg, 'width', '46px'); assertStyle(svg, 'height', '46px'); - const background = colorElement.shadowRoot!.querySelector('#background')!; - assertStyle(background, 'r', '25px'); + assertStyle(svg, 'border', '0px none rgb(0, 0, 0)'); }); test('color can be unchecked', () => { @@ -52,8 +51,7 @@ const svg = colorElement.shadowRoot!.querySelector('svg')!; assertStyle(svg, 'width', '50px'); assertStyle(svg, 'height', '50px'); - const background = colorElement.shadowRoot!.querySelector('#background')!; - assertStyle(background, 'r', '24px'); + assertStyle(svg, 'border', '1px solid rgba(0, 0, 0, 0)'); }); test('background color can be hidden', () => {
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/colors_focus_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/colors_focus_test.ts index 351752cb2..08bb0bb 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/colors_focus_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/colors_focus_test.ts
@@ -21,7 +21,7 @@ (mock: CustomizeChromePageHandlerRemote) => CustomizeChromeApiProxy.setInstance( mock, new CustomizeChromePageCallbackRouter())); - handler.setResultFor('getChromeColors', new Promise(() => {})); + handler.setResultFor('getOverviewChromeColors', new Promise(() => {})); colorsElement = new ColorsElement(); document.body.appendChild(colorsElement); });
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/colors_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/colors_test.ts index d1d2ff3..0ba0c82 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/colors_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/colors_test.ts
@@ -5,7 +5,8 @@ import 'chrome://webui-test/mojo_webui_test_support.js'; import {ColorElement} from 'chrome://customize-chrome-side-panel.top-chrome/color.js'; -import {Color, ColorsElement, DARK_DEFAULT_COLOR, LIGHT_DEFAULT_COLOR} from 'chrome://customize-chrome-side-panel.top-chrome/colors.js'; +import {Color, DARK_DEFAULT_COLOR, LIGHT_DEFAULT_COLOR} from 'chrome://customize-chrome-side-panel.top-chrome/color_utils.js'; +import {ColorsElement} from 'chrome://customize-chrome-side-panel.top-chrome/colors.js'; import {ChromeColor, CustomizeChromePageCallbackRouter, CustomizeChromePageHandlerRemote, CustomizeChromePageRemote, Theme} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome.mojom-webui.js'; import {CustomizeChromeApiProxy} from 'chrome://customize-chrome-side-panel.top-chrome/customize_chrome_api_proxy.js'; import {ManagedDialogElement} from 'chrome://resources/cr_components/managed_dialog/managed_dialog.js'; @@ -32,7 +33,8 @@ callbackRouter = CustomizeChromeApiProxy.getInstance() .callbackRouter.$.bindNewPipeAndPassRemote(); chromeColorsResolver = new PromiseResolver(); - handler.setResultFor('getChromeColors', chromeColorsResolver.promise); + handler.setResultFor( + 'getOverviewChromeColors', chromeColorsResolver.promise); colorsElement = new ColorsElement(); document.body.appendChild(colorsElement); });
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/side_panel_customize_chrome_browsertest.js b/chrome/test/data/webui/side_panel/customize_chrome/side_panel_customize_chrome_browsertest.js index aac9e09a..0e670cb 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/side_panel_customize_chrome_browsertest.js +++ b/chrome/test/data/webui/side_panel/customize_chrome/side_panel_customize_chrome_browsertest.js
@@ -134,6 +134,15 @@ } }; +var SidePanelCustomizeChromeChromeColorsTest = + class extends SidePanelCustomizeChromeBrowserTest { + /** @override */ + get browsePreload() { + return 'chrome://customize-chrome-side-panel.top-chrome/test_loader.html' + + '?module=side_panel_customize_chrome/chrome_colors_test.js'; + } +}; + TEST_F('SidePanelCustomizeChromeButtonLabelTest', 'All', function() { mocha.run(); }); @@ -182,3 +191,7 @@ TEST_F('SidePanelCustomizeChromeThemeSnapshotTest', 'All', function() { mocha.run(); }); + +TEST_F('SidePanelCustomizeChromeChromeColorsTest', 'All', function() { + mocha.run(); +});
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts b/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts index a87f74e..c07ee84d 100644 --- a/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts +++ b/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts
@@ -839,6 +839,114 @@ assertContainerInnerHTML(expected); }); + test('updateContent textStyle overline', () => { + // root htmlTag='#document' id=1 + // ++paragraph htmlTag='p' id=2 + // ++++staticText name='This should be overlined.' textStyle='overline' id=3 + // ++++staticText name='Regular text.' id=4 + // ++++staticText name='This is overlined and bolded.' textStyle='overline + // underline'id=5 + const axTree = { + rootId: 1, + nodes: [ + { + id: 1, + role: 'rootWebArea', + htmlTag: '#document', + childIds: [2], + }, + { + id: 2, + role: 'paragraph', + htmlTag: 'p', + childIds: [3, 4, 5], + }, + { + id: 3, + role: 'staticText', + textStyle: 'overline', + name: 'This should be overlined.', + }, + { + id: 4, + role: 'staticText', + name: 'Regular text.', + }, + { + id: 5, + role: 'staticText', + textStyle: 'overline underline', + name: 'This is overlined and bolded.', + }, + ], + }; + chrome.readAnything.setContentForTesting(axTree, [2]); + const expected = '<div><p><span style="text-decoration: overline;">This ' + + 'should be overlined.</span>Regular text.<b style="text-decoration: ' + + 'overline;">This is overlined and bolded.</b></p></div>'; + assertContainerInnerHTML(expected); + }); + + test('updateContent textStyle bold', () => { + // root htmlTag='#document' id=1 + // ++paragraph htmlTag='p' id=2 + // ++++staticText name='Regular text.' id=3 + // ++++staticText name='This should be bolded.' textStyle='underline' id=4 + // ++paragraph htmlTag='p' id=5 + // ++++staticText name='Bolded text.' textStyle='italic' id=6 + // ++++staticText name='Bolded text.' textStyle='bold' id=7 + const axTree = { + rootId: 1, + nodes: [ + { + id: 1, + role: 'rootWebArea', + htmlTag: '#document', + childIds: [2, 5], + }, + { + id: 2, + role: 'paragraph', + htmlTag: 'p', + childIds: [3, 4], + }, + { + id: 3, + role: 'staticText', + name: 'Regular text.', + }, + { + id: 4, + role: 'staticText', + textStyle: 'underline', + name: 'This should be bolded.', + }, + { + id: 5, + role: 'paragraph', + htmlTag: 'p', + childIds: [6, 7], + }, + { + id: 6, + role: 'staticText', + textStyle: 'italic', + name: 'Bolded text.', + }, + { + id: 7, + role: 'staticText', + textStyle: 'bold', + name: 'Bolded text.', + }, + ], + }; + chrome.readAnything.setContentForTesting(axTree, [2, 5]); + const expected = '<div><p>Regular text.<b>This should be bolded.</b></p>' + + '<p><b>Bolded text.</b><b>Bolded text.</b></p></div>'; + assertContainerInnerHTML(expected); + }); + test('updateContent noContentNodes', () => { // Fake chrome.readAnything methods for the following AXTree // root htmlTag='#document' id=1
diff --git a/chrome/test/data/webui/side_panel/user_notes/app_test.ts b/chrome/test/data/webui/side_panel/user_notes/app_test.ts index f8b6315e9..72db37d 100644 --- a/chrome/test/data/webui/side_panel/user_notes/app_test.ts +++ b/chrome/test/data/webui/side_panel/user_notes/app_test.ts
@@ -163,4 +163,14 @@ deleteButton.click(); await testProxy.whenCalled('deleteNote'); }); + + test('refresh notes when url changes', async () => { + let notesElements = queryNotes(); + assertEquals(notesElements.length, 3); + testProxy.setNotes([]); + testProxy.getCallbackRouterRemote().currentTabUrlChanged(); + await flushTasks(); + notesElements = queryNotes(); + assertEquals(notesElements.length, 1); + }); }); \ No newline at end of file
diff --git a/chrome/test/data/webui/side_panel/user_notes/test_user_notes_api_proxy.ts b/chrome/test/data/webui/side_panel/user_notes/test_user_notes_api_proxy.ts index fc4f453..9bdb35d 100644 --- a/chrome/test/data/webui/side_panel/user_notes/test_user_notes_api_proxy.ts +++ b/chrome/test/data/webui/side_panel/user_notes/test_user_notes_api_proxy.ts
@@ -10,6 +10,8 @@ UserNotesApiProxy { private callbackRouter_: UserNotesPageCallbackRouter = new UserNotesPageCallbackRouter(); + private callbackRouterRemote_ = + this.callbackRouter_.$.bindNewPipeAndPassRemote(); private notes_: Note[]; constructor() { @@ -52,6 +54,10 @@ return this.callbackRouter_; } + getCallbackRouterRemote() { + return this.callbackRouterRemote_; + } + setNotes(notes: Note[]) { this.notes_ = notes; }
diff --git a/chrome/updater/app/app_server.cc b/chrome/updater/app/app_server.cc index 5a68d8ed..ef28150 100644 --- a/chrome/updater/app/app_server.cc +++ b/chrome/updater/app/app_server.cc
@@ -29,7 +29,9 @@ #include "chrome/updater/update_service_internal_impl_qualifying.h" #include "chrome/updater/updater_scope.h" #include "chrome/updater/updater_version.h" +#include "chrome/updater/util/util.h" #include "components/prefs/pref_service.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace updater { @@ -129,21 +131,25 @@ updater_scope(), prefs_->GetPrefService()); if (ShouldUninstall(persisted_data->GetAppIds(), server_starts_, persisted_data->GetHadApps())) { - base::CommandLine command_line( - base::CommandLine::ForCurrentProcess()->GetProgram()); - command_line.AppendSwitch(kUninstallIfUnusedSwitch); - if (IsSystemInstall(updater_scope())) - command_line.AppendSwitch(kSystemSwitch); - command_line.AppendSwitch(kEnableLoggingSwitch); - command_line.AppendSwitchASCII(kLoggingModuleSwitch, - kLoggingModuleSwitchValue); - VLOG(2) << "Launching uninstall command: " - << command_line.GetCommandLineString(); - - base::Process process = base::LaunchProcess(command_line, {}); - if (!process.IsValid()) { - VLOG(2) << "Invalid process launching command: " + absl::optional<base::FilePath> executable = + GetUpdaterExecutablePath(updater_scope()); + if (executable) { + base::CommandLine command_line(*executable); + command_line.AppendSwitch(kUninstallIfUnusedSwitch); + if (IsSystemInstall(updater_scope())) { + command_line.AppendSwitch(kSystemSwitch); + } + command_line.AppendSwitch(kEnableLoggingSwitch); + command_line.AppendSwitchASCII(kLoggingModuleSwitch, + kLoggingModuleSwitchValue); + VLOG(2) << "Launching uninstall command: " << command_line.GetCommandLineString(); + + base::Process process = base::LaunchProcess(command_line, {}); + if (!process.IsValid()) { + VLOG(2) << "Invalid process launching command: " + << command_line.GetCommandLineString(); + } } } }
diff --git a/chrome/updater/mac/BUILD.gn b/chrome/updater/mac/BUILD.gn index 5bc14c7..f113bba9 100644 --- a/chrome/updater/mac/BUILD.gn +++ b/chrome/updater/mac/BUILD.gn
@@ -214,15 +214,36 @@ ] } +process_version("launcher_version") { + sources = [ "//chrome/VERSION" ] + template_file = "launcher_version.h.in" + output = "$target_gen_dir/launcher_version.h" +} + +source_set("launcher_sources") { + sources = [ + "launcher_constants.h", + "launcher_main.c", + ] + + public_deps = [ + "//chrome/updater:branding_header", + "//chrome/updater/mac:launcher_version", + ] +} + executable("launcher") { output_name = "launcher" - sources = [ "launcher_main.cc" ] + sources = [ "launcher_constants_prod.c" ] + + frameworks = [ + "CoreFoundation.framework", + "Security.framework", + ] deps = [ + ":launcher_sources", ":updater_plist", - "//base", - "//chrome/updater:base", - "//chrome/updater:constants_prod", ] inputs = [ "$target_gen_dir/updater_plist_tweaked.plist" ] @@ -235,9 +256,14 @@ ] if (is_asan) { - # ASAN injects a dylib that we package in ../MacOS. + # ASAN toolchain injects libclang_rt.asan_osx_dynamic.dylib into + # ./VERSION/GoogleUpdater.app/Contents/MacOS/. Adjust the rpaths so that + # this executable can find it. ldflags += [ + # When run from ./VERSION/GoogleUpdater.app/Contents/Helpers/launcher. "-Wl,-rpath,@executable_path/../MacOS", + + # When run from ./launcher. "-Wl,-rpath,@executable_path/${chrome_version_full}/${updater_product_full_name}.app/Contents/MacOS", ] } @@ -245,13 +271,16 @@ executable("launcher_test") { output_name = "launcher_test" - sources = [ "launcher_main.cc" ] + sources = [ "launcher_constants_test.c" ] deps = [ + ":launcher_sources", ":updater_plist", - "//base", - "//chrome/updater:base", - "//chrome/updater:constants_test", + ] + + frameworks = [ + "CoreFoundation.framework", + "Security.framework", ] inputs = [ "$target_gen_dir/updater_plist_tweaked.plist" ] @@ -264,10 +293,15 @@ ] if (is_asan) { - # ASAN injects a dylib that we package in ../MacOS. + # ASAN toolchain injects libclang_rt.asan_osx_dynamic.dylib into + # ./VERSION/GoogleUpdater.app/Contents/MacOS/. Adjust the rpaths so that + # this executable can find it. ldflags += [ + # When run from ./VERSION/GoogleUpdater.app/Contents/Helpers/launcher. "-Wl,-rpath,@executable_path/../MacOS", - "-Wl,-rpath,@executable_path/${chrome_version_full}/${updater_product_full_name}_test.app/Contents/MacOS", + + # When run from ./launcher. + "-Wl,-rpath,@executable_path/${chrome_version_full}/${updater_product_full_name}.app/Contents/MacOS", ] } }
diff --git a/chrome/updater/mac/launcher_constants.h b/chrome/updater/mac/launcher_constants.h new file mode 100644 index 0000000..4a255b1 --- /dev/null +++ b/chrome/updater/mac/launcher_constants.h
@@ -0,0 +1,19 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_UPDATER_MAC_LAUNCHER_CONSTANTS_H_ +#define CHROME_UPDATER_MAC_LAUNCHER_CONSTANTS_H_ + +#include <stdbool.h> + +// The path to the executable varies between test and production builds, and by +// vendor. Refer to //docs/updater/design_doc.md#testing. +extern const char kBundlePath[]; +extern const char kExecutablePath[]; +extern const char kExecutableName[]; + +// Test builds skip the signing checks. +extern const bool kCheckSigning; + +#endif // CHROME_UPDATER_MAC_LAUNCHER_CONSTANTS_H_
diff --git a/chrome/updater/mac/launcher_constants_prod.c b/chrome/updater/mac/launcher_constants_prod.c new file mode 100644 index 0000000..8ec1f64 --- /dev/null +++ b/chrome/updater/mac/launcher_constants_prod.c
@@ -0,0 +1,21 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/updater/mac/launcher_constants.h" + +#include <stdbool.h> + +#include "chrome/updater/mac/launcher_version.h" +#include "chrome/updater/updater_branding.h" + +const char kBundlePath[] = + "/Library/" COMPANY_SHORTNAME_STRING "/" PRODUCT_FULLNAME_STRING + "/" PRODUCT_VERSION "/" PRODUCT_FULLNAME_STRING ".app"; +const char kExecutablePath[] = + "/Library/" COMPANY_SHORTNAME_STRING "/" PRODUCT_FULLNAME_STRING + "/" PRODUCT_VERSION "/" PRODUCT_FULLNAME_STRING + ".app/Contents/MacOS/" PRODUCT_FULLNAME_STRING; +const char kExecutableName[] = PRODUCT_FULLNAME_STRING; + +const bool kCheckSigning = true;
diff --git a/chrome/updater/mac/launcher_constants_test.c b/chrome/updater/mac/launcher_constants_test.c new file mode 100644 index 0000000..05ded1a9 --- /dev/null +++ b/chrome/updater/mac/launcher_constants_test.c
@@ -0,0 +1,21 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/updater/mac/launcher_constants.h" + +#include <stdbool.h> + +#include "chrome/updater/mac/launcher_version.h" +#include "chrome/updater/updater_branding.h" + +const char kBundlePath[] = + "/Library/" COMPANY_SHORTNAME_STRING "/" PRODUCT_FULLNAME_STRING + "/" PRODUCT_VERSION "/" PRODUCT_FULLNAME_STRING "_test.app"; +const char kExecutablePath[] = + "/Library/" COMPANY_SHORTNAME_STRING "/" PRODUCT_FULLNAME_STRING + "/" PRODUCT_VERSION "/" PRODUCT_FULLNAME_STRING + "_test.app/Contents/MacOS/" PRODUCT_FULLNAME_STRING "_test"; +const char kExecutableName[] = PRODUCT_FULLNAME_STRING "_test"; + +const bool kCheckSigning = false;
diff --git a/chrome/updater/mac/launcher_main.c b/chrome/updater/mac/launcher_main.c new file mode 100644 index 0000000..e695855 --- /dev/null +++ b/chrome/updater/mac/launcher_main.c
@@ -0,0 +1,621 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// launcher_main.c implements a main method that launches +// `updater --server --service=update [--system] [logging flags]`. +// Because the launcher is sometimes used in a root setuid context, it has +// minimal dependencies and tries to harden the environment. +// +// In the system (setuid) context, the launcher verifies several security +// attributes of the binary it intends to launch, the path leading to the +// binary it intends to launch, and the non-chrootedness of its context; if any +// of these checks fail, it prints a diagnostic to stderr and returns a nonzero +// exit code (see <sysexits.h>). +// +// It isolates the subprocess from its calling environment by launching it into +// a new session, with a fixed environ and argv, with standard file handles +// pointing to /dev/null and all signal handling reset to default. macOS +// clears Mach exception ports before launching a setuid binary, so the +// launcher does not repeat this work. posix_spawn will fail (and the launcher +// will therefore print a diagnostic and return nonzero) if it cannot honor all +// of these settings. +// +// In the system context, the launcher resets its own bootstrap port to the +// privileged systemwide session, resets uid and gid to 0 (real, saved, and +// effective), resets rlimits to default values, resets its umask to 022, +// resets its working directory to '/', and resets its kernel security groups. +// It expects the subprocess to inherit all of these. It fails with a suitable +// diagnostic message and return value if any of these operations fail. +// +// This list of security checks and isolation mechanisms may not be exhaustive. +// +// If the launch is successful, it returns 0 (EX_OK). It does not become the +// subprocess and it does not wait for the subprocess to exit. It does not +// report the PID of the process it creates. + +#include <CommonCrypto/CommonDigest.h> +#include <CoreFoundation/CoreFoundation.h> +#include <Security/Security.h> +#include <bootstrap.h> +#include <err.h> +#include <errno.h> +#include <libproc.h> +#include <limits.h> +#include <mach/exception_types.h> +#include <mach/task.h> +#include <mach/task_special_ports.h> +#include <mach/vm_param.h> +#include <machine/vmparam.h> +#include <membership.h> +#include <pwd.h> +#include <signal.h> +#include <spawn.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/acl.h> +#include <sys/param.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/syslimits.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <sys/vnode.h> +#include <sysexits.h> +#include <unistd.h> + +#include "chrome/updater/mac/launcher_constants.h" +#include "chrome/updater/updater_branding.h" + +#define ARRAYSIZE(x) (sizeof(x) / sizeof(*(x))) + +// CopyCStringFromCFString converts a CFString to a C string allocated via +// malloc. The caller is responsible for releasing the string. +// +// If NULL is passed as an argument, this returns an empty string (a 1-byte +// buffer containing a single zero). +// +// If this method cannot allocate memory for a result or cannot convert the +// provided CFString to a C string for any other reason, it exits with a failure +// status. +static const char* CopyCStringFromCFString(CFStringRef cfstr) { + if (!cfstr) { + char* ret = calloc(1, 1); + if (!ret) { + err(EX_UNAVAILABLE, "out of memory"); + } + return ret; + } + CFIndex buf_sz = 1 + CFStringGetMaximumSizeForEncoding( + CFStringGetLength(cfstr), kCFStringEncodingUTF8); + char* buf = malloc((size_t)buf_sz); + if (!buf) { + err(EX_UNAVAILABLE, "out of memory"); + } + if (!CFStringGetCString(cfstr, buf, buf_sz, kCFStringEncodingUTF8)) { + errx(EX_UNAVAILABLE, "can't convert string"); + } + return buf; +} + +// CopySecError converts an OSStatus from a Security.h API to a C string +// allocated via malloc. The caller is responsible for releasing the string +// (assuming the process isn't crashing). +static const char* CopySecError(OSStatus code) { + CFStringRef cfstr = SecCopyErrorMessageString(code, NULL); + if (!cfstr) { + char* ret = NULL; + if (asprintf(&ret, "unknown error %d", code) < 0) { + err(EX_UNAVAILABLE, "can't asprintf unknown error %d", code); + } + return ret; + } + const char* buf = CopyCStringFromCFString(cfstr); + CFRelease(cfstr); + return buf; +} + +static bool StrAppend(char* dest, const char* suffix, size_t dest_size) { + return strlcat(dest, suffix, dest_size) < dest_size; +} + +// ErrSec exits the program with the specified return code, emitting an error +// message of the form <msg>: <error>, using SecCopyErrorMessageString to get a +// readable error message from the error code. +static __attribute__((noreturn)) void ErrSec(int rc, + OSStatus error, + const char* msg) { + errx(rc, "%s: %s", msg, CopySecError(error)); +} + +// Checks whether extended POSIX ACLs allow write access on the specified path. +// ACLs for the specified principal are skipped -- this should be root's UUID. +static bool AclPermitsWrite(char const* const path, guid_t root_uuid) { + acl_t acl = acl_get_link_np(path, ACL_TYPE_EXTENDED); + if (!acl) { + if (errno == ENOENT) { + // No ACL is associated with this file. + return false; + } + err(EX_OSERR, "couldn't get acl on %s", path); + } + + acl_entry_t entry = NULL; + for (int rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); !rc; + rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { + acl_tag_t tag = 0; + if (acl_get_tag_type(entry, &tag)) { + err(EX_OSERR, "getting ACL tag for %s", path); + } + if (tag != ACL_EXTENDED_ALLOW) { + continue; + } + + guid_t* principal_p = acl_get_qualifier(entry); + if (!principal_p) { + err(EX_OSERR, "getting ACL qualifier for %s", path); + } + if (!memcmp(principal_p->g_guid, root_uuid.g_guid, KAUTH_GUID_SIZE)) { + // Skip ACLs that grant permission to root. + acl_free(principal_p); + continue; + } + acl_free(principal_p); + + uint64_t permset_mask = 0; + if (acl_get_permset_mask_np(entry, &permset_mask)) { + err(EX_OSERR, "getting ACL perms for %s", path); + } + if (permset_mask & + (ACL_WRITE_DATA | ACL_ADD_FILE | ACL_DELETE | ACL_APPEND_DATA | + ACL_ADD_SUBDIRECTORY | ACL_DELETE_CHILD | ACL_WRITE_ATTRIBUTES | + ACL_WRITE_EXTATTRIBUTES | ACL_WRITE_SECURITY | ACL_CHANGE_OWNER)) { + acl_free(acl); + return true; + } + } + acl_free(acl); + return false; +} + +// VerifyPathOrDie verifies that path (must be absolute) and all of its prefixes +// are owned by root and cannot be written others. It iterates in root-to-leaf +// order to mitigate the opportunity for time-of-check/time-of-use flaws, since +// at each step, we know the path so far can only have been changed out from +// under us by something with root permissions. It forbids symlinks. +// +// If verification fails, the program prints an error (to stderr) and exits. +static void VerifyPathOrDie(const char* const path, guid_t root_uuid) { + if (path[0] != '/') { + errx(EX_SOFTWARE, "path not absolute: %s", path); + } + + size_t len = strlen(path); + char* accumulating_path = calloc(strlen(path) + 1, 1); + for (size_t i = 0; i < len; ++i) { + accumulating_path[i] = path[i]; + if (i && path[i + 1] != '/' && path[i + 1] != '\0') { + continue; + } + // We've reached root, some directory, or the full path; check it. + struct stat attribs = {}; + if (lstat(accumulating_path, &attribs)) { + err(EX_NOPERM, "can't stat %s", accumulating_path); + } + + if (S_ISLNK(attribs.st_mode)) { + errx(EX_OSFILE, "%s is a symlink", accumulating_path); + } + if (attribs.st_mode & 022) { + errx(EX_OSFILE, "loose permissions (0%o) on %s", attribs.st_mode & 07777, + accumulating_path); + } + if (attribs.st_uid) { + errx(EX_CONFIG, "non-root user %u owns %s", attribs.st_uid, + accumulating_path); + } + if (AclPermitsWrite(accumulating_path, root_uuid)) { + errx(EX_CONFIG, "loose permissions (extended ACL) on %s", + accumulating_path); + } + } + free(accumulating_path); +} + +static bool IsChrooted() { + struct proc_vnodepathinfo vnodepathinfo = {}; + if (proc_pidinfo(getpid(), PROC_PIDVNODEPATHINFO, 0, &vnodepathinfo, + sizeof(vnodepathinfo)) < 0) { + err(EX_OSERR, "proc_pidinfo"); + } + + return vnodepathinfo.pvi_rdir.vip_vi.vi_type == VDIR; +} + +// An rlimit configuration for some specified resource. "which" is expected +// to be an RLIMIT constant. +typedef struct rlimit_config_struct { + int which; + struct rlimit rlimit; +} rlimit_config; + +// Increase the limit for the resource defined by config->which to the values +// in config->soft (for rlim_cur) and config->hard (for rlim_max). This only +// ever increases limits; if the existing limit is already higher, it does +// not change the limit. If one part of the rlimit change is an increase and +// the other is not, it applies only the increase. +// +// If the getrlimit call to find existing values fails, this returns its +// return code (and does not change anything). Otherwise, it returns the +// return code from its call to setrlimit. +static int IncreaseRlimit(const rlimit_config* config) { + struct rlimit lim; + int rc = getrlimit(config->which, &lim); + if (rc) { + return rc; + } + if (lim.rlim_cur < config->rlimit.rlim_cur) { + lim.rlim_cur = config->rlimit.rlim_cur; + } + if (lim.rlim_max < config->rlimit.rlim_max) { + lim.rlim_max = config->rlimit.rlim_max; + } + // `cur` > `max` can occur for some `config`s, at least the maxproc one. + if (lim.rlim_cur > lim.rlim_max) { + lim.rlim_max = lim.rlim_cur; + } + return setrlimit(config->which, &lim); +} + +// Array terminated with an rlimit_config with `which` set to +// kEndOfDefaultRlimits. Omits RLIMIT_NPROC, since its correct value is +// machine-specific; we use sysctlbyname to get the real caps and call +// setrlimit separately for this. +static const rlimit_config default_rlimits[] = { + {.which = RLIMIT_CORE, + .rlimit = {.rlim_cur = DFLCSIZ, .rlim_max = MAXCSIZ}}, + {.which = RLIMIT_CPU, + .rlimit = {.rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY}}, + {.which = RLIMIT_FSIZE, + .rlimit = {.rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY}}, + {.which = RLIMIT_DATA, + .rlimit = {.rlim_cur = DFLDSIZ, .rlim_max = MAXDSIZ}}, + {.which = RLIMIT_STACK, + .rlimit = {.rlim_cur = DFLSSIZ, .rlim_max = MAXSSIZ - PAGE_MAX_SIZE}}, + {.which = RLIMIT_RSS, + .rlimit = {.rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY}}, + {.which = RLIMIT_MEMLOCK, + .rlimit = {.rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY}}, + {.which = RLIMIT_NOFILE, + .rlimit = {.rlim_cur = NOFILE, .rlim_max = OPEN_MAX}}, +}; + +// Check whether the code object referenced via distant_code is validly signed. +// Returns an OSStatus in the errSec... space describing the result of the +// check. +// +// Like many Security.h APIs, the SecStaticCodeRef argument (distant_code) can +// be a "live" SecCodeRef instead. If a live SecCodeRef is provided, this check +// runs against the running image rather than the file on disk. +static OSStatus CheckSignature(SecStaticCodeRef distant_code) { + if (!distant_code) { + errx(EX_SOFTWARE, "can't check signature that doesn't exist"); + } + + SecRequirementRef req; + OSStatus rc = SecRequirementCreateWithString( + // Magic numbers from + // https://chromium.googlesource.com/chromium/src/+/7b1441f65d5bef3c0fe531809cccdeb40f9465c6/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_mac.cc#49 + CFSTR("anchor apple generic and " + "certificate 1[field.1.2.840.113635.100.6.2.6] and " + "certificate leaf[field.1.2.840.113635.100.6.1.13] and " + "certificate leaf[subject.OU] = " + "\"" MAC_TEAM_IDENTIFIER_STRING "\" and " + "identifier \"" MAC_BUNDLE_IDENTIFIER_STRING "\""), + kSecCSDefaultFlags, &req); + if (rc != errSecSuccess) { + ErrSec(EX_UNAVAILABLE, rc, "can't create requirement"); + } + + // We now have the pieces we need: a security requirement and the code + // signing object for the connecting process. Evaluate it, clean up our + // various Core Foundation objects, then return the verdict. Use live + // validity checks if possible. + if (CFGetTypeID(distant_code) == SecCodeGetTypeID()) { + SecCodeRef distant_live_code = (SecCodeRef)distant_code; + rc = SecCodeCheckValidity(distant_live_code, kSecCSDefaultFlags, req); + } else { + // This really is a static code ref. + rc = SecStaticCodeCheckValidity(distant_code, + kSecCSCheckAllArchitectures | + kSecCSCheckNestedCode | + kSecCSStrictValidate, + req); + } + + CFRelease(req); + return rc; +} + +static void Harden(const char* target_path) { + if (IsChrooted()) { + err(EX_CONFIG, "chrooted"); + } + if (setuid(0)) { + err(EX_NOPERM, "can't setuid 0"); + } + if (setgid(0)) { + err(EX_NOPERM, "can't setgid 0"); + } + + // Check supported platforms. POSIX_SPAWN_SETSID doesn't work until + // macOS 10.12, known internally to uname as 16.0.0. + struct utsname sysinfo = {}; + if (uname(&sysinfo)) { + err(EX_OSERR, "can't get uname"); + } + char* scan_end = NULL; + long os_major = strtol(sysinfo.release, &scan_end, 10); + if (scan_end == sysinfo.release) { + errx(EX_OSERR, "empty uname.release"); + } + if (*scan_end != '.') { + errx(EX_PROTOCOL, "malformed uname.release (%s)", sysinfo.release); + } + if (os_major < 16L) { + errx(EX_UNAVAILABLE, "launcher requires macOS 10.12 or later"); + } + + // Set process count limits to system caps. + int32_t maxproc = -1; + size_t maxprocsz = sizeof(maxproc); + if (sysctlbyname("kern.maxproc", &maxproc, &maxprocsz, NULL, 0)) { + err(EX_UNAVAILABLE, "can't get kern.maxproc"); + } + int32_t maxprocperuid = -1; + size_t maxprocperuidsz = sizeof(maxprocperuid); + if (sysctlbyname("kern.maxprocperuid", &maxprocperuid, &maxprocperuidsz, NULL, + 0)) { + err(EX_UNAVAILABLE, "can't get kern.maxprocperuid"); + } + rlimit_config nproc = { + .which = RLIMIT_NPROC, + .rlimit = {.rlim_cur = maxprocperuid, .rlim_max = maxproc}}; + if (IncreaseRlimit(&nproc)) { + err(EX_OSERR, "can't set rlimit %d", RLIMIT_NPROC); + } + + // Reset other resource limits. + for (size_t i = 0; i < ARRAYSIZE(default_rlimits); i++) { + if (IncreaseRlimit(&default_rlimits[i])) { + err(EX_OSERR, "can't set rlimit %d", default_rlimits[i].which); + } + } + + // Find the startup port, the bootstrap port for all daemons. We use this as + // our bootstrap port so our requests to other root-level services can't be + // intercepted by something running in a user context. The subprocess will + // inherit this. + // + // The startup port is uniquely recognizable as the port that is its own + // parent. + // + // Empirical observation indicates that each next_port is likely to leak; each + // port acquires references not owned by this code (possibly from the MacOS + // APIs themselves). This implementation does not depend on this property, + // however. + mach_port_t startup_port = MACH_PORT_NULL; + mach_port_t next_port = bootstrap_port; + // Give next_port its own reference count for bootstrap_port so it won't be + // deallocated immediately if/when it "falls off" the end of this + // traversal. + kern_return_t kr = mach_port_mod_refs(mach_task_self(), bootstrap_port, + MACH_PORT_RIGHT_SEND, 1); + if (kr != KERN_SUCCESS && kr != KERN_INVALID_RIGHT) { + errx(EX_OSERR, "can't add send count for bootstrap_port: %d", kr); + } + do { + if (startup_port != MACH_PORT_NULL) { + mach_port_deallocate(mach_task_self(), startup_port); + } + startup_port = next_port; + kern_return_t bootstrap_err = bootstrap_parent(startup_port, &next_port); + if (bootstrap_err != KERN_SUCCESS) { + errx(EX_NOPERM, "bootstrap_parent: %d", bootstrap_err); + } + } while (startup_port != next_port); + + // Release the the extra retains: transfer one right, one retain from `start`, + // and one retain from `next_port`. + task_set_bootstrap_port(mach_task_self(), startup_port); + mach_port_t old_bootstrap = bootstrap_port; + bootstrap_port = startup_port; + mach_port_deallocate(mach_task_self(), old_bootstrap); + mach_port_deallocate(mach_task_self(), next_port); + + // initgroups and mbr_uid_to_uuid must be done only after bootstrap_port has + // become the startup port, since they make calls to opendirectoryd; looking + // it up can be redirected in a subset port, so using only the startup port + // ensures we're talking to the real one. + if (initgroups("root", 0)) { + err(EX_OSERR, "can't initgroups"); + } + guid_t root_uuid; + if (mbr_uid_to_uuid(0, root_uuid.g_guid)) { + err(EX_OSERR, "can't get root's uuid"); + } + + // Verify paths. verifyPath is recursive and prints out error messages on its + // own if something goes wrong. + VerifyPathOrDie(target_path, root_uuid); + + // Check signing. + if (kCheckSigning) { + CFStringRef cf_subprocess_path = + CFStringCreateWithCString(NULL, target_path, kCFStringEncodingUTF8); + CFURLRef subprocess_path_url = CFURLCreateWithFileSystemPath( + NULL, cf_subprocess_path, kCFURLPOSIXPathStyle, false); + CFRelease(cf_subprocess_path); + SecStaticCodeRef subprocess_code; + OSStatus os_rc = SecStaticCodeCreateWithPath( + subprocess_path_url, kSecCSDefaultFlags, &subprocess_code); + CFRelease(subprocess_path_url); + if (os_rc != errSecSuccess) { + ErrSec(EX_UNAVAILABLE, os_rc, + "can't get code signing info for subprocess"); + } + os_rc = CheckSignature(subprocess_code); + if (os_rc != errSecSuccess) { + ErrSec(EX_CONFIG, os_rc, "subprocess verification failed"); + } + CFRelease(subprocess_code); + + CFStringRef cf_bundle_path = + CFStringCreateWithCString(NULL, kBundlePath, kCFStringEncodingUTF8); + CFURLRef bundle_path_url = CFURLCreateWithFileSystemPath( + NULL, cf_bundle_path, kCFURLPOSIXPathStyle, false); + SecStaticCodeRef bundle_code; + os_rc = SecStaticCodeCreateWithPath(bundle_path_url, kSecCSDefaultFlags, + &bundle_code); + CFRelease(bundle_path_url); + CFRelease(cf_bundle_path); + if (os_rc != errSecSuccess) { + ErrSec(EX_UNAVAILABLE, os_rc, "can't get code signing info for bundle"); + } + os_rc = CheckSignature(bundle_code); + if (os_rc != errSecSuccess) { + ErrSec(EX_CONFIG, os_rc, "bundle verification failed"); + } + CFRelease(bundle_code); + // Signing checks have passed. + } +} + +static void Launch(bool is_system, const char* path) { + if (chdir("/")) { + err(EX_OSFILE, "can't chdir to /"); + } + umask(022); + alarm(0); + + // Configure posix_spawn. + sigset_t empty_sigset; // Zero-initialization of sigset_t is not portable. + sigemptyset(&empty_sigset); + sigset_t full_sigset; + sigfillset(&full_sigset); + posix_spawnattr_t spawn_attrs = NULL; + int posix_err = posix_spawnattr_init(&spawn_attrs); + if (posix_err) { + errc(EX_UNAVAILABLE, posix_err, "can't init spawn attrs"); + } + posix_err = posix_spawnattr_setflags( + &spawn_attrs, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK | + POSIX_SPAWN_SETSID | POSIX_SPAWN_CLOEXEC_DEFAULT); + if (posix_err) { + errc(EX_OSERR, posix_err, "can't set spawn flags"); + } + posix_err = posix_spawnattr_setsigdefault(&spawn_attrs, &full_sigset); + if (posix_err) { + errc(EX_OSERR, posix_err, "can't set default signal handlers"); + } + posix_err = posix_spawnattr_setsigmask(&spawn_attrs, &empty_sigset); + if (posix_err) { + errc(EX_OSERR, posix_err, "can't clear signal mask"); + } + + cpu_type_t cpu_any = CPU_TYPE_ANY; + size_t ocount = 0; + posix_err = posix_spawnattr_setbinpref_np(&spawn_attrs, 1, &cpu_any, &ocount); + if (posix_err) { + errc(EX_OSERR, posix_err, "can't set CPU_TYPE_ANY binpref"); + } + posix_err = posix_spawnattr_setspecialport_np(&spawn_attrs, bootstrap_port, + TASK_BOOTSTRAP_PORT); + if (posix_err) { + errc(EX_OSERR, posix_err, "can't set bootstrap port"); + } + // There is no need to clear task-level exception ports, because in the isRoot + // context, macOS already did that as a consequence of launching a setuid + // process. Refer to kern_exec.c in xnu source. + + posix_spawn_file_actions_t file_actions = NULL; + posix_err = posix_spawn_file_actions_init(&file_actions); + if (posix_err) { + errc(EX_UNAVAILABLE, posix_err, "can't init file actions"); + } + posix_err = posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, + "/dev/null", O_RDONLY, 0); + if (posix_err) { + errc(EX_OSERR, posix_err, "can't point /dev/null to stdin"); + } + posix_err = posix_spawn_file_actions_addopen(&file_actions, STDOUT_FILENO, + "/dev/null", O_WRONLY, 0); + if (posix_err) { + errc(EX_OSERR, posix_err, "can't point stdout to /dev/null"); + } + posix_err = posix_spawn_file_actions_adddup2(&file_actions, STDOUT_FILENO, + STDERR_FILENO); + if (posix_err) { + errc(EX_OSERR, posix_err, + "can't point stderr to /dev/null (as dup2 of stdout)"); + } + + char* const argv[] = { + (char*)kExecutableName, // posix_spawn will not overwrite the argv. + "--server", + "--service=update", + "--enable-logging", + "--vmodule=*/components/update_client/*=2,*/chrome/updater/*=2", + is_system ? "--system" : NULL, + NULL}; + static char* const env[] = {"PWD=/", "PATH=/usr/bin:/bin:/usr/sbin:/sbin", + NULL}; + + posix_err = posix_spawn(NULL, path, &file_actions, &spawn_attrs, argv, env); + if (posix_err) { + errc(EX_UNAVAILABLE, posix_err, "posix_spawn failed"); + } +} + +void UserMain(uid_t euid) { + // Find home directory. + const char* home = getenv("HOME"); + if (!home) { + // getpwuid is thread-safe on macOS. The program may become multi-threaded + // once we invoke Apple APIs. + struct passwd* pwd = getpwuid(euid); + if (pwd) { + home = pwd->pw_dir; + } + } + if (!home) { + err(EX_OSERR, "unable to find user homedir"); + } + char path[PATH_MAX] = ""; + if (!StrAppend(path, home, ARRAYSIZE(path))) { + err(EX_OSERR, "path to homedir is too long"); + } + if (!StrAppend(path, kExecutablePath, ARRAYSIZE(path))) { + err(EX_OSERR, "path to updater executable is too long"); + } + + Launch(false, path); +} + +void SystemMain() { + Harden(kExecutablePath); + Launch(true, kExecutablePath); +} + +int main(int argc, char** argv) { + const uid_t euid = geteuid(); + if (euid == 0) { + SystemMain(); + } else { + UserMain(euid); + } + return EX_OK; +}
diff --git a/chrome/updater/mac/launcher_main.cc b/chrome/updater/mac/launcher_main.cc deleted file mode 100644 index 29739511..0000000 --- a/chrome/updater/mac/launcher_main.cc +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <sys/types.h> -#include <unistd.h> - -#include "base/command_line.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/process/launch.h" -#include "chrome/updater/constants.h" -#include "chrome/updater/updater_scope.h" -#include "chrome/updater/util/util.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -namespace updater { - -// This is a placeholder main for a non-side-by-side launcher that launches an -// UpdateService-handling server. -int Main() { - const UpdaterScope scope = - geteuid() == 0 ? UpdaterScope::kSystem : UpdaterScope::kUser; - const absl::optional<base::FilePath> updater_path = - GetUpdaterExecutablePath(scope); - if (!updater_path) { - return kErrorGettingUpdaterPath; - } - - // TODO(crbug.com/1339108): We need to check directories top-down, not bottom- - // up. - // If the file (or any parent directory) is not owned by this user (nor owned - // by root), or is world-writable, fail. - base::FilePath check_path = *updater_path; - while (check_path.DirName() != check_path) { - base::stat_wrapper_t sb = {}; - if (base::File::Stat(check_path.value().c_str(), &sb)) { - return kErrorStattingPath; - } - if ((sb.st_uid != 0 && sb.st_uid != geteuid()) || - ((sb.st_mode & base::FILE_PERMISSION_WRITE_BY_OTHERS) != 0)) { - return kErrorPathOwnershipMismatch; - } - // TODO(crbug.com/1339108): Handle (forbid?) symlinks. Symlinks are - // problematic since the parents of the symlink might have different access - // controls than the parents of the symlink's destination. - // TODO(crbug.com/1339108): Check POSIX.1e ACLs. - check_path = check_path.DirName(); - } - - // TODO(crbug.com/1339108): Check code signing, unless this is not code - // signed? - - // TODO(crbug.com/1339108): Check for chroot (if scope == kSystem). - - base::CommandLine command_line(*updater_path); - command_line.AppendSwitch(kServerSwitch); - command_line.AppendSwitchASCII(kServerServiceSwitch, - kServerUpdateServiceSwitchValue); - if (scope == UpdaterScope::kSystem) { - command_line.AppendSwitch(kSystemSwitch); - } - command_line.AppendSwitch(kEnableLoggingSwitch); - command_line.AppendSwitchASCII(kLoggingModuleSwitch, - kLoggingModuleSwitchValue); - base::LaunchOptions opts; - opts.clear_environment = true; - // TODO(crbug.com/1339108): Reset rlimits to default values, unless current - // limits are higher. - // TODO(crbug.com/1339108): Reset POSIX signal dispositions. - // TODO(crbug.com/1339108): Climb bootstrap ports until the bootstrap port is - // the top-level "system" bootstrap port. - // TODO(crbug.com/1339108): Run the process in a separate terminal session. - if (!base::LaunchProcess(command_line, opts).IsValid()) { - return kErrorLaunchingProcess; - } - return 0; -} - -} // namespace updater - -int main(int argc, const char* const* argv) { - return updater::Main(); -}
diff --git a/chrome/updater/mac/launcher_version.h.in b/chrome/updater/mac/launcher_version.h.in new file mode 100644 index 0000000..f3610361 --- /dev/null +++ b/chrome/updater/mac/launcher_version.h.in
@@ -0,0 +1,10 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_UPDATER_MAC_LAUNCHER_VERSION_H_ +#define CHROME_UPDATER_MAC_LAUNCHER_VERSION_H_ + +#define PRODUCT_VERSION "@MAJOR@.@MINOR@.@BUILD@.@PATCH@" + +#endif // CHROME_UPDATER_UPDATER_VERSION_H_
diff --git a/chrome/updater/mac/setup/setup.mm b/chrome/updater/mac/setup/setup.mm index 74e512b0..a7e0e65 100644 --- a/chrome/updater/mac/setup/setup.mm +++ b/chrome/updater/mac/setup/setup.mm
@@ -267,7 +267,15 @@ install_dir->Append("launcher").value().c_str())) { return kErrorFailedToRenameLauncher; } - // TODO(crbug.com/1339108): If kSystem, mark setuid on the launcher. + if (scope == UpdaterScope::kSystem) { + base::FilePath path = install_dir->Append("launcher"); + struct stat info; + if (stat(path.value().c_str(), &info) || info.st_uid || + lchmod(path.value().c_str(), + S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | S_ISUID)) { + VPLOG(1) << "Launcher lchmod failed. Cross-user on-demand will not work"; + } + } if (!CreateWakeLaunchdJobPlist(scope, *updater_executable_path)) { return kErrorFailedToCreateWakeLaunchdJobPlist;
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc index 3923932..c7e1ee2 100644 --- a/chrome/updater/test/integration_tests_win.cc +++ b/chrome/updater/test/integration_tests_win.cc
@@ -222,13 +222,15 @@ const HKEY root = UpdaterScopeToHKeyRoot(scope); if (is_active_and_sxs) { - for (const wchar_t* key : {CLIENT_STATE_KEY, CLIENTS_KEY, UPDATER_KEY}) { + for (const wchar_t* key : {CLIENTS_KEY, UPDATER_KEY}) { EXPECT_EQ(is_installed, RegKeyExists(root, key)); } EXPECT_EQ(is_installed, base::PathExists(*GetGoogleUpdateExePath(scope))); if (is_installed) { + EXPECT_TRUE(RegKeyExists(root, CLIENT_STATE_KEY)); + std::wstring pv; EXPECT_EQ(ERROR_SUCCESS, base::win::RegKey(
diff --git a/chrome/updater/util/linux_util.cc b/chrome/updater/util/linux_util.cc index 2f0bcd6..1d9c8cab 100644 --- a/chrome/updater/util/linux_util.cc +++ b/chrome/updater/util/linux_util.cc
@@ -42,15 +42,6 @@ return base::FilePath(kExecutableName); } -absl::optional<base::FilePath> GetUpdaterExecutablePath(UpdaterScope scope) { - absl::optional<base::FilePath> path = GetVersionedInstallDirectory(scope); - if (!path) { - return absl::nullopt; - } - - return path->AppendASCII(kExecutableName); -} - absl::optional<base::FilePath> GetBaseInstallDirectory(UpdaterScope scope) { absl::optional<base::FilePath> path = GetApplicationDataDirectory(scope); return path ? absl::optional<base::FilePath>(
diff --git a/chrome/updater/util/mac_util.mm b/chrome/updater/util/mac_util.mm index 06e9957..4f7c505 100644 --- a/chrome/updater/util/mac_util.mm +++ b/chrome/updater/util/mac_util.mm
@@ -167,14 +167,6 @@ base::StrCat({PRODUCT_FULLNAME_STRING, kExecutableSuffix, ".app"})); } -absl::optional<base::FilePath> GetUpdaterExecutablePath(UpdaterScope scope) { - absl::optional<base::FilePath> path = GetVersionedInstallDirectory(scope); - if (!path) - return absl::nullopt; - return path->Append(ExecutableFolderPath()) - .AppendASCII(base::StrCat({PRODUCT_FULLNAME_STRING, kExecutableSuffix})); -} - base::FilePath GetExecutableRelativePath() { return ExecutableFolderPath().Append( base::StrCat({PRODUCT_FULLNAME_STRING, kExecutableSuffix}));
diff --git a/chrome/updater/util/util.cc b/chrome/updater/util/util.cc index 2ee5a5b..36e927a 100644 --- a/chrome/updater/util/util.cc +++ b/chrome/updater/util/util.cc
@@ -170,6 +170,14 @@ return GetVersionedInstallDirectory(scope, base::Version(kUpdaterVersion)); } +absl::optional<base::FilePath> GetUpdaterExecutablePath(UpdaterScope scope) { + absl::optional<base::FilePath> path = GetVersionedInstallDirectory(scope); + if (!path) { + return absl::nullopt; + } + return path->Append(GetExecutableRelativePath()); +} + TagParsingResult::TagParsingResult() = default; TagParsingResult::TagParsingResult(absl::optional<tagging::TagArgs> tag_args, tagging::ErrorCode error)
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastContentWindowAndroid.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastContentWindowAndroid.java index 70a3e26..8d96ed6 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastContentWindowAndroid.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastContentWindowAndroid.java
@@ -41,11 +41,11 @@ @SuppressWarnings("unused") @CalledByNative private static CastContentWindowAndroid create(long nativeCastContentWindowAndroid, - boolean enableTouchInput, boolean shouldRequestAudioFocus, boolean turnOnScreen, - boolean keepScreenOn, String sessionId, String displayId) { + boolean enableTouchInput, boolean turnOnScreen, boolean keepScreenOn, String sessionId, + String displayId) { return new CastContentWindowAndroid(nativeCastContentWindowAndroid, - getContextWithDisplay(displayId), enableTouchInput, shouldRequestAudioFocus, - turnOnScreen, keepScreenOn, sessionId); + getContextWithDisplay(displayId), enableTouchInput, turnOnScreen, keepScreenOn, + sessionId); } private static Context getContextWithDisplay(String displayId) { @@ -66,22 +66,24 @@ } private CastContentWindowAndroid(long nativeCastContentWindowAndroid, final Context context, - boolean enableTouchInput, boolean shouldRequestAudioFocus, boolean turnOnScreen, - boolean keepScreenOn, String sessionId) { + boolean enableTouchInput, boolean turnOnScreen, boolean keepScreenOn, + String sessionId) { mNativeCastContentWindowAndroid = nativeCastContentWindowAndroid; mContext = context; Log.i(TAG, "Creating new CastContentWindowAndroid(No. " + sInstanceId++ + ") Seesion ID: " + sessionId); - mComponent = new CastWebContentsComponent(sessionId, this, this, enableTouchInput, - shouldRequestAudioFocus, turnOnScreen, keepScreenOn); + mComponent = new CastWebContentsComponent( + sessionId, this, this, enableTouchInput, turnOnScreen, keepScreenOn); } @SuppressWarnings("unused") @CalledByNative - private void createWindowForWebContents(WebContents webContents, String appId) { + private void createWindowForWebContents( + WebContents webContents, String appId, boolean shouldRequestAudioFocus) { if (DEBUG) Log.d(TAG, "createWindowForWebContents"); - mStartParams = new CastWebContentsComponent.StartParams(mContext, webContents, appId); + mStartParams = new CastWebContentsComponent.StartParams( + mContext, webContents, appId, shouldRequestAudioFocus); maybeStartComponent(); }
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java index 38a59569..a2797bbc 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java
@@ -33,7 +33,9 @@ * Callback interface for when the associated component is closed or the * WebContents is detached. */ - public interface OnComponentClosedHandler { void onComponentClosed(); } + public interface OnComponentClosedHandler { + void onComponentClosed(); + } /** * Callback interface for when UI events occur. @@ -49,11 +51,14 @@ public final Context context; public final WebContents webContents; public final String appId; + public final boolean shouldRequestAudioFocus; - public StartParams(Context context, WebContents webContents, String appId) { + public StartParams(Context context, WebContents webContents, String appId, + boolean shouldRequestAudioFocus) { this.context = context; this.webContents = webContents; this.appId = appId; + this.shouldRequestAudioFocus = shouldRequestAudioFocus; } @Override @@ -88,7 +93,7 @@ if (mStarted) return; // No-op if already started. if (DEBUG) Log.d(TAG, "start: SHOW_WEB_CONTENT in activity"); startCastActivity(params.context, params.webContents, mEnableTouchInput, - mShouldRequestAudioFocus, mTurnOnScreen); + params.shouldRequestAudioFocus, mTurnOnScreen); mStarted = true; } @@ -160,26 +165,23 @@ private boolean mStarted; private boolean mEnableTouchInput; private boolean mMediaPlaying; - private final boolean mShouldRequestAudioFocus; private final boolean mTurnOnScreen; private final boolean mKeepScreenOn; public CastWebContentsComponent(String sessionId, OnComponentClosedHandler onComponentClosedHandler, - SurfaceEventHandler surfaceEventHandler, boolean enableTouchInput, - boolean shouldRequestAudioFocus, boolean turnOnScreen, boolean keepScreenOn) { + SurfaceEventHandler surfaceEventHandler, boolean enableTouchInput, boolean turnOnScreen, + boolean keepScreenOn) { if (DEBUG) { Log.d(TAG, "New CastWebContentsComponent. Instance ID: " + sessionId - + "; enableTouchInput:" + enableTouchInput - + "; shouldRequestAudioFocus:" + shouldRequestAudioFocus); + + "; enableTouchInput:" + enableTouchInput); } mComponentClosedHandler = onComponentClosedHandler; mEnableTouchInput = enableTouchInput; mSessionId = sessionId; mSurfaceEventHandler = surfaceEventHandler; - mShouldRequestAudioFocus = shouldRequestAudioFocus; mTurnOnScreen = turnOnScreen; mKeepScreenOn = keepScreenOn; @@ -192,7 +194,7 @@ filter.addAction(CastWebContentsIntentUtils.ACTION_ACTIVITY_STOPPED); filter.addAction(CastWebContentsIntentUtils.ACTION_ON_VISIBILITY_CHANGE); filter.addAction(CastWebContentsIntentUtils.ACTION_REQUEST_MEDIA_PLAYING_STATUS); - return new LocalBroadcastReceiverScope(filter, this ::onReceiveIntent); + return new LocalBroadcastReceiverScope(filter, this::onReceiveIntent); }); } @@ -240,7 +242,8 @@ if (DEBUG) { Log.d(TAG, "Starting WebContents with delegate: " + mDelegate.getClass().getSimpleName() - + "; Instance ID: " + mSessionId + "; App ID: " + params.appId); + + "; Instance ID: " + mSessionId + "; App ID: " + params.appId + + "; shouldRequestAudioFocus: " + params.shouldRequestAudioFocus); } mHasWebContentsState.set(params.webContents); mDelegate.start(params);
diff --git a/chromecast/browser/android/cast_content_window_android.cc b/chromecast/browser/android/cast_content_window_android.cc index d6c64110..c9e442c 100644 --- a/chromecast/browser/android/cast_content_window_android.cc +++ b/chromecast/browser/android/cast_content_window_android.cc
@@ -10,6 +10,7 @@ #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" #include "chromecast/browser/jni_headers/CastContentWindowAndroid_jni.h" +#include "components/media_control/browser/media_blocker.h" #include "content/public/browser/web_contents_observer.h" namespace chromecast { @@ -21,18 +22,28 @@ base::android::ScopedJavaLocalRef<jobject> CreateJavaWindow( jlong native_window, bool enable_touch_input, - bool should_request_audio_focus, bool turn_on_screen, bool keep_screen_on, const std::string& session_id, const std::string& display_id) { JNIEnv* env = base::android::AttachCurrentThread(); return Java_CastContentWindowAndroid_create( - env, native_window, enable_touch_input, should_request_audio_focus, - turn_on_screen, keep_screen_on, ConvertUTF8ToJavaString(env, session_id), + env, native_window, enable_touch_input, turn_on_screen, keep_screen_on, + ConvertUTF8ToJavaString(env, session_id), ConvertUTF8ToJavaString(env, display_id)); } +bool ShouldRequestAudioFocus(bool is_remote_control_mode, + const media_control::MediaBlocker* media_blocker) { + if (is_remote_control_mode) { + return false; + } + if (!media_blocker) { + return true; + } + return !media_blocker->media_loading_blocked(); +} + } // namespace CastContentWindowAndroid::CastContentWindowAndroid( @@ -41,7 +52,6 @@ web_contents_attached_(false), java_window_(CreateJavaWindow(reinterpret_cast<jlong>(this), params_->enable_touch_input, - params_->should_request_audio_focus, params_->turn_on_screen, params_->keep_screen_on, params_->session_id, @@ -67,7 +77,9 @@ Java_CastContentWindowAndroid_createWindowForWebContents( env, java_window_, java_web_contents, - ConvertUTF8ToJavaString(env, params_->activity_id)); + ConvertUTF8ToJavaString(env, params_->activity_id), + ShouldRequestAudioFocus(params_->is_remote_control_mode, + cast_web_contents()->media_blocker())); web_contents_attached_ = true; cast_web_contents()->web_contents()->Focus(); }
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java index bdc6e69..ea994cd7 100644 --- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java +++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
@@ -74,7 +74,7 @@ when(mDisplay.getDisplayId()).thenReturn(DISPLAY_ID); mActivity = Mockito.spy(Robolectric.buildActivity(Activity.class).setup().get()); mShadowActivity = Shadows.shadowOf(mActivity); - mStartParams = new StartParams(mActivity, mWebContents, APP_ID); + mStartParams = new StartParams(mActivity, mWebContents, APP_ID, false); } @Test @@ -82,7 +82,7 @@ Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.start(mStartParams, false); Intent intent = mShadowActivity.getNextStartedActivity(); Assert.assertEquals( @@ -103,10 +103,10 @@ return mDisplay; } }); - StartParams startParams = new StartParams(context, mWebContents, APP_ID); + StartParams startParams = new StartParams(context, mWebContents, APP_ID, false); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.start(startParams, false); ArgumentCaptor<Bundle> bundle = ArgumentCaptor.forClass(Bundle.class); @@ -119,7 +119,7 @@ Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.start(mStartParams, true); component.stop(mActivity); @@ -140,7 +140,7 @@ .registerReceiver(receiver, intentFilter); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.start(mStartParams, false); component.stop(ContextUtils.getApplicationContext()); @@ -155,7 +155,7 @@ Assume.assumeTrue(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.start(mStartParams, false); component.stop(mActivity); @@ -171,7 +171,7 @@ Assume.assumeTrue(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.start(mStartParams, false); component.stop(mActivity); @@ -189,7 +189,7 @@ .registerReceiver(receiver, intentFilter); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.enableTouchInput(true); LocalBroadcastManager.getInstance(ContextUtils.getApplicationContext()) @@ -203,7 +203,7 @@ Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.enableTouchInput(true); component.start(mStartParams, false); @@ -218,7 +218,7 @@ Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.enableTouchInput(false); component.start(mStartParams, false); @@ -234,7 +234,7 @@ Mockito.mock(CastWebContentsComponent.OnComponentClosedHandler.class); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, callback, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, callback, null, false, true, false); component.start(mStartParams, false); CastWebContentsComponent.onComponentClosed(SESSION_ID); verify(callback).onComponentClosed(); @@ -245,7 +245,7 @@ @Test public void testStopDoesNotUnbindServiceIfStartWasNotCalled() { CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); component.stop(mActivity); @@ -258,7 +258,7 @@ Mockito.mock(CastWebContentsComponent.SurfaceEventHandler.class); CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, callback, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, callback, false, true, false); component.start(mStartParams, false); CastWebContentsComponent.onVisibilityChange(SESSION_ID, 2); component.stop(mActivity); @@ -269,12 +269,12 @@ @Test public void testStartWebContentsComponentMultipleTimes() { CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); CastWebContentsComponent.Delegate delegate = mock(CastWebContentsComponent.Delegate.class); component.start(mStartParams, delegate); Assert.assertTrue(component.isStarted()); verify(delegate, times(1)).start(eq(mStartParams)); - StartParams params2 = new StartParams(mActivity, mWebContents, "test"); + StartParams params2 = new StartParams(mActivity, mWebContents, "test", true); component.start(params2, delegate); Assert.assertTrue(component.isStarted()); verify(delegate, times(2)).start(any(StartParams.class)); @@ -290,7 +290,7 @@ // in focus, and issues with onNewIntent() and duplicate detection can cause unintended // side effects. CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); CastWebContentsComponent.Delegate delegate = component.new ActivityDelegate(); component.start(mStartParams, delegate); Assert.assertEquals(mShadowActivity.getNextStartedActivity().getComponent().getClassName(), @@ -302,7 +302,7 @@ @Test public void testSetMediaPlayingBroadcastsMediaStatus() { CastWebContentsComponent component = - new CastWebContentsComponent(SESSION_ID, null, null, false, false, true, false); + new CastWebContentsComponent(SESSION_ID, null, null, false, true, false); IntentFilter filter = new IntentFilter(CastWebContentsIntentUtils.ACTION_MEDIA_PLAYING); Intent receivedIntent0 = verifyBroadcastedIntent( new IntentFilter(CastWebContentsIntentUtils.ACTION_MEDIA_PLAYING), @@ -318,7 +318,7 @@ public void testRequestMediaStatusBroadcastsMediaStatus() { String sessionId = "abcdef0"; CastWebContentsComponent component = - new CastWebContentsComponent(sessionId, null, null, false, false, true, false); + new CastWebContentsComponent(sessionId, null, null, false, true, false); CastWebContentsComponent.Delegate delegate = mock(CastWebContentsComponent.Delegate.class); component.start(mStartParams, delegate); Assert.assertTrue(component.isStarted()); @@ -334,6 +334,32 @@ Assert.assertTrue(CastWebContentsIntentUtils.isMediaPlaying(receivedIntent1)); } + @Test + public void requestsAudioFocusIfStartParamsAsks() { + Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); + CastWebContentsComponent component = + new CastWebContentsComponent(SESSION_ID, null, null, false, true, true); + CastWebContentsComponent.Delegate delegate = component.new ActivityDelegate(); + CastWebContentsComponent.StartParams startParams = new StartParams( + mActivity, mWebContents, APP_ID, true /* shouldRequestAudioFocus */); + component.start(startParams, delegate); + Intent intent = mShadowActivity.getNextStartedActivity(); + Assert.assertTrue(CastWebContentsIntentUtils.shouldRequestAudioFocus(intent)); + } + + @Test + public void doesNotRequestAudioFocusIfStartParamsDoNotAsk() { + Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE); + CastWebContentsComponent component = + new CastWebContentsComponent(SESSION_ID, null, null, false, true, true); + CastWebContentsComponent.Delegate delegate = component.new ActivityDelegate(); + CastWebContentsComponent.StartParams startParams = new StartParams( + mActivity, mWebContents, APP_ID, false /* shouldRequestAudioFocus */); + component.start(startParams, delegate); + Intent intent = mShadowActivity.getNextStartedActivity(); + Assert.assertFalse(CastWebContentsIntentUtils.shouldRequestAudioFocus(intent)); + } + private void requestMediaPlayingStatus(String sessionId) { Intent intent = CastWebContentsIntentUtils.requestMediaPlayingStatus(sessionId); LocalBroadcastManager.getInstance(ApplicationProvider.getApplicationContext())
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index f28453c..ecaf1969 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -115,7 +115,6 @@ #include "components/cdm/browser/cdm_message_filter_android.h" #include "components/crash/core/app/crashpad.h" #include "media/audio/android/audio_manager_android.h" -#include "media/audio/audio_features.h" #else #include "chromecast/browser/memory_pressure_controller_impl.h" #endif // BUILDFLAG(IS_ANDROID) @@ -160,13 +159,6 @@ &::media::kVaapiVideoDecodeLinux, #endif // BUILDFLAG(USE_V4L2_CODEC) }); - -#if BUILDFLAG(IS_ANDROID) - cast_feature_list_creator_->SetExtraDisableFeatures({ - // Disable AAudio improve AV sync performance. - &::features::kUseAAudioDriver, - }); -#endif } CastContentBrowserClient::~CastContentBrowserClient() {
diff --git a/chromecast/browser/cast_web_contents.h b/chromecast/browser/cast_web_contents.h index 3948641e..5a3975a 100644 --- a/chromecast/browser/cast_web_contents.h +++ b/chromecast/browser/cast_web_contents.h
@@ -36,6 +36,10 @@ class WebContents; } // namespace content +namespace media_control { +class MediaBlocker; +} // namespace media_control + namespace url_rewrite { class UrlRequestRewriteRulesManager; } // namespace url_rewrite @@ -184,6 +188,7 @@ virtual PageState page_state() const = 0; virtual url_rewrite::UrlRequestRewriteRulesManager* url_rewrite_rules_manager() = 0; + virtual const media_control::MediaBlocker* media_blocker() const = 0; // mojom::CastWebContents implementation: void SetAppProperties(const std::string& app_id,
diff --git a/chromecast/browser/cast_web_contents_impl.cc b/chromecast/browser/cast_web_contents_impl.cc index d8b9b41a..0702f98 100644 --- a/chromecast/browser/cast_web_contents_impl.cc +++ b/chromecast/browser/cast_web_contents_impl.cc
@@ -28,18 +28,16 @@ #include "chromecast/common/queryable_data.h" #include "chromecast/net/connectivity_checker.h" #include "components/cast/message_port/cast/message_port_cast.h" +#include "components/media_control/browser/media_blocker.h" #include "components/media_control/mojom/media_playback_options.mojom.h" -#include "components/url_rewrite/common/url_request_rewrite_rules.h" #include "content/public/browser/message_port_provider.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/common/bindings_policy.h" #include "mojo/public/cpp/bindings/associated_remote.h" -#include "mojo/public/cpp/bindings/pending_associated_remote.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/base/net_errors.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -121,8 +119,9 @@ } void CastWebContentsImpl::RemoveRenderProcessHostObserver() { - if (main_process_host_) + if (main_process_host_) { main_process_host_->RemoveObserver(this); + } main_process_host_ = nullptr; } @@ -245,6 +244,11 @@ return &*url_rewrite_rules_manager_; } +const media_control::MediaBlocker* CastWebContentsImpl::media_blocker() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return media_blocker_.get(); +} + void CastWebContentsImpl::AddRendererFeatures(base::Value features) { DCHECK(features.is_dict()); renderer_features_ = std::move(features); @@ -292,8 +296,9 @@ void CastWebContentsImpl::ClosePage() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!web_contents_ || closing_) + if (!web_contents_ || closing_) { return; + } closing_ = true; web_contents_->DispatchBeforeUnload(false /* auto_cancel */); web_contents_->ClosePage(); @@ -325,8 +330,9 @@ } void CastWebContentsImpl::SetWebVisibilityAndPaint(bool visible) { - if (!web_contents_) + if (!web_contents_) { return; + } if (visible) { web_contents_->WasShown(); } else { @@ -340,18 +346,21 @@ } void CastWebContentsImpl::BlockMediaLoading(bool blocked) { - if (media_blocker_) + if (media_blocker_) { media_blocker_->BlockMediaLoading(blocked); + } } void CastWebContentsImpl::BlockMediaStarting(bool blocked) { - if (media_blocker_) + if (media_blocker_) { media_blocker_->BlockMediaStarting(blocked); + } } void CastWebContentsImpl::EnableBackgroundVideoPlayback(bool enabled) { - if (media_blocker_) + if (media_blocker_) { media_blocker_->EnableBackgroundVideoPlayback(enabled); + } } void CastWebContentsImpl::SetAppProperties( @@ -362,8 +371,9 @@ bool enforce_feature_permissions, const std::vector<int32_t>& feature_permissions, const std::vector<std::string>& additional_feature_permission_origins) { - if (!web_contents_) + if (!web_contents_) { return; + } shell::CastNavigationUIData::SetAppPropertiesForWebContents( web_contents_, session_id, is_audio_app); new shell::CastPermissionUserData( @@ -394,8 +404,9 @@ // If origin is set as wildcard, no origin scoping would be applied. absl::optional<std::u16string> target_origin_utf16; constexpr char kWildcardOrigin[] = "*"; - if (target_origin != kWildcardOrigin) + if (target_origin != kWildcardOrigin) { target_origin_utf16 = base::UTF8ToUTF16(target_origin); + } content::MessagePortProvider::PostMessageToFrame( web_contents()->GetPrimaryPage(), std::u16string(), target_origin_utf16, @@ -407,8 +418,9 @@ base::OnceCallback<void(base::Value)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!web_contents_ || closing_ || !main_frame_loaded_ || - !web_contents_->GetPrimaryMainFrame()) + !web_contents_->GetPrimaryMainFrame()) { return; + } web_contents_->GetPrimaryMainFrame()->ExecuteJavaScript(javascript, std::move(callback)); @@ -623,8 +635,9 @@ content::NavigationHandle* navigation_handle) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(navigation_handle); - if (!web_contents_ || closing_ || stopped_) + if (!web_contents_ || closing_ || stopped_) { return; + } if (!navigation_handle->IsInMainFrame() || navigation_handle->IsSameDocument()) { @@ -656,10 +669,12 @@ content::NavigationHandle* navigation_handle) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(navigation_handle); - if (!web_contents_ || closing_ || stopped_) + if (!web_contents_ || closing_ || stopped_) { return; - if (!navigation_handle->IsInMainFrame()) + } + if (!navigation_handle->IsInMainFrame()) { return; + } // Main frame navigation was redirected by the server. LOG(INFO) << "Navigation was redirected by server: " << navigation_handle->GetURL(); @@ -668,8 +683,9 @@ void CastWebContentsImpl::ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) { DCHECK(navigation_handle); - if (!web_contents_ || closing_ || stopped_) + if (!web_contents_ || closing_ || stopped_) { return; + } // We want to honor the autoplay feature policy (via allow="autoplay") without // explicit user activation, since media on Cast is extremely likely to have @@ -680,8 +696,9 @@ // Main frames should have autoplay enabled by default, since autoplay // delegation via parent frame doesn't work here. - if (navigation_handle->IsInMainFrame()) + if (navigation_handle->IsInMainFrame()) { autoplay_flags |= blink::mojom::kAutoplayFlagForceAllow; + } mojo::AssociatedRemote<blink::mojom::AutoplayConfigurationClient> client; navigation_handle->GetRenderFrameHost() @@ -853,11 +870,13 @@ void CastWebContentsImpl::NotifyPageState() { // Don't notify if the page state didn't change. - if (last_state_ == page_state_) + if (last_state_ == page_state_) { return; + } // Don't recursively notify the observers. - if (notifying_) + if (notifying_) { return; + } notifying_ = true; if (stopped_ && !stop_notified_) { stop_notified_ = true; @@ -885,11 +904,13 @@ const content::GlobalRequestID& request_id, const blink::mojom::ResourceLoadInfo& resource_load_info) { if (!web_contents_ || - render_frame_host != web_contents_->GetPrimaryMainFrame()) + render_frame_host != web_contents_->GetPrimaryMainFrame()) { return; + } int net_error = resource_load_info.net_error; - if (net_error == net::OK) + if (net_error == net::OK) { return; + } metrics::CastMetricsHelper* metrics_helper = metrics::CastMetricsHelper::GetInstance(); metrics_helper->RecordApplicationEventWithValue( @@ -905,8 +926,9 @@ void CastWebContentsImpl::InnerWebContentsCreated( content::WebContents* inner_web_contents) { - if (!params_->handle_inner_contents) + if (!params_->handle_inner_contents) { return; + } mojom::CastWebViewParamsPtr params = mojom::CastWebViewParams::New(); params->enabled_for_dev = params_->enabled_for_dev; @@ -931,8 +953,9 @@ void CastWebContentsImpl::TitleWasSet(content::NavigationEntry* entry) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!entry) + if (!entry) { return; + } for (auto& observer : observers_) { observer->UpdateTitle(base::UTF16ToUTF8(entry->GetTitle())); } @@ -964,8 +987,9 @@ const std::vector<blink::mojom::FaviconURLPtr>& candidates) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (candidates.empty()) + if (candidates.empty()) { return; + } GURL icon_url; bool found_touch_icon = false; // icon search order: @@ -1039,8 +1063,9 @@ void CastWebContentsImpl::DisableDebugging() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!params_->enabled_for_dev || !web_contents_) + if (!params_->enabled_for_dev || !web_contents_) { return; + } LOG(INFO) << "Disabling dev console for CastWebContentsImpl"; remote_debugging_server_->DisableWebContentsForDebugging(web_contents_); }
diff --git a/chromecast/browser/cast_web_contents_impl.h b/chromecast/browser/cast_web_contents_impl.h index 4a430bf..35406a9 100644 --- a/chromecast/browser/cast_web_contents_impl.h +++ b/chromecast/browser/cast_web_contents_impl.h
@@ -25,6 +25,7 @@ #include "chromecast/browser/mojom/cast_web_service.mojom.h" #include "chromecast/browser/named_message_port_connector_cast.h" #include "chromecast/mojo/remote_interfaces.h" +#include "components/media_control/browser/media_blocker.h" #include "components/on_load_script_injector/browser/on_load_script_injector_host.h" #include "components/url_rewrite/browser/url_request_rewrite_rules_manager.h" #include "content/public/browser/render_process_host_observer.h" @@ -64,6 +65,7 @@ PageState page_state() const override; url_rewrite::UrlRequestRewriteRulesManager* url_rewrite_rules_manager() override; + const media_control::MediaBlocker* media_blocker() const override; // CastWebContents implementation: int tab_id() const override;
diff --git a/chromecast/browser/mojom/cast_web_service.mojom b/chromecast/browser/mojom/cast_web_service.mojom index a0d9f5c..90f4a64 100644 --- a/chromecast/browser/mojom/cast_web_service.mojom +++ b/chromecast/browser/mojom/cast_web_service.mojom
@@ -133,7 +133,7 @@ bool enable_touch_input = false; // Enable if this CastContentWindow is for running a remote control app. - bool should_request_audio_focus = true; + bool is_remote_control_mode = false; // Turns on the device screen when the window is made visible. bool turn_on_screen = true;
diff --git a/chromecast/browser/test/mock_cast_web_view.h b/chromecast/browser/test/mock_cast_web_view.h index efff9af..edc49a5 100644 --- a/chromecast/browser/test/mock_cast_web_view.h +++ b/chromecast/browser/test/mock_cast_web_view.h
@@ -27,6 +27,10 @@ url_rewrite_rules_manager, (), (override)); + MOCK_METHOD(const media_control::MediaBlocker*, + media_blocker, + (), + (const override)); MOCK_METHOD(void, AddRendererFeatures, (base::Value), (override)); MOCK_METHOD(void, SetInterfacesForRenderer,
diff --git a/chromecast/cast_core/runtime/browser/runtime_application_service_impl.cc b/chromecast/cast_core/runtime/browser/runtime_application_service_impl.cc index a980733..0b5c5ca 100644 --- a/chromecast/cast_core/runtime/browser/runtime_application_service_impl.cc +++ b/chromecast/cast_core/runtime/browser/runtime_application_service_impl.cc
@@ -300,10 +300,10 @@ params->renderer_type = mojom::RendererType::MOJO_RENDERER; params->handle_inner_contents = true; params->session_id = runtime_application_->GetCastSessionId(); - params->should_request_audio_focus = !IsRemoteControlMode(); - params->activity_id = params->should_request_audio_focus - ? runtime_application_->GetAppId() - : params->session_id; + params->is_remote_control_mode = IsRemoteControlMode(); + params->activity_id = params->is_remote_control_mode + ? params->session_id + : runtime_application_->GetAppId(); params->enabled_for_dev = IsEnabledForDev(); params->enable_url_rewrite_rules = false; return web_service_->CreateWebViewInternal(std::move(params));
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 4fcc007..0ce2835 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -15310.0.0 \ No newline at end of file +15324.0.0 \ No newline at end of file
diff --git a/chromeos/ash/components/dbus/arc/BUILD.gn b/chromeos/ash/components/dbus/arc/BUILD.gn index d0774f4..6b5c9088 100644 --- a/chromeos/ash/components/dbus/arc/BUILD.gn +++ b/chromeos/ash/components/dbus/arc/BUILD.gn
@@ -29,6 +29,8 @@ "arc_data_snapshotd_client.h", "arc_keymaster_client.cc", "arc_keymaster_client.h", + "arc_keymint_client.cc", + "arc_keymint_client.h", "arc_midis_client.cc", "arc_midis_client.h", "arc_obb_mounter_client.cc", @@ -43,6 +45,8 @@ "fake_arc_data_snapshotd_client.h", "fake_arc_keymaster_client.cc", "fake_arc_keymaster_client.h", + "fake_arc_keymint_client.cc", + "fake_arc_keymint_client.h", "fake_arc_midis_client.cc", "fake_arc_midis_client.h", "fake_arc_obb_mounter_client.cc",
diff --git a/chromeos/ash/components/dbus/arc/arc_keymint_client.cc b/chromeos/ash/components/dbus/arc/arc_keymint_client.cc new file mode 100644 index 0000000..a42746a4 --- /dev/null +++ b/chromeos/ash/components/dbus/arc/arc_keymint_client.cc
@@ -0,0 +1,99 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/ash/components/dbus/arc/arc_keymint_client.h" + +#include <memory> +#include <utility> + +#include "base/functional/bind.h" +#include "base/functional/callback.h" +#include "base/functional/callback_helpers.h" +#include "chromeos/ash/components/dbus/arc/fake_arc_keymint_client.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "dbus/object_proxy.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace ash { + +namespace { + +ArcKeyMintClient* g_instance = nullptr; + +void OnVoidDBusMethod(chromeos::VoidDBusMethodCallback callback, + dbus::Response* response) { + std::move(callback).Run(response != nullptr); +} + +class ArcKeyMintClientImpl : public ArcKeyMintClient { + public: + ArcKeyMintClientImpl() = default; + + ArcKeyMintClientImpl(const ArcKeyMintClientImpl&) = delete; + ArcKeyMintClientImpl& operator=(const ArcKeyMintClientImpl&) = delete; + + ~ArcKeyMintClientImpl() override = default; + + void BootstrapMojoConnection( + base::ScopedFD fd, + chromeos::VoidDBusMethodCallback callback) override { + dbus::MethodCall method_call(arc::keymint::kArcKeyMintInterfaceName, + arc::keymint::kBootstrapMojoConnectionMethod); + dbus::MessageWriter writer(&method_call); + + writer.AppendFileDescriptor(fd.get()); + proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::BindOnce(&OnVoidDBusMethod, std::move(callback))); + } + + void Init(dbus::Bus* bus) override { + proxy_ = bus->GetObjectProxy( + arc::keymint::kArcKeyMintServiceName, + dbus::ObjectPath(arc::keymint::kArcKeyMintServicePath)); + } + + private: + // Owned by the D-Bus implementation, who outlives this class. + dbus::ObjectProxy* proxy_ = nullptr; +}; + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// ArcKeyMintClient + +// static +ArcKeyMintClient* ArcKeyMintClient::Get() { + return g_instance; +} + +// static +void ArcKeyMintClient::Initialize(dbus::Bus* bus) { + CHECK(bus); + (new ArcKeyMintClientImpl())->Init(bus); +} + +// static +void ArcKeyMintClient::InitializeFake() { + (new FakeArcKeyMintClient())->Init(nullptr); +} + +// static +void ArcKeyMintClient::Shutdown() { + CHECK(g_instance); + delete g_instance; +} + +ArcKeyMintClient::ArcKeyMintClient() { + CHECK(!g_instance); + g_instance = this; +} + +ArcKeyMintClient::~ArcKeyMintClient() { + CHECK_EQ(g_instance, this); + g_instance = nullptr; +} + +} // namespace ash
diff --git a/chromeos/ash/components/dbus/arc/arc_keymint_client.h b/chromeos/ash/components/dbus/arc/arc_keymint_client.h new file mode 100644 index 0000000..e6f36cb --- /dev/null +++ b/chromeos/ash/components/dbus/arc/arc_keymint_client.h
@@ -0,0 +1,48 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_ASH_COMPONENTS_DBUS_ARC_ARC_KEYMINT_CLIENT_H_ +#define CHROMEOS_ASH_COMPONENTS_DBUS_ARC_ARC_KEYMINT_CLIENT_H_ + +#include "base/files/scoped_file.h" +#include "chromeos/dbus/common/dbus_client.h" +#include "chromeos/dbus/common/dbus_method_call_status.h" + +namespace ash { + +// ArcKeyMintClient is used to bootstrap a Mojo connection with the +// arc-keymintd daemon in Chrome OS. +class COMPONENT_EXPORT(ASH_DBUS_ARC) ArcKeyMintClient + : public chromeos::DBusClient { + public: + // Returns the global instance if initialized. May return null. + static ArcKeyMintClient* Get(); + + // Creates and initializes the global instance. |bus| must not be null. + static void Initialize(dbus::Bus* bus); + + // Creates and initializes a fake global instance. + static void InitializeFake(); + + // Destroys the global instance if it has been initialized. + static void Shutdown(); + + ArcKeyMintClient(const ArcKeyMintClient&) = delete; + ArcKeyMintClient& operator=(const ArcKeyMintClient&) = delete; + + // Bootstrap the Mojo connection between Chrome and the keymint service. + // Should pass in the child end of the Mojo pipe. + virtual void BootstrapMojoConnection( + base::ScopedFD fd, + chromeos::VoidDBusMethodCallback callback) = 0; + + protected: + // Initialize() should be used instead. + ArcKeyMintClient(); + ~ArcKeyMintClient() override; +}; + +} // namespace ash + +#endif // CHROMEOS_ASH_COMPONENTS_DBUS_ARC_ARC_KEYMINT_CLIENT_H_
diff --git a/chromeos/ash/components/dbus/arc/fake_arc_keymint_client.cc b/chromeos/ash/components/dbus/arc/fake_arc_keymint_client.cc new file mode 100644 index 0000000..c640b7b0 --- /dev/null +++ b/chromeos/ash/components/dbus/arc/fake_arc_keymint_client.cc
@@ -0,0 +1,24 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/ash/components/dbus/arc/fake_arc_keymint_client.h" + +#include <utility> + +#include "base/functional/bind.h" +#include "base/functional/callback.h" +#include "base/task/single_thread_task_runner.h" + +namespace ash { + +void FakeArcKeyMintClient::Init(dbus::Bus* bus) {} + +void FakeArcKeyMintClient::BootstrapMojoConnection( + base::ScopedFD fd, + chromeos::VoidDBusMethodCallback callback) { + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), false)); +} + +} // namespace ash
diff --git a/chromeos/ash/components/dbus/arc/fake_arc_keymint_client.h b/chromeos/ash/components/dbus/arc/fake_arc_keymint_client.h new file mode 100644 index 0000000..8e1e953a --- /dev/null +++ b/chromeos/ash/components/dbus/arc/fake_arc_keymint_client.h
@@ -0,0 +1,34 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_ASH_COMPONENTS_DBUS_ARC_FAKE_ARC_KEYMINT_CLIENT_H_ +#define CHROMEOS_ASH_COMPONENTS_DBUS_ARC_FAKE_ARC_KEYMINT_CLIENT_H_ + +#include "chromeos/ash/components/dbus/arc/arc_keymint_client.h" + +namespace ash { + +// A fake implementation of ArcKeyMintClient. +class COMPONENT_EXPORT(ASH_DBUS_ARC) FakeArcKeyMintClient + : public ArcKeyMintClient { + public: + FakeArcKeyMintClient() = default; + + FakeArcKeyMintClient(const FakeArcKeyMintClient&) = delete; + FakeArcKeyMintClient& operator=(const FakeArcKeyMintClient&) = delete; + + ~FakeArcKeyMintClient() override = default; + + // chromeos::DBusClient override: + void Init(dbus::Bus* bus) override; + + // ArcKeyMintClient override: + void BootstrapMojoConnection( + base::ScopedFD fd, + chromeos::VoidDBusMethodCallback callback) override; +}; + +} // namespace ash + +#endif // CHROMEOS_ASH_COMPONENTS_DBUS_ARC_FAKE_ARC_KEYMINT_CLIENT_H_
diff --git a/chromeos/ash/components/dbus/shill/fake_shill_ipconfig_client.cc b/chromeos/ash/components/dbus/shill/fake_shill_ipconfig_client.cc index cbdc842..d6fe9e2 100644 --- a/chromeos/ash/components/dbus/shill/fake_shill_ipconfig_client.cc +++ b/chromeos/ash/components/dbus/shill/fake_shill_ipconfig_client.cc
@@ -35,11 +35,10 @@ void FakeShillIPConfigClient::GetProperties( const dbus::ObjectPath& ipconfig_path, chromeos::DBusMethodCallback<base::Value> callback) { - const base::Value* dict = ipconfigs_.FindDictKey(ipconfig_path.value()); - if (!dict) - return; + const base::Value::Dict* dict = ipconfigs_.EnsureDict(ipconfig_path.value()); base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), dict->Clone())); + FROM_HERE, + base::BindOnce(std::move(callback), base::Value(dict->Clone()))); } void FakeShillIPConfigClient::SetProperty( @@ -47,14 +46,10 @@ const std::string& name, const base::Value& value, chromeos::VoidDBusMethodCallback callback) { - base::Value* dict = ipconfigs_.FindDictKey(ipconfig_path.value()); - if (!dict) { - dict = ipconfigs_.SetKey(ipconfig_path.value(), - base::Value(base::Value::Type::DICTIONARY)); - } + base::Value::Dict* dict = ipconfigs_.EnsureDict(ipconfig_path.value()); // Update existing ip config stub object's properties. - dict->SetKey(name, value.Clone()); + dict->Set(name, value.Clone()); base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), true)); } @@ -82,8 +77,8 @@ // ShillIPConfigClient::TestInterface overrides void FakeShillIPConfigClient::AddIPConfig(const std::string& ip_config_path, - const base::Value& properties) { - ipconfigs_.SetKey(ip_config_path, properties.Clone()); + base::Value::Dict properties) { + ipconfigs_.Set(ip_config_path, std::move(properties)); } } // namespace ash
diff --git a/chromeos/ash/components/dbus/shill/fake_shill_ipconfig_client.h b/chromeos/ash/components/dbus/shill/fake_shill_ipconfig_client.h index c083577..e3829c2 100644 --- a/chromeos/ash/components/dbus/shill/fake_shill_ipconfig_client.h +++ b/chromeos/ash/components/dbus/shill/fake_shill_ipconfig_client.h
@@ -48,11 +48,11 @@ // ShillIPConfigClient::TestInterface overrides. void AddIPConfig(const std::string& ip_config_path, - const base::Value& properties) override; + base::Value::Dict properties) override; private: // Dictionary of <ipconfig_path, property dictionaries> - base::Value ipconfigs_{base::Value::Type::DICTIONARY}; + base::Value::Dict ipconfigs_; // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed.
diff --git a/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc b/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc index 2d02ec69..e8c2134 100644 --- a/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc +++ b/chromeos/ash/components/dbus/shill/fake_shill_manager_client.cc
@@ -893,23 +893,20 @@ const bool add_to_visible = true; // IPConfigs - base::Value ipconfig_v4_dictionary(base::Value::Type::DICTIONARY); - ipconfig_v4_dictionary.SetKey(shill::kAddressProperty, - base::Value("100.0.0.1")); - ipconfig_v4_dictionary.SetKey(shill::kGatewayProperty, - base::Value("100.0.0.2")); - ipconfig_v4_dictionary.SetKey(shill::kPrefixlenProperty, base::Value(1)); - ipconfig_v4_dictionary.SetKey(shill::kMethodProperty, - base::Value(shill::kTypeIPv4)); - ipconfig_v4_dictionary.SetKey(shill::kWebProxyAutoDiscoveryUrlProperty, - base::Value("http://wpad.com/wpad.dat")); - ip_configs->AddIPConfig("ipconfig_v4_path", ipconfig_v4_dictionary); - base::Value ipconfig_v6_dictionary(base::Value::Type::DICTIONARY); - ipconfig_v6_dictionary.SetKey(shill::kAddressProperty, - base::Value("0:0:0:0:100:0:0:1")); - ipconfig_v6_dictionary.SetKey(shill::kMethodProperty, - base::Value(shill::kTypeIPv6)); - ip_configs->AddIPConfig("ipconfig_v6_path", ipconfig_v6_dictionary); + base::Value::Dict ipconfig_v4_dictionary; + ipconfig_v4_dictionary.Set(shill::kAddressProperty, "100.0.0.1"); + ipconfig_v4_dictionary.Set(shill::kGatewayProperty, "100.0.0.2"); + ipconfig_v4_dictionary.Set(shill::kPrefixlenProperty, 1); + ipconfig_v4_dictionary.Set(shill::kMethodProperty, shill::kTypeIPv4); + ipconfig_v4_dictionary.Set(shill::kWebProxyAutoDiscoveryUrlProperty, + "http://wpad.com/wpad.dat"); + ip_configs->AddIPConfig("ipconfig_v4_path", + std::move(ipconfig_v4_dictionary)); + base::Value::Dict ipconfig_v6_dictionary; + ipconfig_v6_dictionary.Set(shill::kAddressProperty, "0:0:0:0:100:0:0:1"); + ipconfig_v6_dictionary.Set(shill::kMethodProperty, shill::kTypeIPv6); + ip_configs->AddIPConfig("ipconfig_v6_path", + std::move(ipconfig_v6_dictionary)); bool enabled; std::string state;
diff --git a/chromeos/ash/components/dbus/shill/shill_ipconfig_client.h b/chromeos/ash/components/dbus/shill/shill_ipconfig_client.h index 236241c..e235542 100644 --- a/chromeos/ash/components/dbus/shill/shill_ipconfig_client.h +++ b/chromeos/ash/components/dbus/shill/shill_ipconfig_client.h
@@ -33,10 +33,10 @@ public: // Adds an IPConfig entry. virtual void AddIPConfig(const std::string& ip_config_path, - const base::Value& properties) = 0; + base::Value::Dict properties) = 0; protected: - virtual ~TestInterface() {} + virtual ~TestInterface() = default; }; // Creates and initializes the global instance. |bus| must not be null.
diff --git a/chromeos/ash/components/device_activity/device_activity_client.cc b/chromeos/ash/components/device_activity/device_activity_client.cc index 41bf58d7..0b35d86 100644 --- a/chromeos/ash/components/device_activity/device_activity_client.cc +++ b/chromeos/ash/components/device_activity/device_activity_client.cc
@@ -470,14 +470,24 @@ } if (!device_active_use_case_ptr->IsLastKnownPingTimestampSet()) { - RecordPreservedFileState( - DeviceActivityClient::PreservedFileState::kReadOkLocalStateEmpty); + if (use_case == + private_computing::PrivateComputingUseCase::CROS_FRESNEL_DAILY) { + // Only record the successfully read from preserved file for daily use + // case. + RecordPreservedFileState( + DeviceActivityClient::PreservedFileState::kReadOkLocalStateEmpty); + } VLOG(1) << "Updating local pref timestamp value with file timestamp = " << last_ping_time; device_active_use_case_ptr->SetLastKnownPingTimestamp(last_ping_time); } else { - RecordPreservedFileState( - DeviceActivityClient::PreservedFileState::kReadOkLocalStateSet); + if (use_case == + private_computing::PrivateComputingUseCase::CROS_FRESNEL_DAILY) { + // Only record the successfully read from preserved file for daily use + // case. + RecordPreservedFileState( + DeviceActivityClient::PreservedFileState::kReadOkLocalStateSet); + } VLOG(1) << "Preserved File was read successfully but local state is " "already set. " << "Device was most likely restarted and not powerwashed, so "
diff --git a/chromeos/ash/components/disks/disk_mount_manager_unittest.cc b/chromeos/ash/components/disks/disk_mount_manager_unittest.cc index d65e6eb..a2743f8 100644 --- a/chromeos/ash/components/disks/disk_mount_manager_unittest.cc +++ b/chromeos/ash/components/disks/disk_mount_manager_unittest.cc
@@ -18,6 +18,7 @@ #include "base/test/bind.h" #include "base/test/mock_callback.h" #include "base/test/task_environment.h" +#include "base/test/test_future.h" #include "chromeos/ash/components/dbus/cros_disks/cros_disks_client.h" #include "chromeos/ash/components/dbus/cros_disks/fake_cros_disks_client.h" #include "chromeos/ash/components/disks/disk.h" @@ -1507,16 +1508,7 @@ MountError::kSuccess, kDevice1MountPath)); } -void SaveUnmountResult(MountError* save_error, - base::OnceClosure done_callback, - MountError error_code) { - *save_error = error_code; - std::move(done_callback).Run(); -} - TEST_F(DiskMountManagerTest, UnmountDeviceRecursively) { - base::RunLoop run_loop; - auto disk_sda = Disk::Builder().SetDevicePath("/dev/sda").SetIsParent(true).Build(); EXPECT_TRUE( @@ -1536,20 +1528,16 @@ EXPECT_TRUE( DiskMountManager::GetInstance()->AddDiskForTest(std::move(disk_sda2))); - MountError error_code = MountError::kUnknownError; + base::test::TestFuture<MountError> future; DiskMountManager::GetInstance()->UnmountDeviceRecursively( - "/dev/sda", - base::BindOnce(&SaveUnmountResult, base::Unretained(&error_code), - run_loop.QuitClosure())); - run_loop.Run(); + "/dev/sda", future.GetCallback()); + EXPECT_TRUE(future.Wait()); EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count()); - EXPECT_EQ(MountError::kSuccess, error_code); + EXPECT_EQ(MountError::kSuccess, future.Get()); } TEST_F(DiskMountManagerTest, UnmountDeviceRecursively_NoMounted) { - base::RunLoop run_loop; - auto disk_sda = Disk::Builder().SetDevicePath("/dev/sda").SetIsParent(true).Build(); EXPECT_TRUE( @@ -1559,15 +1547,13 @@ EXPECT_TRUE( DiskMountManager::GetInstance()->AddDiskForTest(std::move(disk_sda1))); - MountError error_code = MountError::kUnknownError; + base::test::TestFuture<MountError> future; DiskMountManager::GetInstance()->UnmountDeviceRecursively( - "/dev/sda", - base::BindOnce(&SaveUnmountResult, base::Unretained(&error_code), - run_loop.QuitClosure())); - run_loop.Run(); + "/dev/sda", future.GetCallback()); + EXPECT_TRUE(future.Wait()); EXPECT_EQ(0, fake_cros_disks_client_->unmount_call_count()); - EXPECT_EQ(MountError::kSuccess, error_code); + EXPECT_EQ(MountError::kSuccess, future.Get()); } TEST_F(DiskMountManagerTest, UnmountDeviceRecursively_NoDisk) { @@ -1582,16 +1568,14 @@ EXPECT_TRUE( DiskMountManager::GetInstance()->AddDiskForTest(std::move(disk_sda1))); - MountError error_code = MountError::kUnknownError; + base::test::TestFuture<MountError> future; // Unmount sdB instead of sdA. DiskMountManager::GetInstance()->UnmountDeviceRecursively( - "/dev/sdb", - base::BindOnce(&SaveUnmountResult, base::Unretained(&error_code), - run_loop.QuitClosure())); - run_loop.Run(); + "/dev/sdb", future.GetCallback()); + EXPECT_TRUE(future.Wait()); EXPECT_EQ(0, fake_cros_disks_client_->unmount_call_count()); - EXPECT_EQ(MountError::kInvalidDevicePath, error_code); + EXPECT_EQ(MountError::kInvalidDevicePath, future.Get()); } void SetUnmountError(FakeCrosDisksClient* client, MountError error_code) { @@ -1599,8 +1583,6 @@ } TEST_F(DiskMountManagerTest, UnmountDeviceRecursively_FailFirst) { - base::RunLoop run_loop; - auto disk_sda = Disk::Builder().SetDevicePath("/dev/sda").SetIsParent(true).Build(); EXPECT_TRUE( @@ -1627,20 +1609,16 @@ &SetUnmountError, base::Unretained(fake_cros_disks_client_), MountError::kSuccess)); - MountError error_code = MountError::kUnknownError; + base::test::TestFuture<MountError> future; DiskMountManager::GetInstance()->UnmountDeviceRecursively( - "/dev/sda", - base::BindOnce(&SaveUnmountResult, base::Unretained(&error_code), - run_loop.QuitClosure())); - run_loop.Run(); + "/dev/sda", future.GetCallback()); + EXPECT_TRUE(future.Wait()); EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count()); - EXPECT_EQ(MountError::kInsufficientPermissions, error_code); + EXPECT_EQ(MountError::kInsufficientPermissions, future.Get()); } TEST_F(DiskMountManagerTest, UnmountDeviceRecursively_AlreadyUnmounted) { - base::RunLoop run_loop; - auto disk_sda = Disk::Builder().SetDevicePath("/dev/sda").SetIsParent(true).Build(); EXPECT_TRUE( @@ -1656,15 +1634,13 @@ // Fail the unmount with "not mounted". fake_cros_disks_client_->MakeUnmountFail(MountError::kPathNotMounted); - MountError error_code = MountError::kUnknownError; + base::test::TestFuture<MountError> future; DiskMountManager::GetInstance()->UnmountDeviceRecursively( - "/dev/sda", - base::BindOnce(&SaveUnmountResult, base::Unretained(&error_code), - run_loop.QuitClosure())); - run_loop.Run(); + "/dev/sda", future.GetCallback()); + EXPECT_TRUE(future.Wait()); EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count()); - EXPECT_EQ(MountError::kSuccess, error_code); + EXPECT_EQ(MountError::kSuccess, future.Get()); } TEST_F(DiskMountManagerTest, Mount_MountUnsetsFirstMount) {
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc index 0e2f574b..74dc4bb6 100644 --- a/chromeos/ash/components/drivefs/drivefs_pin_manager.cc +++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.cc
@@ -335,40 +335,22 @@ bool DriveFsPinManager::Remove(const StableId id, const std::string& path, - int64_t bytes_transferred) { + int64_t transferred) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - const Files::node_type node = files_to_track_.extract(id); - if (!node) { + const Files::iterator it = files_to_track_.find(id); + if (it == files_to_track_.end()) { + VLOG(3) << "Not tracked: " << id << " " << path; return false; } - DCHECK_EQ(node.key(), id); - const Progress& progress = node.mapped(); - - LOG_IF(ERROR, path != progress.path) - << "Changed path of " << id << " " << Quote(progress.path) << " to " - << Quote(path); - - if (bytes_transferred < 0) { - bytes_transferred = progress.total; - } else if (progress.total != bytes_transferred) { - LOG(ERROR) << "Expected final progress " - << HumanReadableSize(progress.total) << " instead of " - << HumanReadableSize(bytes_transferred) << " for " << id << " " - << Quote(path); - progress_.bytes_to_pin += bytes_transferred - progress.total; - progress_.required_space += - RoundToBlockSize(bytes_transferred) - RoundToBlockSize(progress.total); + if (transferred < 0) { + Update(*it, path, it->second.total, -1); + } else { + Update(*it, path, transferred, transferred); } - LOG_IF(ERROR, progress.transferred > bytes_transferred) - << "Progress went backwards from " - << HumanReadableSize(progress.transferred) << " to " - << HumanReadableSize(bytes_transferred) << " for " << id << " " - << Quote(path); - progress_.pinned_bytes += bytes_transferred - progress.transferred; - + files_to_track_.erase(it); VLOG(3) << "Stopped tracking " << id << " " << Quote(path); return true; } @@ -378,13 +360,6 @@ const int64_t transferred, const int64_t total) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK_GE(total, 0) << " for " << id << " " << Quote(path); - - if (transferred < 0) { - LOG(ERROR) << "Negative transferred = " << HumanReadableSize(transferred) - << " for " << id << " " << Quote(path); - return false; - } const Files::iterator it = files_to_track_.find(id); if (it == files_to_track_.end()) { @@ -393,30 +368,46 @@ } DCHECK_EQ(it->first, id); - Progress& progress = it->second; + return Update(*it, path, transferred, total); +} + +bool DriveFsPinManager::Update(Files::value_type& entry, + const std::string& path, + int64_t transferred, + int64_t total) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + auto& [id, progress] = entry; + bool modified = false; if (path != progress.path) { - LOG(ERROR) << "Changed path of " << id << " " << Quote(progress.path) - << " to " << Quote(path); + VLOG(1) << "Changed path of " << id << " " << Quote(progress.path) << " to " + << Quote(path); progress.path = path; + modified = true; } - if (transferred == progress.transferred && total == progress.total && - progress.in_progress) { - return false; + if (!progress.in_progress) { + LOG_IF(ERROR, progress.transferred > 0) + << "Queued " << id << " " << Quote(path) << " already has transferred " + << HumanReadableSize(progress.transferred); + + progress.in_progress = true; + modified = true; } - progress.in_progress = true; + if (transferred != progress.transferred && transferred >= 0) { + LOG_IF(ERROR, transferred < progress.transferred) + << "Progress went backwards from " + << HumanReadableSize(progress.transferred) << " to " + << HumanReadableSize(transferred) << " for " << id << " " + << Quote(path); + progress_.pinned_bytes += transferred - progress.transferred; + progress.transferred = transferred; + modified = true; + } - LOG_IF(ERROR, transferred < progress.transferred) - << "Progress went backwards from " - << HumanReadableSize(progress.transferred) << " to " - << HumanReadableSize(transferred) << " for " << id << " " << Quote(path); - - progress_.pinned_bytes += transferred - progress.transferred; - progress.transferred = transferred; - - if (total != progress.total) { + if (total != progress.total && total >= 0) { LOG(ERROR) << "Changed expected size of " << id << " " << Quote(path) << " from " << HumanReadableSize(progress.total) << " to " << HumanReadableSize(total); @@ -424,40 +415,10 @@ progress_.required_space += RoundToBlockSize(total) - RoundToBlockSize(progress.total); progress.total = total; + modified = true; } - return true; -} - -bool DriveFsPinManager::MarkInProgress(const StableId id, - const std::string& path) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - const Files::iterator it = files_to_track_.find(id); - if (it == files_to_track_.end()) { - VLOG(3) << "Not tracked: " << id << " " << path; - return false; - } - - DCHECK_EQ(it->first, id); - Progress& progress = it->second; - - if (path != progress.path) { - LOG(ERROR) << "Changed path of " << id << " " << Quote(progress.path) - << " to " << Quote(path); - progress.path = path; - } - - if (progress.in_progress) { - return false; - } - - LOG_IF(ERROR, progress.transferred > 0) - << "Queued " << id << " " << Quote(path) << " already has transferred " - << HumanReadableSize(progress.transferred); - - progress.in_progress = true; - return true; + return modified; } DriveFsPinManager::DriveFsPinManager(base::FilePath profile_path, @@ -740,12 +701,20 @@ using State = mojom::ItemEvent::State; switch (event->state) { case State::kQueued: - if (MarkInProgress(id, event->path)) { - VLOG(2) << "Queued " << id << " " << Quote(event->path) << ": " - << Quote(*event); - VLOG_IF(1, !VLOG_IS_ON(2)) - << "Queued " << id << " " << Quote(event->path); + // kQueued events come with a bytes_to_transfer field incorrectly set to + // zero (b/266462624). So we set it to -1 to ignore it. + event->bytes_to_transfer = -1; + [[fallthrough]]; + + case State::kInProgress: + if (Update(id, event->path, event->bytes_transferred, + event->bytes_to_transfer)) { + VLOG(3) << Quote(event->state) << " " << id << " " + << Quote(event->path) << ": " << Quote(*event); + VLOG_IF(2, !VLOG_IS_ON(3)) + << Quote(event->state) << " " << id << " " << Quote(event->path); progress_.useful_events++; + NotifyProgress(); } else { VLOG(3) << "Duplicated event: " << Quote(*event); progress_.duplicated_events++; @@ -754,9 +723,9 @@ case State::kCompleted: if (Remove(id, event->path)) { - VLOG(2) << "Synced " << id << " " << Quote(event->path) << ": " + VLOG(3) << "Synced " << id << " " << Quote(event->path) << ": " << Quote(*event); - VLOG_IF(1, !VLOG_IS_ON(2)) + VLOG_IF(2, !VLOG_IS_ON(3)) << "Synced " << id << " " << Quote(event->path); progress_.useful_events++; progress_.pinned_files++; @@ -769,8 +738,8 @@ case State::kFailed: if (Remove(id, event->path, 0)) { - LOG(ERROR) << "Cannot sync " << id << " " << Quote(event->path) - << ": " << Quote(*event); + LOG(ERROR) << Quote(event->state) << " " << id << " " + << Quote(event->path) << ": " << Quote(*event); progress_.failed_files++; progress_.useful_events++; NotifyProgress(); @@ -779,21 +748,6 @@ progress_.duplicated_events++; } continue; - - case State::kInProgress: - if (Update(id, event->path, event->bytes_transferred, - event->bytes_to_transfer)) { - VLOG(2) << "Syncing " << id << " " << Quote(event->path) << " at " - << Percentage(event->bytes_transferred, - event->bytes_to_transfer) - << "%: " << Quote(*event); - progress_.useful_events++; - NotifyProgress(); - } else { - VLOG(3) << "Duplicated event: " << Quote(*event); - progress_.duplicated_events++; - } - continue; } LOG(ERROR) << "Unexpected event type: " << Quote(*event);
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager.h b/chromeos/ash/components/drivefs/drivefs_pin_manager.h index 2547830..33d65b8 100644 --- a/chromeos/ash/components/drivefs/drivefs_pin_manager.h +++ b/chromeos/ash/components/drivefs/drivefs_pin_manager.h
@@ -198,33 +198,6 @@ } private: - // Adds an item to the files to pin. Does nothing if an item with the same ID - // already exists in files_to_pin_. Updates the total number of bytes to - // transfer and the required space. Returns whether an item was actually - // added. - bool Add(StableId id, const std::string& path, int64_t size); - - // Removes an item from the map. Does nothing if the item is not in the map. - // Updates the total number of bytes transferred so far. - // If `bytes_transferred` is negative, use the total expected size. - // Returns whether an item was actually removed. - bool Remove(StableId id, - const std::string& path, - int64_t bytes_transferred = -1); - - // Updates an item in the map. Does nothing if the item is not in the map. - // Updates the total number of bytes transferred so far. - // Returns whether anything has actually been updated. - bool Update(StableId id, - const std::string& path, - int64_t transferred, - int64_t total); - - // Updates an item to mark it in progress. - // Does nothing if the item is not in the map. - // Returns whether anything has actually been updated. - bool MarkInProgress(StableId id, const std::string& path); - // Struct keeping track of the progress of a file being synced. struct Progress { // Path inside the Drive folder. @@ -247,6 +220,33 @@ } }; + using Files = std::map<StableId, Progress>; + + // Adds an item to the files to pin. Does nothing if an item with the same ID + // already exists in files_to_pin_. Updates the total number of bytes to + // transfer and the required space. Returns whether an item was actually + // added. + bool Add(StableId id, const std::string& path, int64_t size); + + // Removes an item from the map. Does nothing if the item is not in the map. + // Updates the total number of bytes transferred so far. If `transferred` is + // negative, use the total expected size. Returns whether an item was actually + // removed. + bool Remove(StableId id, const std::string& path, int64_t transferred = -1); + + // Updates an item in the map. Does nothing if the item is not in the map. + // Updates the total number of bytes transferred so far. Updates the required + // space. If `transferred` or `total` is negative, then the matching argument + // is ignored. Returns whether anything has actually been updated. + bool Update(StableId id, + const std::string& path, + int64_t transferred, + int64_t total); + bool Update(Files::value_type& entry, + const std::string& path, + int64_t transferred, + int64_t total); + // Invoked on retrieval of available space in the `~/GCache` directory. void OnFreeSpaceRetrieved(int64_t free_space); @@ -316,13 +316,14 @@ base::ElapsedTimer timer_; // Map that tracks the in-progress files indexed by their stable ID. - using Files = std::map<StableId, Progress>; Files files_to_pin_ GUARDED_BY_CONTEXT(sequence_checker_); Files files_to_track_ GUARDED_BY_CONTEXT(sequence_checker_); base::WeakPtrFactory<DriveFsPinManager> weak_ptr_factory_{this}; FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, Add); + FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, Update); + FRIEND_TEST_ALL_PREFIXES(DriveFsPinManagerTest, Remove); }; COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DRIVEFS)
diff --git a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc b/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc index 4bf21be..26267a78 100644 --- a/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc +++ b/chromeos/ash/components/drivefs/drivefs_pin_manager_unittest.cc
@@ -309,6 +309,324 @@ } } +// Tests DriveFsPinManagerTest::Update(). +TEST_F(DriveFsPinManagerTest, Update) { + DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_); + + DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_); + manager.progress_.pinned_bytes = 5000; + manager.progress_.bytes_to_pin = 10000; + manager.progress_.required_space = 20480; + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 5000); + EXPECT_EQ(progress.bytes_to_pin, 10000); + EXPECT_EQ(progress.required_space, 20480); + } + + const DriveFsPinManager::StableId id1 = DriveFsPinManager::StableId(549); + const std::string path1 = "Path 1"; + const int64_t size1 = 2000; + + const DriveFsPinManager::StableId id2 = DriveFsPinManager::StableId(17); + const std::string path2 = "Path 2"; + const int64_t size2 = 5000; + + // Put in place a file to track. + { + const auto [it, ok] = manager.files_to_track_.try_emplace( + id1, DriveFsPinManager::Progress{.path = path1, .total = size1}); + ASSERT_TRUE(ok); + } + + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + // Try to update an unknown file. + EXPECT_FALSE(manager.Update(id2, path2, size2, size2)); + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + { + const auto it = manager.files_to_track_.find(id1); + ASSERT_NE(it, manager.files_to_track_.end()); + const auto& [got_id, progress] = *it; + EXPECT_EQ(got_id, id1); + EXPECT_EQ(progress.path, path1); + EXPECT_EQ(progress.total, size1); + EXPECT_EQ(progress.transferred, 0); + EXPECT_FALSE(progress.in_progress); + } + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 5000); + EXPECT_EQ(progress.bytes_to_pin, 10000); + EXPECT_EQ(progress.required_space, 20480); + } + + // Mark file as in progress. + EXPECT_TRUE(manager.Update(id1, path1, -1, -1)); + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + { + const auto it = manager.files_to_track_.find(id1); + ASSERT_NE(it, manager.files_to_track_.end()); + const auto& [got_id, progress] = *it; + EXPECT_EQ(got_id, id1); + EXPECT_EQ(progress.path, path1); + EXPECT_EQ(progress.total, size1); + EXPECT_EQ(progress.transferred, 0); + EXPECT_TRUE(progress.in_progress); + } + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 5000); + EXPECT_EQ(progress.bytes_to_pin, 10000); + EXPECT_EQ(progress.required_space, 20480); + } + + // These updates should not modify anything. + EXPECT_FALSE(manager.Update(id1, path1, -1, -1)); + EXPECT_FALSE(manager.Update(id1, path1, 0, -1)); + EXPECT_FALSE(manager.Update(id1, path1, -1, size1)); + EXPECT_FALSE(manager.Update(id1, path1, 0, size1)); + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + { + const auto it = manager.files_to_track_.find(id1); + ASSERT_NE(it, manager.files_to_track_.end()); + const auto& [got_id, progress] = *it; + EXPECT_EQ(got_id, id1); + EXPECT_EQ(progress.path, path1); + EXPECT_EQ(progress.total, size1); + EXPECT_EQ(progress.transferred, 0); + EXPECT_TRUE(progress.in_progress); + } + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 5000); + EXPECT_EQ(progress.bytes_to_pin, 10000); + EXPECT_EQ(progress.required_space, 20480); + } + + // Update total size. + EXPECT_TRUE(manager.Update(id1, path1, -1, size2)); + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + { + const auto it = manager.files_to_track_.find(id1); + ASSERT_NE(it, manager.files_to_track_.end()); + const auto& [got_id, progress] = *it; + EXPECT_EQ(got_id, id1); + EXPECT_EQ(progress.path, path1); + EXPECT_EQ(progress.total, size2); + EXPECT_EQ(progress.transferred, 0); + EXPECT_TRUE(progress.in_progress); + } + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 5000); + EXPECT_EQ(progress.bytes_to_pin, 13000); + EXPECT_EQ(progress.required_space, 24576); + } + + // Update transferred bytes. + EXPECT_TRUE(manager.Update(id1, path1, size1, -1)); + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + { + const auto it = manager.files_to_track_.find(id1); + ASSERT_NE(it, manager.files_to_track_.end()); + const auto& [got_id, progress] = *it; + EXPECT_EQ(got_id, id1); + EXPECT_EQ(progress.path, path1); + EXPECT_EQ(progress.total, size2); + EXPECT_EQ(progress.transferred, size1); + EXPECT_TRUE(progress.in_progress); + } + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 7000); + EXPECT_EQ(progress.bytes_to_pin, 13000); + EXPECT_EQ(progress.required_space, 24576); + } + + // Update path. + EXPECT_TRUE(manager.Update(id1, path2, -1, -1)); + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + { + const auto it = manager.files_to_track_.find(id1); + ASSERT_NE(it, manager.files_to_track_.end()); + const auto& [got_id, progress] = *it; + EXPECT_EQ(got_id, id1); + EXPECT_EQ(progress.path, path2); + EXPECT_EQ(progress.total, size2); + EXPECT_EQ(progress.transferred, size1); + EXPECT_TRUE(progress.in_progress); + } + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 7000); + EXPECT_EQ(progress.bytes_to_pin, 13000); + EXPECT_EQ(progress.required_space, 24576); + } + + // Progress goes backwards. + EXPECT_TRUE(manager.Update(id1, path2, 1000, -1)); + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + { + const auto it = manager.files_to_track_.find(id1); + ASSERT_NE(it, manager.files_to_track_.end()); + const auto& [got_id, progress] = *it; + EXPECT_EQ(got_id, id1); + EXPECT_EQ(progress.path, path2); + EXPECT_EQ(progress.total, size2); + EXPECT_EQ(progress.transferred, 1000); + EXPECT_TRUE(progress.in_progress); + } + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 6000); + EXPECT_EQ(progress.bytes_to_pin, 13000); + EXPECT_EQ(progress.required_space, 24576); + } +} + +// Tests DriveFsPinManagerTest::Remove(). +TEST_F(DriveFsPinManagerTest, Remove) { + DriveFsPinManager manager(temp_dir_.GetPath(), &mock_drivefs_); + + DCHECK_CALLED_ON_VALID_SEQUENCE(manager.sequence_checker_); + manager.progress_.pinned_bytes = 5000; + manager.progress_.bytes_to_pin = 10000; + manager.progress_.required_space = 20480; + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 5000); + EXPECT_EQ(progress.bytes_to_pin, 10000); + EXPECT_EQ(progress.required_space, 20480); + } + + const DriveFsPinManager::StableId id1 = DriveFsPinManager::StableId(549); + const std::string path1 = "Path 1"; + + const DriveFsPinManager::StableId id2 = DriveFsPinManager::StableId(17); + const std::string path2 = "Path 2"; + + // Put in place a file to track. + { + const auto [it, ok] = manager.files_to_track_.try_emplace( + id1, DriveFsPinManager::Progress{.path = path1, + .transferred = 1200, + .total = 3000, + .in_progress = true}); + ASSERT_TRUE(ok); + } + + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + // Try to remove an unknown file. + EXPECT_FALSE(manager.Remove(id2, path2)); + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + { + const auto it = manager.files_to_track_.find(id1); + ASSERT_NE(it, manager.files_to_track_.end()); + const auto& [got_id, progress] = *it; + EXPECT_EQ(got_id, id1); + EXPECT_EQ(progress.path, path1); + EXPECT_EQ(progress.total, 3000); + EXPECT_EQ(progress.transferred, 1200); + EXPECT_TRUE(progress.in_progress); + } + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 5000); + EXPECT_EQ(progress.bytes_to_pin, 10000); + EXPECT_EQ(progress.required_space, 20480); + } + + // Remove file with default final size. + EXPECT_TRUE(manager.Remove(id1, path2)); + EXPECT_THAT(manager.files_to_track_, IsEmpty()); + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 6800); + EXPECT_EQ(progress.bytes_to_pin, 10000); + EXPECT_EQ(progress.required_space, 20480); + } + + // Put in place a file to track. + { + const auto [it, ok] = manager.files_to_track_.try_emplace( + id1, DriveFsPinManager::Progress{.path = path1, + .transferred = 1200, + .total = 3000, + .in_progress = true}); + ASSERT_TRUE(ok); + } + + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + // Remove file while setting size to zero. + EXPECT_TRUE(manager.Remove(id1, path2, 0)); + EXPECT_THAT(manager.files_to_track_, IsEmpty()); + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 5600); + EXPECT_EQ(progress.bytes_to_pin, 7000); + EXPECT_EQ(progress.required_space, 16384); + } + + // Put in place a file to track. + { + const auto [it, ok] = manager.files_to_track_.try_emplace( + id1, DriveFsPinManager::Progress{.path = path1, + .transferred = 5000, + .total = 6000, + .in_progress = true}); + ASSERT_TRUE(ok); + } + + EXPECT_THAT(manager.files_to_track_, SizeIs(1)); + + // Remove file while setting size to a different value that the expected one. + EXPECT_TRUE(manager.Remove(id1, path1, 10000)); + EXPECT_THAT(manager.files_to_track_, IsEmpty()); + + { + const SetupProgress progress = manager.GetProgress(); + EXPECT_EQ(progress.pinned_files, 0); + EXPECT_EQ(progress.pinned_bytes, 10600); + EXPECT_EQ(progress.bytes_to_pin, 11000); + EXPECT_EQ(progress.required_space, 20480); + } +} + TEST_F(DriveFsPinManagerTest, CannotGetFreeSpace) { base::MockOnceCallback<void(SetupStage)> mock_callback;
diff --git a/chromeos/ash/components/network/cellular_esim_profile_handler_impl.cc b/chromeos/ash/components/network/cellular_esim_profile_handler_impl.cc index e5b2173..2064160 100644 --- a/chromeos/ash/components/network/cellular_esim_profile_handler_impl.cc +++ b/chromeos/ash/components/network/cellular_esim_profile_handler_impl.cc
@@ -229,14 +229,14 @@ GetAutoRefreshedEuiccPathsFromPrefs(); // Keep all paths which were already in prefs. - base::Value euicc_paths(base::Value::Type::LIST); + base::Value::List euicc_paths; for (const auto& path : auto_refreshed_euicc_paths) euicc_paths.Append(path); // Add new path. euicc_paths.Append(new_path); - device_prefs_->Set(prefs::kESimRefreshedEuiccs, std::move(euicc_paths)); + device_prefs_->SetList(prefs::kESimRefreshedEuiccs, std::move(euicc_paths)); } void CellularESimProfileHandlerImpl::UpdateProfilesFromHermes() { @@ -273,12 +273,12 @@ ss << "New set of eSIM profiles have been fetched from Hermes: "; // Store the updated list of profiles in prefs. - base::Value list(base::Value::Type::LIST); + base::Value::List list; for (const auto& profile : profiles_from_hermes) { list.Append(profile.ToDictionaryValue()); ss << "{iccid: " << profile.iccid() << ", eid: " << profile.eid() << "}, "; } - device_prefs_->Set(prefs::kESimProfiles, std::move(list)); + device_prefs_->SetList(prefs::kESimProfiles, std::move(list)); if (profiles_from_hermes.empty()) ss << "<empty>";
diff --git a/chromeos/ash/components/network/hotspot_controller_unittest.cc b/chromeos/ash/components/network/hotspot_controller_unittest.cc index 2d2c104..ad8d453 100644 --- a/chromeos/ash/components/network/hotspot_controller_unittest.cc +++ b/chromeos/ash/components/network/hotspot_controller_unittest.cc
@@ -47,24 +47,25 @@ } void SetValidTetheringCapabilities() { - base::Value capabilities_dict(base::Value::Type::DICTIONARY); - base::Value upstream_list(base::Value::Type::LIST); - upstream_list.Append(base::Value(shill::kTypeCellular)); - capabilities_dict.GetDict().Set(shill::kTetheringCapUpstreamProperty, - std::move(upstream_list)); + base::Value::Dict capabilities_dict; + base::Value::List upstream_list; + upstream_list.Append(shill::kTypeCellular); + capabilities_dict.Set(shill::kTetheringCapUpstreamProperty, + std::move(upstream_list)); // Add WiFi to the downstream technology list in Shill - base::Value downstream_list(base::Value::Type::LIST); - downstream_list.Append(base::Value(shill::kTypeWifi)); - capabilities_dict.GetDict().Set(shill::kTetheringCapDownstreamProperty, - std::move(downstream_list)); + base::Value::List downstream_list; + downstream_list.Append(shill::kTypeWifi); + capabilities_dict.Set(shill::kTetheringCapDownstreamProperty, + std::move(downstream_list)); // Add allowed WiFi security mode in Shill - base::Value security_list(base::Value::Type::LIST); - security_list.Append(base::Value(shill::kSecurityWpa2)); - security_list.Append(base::Value(shill::kSecurityWpa3)); - capabilities_dict.GetDict().Set(shill::kTetheringCapSecurityProperty, - std::move(security_list)); + base::Value::List security_list; + security_list.Append(shill::kSecurityWpa2); + security_list.Append(shill::kSecurityWpa3); + capabilities_dict.Set(shill::kTetheringCapSecurityProperty, + std::move(security_list)); network_state_test_helper_.manager_test()->SetManagerProperty( - shill::kTetheringCapabilitiesProperty, capabilities_dict); + shill::kTetheringCapabilitiesProperty, + base::Value(std::move(capabilities_dict))); base::RunLoop().RunUntilIdle(); }
diff --git a/chromeos/ash/components/network/hotspot_state_handler_unittest.cc b/chromeos/ash/components/network/hotspot_state_handler_unittest.cc index 7f33a0a..304ee4e 100644 --- a/chromeos/ash/components/network/hotspot_state_handler_unittest.cc +++ b/chromeos/ash/components/network/hotspot_state_handler_unittest.cc
@@ -193,14 +193,11 @@ EXPECT_EQ(1u, observer_.hotspot_status_changed_count()); // Update tethering status with one active client. - base::Value active_clients_list(base::Value::Type::LIST); - base::Value client(base::Value::Type::DICTIONARY); - client.GetDict().Set(shill::kTetheringStatusClientIPv4Property, - base::Value("IPV4:001")); - client.GetDict().Set(shill::kTetheringStatusClientHostnameProperty, - base::Value("hostname1")); - client.GetDict().Set(shill::kTetheringStatusClientMACProperty, - base::Value("persist")); + base::Value::List active_clients_list; + base::Value::Dict client; + client.Set(shill::kTetheringStatusClientIPv4Property, "IPV4:001"); + client.Set(shill::kTetheringStatusClientHostnameProperty, "hostname1"); + client.Set(shill::kTetheringStatusClientMACProperty, "persist"); active_clients_list.Append(std::move(client)); status_dict.GetDict().Set(shill::kTetheringStatusClientsProperty, std::move(active_clients_list)); @@ -244,8 +241,8 @@ hotspot_state_handler_->GetHotspotCapabilities().allow_status); EXPECT_EQ(0u, observer_.hotspot_capabilities_changed_count()); - base::Value upstream_list(base::Value::Type::LIST); - upstream_list.Append(base::Value(shill::kTypeCellular)); + base::Value::List upstream_list; + upstream_list.Append(shill::kTypeCellular); capabilities_dict.GetDict().Set(shill::kTetheringCapUpstreamProperty, std::move(upstream_list)); network_state_test_helper_.manager_test()->SetManagerProperty( @@ -258,14 +255,14 @@ EXPECT_EQ(1u, observer_.hotspot_capabilities_changed_count()); // Add WiFi to the downstream technology list in Shill - base::Value downstream_list(base::Value::Type::LIST); - downstream_list.Append(base::Value(shill::kTypeWifi)); + base::Value::List downstream_list; + downstream_list.Append(shill::kTypeWifi); capabilities_dict.GetDict().Set(shill::kTetheringCapDownstreamProperty, std::move(downstream_list)); // Add allowed WiFi security mode in Shill - base::Value security_list(base::Value::Type::LIST); - security_list.Append(base::Value(shill::kSecurityWpa2)); - security_list.Append(base::Value(shill::kSecurityWpa3)); + base::Value::List security_list; + security_list.Append(shill::kSecurityWpa2); + security_list.Append(shill::kSecurityWpa3); capabilities_dict.GetDict().Set(shill::kTetheringCapSecurityProperty, std::move(security_list)); network_state_test_helper_.manager_test()->SetManagerProperty(
diff --git a/chromeos/ash/components/network/managed_network_configuration_handler_impl.cc b/chromeos/ash/components/network/managed_network_configuration_handler_impl.cc index 3742533..8145de1f 100644 --- a/chromeos/ash/components/network/managed_network_configuration_handler_impl.cc +++ b/chromeos/ash/components/network/managed_network_configuration_handler_impl.cc
@@ -1100,6 +1100,7 @@ } if (!network->IsConnectedState()) return; // No (non saved) IP Configs for non connected networks. + base::Value::Dict& properties_dict = properties->GetDict(); const DeviceState* device_state = network->device_path().empty() @@ -1108,15 +1109,14 @@ // Get the hardware MAC address from the DeviceState. if (device_state && !device_state->mac_address().empty()) { - properties->SetKey(shill::kAddressProperty, - base::Value(device_state->mac_address())); + properties_dict.Set(shill::kAddressProperty, device_state->mac_address()); } // Get the IPConfig properties from the device and store them in "IPConfigs" // (plural) in the properties dictionary. (Note: Shill only provides a single // "IPConfig" property for a network service, but a consumer of this API may // want information about all ipv4 and ipv6 IPConfig properties. - base::Value ip_configs(base::Value::Type::LIST); + base::Value::List ip_configs; if (!device_state || device_state->ip_configs().empty()) { // Shill may not provide IPConfigs for external Cellular devices/dongles @@ -1133,8 +1133,8 @@ for (const auto iter : device_state->ip_configs()) ip_configs.Append(iter.second.Clone()); } - if (!ip_configs.GetList().empty()) { - properties->SetKey(shill::kIPConfigsProperty, std::move(ip_configs)); + if (!ip_configs.empty()) { + properties_dict.Set(shill::kIPConfigsProperty, std::move(ip_configs)); } }
diff --git a/chromeos/ash/components/network/managed_network_configuration_handler_unittest.cc b/chromeos/ash/components/network/managed_network_configuration_handler_unittest.cc index e4c13b36..647ecaf 100644 --- a/chromeos/ash/components/network/managed_network_configuration_handler_unittest.cc +++ b/chromeos/ash/components/network/managed_network_configuration_handler_unittest.cc
@@ -304,25 +304,29 @@ return; } ASSERT_TRUE(validated_policy.is_dict()); + const base::Value::Dict& validated_policy_dict = validated_policy.GetDict(); - base::Value network_configs(base::Value::Type::LIST); - const base::Value* found_network_configs = validated_policy.FindListKey( - ::onc::toplevel_config::kNetworkConfigurations); + base::Value::List network_configs; + const base::Value::List* found_network_configs = + validated_policy_dict.FindList( + ::onc::toplevel_config::kNetworkConfigurations); if (found_network_configs) { - for (const auto& network_config : found_network_configs->GetList()) { + for (const auto& network_config : *found_network_configs) { network_configs.Append(network_config.Clone()); } } - base::Value global_config(base::Value::Type::DICTIONARY); - const base::Value* found_global_config = validated_policy.FindDictKey( - ::onc::toplevel_config::kGlobalNetworkConfiguration); + base::Value::Dict global_config; + const base::Value::Dict* found_global_config = + validated_policy_dict.FindDict( + ::onc::toplevel_config::kGlobalNetworkConfiguration); if (found_global_config) { global_config = found_global_config->Clone(); } managed_network_configuration_handler_->SetPolicy( - onc_source, userhash, network_configs, global_config); + onc_source, userhash, base::Value(std::move(network_configs)), + base::Value(std::move(global_config))); } void SetUpEntry(const std::string& path_to_shill_json,
diff --git a/chromeos/ash/components/network/network_device_handler_unittest.cc b/chromeos/ash/components/network/network_device_handler_unittest.cc index 0d2b140f..d2175d15 100644 --- a/chromeos/ash/components/network/network_device_handler_unittest.cc +++ b/chromeos/ash/components/network/network_device_handler_unittest.cc
@@ -71,10 +71,11 @@ "cellular1"); device_test->AddDevice(kDefaultWifiDevicePath, shill::kTypeWifi, "wifi1"); - base::Value test_ip_configs(base::Value::Type::LIST); + base::Value::List test_ip_configs; test_ip_configs.Append("ip_config1"); device_test->SetDeviceProperty(kDefaultWifiDevicePath, - shill::kIPConfigsProperty, test_ip_configs, + shill::kIPConfigsProperty, + base::Value(std::move(test_ip_configs)), /*notify_changed=*/true); base::RunLoop().RunUntilIdle();
diff --git a/chromeos/ash/components/network/network_state_handler_unittest.cc b/chromeos/ash/components/network/network_state_handler_unittest.cc index 269a229..fd058ad4 100644 --- a/chromeos/ash/components/network/network_state_handler_unittest.cc +++ b/chromeos/ash/components/network/network_state_handler_unittest.cc
@@ -2274,12 +2274,12 @@ ShillIPConfigClient::TestInterface* ip_config_test = ShillIPConfigClient::Get()->GetTestInterface(); const std::string kIPConfigPath = "test_ip_config"; - base::Value ip_config_properties(base::Value::Type::DICTIONARY); - ip_config_test->AddIPConfig(kIPConfigPath, ip_config_properties); - base::Value device_ip_configs(base::Value::Type::LIST); + ip_config_test->AddIPConfig(kIPConfigPath, base::Value::Dict()); + base::Value::List device_ip_configs; device_ip_configs.Append(kIPConfigPath); device_test_->SetDeviceProperty(kShillManagerClientStubWifiDevice, - shill::kIPConfigsProperty, device_ip_configs, + shill::kIPConfigsProperty, + base::Value(std::move(device_ip_configs)), /*notify_changed=*/true); service_test_->SetServiceProperty(kShillManagerClientStubDefaultWifi, shill::kIPConfigProperty,
diff --git a/chromeos/ash/components/network/network_test_helper_base.cc b/chromeos/ash/components/network/network_test_helper_base.cc index d4e0c04..d94ffdc4 100644 --- a/chromeos/ash/components/network/network_test_helper_base.cc +++ b/chromeos/ash/components/network/network_test_helper_base.cc
@@ -70,11 +70,11 @@ // Set initial IPConfigs for the wifi device. The IPConfigs are set up in // FakeShillManagerClient::SetupDefaultEnvironment() and do not get cleared. - base::Value ip_configs(base::Value::Type::LIST); + base::Value::List ip_configs; ip_configs.Append("ipconfig_v4_path"); ip_configs.Append("ipconfig_v6_path"); device_test_->SetDeviceProperty(kDevicePath, shill::kIPConfigsProperty, - ip_configs, + base::Value(std::move(ip_configs)), /*notify_changed=*/false); base::RunLoop().RunUntilIdle(); }
diff --git a/chromeos/ash/components/network/onc/network_onc_utils.cc b/chromeos/ash/components/network/onc/network_onc_utils.cc index 4933a18..e60970a7 100644 --- a/chromeos/ash/components/network/onc/network_onc_utils.cc +++ b/chromeos/ash/components/network/onc/network_onc_utils.cc
@@ -167,8 +167,7 @@ void SetProxyForScheme(const net::ProxyConfig::ProxyRules& proxy_rules, const std::string& scheme, const std::string& onc_scheme, - base::Value* dict) { - DCHECK(dict->is_dict()); + base::Value::Dict& dict) { const net::ProxyList* proxy_list = nullptr; if (proxy_rules.type == net::ProxyConfig::ProxyRules::Type::PROXY_LIST) { proxy_list = &proxy_rules.single_proxies; @@ -189,11 +188,10 @@ // Only prefix the host with a non-default scheme. if (server.scheme() != default_scheme) host = SchemeToString(server.scheme()) + "://" + host; - base::Value url_dict(base::Value::Type::DICTIONARY); - url_dict.SetKey(::onc::proxy::kHost, base::Value(host)); - url_dict.SetKey(::onc::proxy::kPort, - base::Value(server.host_port_pair().port())); - dict->SetKey(onc_scheme, std::move(url_dict)); + base::Value::Dict url_dict; + url_dict.Set(::onc::proxy::kHost, host); + url_dict.Set(::onc::proxy::kPort, server.host_port_pair().port()); + dict.Set(onc_scheme, std::move(url_dict)); } // Returns the NetworkConfiugration with |guid| from |network_configs|, or @@ -419,59 +417,55 @@ ProxyConfigDictionary proxy_config(proxy_config_value.GetDict().Clone()); // Create the result Value and populate it. - base::Value proxy_settings(base::Value::Type::DICTIONARY); + base::Value::Dict proxy_settings; ProxyPrefs::ProxyMode mode; if (!proxy_config.GetMode(&mode)) return base::Value(); switch (mode) { case ProxyPrefs::MODE_DIRECT: { - proxy_settings.SetKey(::onc::proxy::kType, - base::Value(::onc::proxy::kDirect)); + proxy_settings.Set(::onc::proxy::kType, ::onc::proxy::kDirect); break; } case ProxyPrefs::MODE_AUTO_DETECT: { - proxy_settings.SetKey(::onc::proxy::kType, - base::Value(::onc::proxy::kWPAD)); + proxy_settings.Set(::onc::proxy::kType, ::onc::proxy::kWPAD); break; } case ProxyPrefs::MODE_PAC_SCRIPT: { - proxy_settings.SetKey(::onc::proxy::kType, - base::Value(::onc::proxy::kPAC)); + proxy_settings.Set(::onc::proxy::kType, ::onc::proxy::kPAC); std::string pac_url; proxy_config.GetPacUrl(&pac_url); - proxy_settings.SetKey(::onc::proxy::kPAC, base::Value(pac_url)); + proxy_settings.Set(::onc::proxy::kPAC, pac_url); break; } case ProxyPrefs::MODE_FIXED_SERVERS: { - proxy_settings.SetKey(::onc::proxy::kType, - base::Value(::onc::proxy::kManual)); - base::Value manual(base::Value::Type::DICTIONARY); + proxy_settings.Set(::onc::proxy::kType, ::onc::proxy::kManual); + base::Value::Dict manual; std::string proxy_rules_string; if (proxy_config.GetProxyServer(&proxy_rules_string)) { net::ProxyConfig::ProxyRules proxy_rules; proxy_rules.ParseFromString(proxy_rules_string); SetProxyForScheme(proxy_rules, url::kFtpScheme, ::onc::proxy::kFtp, - &manual); + manual); SetProxyForScheme(proxy_rules, url::kHttpScheme, ::onc::proxy::kHttp, - &manual); + manual); SetProxyForScheme(proxy_rules, url::kHttpsScheme, ::onc::proxy::kHttps, - &manual); + manual); SetProxyForScheme(proxy_rules, kSocksScheme, ::onc::proxy::kSocks, - &manual); + manual); } - proxy_settings.SetKey(::onc::proxy::kManual, std::move(manual)); + proxy_settings.Set(::onc::proxy::kManual, std::move(manual)); // Convert the 'bypass_list' string into dictionary entries. std::string bypass_rules_string; if (proxy_config.GetBypassList(&bypass_rules_string)) { net::ProxyBypassRules bypass_rules; bypass_rules.ParseFromString(bypass_rules_string); - base::Value exclude_domains(base::Value::Type::LIST); + base::Value::List exclude_domains; for (const auto& rule : bypass_rules.rules()) exclude_domains.Append(rule->ToString()); - if (!exclude_domains.GetList().empty()) { - proxy_settings.SetKey(::onc::proxy::kExcludeDomains, - std::move(exclude_domains)); + if (!exclude_domains.empty()) { + proxy_settings.Set(::onc::proxy::kExcludeDomains, + std::move(exclude_domains)); } } break; @@ -481,7 +475,7 @@ return base::Value(); } } - return proxy_settings; + return base::Value(std::move(proxy_settings)); } base::flat_map<std::string, std::string> GetVariableExpansionsForUser(
diff --git a/chromeos/ash/components/network/onc/network_onc_utils_unittest.cc b/chromeos/ash/components/network/onc/network_onc_utils_unittest.cc index c050bf8..0a383c1f 100644 --- a/chromeos/ash/components/network/onc/network_onc_utils_unittest.cc +++ b/chromeos/ash/components/network/onc/network_onc_utils_unittest.cc
@@ -33,7 +33,7 @@ test_utils::ReadTestJson("proxy_config_from_onc.json"); ASSERT_TRUE(additional_tests.is_list()); for (const base::Value& value : additional_tests.GetList()) - list_of_tests.Append(value.Clone()); + list_of_tests.GetList().Append(value.Clone()); int index = 0; for (const base::Value& test_case : list_of_tests.GetList()) {
diff --git a/chromeos/ash/components/network/profile_policies_unittest.cc b/chromeos/ash/components/network/profile_policies_unittest.cc index 51e1290..4de5b370 100644 --- a/chromeos/ash/components/network/profile_policies_unittest.cc +++ b/chromeos/ash/components/network/profile_policies_unittest.cc
@@ -28,11 +28,11 @@ // list. base::Value NetworkConfigsList( std::initializer_list<const base::Value*> network_configs) { - base::Value result(base::Value::Type::LIST); + base::Value::List result; for (const auto* network_config : network_configs) { result.Append(network_config->Clone()); } - return result; + return base::Value(std::move(result)); } // Creates a very basic for-testing NetworkConfig, essentially
diff --git a/chromeos/ash/components/network/prohibited_technologies_handler_unittest.cc b/chromeos/ash/components/network/prohibited_technologies_handler_unittest.cc index 53e9f49..3935d3a 100644 --- a/chromeos/ash/components/network/prohibited_technologies_handler_unittest.cc +++ b/chromeos/ash/components/network/prohibited_technologies_handler_unittest.cc
@@ -70,16 +70,16 @@ void PreparePolicies() { { - base::Value val(base::Value::Type::LIST); + base::Value::List val; val.Append("WiFi"); - global_config_disable_wifi.SetKey("DisableNetworkTypes", std::move(val)); + global_config_disable_wifi.Set("DisableNetworkTypes", std::move(val)); } { - base::Value val(base::Value::Type::LIST); + base::Value::List val; val.Append("WiFi"); val.Append("Cellular"); - global_config_disable_wifi_and_cell.SetKey("DisableNetworkTypes", - std::move(val)); + global_config_disable_wifi_and_cell.Set("DisableNetworkTypes", + std::move(val)); } } @@ -98,16 +98,17 @@ base::RunLoop().RunUntilIdle(); } - void SetupPolicy(const base::Value& global_config, bool user_policy) { + void SetupPolicy(const base::Value::Dict& global_config, bool user_policy) { if (user_policy) { - managed_config_handler_->SetPolicy( - ::onc::ONC_SOURCE_USER_POLICY, helper_.UserHash(), - base::Value(base::Value::Type::LIST), global_config); + managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_USER_POLICY, + helper_.UserHash(), + base::Value(base::Value::Type::LIST), + base::Value(global_config.Clone())); } else { managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, std::string(), // no username hash base::Value(base::Value::Type::LIST), - global_config); + base::Value(global_config.Clone())); } base::RunLoop().RunUntilIdle(); } @@ -116,9 +117,8 @@ return helper_.network_state_handler(); } - base::Value global_config_disable_wifi{base::Value::Type::DICTIONARY}; - base::Value global_config_disable_wifi_and_cell{ - base::Value::Type::DICTIONARY}; + base::Value::Dict global_config_disable_wifi; + base::Value::Dict global_config_disable_wifi_and_cell; std::unique_ptr<ProhibitedTechnologiesHandler> prohibited_technologies_handler_; @@ -159,7 +159,7 @@ EXPECT_TRUE(network_state_handler()->IsTechnologyEnabled( NetworkTypePattern::Cellular())); - SetupPolicy(base::Value(base::Value::Type::DICTIONARY), + SetupPolicy(base::Value::Dict(), true); // wait for user policy // Should be disabled after logged in @@ -195,7 +195,7 @@ TEST_F(ProhibitedTechnologiesHandlerTest, IsGloballyProhibitedTechnologyWorksAfterReenabling) { LoginToRegularUser(); - SetupPolicy(base::Value(base::Value::Type::DICTIONARY), + SetupPolicy(base::Value::Dict(), true); // wait for user policy EXPECT_TRUE( @@ -223,7 +223,7 @@ NetworkTypePattern::Cellular())); LoginToRegularUser(); - SetupPolicy(base::Value(base::Value::Type::DICTIONARY), + SetupPolicy(base::Value::Dict(), true); // receive user policy // Cellular should be prohibited EXPECT_FALSE(network_state_handler()->IsTechnologyEnabled(
diff --git a/chromeos/ash/components/network/shill_property_handler_unittest.cc b/chromeos/ash/components/network/shill_property_handler_unittest.cc index 87d5261..2e89a4cd 100644 --- a/chromeos/ash/components/network/shill_property_handler_unittest.cc +++ b/chromeos/ash/components/network/shill_property_handler_unittest.cc
@@ -489,12 +489,12 @@ ShillIPConfigClient::Get()->SetProperty(dbus::ObjectPath(kTestIPConfigPath), shill::kAddressProperty, ip_address, base::DoNothing()); - base::Value dns_servers(base::Value::Type::LIST); + base::Value::List dns_servers; dns_servers.Append("192.168.1.100"); dns_servers.Append("192.168.1.101"); - ShillIPConfigClient::Get()->SetProperty(dbus::ObjectPath(kTestIPConfigPath), - shill::kNameServersProperty, - dns_servers, base::DoNothing()); + ShillIPConfigClient::Get()->SetProperty( + dbus::ObjectPath(kTestIPConfigPath), shill::kNameServersProperty, + base::Value(std::move(dns_servers)), base::DoNothing()); base::Value prefixlen(8); ShillIPConfigClient::Get()->SetProperty(dbus::ObjectPath(kTestIPConfigPath), shill::kPrefixlenProperty, prefixlen,
diff --git a/chromeos/ash/services/device_sync/cryptauth_device_manager_impl.cc b/chromeos/ash/services/device_sync/cryptauth_device_manager_impl.cc index 57c2aa47..0256bf5 100644 --- a/chromeos/ash/services/device_sync/cryptauth_device_manager_impl.cc +++ b/chromeos/ash/services/device_sync/cryptauth_device_manager_impl.cc
@@ -71,9 +71,9 @@ const char kDictionaryKeySoftwareFeatures[] = "software_features"; // Converts BeaconSeed protos to a list value that can be stored in user prefs. -base::Value BeaconSeedsToListValue( +base::Value::List BeaconSeedsToListValue( const google::protobuf::RepeatedPtrField<cryptauth::BeaconSeed>& seeds) { - base::Value list(base::Value::Type::LIST); + base::Value::List list; for (int i = 0; i < seeds.size(); i++) { cryptauth::BeaconSeed seed = seeds.Get(i); @@ -85,7 +85,7 @@ continue; } - base::Value beacon_seed_value(base::Value::Type::DICTIONARY); + base::Value::Dict beacon_seed_value; // Note that the |BeaconSeed|s' data is stored in Base64Url encoding because // dictionary values must be valid UTF8 strings. @@ -93,15 +93,14 @@ base::Base64UrlEncode(seed.data(), base::Base64UrlEncodePolicy::INCLUDE_PADDING, &seed_data_b64); - beacon_seed_value.SetStringKey(kExternalDeviceKeyBeaconSeedData, - seed_data_b64); + beacon_seed_value.Set(kExternalDeviceKeyBeaconSeedData, seed_data_b64); // Set the timestamps as string representations of their numeric value // since there is no notion of a base::LongValue. - beacon_seed_value.SetStringKey(kExternalDeviceKeyBeaconSeedStartMs, - std::to_string(seed.start_time_millis())); - beacon_seed_value.SetStringKey(kExternalDeviceKeyBeaconSeedEndMs, - std::to_string(seed.end_time_millis())); + beacon_seed_value.Set(kExternalDeviceKeyBeaconSeedStartMs, + std::to_string(seed.start_time_millis())); + beacon_seed_value.Set(kExternalDeviceKeyBeaconSeedEndMs, + std::to_string(seed.end_time_millis())); list.Append(std::move(beacon_seed_value)); } @@ -126,17 +125,17 @@ // Converts supported and enabled SoftwareFeature protos to a single dictionary // value that can be stored in user prefs. -base::Value SupportedAndEnabledSoftwareFeaturesToDictionaryValue( +base::Value::Dict SupportedAndEnabledSoftwareFeaturesToDictionaryValue( const google::protobuf::RepeatedPtrField<std::string>& supported_software_features, const google::protobuf::RepeatedPtrField<std::string>& enabled_software_features, bool legacy_unlock_key, bool legacy_mobile_hotspot_supported) { - base::Value dictionary(base::Value::Type::DICTIONARY); + base::Value::Dict dictionary; for (const auto& supported_software_feature : supported_software_features) { - dictionary.SetIntKey( + dictionary.Set( supported_software_feature, static_cast<int>(multidevice::SoftwareFeatureState::kSupported)); } @@ -147,7 +146,7 @@ SoftwareFeatureStringToEnum(software_feature_key); absl::optional<int> software_feature_state = - dictionary.FindIntKey(software_feature_key); + dictionary.FindInt(software_feature_key); bool software_feature_success_result = true; if (!software_feature_state || static_cast<multidevice::SoftwareFeatureState>( @@ -169,7 +168,7 @@ RecordDeviceSyncSoftwareFeaturesResult( software_feature_success_result /* success */, software_feature); - dictionary.SetIntKey( + dictionary.Set( software_feature_key, static_cast<int>(multidevice::SoftwareFeatureState::kEnabled)); } @@ -180,16 +179,16 @@ // software features, and only serving the deprecated booleans. std::string software_feature_key = SoftwareFeatureEnumToString(cryptauth::SoftwareFeature::EASY_UNLOCK_HOST); - if (legacy_unlock_key && !dictionary.FindIntKey(software_feature_key)) { - dictionary.SetIntKey( + if (legacy_unlock_key && !dictionary.FindInt(software_feature_key)) { + dictionary.Set( software_feature_key, static_cast<int>(multidevice::SoftwareFeatureState::kEnabled)); } software_feature_key = SoftwareFeatureEnumToString( cryptauth::SoftwareFeature::MAGIC_TETHER_HOST); if (legacy_mobile_hotspot_supported && - !dictionary.FindIntKey(software_feature_key)) { - dictionary.SetIntKey( + !dictionary.FindInt(software_feature_key)) { + dictionary.Set( software_feature_key, static_cast<int>(multidevice::SoftwareFeatureState::kSupported)); } @@ -199,8 +198,9 @@ // Converts an unlock key proto to a dictionary that can be stored in user // prefs. -base::Value UnlockKeyToDictionary(const cryptauth::ExternalDeviceInfo& device) { - base::Value dictionary{base::Value::Type::DICTIONARY}; +base::Value::Dict UnlockKeyToDictionary( + const cryptauth::ExternalDeviceInfo& device) { + base::Value::Dict dictionary; // The device public key is a required value. if (!device.has_public_key()) @@ -213,14 +213,14 @@ base::Base64UrlEncode(device.public_key(), base::Base64UrlEncodePolicy::INCLUDE_PADDING, &public_key_b64); - dictionary.SetStringKey(kExternalDeviceKeyPublicKey, public_key_b64); + dictionary.Set(kExternalDeviceKeyPublicKey, public_key_b64); if (device.has_friendly_device_name()) { std::string device_name_b64; base::Base64UrlEncode(device.friendly_device_name(), base::Base64UrlEncodePolicy::INCLUDE_PADDING, &device_name_b64); - dictionary.SetStringKey(kExternalDeviceKeyDeviceName, device_name_b64); + dictionary.Set(kExternalDeviceKeyDeviceName, device_name_b64); } if (device.has_bluetooth_address()) { @@ -228,36 +228,34 @@ base::Base64UrlEncode(device.bluetooth_address(), base::Base64UrlEncodePolicy::INCLUDE_PADDING, &bluetooth_address_b64); - dictionary.SetStringKey(kExternalDeviceKeyBluetoothAddress, - bluetooth_address_b64); + dictionary.Set(kExternalDeviceKeyBluetoothAddress, bluetooth_address_b64); } if (device.has_unlockable()) { - dictionary.SetBoolKey(kExternalDeviceKeyUnlockable, device.unlockable()); + dictionary.Set(kExternalDeviceKeyUnlockable, device.unlockable()); } if (device.has_last_update_time_millis()) { - dictionary.SetStringKey(kExternalDeviceKeyLastUpdateTimeMillis, - std::to_string(device.last_update_time_millis())); + dictionary.Set(kExternalDeviceKeyLastUpdateTimeMillis, + std::to_string(device.last_update_time_millis())); } if (device.has_device_type() && cryptauth::DeviceType_IsValid( DeviceTypeStringToEnum(device.device_type()))) { - dictionary.SetIntKey(kExternalDeviceKeyDeviceType, - DeviceTypeStringToEnum(device.device_type())); + dictionary.Set(kExternalDeviceKeyDeviceType, + DeviceTypeStringToEnum(device.device_type())); } - dictionary.SetKey(kExternalDeviceKeyBeaconSeeds, - BeaconSeedsToListValue(device.beacon_seeds())); + dictionary.Set(kExternalDeviceKeyBeaconSeeds, + BeaconSeedsToListValue(device.beacon_seeds())); if (device.has_arc_plus_plus()) { - dictionary.SetBoolKey(kExternalDeviceKeyArcPlusPlus, - device.arc_plus_plus()); + dictionary.Set(kExternalDeviceKeyArcPlusPlus, device.arc_plus_plus()); } if (device.has_pixel_phone()) { - dictionary.SetBoolKey(kExternalDeviceKeyPixelPhone, device.pixel_phone()); + dictionary.Set(kExternalDeviceKeyPixelPhone, device.pixel_phone()); } if (device.has_no_pii_device_name()) { @@ -265,8 +263,7 @@ base::Base64UrlEncode(device.no_pii_device_name(), base::Base64UrlEncodePolicy::INCLUDE_PADDING, &no_pii_device_name_b64); - dictionary.SetStringKey(kExternalDeviceKeyNoPiiDeviceName, - no_pii_device_name_b64); + dictionary.Set(kExternalDeviceKeyNoPiiDeviceName, no_pii_device_name_b64); } // In the case that the CryptAuth server is not yet serving SoftwareFeatures, @@ -277,11 +274,11 @@ bool legacy_mobile_hotspot_supported = device.has_mobile_hotspot_supported() && device.mobile_hotspot_supported(); - dictionary.SetKey(kDictionaryKeySoftwareFeatures, - SupportedAndEnabledSoftwareFeaturesToDictionaryValue( - device.supported_software_features(), - device.enabled_software_features(), legacy_unlock_key, - legacy_mobile_hotspot_supported)); + dictionary.Set(kDictionaryKeySoftwareFeatures, + SupportedAndEnabledSoftwareFeaturesToDictionaryValue( + device.supported_software_features(), + device.enabled_software_features(), legacy_unlock_key, + legacy_mobile_hotspot_supported)); return dictionary; } @@ -289,19 +286,20 @@ void AddBeaconSeedsToExternalDevice( const base::Value::List& beacon_seeds, cryptauth::ExternalDeviceInfo* external_device) { - for (const base::Value& seed_dictionary : beacon_seeds) { - if (!seed_dictionary.is_dict()) { + for (const base::Value& seed_dictionary_value : beacon_seeds) { + if (!seed_dictionary_value.is_dict()) { PA_LOG(WARNING) << "Unable to retrieve BeaconSeed dictionary; " << "skipping."; continue; } + const base::Value::Dict& seed_dictionary = seed_dictionary_value.GetDict(); const std::string* seed_data_b64 = - seed_dictionary.FindStringKey(kExternalDeviceKeyBeaconSeedData); + seed_dictionary.FindString(kExternalDeviceKeyBeaconSeedData); const std::string* start_time_millis_str = - seed_dictionary.FindStringKey(kExternalDeviceKeyBeaconSeedStartMs); + seed_dictionary.FindString(kExternalDeviceKeyBeaconSeedStartMs); const std::string* end_time_millis_str = - seed_dictionary.FindStringKey(kExternalDeviceKeyBeaconSeedEndMs); + seed_dictionary.FindString(kExternalDeviceKeyBeaconSeedEndMs); if (!seed_data_b64 || !start_time_millis_str || !end_time_millis_str) { PA_LOG(WARNING) << "Unable to deserialize BeaconSeed due to missing " @@ -694,7 +692,7 @@ } for (const auto& device : response.devices()) { - base::Value device_dictionary = UnlockKeyToDictionary(device); + base::Value::Dict device_dictionary = UnlockKeyToDictionary(device); const std::string& device_name = device.has_friendly_device_name() ? device.friendly_device_name()
diff --git a/chromeos/ash/services/hotspot_config/cros_hotspot_config_unittest.cc b/chromeos/ash/services/hotspot_config/cros_hotspot_config_unittest.cc index 6b489a33..0bad3be 100644 --- a/chromeos/ash/services/hotspot_config/cros_hotspot_config_unittest.cc +++ b/chromeos/ash/services/hotspot_config/cros_hotspot_config_unittest.cc
@@ -76,24 +76,25 @@ } void SetValidHotspotCapabilities() { - base::Value capabilities_dict(base::Value::Type::DICTIONARY); - base::Value upstream_list(base::Value::Type::LIST); - upstream_list.Append(base::Value(shill::kTypeCellular)); - capabilities_dict.GetDict().Set(shill::kTetheringCapUpstreamProperty, - std::move(upstream_list)); + base::Value::Dict capabilities_dict; + base::Value::List upstream_list; + upstream_list.Append(shill::kTypeCellular); + capabilities_dict.Set(shill::kTetheringCapUpstreamProperty, + std::move(upstream_list)); // Add WiFi to the downstream technology list in Shill - base::Value downstream_list(base::Value::Type::LIST); - downstream_list.Append(base::Value(shill::kTypeWifi)); - capabilities_dict.GetDict().Set(shill::kTetheringCapDownstreamProperty, - std::move(downstream_list)); + base::Value::List downstream_list; + downstream_list.Append(shill::kTypeWifi); + capabilities_dict.Set(shill::kTetheringCapDownstreamProperty, + std::move(downstream_list)); // Add allowed WiFi security mode in Shill - base::Value security_list(base::Value::Type::LIST); - security_list.Append(base::Value(shill::kSecurityWpa2)); - security_list.Append(base::Value(shill::kSecurityWpa3)); - capabilities_dict.GetDict().Set(shill::kTetheringCapSecurityProperty, - std::move(security_list)); + base::Value::List security_list; + security_list.Append(shill::kSecurityWpa2); + security_list.Append(shill::kSecurityWpa3); + capabilities_dict.Set(shill::kTetheringCapSecurityProperty, + std::move(security_list)); network_handler_test_helper_->manager_test()->SetManagerProperty( - shill::kTetheringCapabilitiesProperty, capabilities_dict); + shill::kTetheringCapabilitiesProperty, + base::Value(std::move(capabilities_dict))); base::RunLoop().RunUntilIdle(); } @@ -106,11 +107,10 @@ void SetHotspotStateInShill(const std::string& state) { // Update tethering status to active in Shill. - base::Value status_dict(base::Value::Type::DICTIONARY); - status_dict.GetDict().Set(shill::kTetheringStatusStateProperty, - base::Value(state)); + base::Value::Dict status_dict; + status_dict.Set(shill::kTetheringStatusStateProperty, state); network_handler_test_helper_->manager_test()->SetManagerProperty( - shill::kTetheringStatusProperty, status_dict); + shill::kTetheringStatusProperty, base::Value(std::move(status_dict))); base::RunLoop().RunUntilIdle(); }
diff --git a/chromeos/components/onc/onc_mapper.cc b/chromeos/components/onc/onc_mapper.cc index 8766787..12043301 100644 --- a/chromeos/components/onc/onc_mapper.cc +++ b/chromeos/components/onc/onc_mapper.cc
@@ -113,13 +113,15 @@ base::Value::List result_array; int original_index = 0; for (const auto& entry : onc_array) { + bool error = false; base::Value result_entry = MapEntry(original_index, *array_signature.onc_array_entry_signature, - entry, nested_error); - if (!result_entry.is_none()) + entry, &error); + if (!error) { result_array.Append(std::move(result_entry)); - else - DCHECK(*nested_error); + } + + *nested_error |= error; ++original_index; } return result_array;
diff --git a/chromeos/components/onc/onc_validator.cc b/chromeos/components/onc/onc_validator.cc index df63da7..776e7c8 100644 --- a/chromeos/components/onc/onc_validator.cc +++ b/chromeos/components/onc/onc_validator.cc
@@ -175,7 +175,7 @@ DCHECK(!validation_issues_.empty()); *error = true; - return {}; + return base::Value(base::Value::Type::DICT); } base::Value Validator::MapField(const std::string& field_name,
diff --git a/chromeos/components/onc/onc_validator.h b/chromeos/components/onc/onc_validator.h index 2391e06f..1699708d 100644 --- a/chromeos/components/onc/onc_validator.h +++ b/chromeos/components/onc/onc_validator.h
@@ -141,8 +141,7 @@ // Dispatch to the right validation function according to // |signature|. Iterates over all fields and recursively validates/repairs // these. All valid fields are added to the result dictionary. Returns the - // repaired dictionary. Only on error returns a Value of type - // base::Value::Type::NONE. + // repaired dictionary. base::Value MapObject(const OncValueSignature& signature, const base::Value& onc_object, bool* error) override;
diff --git a/chromeos/crosapi/mojom/web_app_types.mojom b/chromeos/crosapi/mojom/web_app_types.mojom index a54194a..55271d19 100644 --- a/chromeos/crosapi/mojom/web_app_types.mojom +++ b/chromeos/crosapi/mojom/web_app_types.mojom
@@ -38,6 +38,7 @@ [MinVersion=1] kAppNotInRegistrarAfterCommit, [MinVersion=2] kHaltedBySyncUninstall, [MinVersion=3] kInstallURLInvalid, + [MinVersion=4] kIconDownloadingFailed, }; // See |webapps::UninstallResultCode|.
diff --git a/chromeos/crosapi/mojom/web_app_types_mojom_traits.cc b/chromeos/crosapi/mojom/web_app_types_mojom_traits.cc index 2f6a19c..c1abc4b 100644 --- a/chromeos/crosapi/mojom/web_app_types_mojom_traits.cc +++ b/chromeos/crosapi/mojom/web_app_types_mojom_traits.cc
@@ -73,6 +73,8 @@ return crosapi::mojom::WebAppInstallResultCode::kHaltedBySyncUninstall; case webapps::InstallResultCode::kInstallURLInvalid: return crosapi::mojom::WebAppInstallResultCode::kInstallURLInvalid; + case webapps::InstallResultCode::kIconDownloadingFailed: + return crosapi::mojom::WebAppInstallResultCode::kIconDownloadingFailed; }; } @@ -162,6 +164,9 @@ case crosapi::mojom::WebAppInstallResultCode::kInstallURLInvalid: *output = webapps::InstallResultCode::kInstallURLInvalid; return true; + case crosapi::mojom::WebAppInstallResultCode::kIconDownloadingFailed: + *output = webapps::InstallResultCode::kIconDownloadingFailed; + return true; }; NOTREACHED();
diff --git a/chromeos/printing/cups_printer_status.h b/chromeos/printing/cups_printer_status.h index bd0c0513..4980881 100644 --- a/chromeos/printing/cups_printer_status.h +++ b/chromeos/printing/cups_printer_status.h
@@ -78,24 +78,17 @@ const base::Time& GetTimestamp() const; - bool IsClientInfoSupported() const { return client_info_supported_; } - // Adds a new CupsPrinterStatusReason to an existing CupsPrinterStatus. void AddStatusReason(const CupsPrinterStatusReason::Reason& reason, const CupsPrinterStatusReason::Severity& severity); void SetAuthenticationInfo(const PrinterAuthenticationInfo& auth_info); - void SetClientInfoSupported(bool supported) { - client_info_supported_ = supported; - } - private: std::string printer_id_; base::flat_set<CupsPrinterStatusReason> status_reasons_; PrinterAuthenticationInfo auth_info_; base::Time timestamp_; - bool client_info_supported_; }; } // namespace chromeos
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni index 70146a2f..328206e 100644 --- a/chromeos/tast_control.gni +++ b/chromeos/tast_control.gni
@@ -304,9 +304,6 @@ # https://crbug.com/1236234 "lacros.AudioPlay", - # https://crbug.com/1198918 - "ui.ScreenRecorder", - # READ COMMENT AT TOP BEFORE ADDING NEW TESTS HERE. ]
diff --git a/components/BUILD.gn b/components/BUILD.gn index 96e970f14..65e6122 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -558,6 +558,7 @@ if (!is_android) { deps += [ + "//components/commerce/core:account_checker_unittests", "//components/commerce/core:commerce_heuristics_data_unittests", "//components/commerce/core:feature_list_unittests", "//components/commerce/core:heuristics_provider_unittests", @@ -1060,6 +1061,7 @@ "//components/browser_ui/client_certificate/android:junit", "//components/browser_ui/media/android:junit", "//components/browser_ui/photo_picker/android:junit", + "//components/browser_ui/settings/android:junit", "//components/browser_ui/util/android:junit", "//components/browser_ui/webshare/android:junit", "//components/browser_ui/widget/android:junit",
diff --git a/components/attribution_reporting/test_utils.cc b/components/attribution_reporting/test_utils.cc index 6d5361fc..d49438c 100644 --- a/components/attribution_reporting/test_utils.cc +++ b/components/attribution_reporting/test_utils.cc
@@ -15,6 +15,7 @@ #include "components/attribution_reporting/filters.h" #include "components/attribution_reporting/source_registration.h" #include "components/attribution_reporting/suitable_origin.h" +#include "components/attribution_reporting/trigger_attestation.h" #include "components/attribution_reporting/trigger_registration.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/origin.h" @@ -117,4 +118,17 @@ return out << *origin; } +bool operator==(const TriggerAttestation& a, const TriggerAttestation& b) { + auto tie = [](const TriggerAttestation& t) { + return std::make_tuple(t.token(), t.aggregatable_report_id()); + }; + return tie(a) == tie(b); +} + +std::ostream& operator<<(std::ostream& out, + const TriggerAttestation& attestation) { + return out << "{token=" << attestation.token() << ",aggregatable_report_id=" + << attestation.aggregatable_report_id() << "}"; +} + } // namespace attribution_reporting
diff --git a/components/attribution_reporting/test_utils.h b/components/attribution_reporting/test_utils.h index 43bddada..13296c7 100644 --- a/components/attribution_reporting/test_utils.h +++ b/components/attribution_reporting/test_utils.h
@@ -20,6 +20,7 @@ class FilterData; class Filters; class SuitableOrigin; +class TriggerAttestation; struct EventTriggerData; struct SourceRegistration; @@ -61,6 +62,10 @@ std::ostream& operator<<(std::ostream&, const SuitableOrigin&); +bool operator==(const TriggerAttestation&, const TriggerAttestation&); + +std::ostream& operator<<(std::ostream&, const TriggerAttestation&); + template <typename T, size_t kMaxSize> bool operator==(const BoundedList<T, kMaxSize>& a, const BoundedList<T, kMaxSize>& b) {
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc index 11f2d64..686d976a 100644 --- a/components/autofill/content/browser/content_autofill_driver.cc +++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -71,6 +71,11 @@ GetAutofillAgent()->TriggerReparse(); } +void ContentAutofillDriver::TriggerReparseInAllFrames() { + // TODO(crbug.com/1334642): Implement. + NOTIMPLEMENTED(); +} + // static ContentAutofillDriver* ContentAutofillDriver::GetForRenderFrameHost( content::RenderFrameHost* render_frame_host) {
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h index 0dec0aa..6a98664ae 100644 --- a/components/autofill/content/browser/content_autofill_driver.h +++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -165,6 +165,8 @@ void HandleParsedForms(const std::vector<FormData>& forms) override {} void PopupHidden() override; net::IsolationInfo IsolationInfo() override; + void SetShouldSuppressKeyboard(bool suppress) override; + void TriggerReparseInAllFrames() override; // Called to inform the browser that in the field with `form_global_id` and // `field_global_id`, the context menu was triggered. This is different from @@ -215,11 +217,6 @@ const content::RenderWidgetHost::KeyPressEventCallback& handler); void UnsetKeyPressHandler(); - // Sets whether the keyboard should be suppressed. Used to keep the keyboard - // hidden while the bottom sheet (e.g. Touch To Fill) is shown. Forwarded to - // the last-queried source remembered by ContentAutofillRouter. - virtual void SetShouldSuppressKeyboard(bool suppress); - // Callbacks that are called also in other functions by ContentAutofillRouter. void FocusNoLongerOnFormCallback(bool had_interacted_form); void UnsetKeyPressHandlerCallback();
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc index c74136a..900f889 100644 --- a/components/autofill/content/renderer/form_autofill_util.cc +++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1434,7 +1434,8 @@ field_data->label_source = FormFieldData::LabelSource::kFor; base::UmaHistogramEnumeration(kAssignedLabelSourceHistogram, label_source); - if (label_source == AssignedLabelSource::kName) { + if (label_source == AssignedLabelSource::kName && + base::FeatureList::IsEnabled(features::kAutofillEnableDevtoolsIssues)) { // Add a DevTools issue informing the developer that the `label`'s for- // attribute is pointing to the name of a field, even though the ID should // be used. @@ -1524,7 +1525,9 @@ DCHECK(!optional_field || form_control_element); DCHECK(!form_element || fieldsets.empty()); - MaybeEmitDuplicateIdForInputIssue(control_elements); + if (base::FeatureList::IsEnabled(features::kAutofillEnableDevtoolsIssues)) { + MaybeEmitDuplicateIdForInputIssue(control_elements); + } // Extracts fields from |control_elements| into `form->fields` and sets // `form->child_frames[i].predecessor` to the field index of the last field @@ -1620,7 +1623,9 @@ } } - MaybeEmitInputWithNoLabelIssue(control_elements, form, fields_extracted); + if (base::FeatureList::IsEnabled(features::kAutofillEnableDevtoolsIssues)) { + MaybeEmitInputWithNoLabelIssue(control_elements, form, fields_extracted); + } // Infers field labels from other tags or <labels> without for="...". bool found_field = false;
diff --git a/components/autofill/core/browser/autofill_driver.h b/components/autofill/core/browser/autofill_driver.h index 5a7ab0e..7cdb687 100644 --- a/components/autofill/core/browser/autofill_driver.h +++ b/components/autofill/core/browser/autofill_driver.h
@@ -68,6 +68,14 @@ // frame. virtual bool CanShowAutofillUi() const = 0; + // Sets whether the keyboard should be suppressed. Used to keep the keyboard + // hidden while the bottom sheet (e.g. Touch To Fill) is shown. Forwarded to + // the last-queried source remembered by `ContentAutofillRouter`. + virtual void SetShouldSuppressKeyboard(bool suppress) = 0; + + // Triggers a reparse on all frames of the same frame tree. + virtual void TriggerReparseInAllFrames() = 0; + // Returns the ax tree id associated with this driver. virtual ui::AXTreeID GetAxTreeId() const = 0;
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc index 0cd3464..bf73fba 100644 --- a/components/autofill/core/browser/autofill_field.cc +++ b/components/autofill/core/browser/autofill_field.cc
@@ -48,7 +48,7 @@ } static_assert( - absl::variant_size<AutofillField::FieldLogEventType>() == 6, + absl::variant_size<AutofillField::FieldLogEventType>() == 7, "If you add a new field event type, you need to update this function"); if (absl::holds_alternative<absl::monostate>(event1)) { @@ -81,6 +81,11 @@ return AreCollapsible(absl::get<E>(event1), absl::get<E>(event2)); } + if (absl::holds_alternative<AutocompleteAttributeFieldLogEvent>(event1)) { + using E = AutocompleteAttributeFieldLogEvent; + return AreCollapsible(absl::get<E>(event1), absl::get<E>(event2)); + } + NOTREACHED(); return false; }
diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h index 08157e20..97be45cd 100644 --- a/components/autofill/core/browser/autofill_field.h +++ b/components/autofill/core/browser/autofill_field.h
@@ -37,7 +37,8 @@ TriggerFillFieldLogEvent, FillFieldLogEvent, TypingFieldLogEvent, - HeuristicPredictionFieldLogEvent>; + HeuristicPredictionFieldLogEvent, + AutocompleteAttributeFieldLogEvent>; AutofillField(); explicit AutofillField(const FormFieldData& field);
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc index 3589b21..087402e9 100644 --- a/components/autofill/core/browser/browser_autofill_manager.cc +++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -862,6 +862,7 @@ if (IsAutofillCreditCardEnabled()) { credit_card_form_event_logger_->OnFormSubmitted(sync_state_, *submitted_form); + touch_to_fill_delegate_->LogMetricsAfterSubmission(*submitted_form); } } @@ -3344,6 +3345,18 @@ autofill_suggestion_method_ = state; } +void BrowserAutofillManager::SetShouldSuppressKeyboard(bool suppress) { + driver()->SetShouldSuppressKeyboard(suppress); +} + +bool BrowserAutofillManager::CanShowAutofillUi() const { + return driver()->CanShowAutofillUi(); +} + +void BrowserAutofillManager::TriggerReparseInAllFrames() { + driver()->TriggerReparseInAllFrames(); +} + void BrowserAutofillManager::ProcessFieldLogEventsInForm( const FormStructure& form_structure) { // TODO(crbug.com/1325851): Log metrics if at least one field in the form was
diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h index 6da2f97..2d0672d 100644 --- a/components/autofill/core/browser/browser_autofill_manager.h +++ b/components/autofill/core/browser/browser_autofill_manager.h
@@ -315,6 +315,15 @@ // keyboard accessory, etc. virtual void SetSuggestionOriginMetricState(AutofillSuggestionMethod state); + // Forwards call to the same-named `AutofillDriver` function. + virtual void SetShouldSuppressKeyboard(bool suppress); + + // Forwards call to the same-named `AutofillDriver` function. + virtual bool CanShowAutofillUi() const; + + // Forwards call to the same-named `AutofillDriver` function. + virtual void TriggerReparseInAllFrames(); + void SetExternalDelegateForTest( std::unique_ptr<AutofillExternalDelegate> external_delegate) { external_delegate_ = std::move(external_delegate);
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc index 34df099..5eef0e39 100644 --- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc +++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -382,6 +382,9 @@ SendFieldsEligibleForManualFillingToRenderer, (const std::vector<FieldGlobalId>& fields), (override)); + MOCK_METHOD(void, SetShouldSuppressKeyboard, (bool), ()); + MOCK_METHOD(bool, CanShowAutofillUi, (), (const)); + MOCK_METHOD(void, TriggerReparseInAllFrames, (), ()); }; } // namespace @@ -847,10 +850,26 @@ expected.rank_in_field_signature_group))); } + // Matches a AutocompleteAttributeFieldLogEvent by equality of fields. + auto Equal(const AutocompleteAttributeFieldLogEvent& expected) { + return VariantWith<AutocompleteAttributeFieldLogEvent>(AllOf( + Field("html_type", &AutocompleteAttributeFieldLogEvent::html_type, + expected.html_type), + Field("html_mode", &AutocompleteAttributeFieldLogEvent::html_mode, + expected.html_mode), + Field( + "rank_in_field_signature_group", + &AutocompleteAttributeFieldLogEvent::rank_in_field_signature_group, + expected.rank_in_field_signature_group))); + } + // Matches a vector of FieldLogEventType objects by equality of fields of each // log event type. auto ArrayEquals( const std::vector<AutofillField::FieldLogEventType>& expected) { + static_assert( + absl::variant_size<AutofillField::FieldLogEventType>() == 7, + "If you add a new field event type, you need to update this function"); std::vector<Matcher<AutofillField::FieldLogEventType>> matchers; for (const auto& event : expected) { if (absl::holds_alternative<AskForValuesToFillFieldLogEvent>(event)) { @@ -866,6 +885,12 @@ event)) { matchers.push_back( Equal(absl::get<HeuristicPredictionFieldLogEvent>(event))); + } else if (absl::holds_alternative<AutocompleteAttributeFieldLogEvent>( + event)) { + matchers.push_back( + Equal(absl::get<AutocompleteAttributeFieldLogEvent>(event))); + } else { + NOTREACHED(); } } return ElementsAreArray(matchers); @@ -5357,7 +5382,7 @@ /*disabled_features=*/{}); } - std::vector<AutofillField::FieldLogEventType> ToHeuristicFieldTypes( + std::vector<AutofillField::FieldLogEventType> ToHeuristicFieldTypeEvents( ServerFieldType heuristic_type) { std::vector<AutofillField::FieldLogEventType> expected_events; #if BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS) @@ -5465,10 +5490,8 @@ for (const auto& autofill_field_ptr : *form_structure) { SCOPED_TRACE(autofill_field_ptr->parseable_label()); - // All parsed fields share the same expected - // HeuristicPredictionFieldLogEvent. std::vector<AutofillField::FieldLogEventType> expected_events = - ToHeuristicFieldTypes(autofill_field_ptr->heuristic_type()); + ToHeuristicFieldTypeEvents(autofill_field_ptr->heuristic_type()); if (autofill_field_ptr->parseable_label() == u"First Name") { // The "First Name" field is the trigger field, so it contains the @@ -5546,10 +5569,8 @@ FillEventId fill_event_id = trigger_fill_field_log_event->fill_event_id; for (const auto& autofill_field_ptr : *form_structure) { SCOPED_TRACE(autofill_field_ptr->parseable_label()); - // All parsed fields share the same expected - // HeuristicPredictionFieldLogEvent. std::vector<AutofillField::FieldLogEventType> expected_events = - ToHeuristicFieldTypes(autofill_field_ptr->heuristic_type()); + ToHeuristicFieldTypeEvents(autofill_field_ptr->heuristic_type()); if (autofill_field_ptr->parseable_label() == u"First Name") { // The "First Name" field is the trigger field, so it contains the @@ -5671,10 +5692,8 @@ for (const auto& autofill_field_ptr : *form_structure) { SCOPED_TRACE(autofill_field_ptr->parseable_label()); - // All parsed fields share the same expected - // HeuristicPredictionFieldLogEvent. std::vector<AutofillField::FieldLogEventType> expected_events = - ToHeuristicFieldTypes(autofill_field_ptr->heuristic_type()); + ToHeuristicFieldTypeEvents(autofill_field_ptr->heuristic_type()); if (autofill_field_ptr->parseable_label() == u"First Name") { // The "First Name" field is the trigger field, so it contains the @@ -5768,10 +5787,8 @@ for (const auto& autofill_field_ptr : *form_structure) { SCOPED_TRACE(autofill_field_ptr->parseable_label()); - // All parsed fields share the same expected - // HeuristicPredictionFieldLogEvent. std::vector<AutofillField::FieldLogEventType> expected_events = - ToHeuristicFieldTypes(autofill_field_ptr->heuristic_type()); + ToHeuristicFieldTypeEvents(autofill_field_ptr->heuristic_type()); if (autofill_field_ptr->parseable_label() == u"First Name") { // The "First Name" field is the trigger field, so it contains the @@ -5844,10 +5861,8 @@ for (const auto& autofill_field_ptr : *form_structure) { SCOPED_TRACE(autofill_field_ptr->parseable_label()); - // All parsed fields share the same expected - // HeuristicPredictionFieldLogEvent. std::vector<AutofillField::FieldLogEventType> expected_events = - ToHeuristicFieldTypes(autofill_field_ptr->heuristic_type()); + ToHeuristicFieldTypeEvents(autofill_field_ptr->heuristic_type()); if (autofill_field_ptr->parseable_label() == u"Name on Card") { // The "Name on Card" field gets focus and shows a suggestion so it @@ -5879,6 +5894,57 @@ } } +// Test that we record AutocompleteAttributeFieldLogEvent for the fields with +// autocomplete attributes in the form. +TEST_F(BrowserAutofillManagerWithLogEventsTest, + LogEventsOnAutocompleteAttributeField) { + // Set up our form data. + FormData form; + form.name = u"MyForm"; + form.url = GURL("https://myform.com/form.html"); + form.action = GURL("https://myform.com/submit.html"); + FormFieldData field; + test::CreateTestFormField("First Name", "firstname", "", "text", "given-name", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Last Name", "lastname", "", "text", "family-name", + &field); + form.fields.push_back(field); + // Set no autocomplete attribute for the middle name. + test::CreateTestFormField("Middle name", "middle", "", "text", "", &field); + form.fields.push_back(field); + // Set an unrecognized autocomplete attribute for the last name. + test::CreateTestFormField("Email", "email", "", "text", "unrecognized", + &field); + form.fields.push_back(field); + + // Simulate having seen this form on page load. + auto form_structure_instance = std::make_unique<FormStructure>(form); + FormStructure* form_structure = form_structure_instance.get(); + form_structure->DetermineHeuristicTypes(nullptr, nullptr); + browser_autofill_manager_->AddSeenFormStructure( + std::move(form_structure_instance)); + + // Simulate form submission. + FormSubmitted(form); + + for (const auto& autofill_field_ptr : *form_structure) { + SCOPED_TRACE(autofill_field_ptr->parseable_label()); + std::vector<AutofillField::FieldLogEventType> expected_events = + ToHeuristicFieldTypeEvents(autofill_field_ptr->heuristic_type()); + if (autofill_field_ptr->parseable_label() != u"Middle name") { + expected_events.insert(expected_events.begin(), + AutocompleteAttributeFieldLogEvent{ + .html_type = autofill_field_ptr->html_type(), + .html_mode = HtmlFieldMode::kNone, + .rank_in_field_signature_group = 1, + }); + } + EXPECT_THAT(autofill_field_ptr->field_log_events(), + ArrayEquals(expected_events)); + } +} + // Test that when Autocomplete is enabled and Autofill is disabled, form // submissions are still received by the SingleFieldFormFillRouter. TEST_F(BrowserAutofillManagerTest, FormSubmittedAutocompleteEnabled) { @@ -9792,6 +9858,21 @@ EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen()); } +TEST_F(BrowserAutofillManagerTest, SetShouldSuppressKeyboard) { + EXPECT_CALL(*autofill_driver_, SetShouldSuppressKeyboard(true)); + browser_autofill_manager_->SetShouldSuppressKeyboard(true); +} + +TEST_F(BrowserAutofillManagerTest, CanShowAutofillUi) { + EXPECT_CALL(*autofill_driver_, CanShowAutofillUi).WillOnce(Return(true)); + EXPECT_TRUE(browser_autofill_manager_->CanShowAutofillUi()); +} + +TEST_F(BrowserAutofillManagerTest, TriggerReparseInAllFrames) { + EXPECT_CALL(*autofill_driver_, TriggerReparseInAllFrames); + browser_autofill_manager_->TriggerReparseInAllFrames(); +} + // Desktop only tests. #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) class BrowserAutofillManagerTestForVirtualCardOption
diff --git a/components/autofill/core/browser/contact_info_sync_util.cc b/components/autofill/core/browser/contact_info_sync_util.cc index 3b15aa5c..696372cf 100644 --- a/components/autofill/core/browser/contact_info_sync_util.cc +++ b/components/autofill/core/browser/contact_info_sync_util.cc
@@ -134,8 +134,6 @@ profile.modification_date().ToTimeT()); specifics->set_language_code(profile.language_code()); specifics->set_profile_label(profile.profile_label()); - specifics->set_initial_creator_id(profile.initial_creator_id()); - specifics->set_last_modifier_id(profile.last_modifier_id()); EntryDataSetter s(profile); // Set name-related values and statuses. @@ -203,8 +201,6 @@ base::Time::FromTimeT(specifics.date_modified_windows_epoch_micros())); profile->set_language_code(specifics.language_code()); profile->set_profile_label(specifics.profile_label()); - profile->set_initial_creator_id(specifics.initial_creator_id()); - profile->set_last_modifier_id(specifics.last_modifier_id()); ProfileSetter s(*profile); // Set name-related values and statuses.
diff --git a/components/autofill/core/browser/contact_info_sync_util_unittest.cc b/components/autofill/core/browser/contact_info_sync_util_unittest.cc index 308184a7..c618d4466 100644 --- a/components/autofill/core/browser/contact_info_sync_util_unittest.cc +++ b/components/autofill/core/browser/contact_info_sync_util_unittest.cc
@@ -15,9 +15,8 @@ using sync_pb::ContactInfoSpecifics; -constexpr char kGuid[] = "00000000-0000-0000-0000-000000000001"; -constexpr char kInvalidGuid[] = "1234"; -constexpr int kNonChromeModifier = 1234; +const char kGuid[] = "00000000-0000-0000-0000-000000000001"; +const char kInvalidGuid[] = "1234"; const auto kUseDate = base::Time::FromDoubleT(123); const auto kModificationDate = base::Time::FromDoubleT(456); @@ -32,9 +31,6 @@ profile.set_modification_date(kModificationDate); profile.set_language_code("en"); profile.set_profile_label("profile_label"); - profile.set_initial_creator_id( - AutofillProfile::kInitialCreatorOrModifierChrome); - profile.set_last_modifier_id(kNonChromeModifier); // Set name-related values and statuses. profile.SetRawInfoWithVerificationStatus(NAME_HONORIFIC_PREFIX, u"Dr.", @@ -130,9 +126,6 @@ specifics.set_date_modified_windows_epoch_micros(kModificationDate.ToTimeT()); specifics.set_language_code("en"); specifics.set_profile_label("profile_label"); - specifics.set_initial_creator_id( - AutofillProfile::kInitialCreatorOrModifierChrome); - specifics.set_last_modifier_id(kNonChromeModifier); // Set name-related values and statuses. SetToken(specifics.mutable_name_honorific(), "Dr.",
diff --git a/components/autofill/core/browser/data_model/autofill_profile.cc b/components/autofill/core/browser/data_model/autofill_profile.cc index 459d9170..09fb6ab 100644 --- a/components/autofill/core/browser/data_model/autofill_profile.cc +++ b/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -275,8 +275,6 @@ has_converted_ = profile.has_converted(); source_ = profile.source_; - initial_creator_id_ = profile.initial_creator_id_; - last_modifier_id_ = profile.last_modifier_id_; return *this; }
diff --git a/components/autofill/core/browser/data_model/autofill_profile.h b/components/autofill/core/browser/data_model/autofill_profile.h index 5499094..f679b1f 100644 --- a/components/autofill/core/browser/data_model/autofill_profile.h +++ b/components/autofill/core/browser/data_model/autofill_profile.h
@@ -54,10 +54,6 @@ kMaxValue = kAccount, }; - // The values used to represent Autofill in the `initial_creator_id()` and - // `last_modifier_id()`. - static constexpr int kInitialCreatorOrModifierChrome = 70073; - AutofillProfile(const std::string& guid, const std::string& origin, Source source = Source::kLocalOrSyncable); @@ -274,16 +270,6 @@ source_ = source; } - int initial_creator_id() const { return initial_creator_id_; } - void set_initial_creator_id(int creator_id) { - initial_creator_id_ = creator_id; - } - - int last_modifier_id() const { return last_modifier_id_; } - void set_last_modifier_id(int modifier_id) { - last_modifier_id_ = modifier_id; - } - // Checks for non-empty setting-inaccessible fields and returns all that were // found. ServerFieldTypeSet FindInaccessibleProfileValues() const; @@ -367,17 +353,6 @@ bool has_converted_; Source source_; - - // Indicates the application that initially created the profile and the - // application that performed the last non-metadata modification of it. - // Only relevant for `source_ == kAccount` profiles, since `kLocalOrSyncable` - // profiles are only used within Autofill. - // The integer values represent a server-side enum `BillableService`, which is - // not duplicated in Chromium. For Autofill, the exact application that - // created/modified the profile is thus opaque. However, Autofill is - // represented by the value `kInitialCreatorOrModifierChrome`. - int initial_creator_id_; - int last_modifier_id_; }; // So we can compare AutofillProfiles with EXPECT_EQ().
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index f61cd1ac..52cb486 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -1330,6 +1330,7 @@ void FormStructure::SetFieldTypesFromAutocompleteAttribute() { has_author_specified_types_ = false; has_author_specified_upi_vpa_hint_ = false; + std::map<FieldSignature, size_t> field_rank_id_map; for (const std::unique_ptr<AutofillField>& field : fields_) { if (!field->parsed_autocomplete) continue; @@ -1350,6 +1351,15 @@ field->SetHtmlType(field->parsed_autocomplete->field_type, field->parsed_autocomplete->mode); + + // Log the field type predicted from autocomplete attribute. + ++field_rank_id_map[field->GetFieldSignature()]; + field->AppendLogEventIfNotRepeated(AutocompleteAttributeFieldLogEvent{ + .html_type = field->parsed_autocomplete->field_type, + .html_mode = field->parsed_autocomplete->mode, + .rank_in_field_signature_group = + field_rank_id_map[field->GetFieldSignature()], + }); } }
diff --git a/components/autofill/core/browser/metrics/autofill_metrics.cc b/components/autofill/core/browser/metrics/autofill_metrics.cc index 766df3a3..a6ede04 100644 --- a/components/autofill/core/browser/metrics/autofill_metrics.cc +++ b/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -2524,15 +2524,22 @@ // only for non-user-visible metrics, one step before experimental. ServerFieldType heuristic_next_gen_type = UNKNOWN_TYPE; + // Field types from Autocomplete attribute. + // Information of the HTML autocomplete attribute, see + // components/autofill/core/common/mojom/autofill_types.mojom. + HtmlFieldMode html_mode = HtmlFieldMode::kNone; + HtmlFieldType html_type = HtmlFieldType::kUnrecognized; + // If multiple fields have the same signature, this indicates the position // within this set of fields. This allows us to understand problems related // to duplicated field signatures. size_t rank_in_field_signature_group = 0; bool had_heuristic_type = false; + bool had_html_type = false; for (const auto& log_event : field_log_events) { - static_assert(absl::variant_size<AutofillField::FieldLogEventType>() == 6, + static_assert(absl::variant_size<AutofillField::FieldLogEventType>() == 7, "When adding new variants check that this function does not " "need to be updated."); if (auto* event = @@ -2596,6 +2603,14 @@ rank_in_field_signature_group = event->rank_in_field_signature_group; had_heuristic_type = true; } + + if (auto* event = + absl::get_if<AutocompleteAttributeFieldLogEvent>(&log_event)) { + html_type = event->html_type; + html_mode = event->html_mode; + rank_in_field_signature_group = event->rank_in_field_signature_group; + had_html_type = true; + } } if (had_value_after_filling != OptionalBoolean::kUndefined || @@ -2651,8 +2666,16 @@ .SetHeuristicTypeLegacy(heuristic_legacy_type) .SetHeuristicTypeDefault(heuristic_default_type) .SetHeuristicTypeExperimental(heuristic_experimental_type) - .SetHeuristicTypeNextGen(heuristic_next_gen_type) - .SetRankInFieldSignatureGroup(rank_in_field_signature_group); + .SetHeuristicTypeNextGen(heuristic_next_gen_type); + } + + if (had_html_type) { + builder.SetHtmlFieldType(static_cast<int>(html_type)) + .SetHtmlFieldMode(static_cast<int>(html_mode)); + } + + if (rank_in_field_signature_group) { + builder.SetRankInFieldSignatureGroup(rank_in_field_signature_group); } builder.Record(ukm_recorder_);
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc index 09dab66..6a7d2a3 100644 --- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -10588,46 +10588,73 @@ ->emplace(form_structure_ptr->global_id(), std::move(form_structure)) .second); + AutofillQueryResponse response; + auto* form_suggestion = response.add_form_suggestions(); + // Server response will match with autocomplete. + AddFieldPredictionToForm(form.fields[0], NAME_LAST, form_suggestion); + // Server response will NOT match with autocomplete. + AddFieldPredictionToForm(form.fields[1], NAME_FIRST, form_suggestion); + // Not logged. + AddFieldPredictionToForm(form.fields[2], NAME_MIDDLE, form_suggestion); + // Server response will have no data. + AddFieldPredictionToForm(form.fields[3], NO_SERVER_DATA, form_suggestion); + + std::string response_string = SerializeAndEncode(response); + autofill_manager().OnLoadedServerPredictionsForTest( + response_string, test::GetEncodedSignatures(*form_structure_ptr)); + SubmitForm(form); // Record Autofill.FieldInfo UKM event at autofill manager reset. autofill_manager().Reset(); auto entries = test_ukm_recorder_->GetEntriesByName(UkmFieldInfoType::kEntryName); - // The local heuristic prediction does not predict the type for the fourth - // field. - ASSERT_EQ(3u, entries.size()); - std::vector<ServerFieldType> heuristic_types{NAME_LAST, NAME_FIRST, - ADDRESS_HOME_LINE1}; + ASSERT_EQ(4u, entries.size()); + // The heuristic type of each field. The local heuristic prediction does not + // predict the type for the fourth field. + std::vector<ServerFieldType> heuristic_types{ + NAME_LAST, NAME_FIRST, ADDRESS_HOME_LINE1, UNKNOWN_TYPE}; + // Field types as per the autocomplete attribute in the input. + std::vector<HtmlFieldType> html_field_types{ + HtmlFieldType::kFamilyName, HtmlFieldType::kAdditionalName, + HtmlFieldType::kUnrecognized, HtmlFieldType::kPostalCode}; for (size_t i = 0; i < entries.size(); ++i) { SCOPED_TRACE(testing::Message() << i); using UFIT = UkmFieldInfoType; const auto* const entry = entries[i]; - std::map<std::string, int64_t> expected = { - {UFIT::kFormSessionIdentifierName, - AutofillMetrics::FormGlobalIdToHash64Bit(form.global_id())}, - {UFIT::kFieldSessionIdentifierName, - AutofillMetrics::FieldGlobalIdToHash64Bit(form.fields[i].global_id())}, - {UFIT::kFieldSignatureName, - Collapse(CalculateFieldSignatureForField(form.fields[i])).value()}, - {UFIT::kHeuristicTypeName, heuristic_types[i]}, - {UFIT::kHeuristicTypeLegacyName, heuristic_types[i]}, -#if BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS) - {UFIT::kHeuristicTypeDefaultName, heuristic_types[i]}, - {UFIT::kHeuristicTypeExperimentalName, heuristic_types[i]}, - {UFIT::kHeuristicTypeNextGenName, heuristic_types[i]}, -#else - {UFIT::kHeuristicTypeDefaultName, UNKNOWN_TYPE}, - {UFIT::kHeuristicTypeExperimentalName, UNKNOWN_TYPE}, - {UFIT::kHeuristicTypeNextGenName, UNKNOWN_TYPE}, -#endif - {UFIT::kIsFocusableName, true}, - {UFIT::kRankInFieldSignatureGroupName, 1}, - {UFIT::kWasFocusedName, false}, + {UFIT::kFormSessionIdentifierName, + AutofillMetrics::FormGlobalIdToHash64Bit(form.global_id())}, + {UFIT::kFieldSessionIdentifierName, + AutofillMetrics::FieldGlobalIdToHash64Bit(form.fields[i].global_id())}, + {UFIT::kFieldSignatureName, + Collapse(CalculateFieldSignatureForField(form.fields[i])).value()}, + {UFIT::kIsFocusableName, true}, + {UFIT::kRankInFieldSignatureGroupName, 1}, + {UFIT::kWasFocusedName, false}, }; - + if (heuristic_types[i] != UNKNOWN_TYPE) { + expected.merge(std::map<std::string, int64_t>({ + {UFIT::kHeuristicTypeName, heuristic_types[i]}, + {UFIT::kHeuristicTypeLegacyName, heuristic_types[i]}, +#if BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS) + {UFIT::kHeuristicTypeDefaultName, heuristic_types[i]}, + {UFIT::kHeuristicTypeExperimentalName, heuristic_types[i]}, + {UFIT::kHeuristicTypeNextGenName, heuristic_types[i]}, +#else + {UFIT::kHeuristicTypeDefaultName, UNKNOWN_TYPE}, + {UFIT::kHeuristicTypeExperimentalName, UNKNOWN_TYPE}, + {UFIT::kHeuristicTypeNextGenName, UNKNOWN_TYPE}, +#endif + })); + } + if (html_field_types[i] != HtmlFieldType::kUnrecognized) { + expected.merge(std::map<std::string, int64_t>({ + {UFIT::kHtmlFieldTypeName, static_cast<int>(html_field_types[i])}, + {UFIT::kHtmlFieldModeName, static_cast<int>(HtmlFieldMode::kNone)}, + })); + } EXPECT_EQ(expected.size(), entry->metrics.size()); for (const auto& [metric, value] : expected) { test_ukm_recorder_->ExpectEntryMetric(entry, metric, value);
diff --git a/components/autofill/core/browser/metrics/log_event.cc b/components/autofill/core/browser/metrics/log_event.cc index 584a2c1b..987bea90 100644 --- a/components/autofill/core/browser/metrics/log_event.cc +++ b/components/autofill/core/browser/metrics/log_event.cc
@@ -79,4 +79,12 @@ event2.rank_in_field_signature_group; } +bool AreCollapsible(const AutocompleteAttributeFieldLogEvent& event1, + const AutocompleteAttributeFieldLogEvent& event2) { + return event1.html_type == event2.html_type && + event1.html_mode == event2.html_mode && + event1.rank_in_field_signature_group == + event2.rank_in_field_signature_group; +} + } // namespace autofill
diff --git a/components/autofill/core/browser/metrics/log_event.h b/components/autofill/core/browser/metrics/log_event.h index 42b3f5f..e79c7738 100644 --- a/components/autofill/core/browser/metrics/log_event.h +++ b/components/autofill/core/browser/metrics/log_event.h
@@ -121,6 +121,20 @@ bool AreCollapsible(const HeuristicPredictionFieldLogEvent& event1, const HeuristicPredictionFieldLogEvent& event2); +// Predict the field type from Autocomplete attribute. +template <typename IsRequired = void> +struct AutocompleteAttributeFieldLogEventImpl { + HtmlFieldType html_type = IsRequired(); + HtmlFieldMode html_mode = IsRequired(); + size_t rank_in_field_signature_group = IsRequired(); +}; +using AutocompleteAttributeFieldLogEvent = + AutocompleteAttributeFieldLogEventImpl<>; + +// Compare two field log events from AutocompleteAttributeFieldLogEvent type. +bool AreCollapsible(const AutocompleteAttributeFieldLogEvent& event1, + const AutocompleteAttributeFieldLogEvent& event2); + } // namespace autofill #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_LOG_EVENT_H_
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc index 5f87c52a..24d71c4 100644 --- a/components/autofill/core/browser/payments/credit_card_access_manager.cc +++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -204,6 +204,9 @@ unmask_details_request_in_progress_ = false; unmask_details_ = unmask_details; + + // TODO(crbug.com/1409151): Rename `offer_fido_opt_in`, and check that the + // user is off the record separately. unmask_details_.offer_fido_opt_in = unmask_details_.offer_fido_opt_in && !payments_client_->is_off_the_record(); @@ -316,6 +319,15 @@ if (opt_in) { ShowWebauthnOfferDialog(/*card_authorization_token=*/std::string()); } else { + // We should not offer to update any user preferences when the user is off + // the record. This also protects against a possible crash when attempting + // to add the maximum amount of strikes to the FIDO auth strike database, as + // strike databases are not present in incognito mode and should not be + // used. + if (personal_data_manager_->IsOffTheRecord()) { + return; + } + GetOrCreateFIDOAuthenticator()->OptOut(); GetOrCreateFIDOAuthenticator() ->GetOrCreateFidoAuthenticationStrikeDatabase()
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc index 15e029fc..d497ec6 100644 --- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc +++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -2003,6 +2003,19 @@ EXPECT_FALSE(IsCreditCardFIDOAuthEnabled()); } +// TODO(crbug.com/1409172): Extend the FIDOAuthOptChange tests to more +// use-cases. +TEST_F(CreditCardAccessManagerTest, FIDOAuthOptChange_OptOut) { + credit_card_access_manager_->FIDOAuthOptChange(/*opt_in=*/false); + ASSERT_TRUE(fido_authenticator_->IsOptOutCalled()); +} + +TEST_F(CreditCardAccessManagerTest, FIDOAuthOptChange_OptOut_OffTheRecord) { + personal_data().set_is_off_the_record_for_testing(/*is_off_the_record=*/true); + credit_card_access_manager_->FIDOAuthOptChange(/*opt_in=*/false); + ASSERT_FALSE(fido_authenticator_->IsOptOutCalled()); +} + // TODO(crbug.com/1109296) Debug issues and re-enable this test on MacOS. #if !BUILDFLAG(IS_APPLE) // Ensures that PrepareToFetchCreditCard() is properly rate limited.
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_client.h index 591161df..09ce205 100644 --- a/components/autofill/core/browser/payments/payments_client.h +++ b/components/autofill/core/browser/payments/payments_client.h
@@ -519,6 +519,10 @@ void set_url_loader_factory_for_testing( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); + // TODO(crbug.com/1409158): Remove this function, as it should not be the + // PaymentsClient's responsibility to check if the user is off the record. The + // sole responsibility of the PaymentsClient is to send requests to the Google + // payments server. bool is_off_the_record() { return is_off_the_record_; } private: @@ -579,6 +583,10 @@ std::string access_token_; // Denotes incognito mode. + // TODO(crbug.com/1409158): Remove this variable, as it should not be the + // PaymentsClient's responsibility to check if the user is off the record. The + // sole responsibility of the PaymentsClient is to send requests to the Google + // payments server. bool is_off_the_record_; // True if |request_| has already retried due to a 401 response from the
diff --git a/components/autofill/core/browser/test_autofill_driver.h b/components/autofill/core/browser/test_autofill_driver.h index 5f34bf2..44e996e 100644 --- a/components/autofill/core/browser/test_autofill_driver.h +++ b/components/autofill/core/browser/test_autofill_driver.h
@@ -75,6 +75,8 @@ net::IsolationInfo IsolationInfo() override; void SendFieldsEligibleForManualFillingToRenderer( const std::vector<FieldGlobalId>& fields) override {} + void SetShouldSuppressKeyboard(bool suppress) override {} + void TriggerReparseInAllFrames() override {} // Methods unique to TestAutofillDriver that tests can use to specialize // functionality.
diff --git a/components/autofill/core/browser/touch_to_fill_delegate_impl.cc b/components/autofill/core/browser/touch_to_fill_delegate_impl.cc index c8b1fc39..0e95cca9 100644 --- a/components/autofill/core/browser/touch_to_fill_delegate_impl.cc +++ b/components/autofill/core/browser/touch_to_fill_delegate_impl.cc
@@ -147,12 +147,32 @@ AutofillSuggestionMethod::KTouchToFillCreditCard); } -void TouchToFillDelegateImpl::OnDismissed() { +void TouchToFillDelegateImpl::OnDismissed(bool dismissed_by_user) { if (IsShowingTouchToFill()) { ttf_credit_card_state_ = TouchToFillState::kWasShown; + dismissed_by_user_ = dismissed_by_user; } } +void TouchToFillDelegateImpl::LogMetricsAfterSubmission( + const FormStructure& submitted_form) const { + // Log whether autofill was used after dismissing the touch to fill (without + // selecting any credit card for filling) + if (ttf_credit_card_state_ == TouchToFillState::kWasShown && + query_form_.global_id() == submitted_form.global_id() && + HasAnyAutofilledFields(submitted_form)) { + base::UmaHistogramBoolean( + "Autofill.TouchToFill.CreditCard.AutofillUsedAfterTouchToFillDismissal", + dismissed_by_user_); + } +} + +bool TouchToFillDelegateImpl::HasAnyAutofilledFields( + const FormStructure& submitted_form) const { + return base::ranges::any_of( + submitted_form, [](const auto& field) { return field->is_autofilled; }); +} + base::WeakPtr<TouchToFillDelegateImpl> TouchToFillDelegateImpl::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
diff --git a/components/autofill/core/browser/touch_to_fill_delegate_impl.h b/components/autofill/core/browser/touch_to_fill_delegate_impl.h index 7701d09..cbf901cc 100644 --- a/components/autofill/core/browser/touch_to_fill_delegate_impl.h +++ b/components/autofill/core/browser/touch_to_fill_delegate_impl.h
@@ -7,6 +7,7 @@ #include "base/memory/weak_ptr.h" #include "components/autofill/core/browser/data_model/credit_card.h" +#include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/ui/touch_to_fill_delegate.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" @@ -88,7 +89,9 @@ void OnCreditCardScanned(const CreditCard& card) override; void ShowCreditCardSettings() override; void SuggestionSelected(std::string unique_id) override; - void OnDismissed() override; + void OnDismissed(bool dismissed_by_user) override; + + void LogMetricsAfterSubmission(const FormStructure& submitted_form) const; base::WeakPtr<TouchToFillDelegateImpl> GetWeakPtr(); @@ -99,11 +102,14 @@ kWasShown, }; + bool HasAnyAutofilledFields(const FormStructure& submitted_form) const; + TouchToFillState ttf_credit_card_state_ = TouchToFillState::kShouldShow; const raw_ptr<BrowserAutofillManager> manager_; FormData query_form_; FormFieldData query_field_; + bool dismissed_by_user_; base::WeakPtrFactory<TouchToFillDelegateImpl> weak_ptr_factory_{this}; };
diff --git a/components/autofill/core/browser/touch_to_fill_delegate_impl_unittest.cc b/components/autofill/core/browser/touch_to_fill_delegate_impl_unittest.cc index 3c24708..6c90ad36 100644 --- a/components/autofill/core/browser/touch_to_fill_delegate_impl_unittest.cc +++ b/components/autofill/core/browser/touch_to_fill_delegate_impl_unittest.cc
@@ -7,6 +7,7 @@ #include "base/test/task_environment.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/data_model/credit_card.h" +#include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_driver.h" #include "components/autofill/core/browser/test_browser_autofill_manager.h" @@ -154,7 +155,7 @@ ON_CALL(autofill_client_, HideTouchToFillCreditCard) .WillByDefault([delegate = touch_to_fill_delegate_weak]() -> void { if (delegate) { - delegate->OnDismissed(); + delegate->OnDismissed(/*dismissed_by_user=*/false); } }); } @@ -472,7 +473,7 @@ TEST_F(TouchToFillDelegateImplUnitTest, OnDismissSetsTouchToFillToNotShowingState) { TryToShowTouchToFill(/*expected_success=*/true); - touch_to_fill_delegate_->OnDismissed(); + touch_to_fill_delegate_->OnDismissed(false); EXPECT_EQ(touch_to_fill_delegate_->IsShowingTouchToFill(), false); } @@ -537,4 +538,20 @@ touch_to_fill_delegate_->SuggestionSelected(credit_card.server_id()); } +TEST_F(TouchToFillDelegateImplUnitTest, SubmissionMetricsAreTracked) { + TryToShowTouchToFill(/*expected_success=*/true); + touch_to_fill_delegate_->OnDismissed(/*dismissed_by_user=*/true); + + // Simulate that the form was autofilled by other means + FormStructure submitted_form(form_); + for (const std::unique_ptr<AutofillField>& field : submitted_form) { + field->is_autofilled = true; + } + + touch_to_fill_delegate_->LogMetricsAfterSubmission(submitted_form); + histogram_tester_.ExpectUniqueSample( + "Autofill.TouchToFill.CreditCard.AutofillUsedAfterTouchToFillDismissal", + true, 1); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h index 4428c73..1507b747 100644 --- a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h +++ b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h
@@ -33,6 +33,10 @@ virtual int GetCvcImageRid() const = 0; virtual bool ShouldRequestExpirationDate() const = 0; #if BUILDFLAG(IS_ANDROID) + virtual std::string GetCardIconString() const = 0; + virtual std::u16string GetCardName() const = 0; + virtual std::u16string GetCardLastFourDigits() const = 0; + virtual std::u16string GetCardExpiration() const = 0; virtual int GetGooglePayImageRid() const = 0; virtual bool ShouldOfferWebauthn() const = 0; virtual bool GetWebauthnOfferStartState() const = 0;
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc index ceb0615..6070bc6 100644 --- a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc +++ b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
@@ -283,6 +283,22 @@ } #if BUILDFLAG(IS_ANDROID) +std::string CardUnmaskPromptControllerImpl::GetCardIconString() const { + return card_.CardIconStringForAutofillSuggestion(); +} + +std::u16string CardUnmaskPromptControllerImpl::GetCardName() const { + return card_.CardNameForAutofillDisplay(); +} + +std::u16string CardUnmaskPromptControllerImpl::GetCardLastFourDigits() const { + return card_.ObfuscatedNumberWithVisibleLastFourDigits(); +} + +std::u16string CardUnmaskPromptControllerImpl::GetCardExpiration() const { + return card_.ExpirationDateForDisplay(); +} + int CardUnmaskPromptControllerImpl::GetGooglePayImageRid() const { return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER; }
diff --git a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h index 80ea7ca0..1fc9eedf 100644 --- a/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h +++ b/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
@@ -23,6 +23,7 @@ class CardUnmaskPromptView; +// This class is owned by `ChromeAutofillClient`. class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController { public: explicit CardUnmaskPromptControllerImpl(PrefService* pref_service); @@ -42,10 +43,11 @@ // Functions called by ChromeAutofillClient. // It is guaranteed that |view_factory| is called before this function // returns, i.e., the callback will not outlive the stack frame of ShowPrompt. - void ShowPrompt(CardUnmaskPromptViewFactory view_factory, - const CreditCard& card, - const CardUnmaskPromptOptions& card_unmask_prompt_options, - base::WeakPtr<CardUnmaskDelegate> delegate); + virtual void ShowPrompt( + CardUnmaskPromptViewFactory view_factory, + const CreditCard& card, + const CardUnmaskPromptOptions& card_unmask_prompt_options, + base::WeakPtr<CardUnmaskDelegate> delegate); // The CVC the user entered went through validation. void OnVerificationResult(AutofillClient::PaymentsRpcResult result); @@ -62,6 +64,10 @@ int GetCvcImageRid() const override; bool ShouldRequestExpirationDate() const override; #if BUILDFLAG(IS_ANDROID) + std::string GetCardIconString() const override; + std::u16string GetCardName() const override; + std::u16string GetCardLastFourDigits() const override; + std::u16string GetCardExpiration() const override; int GetGooglePayImageRid() const override; bool ShouldOfferWebauthn() const override; bool GetWebauthnOfferStartState() const override;
diff --git a/components/autofill/core/browser/ui/touch_to_fill_delegate.h b/components/autofill/core/browser/ui/touch_to_fill_delegate.h index 5a404b6f..ba0479c 100644 --- a/components/autofill/core/browser/ui/touch_to_fill_delegate.h +++ b/components/autofill/core/browser/ui/touch_to_fill_delegate.h
@@ -25,7 +25,7 @@ virtual void OnCreditCardScanned(const CreditCard& card) = 0; virtual void ShowCreditCardSettings() = 0; virtual void SuggestionSelected(std::string unique_id) = 0; - virtual void OnDismissed() = 0; + virtual void OnDismissed(bool dismissed_by_user) = 0; }; } // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc index 1dfba32..7590369c 100644 --- a/components/autofill/core/browser/webdata/autofill_table.cc +++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -290,8 +290,6 @@ // kDateModified = "date_modified" // kLanguageCode = "language_code" // kLabel = "label" -constexpr base::StringPiece kInitialCreatorId = "initial_creator_id"; -constexpr base::StringPiece kLastModifierId = "last_modifier_id"; constexpr base::StringPiece kContactInfoTypeTokensTable = "contact_info_type_tokens"; @@ -1056,8 +1054,6 @@ s.BindInt64(index++, modification_date.ToTimeT()); s.BindString(index++, profile.language_code()); s.BindString(index++, profile.profile_label()); - s.BindInt(index++, profile.initial_creator_id()); - s.BindInt(index++, profile.last_modifier_id()); } // Inserts `profile` into `kContactInfoTable` and `kContactInfoTypeTokensTable`. @@ -1065,9 +1061,9 @@ const AutofillProfile& profile, const base::Time& modification_date) { sql::Statement s; - InsertBuilder(db, s, kContactInfoTable, - {kGuid, kUseCount, kUseDate, kDateModified, kLanguageCode, - kLabel, kInitialCreatorId, kLastModifierId}); + InsertBuilder( + db, s, kContactInfoTable, + {kGuid, kUseCount, kUseDate, kDateModified, kLanguageCode, kLabel}); BindAutofillProfileToContactInfoStatement(profile, modification_date, s); if (!s.Run()) return false; @@ -1091,8 +1087,7 @@ const std::string& guid) { sql::Statement s; if (!SelectByGuid(db, s, kContactInfoTable, - {kUseCount, kUseDate, kDateModified, kLanguageCode, kLabel, - kInitialCreatorId, kLastModifierId}, + {kUseCount, kUseDate, kDateModified, kLanguageCode, kLabel}, guid)) { return nullptr; } @@ -1104,8 +1099,6 @@ profile->set_modification_date(base::Time::FromTimeT(s.ColumnInt64(index++))); profile->set_language_code(s.ColumnString(index++)); profile->set_profile_label(s.ColumnString(index++)); - profile->set_initial_creator_id(s.ColumnInt(index++)); - profile->set_last_modifier_id(s.ColumnInt(index++)); if (!SelectByGuid(db, s, kContactInfoTypeTokensTable, {kType, kValue, kVerificationStatus}, guid)) { @@ -1245,9 +1238,6 @@ case 109: *update_compatible_version = false; return MigrateToVersion109AddVirtualCardUsageDataTable(); - case 110: - *update_compatible_version = false; - return MigrateToVersion110AddInitialCreatorIdAndLastModifierId(); } return true; } @@ -3351,16 +3341,6 @@ {kLastFour, "VARCHAR"}}); } -bool AutofillTable::MigrateToVersion110AddInitialCreatorIdAndLastModifierId() { - sql::Transaction transaction(db_); - return db_->DoesTableExist(kContactInfoTable) && transaction.Begin() && - AddColumnIfNotExists(db_, kContactInfoTable, kInitialCreatorId, - "INTEGER") && - AddColumnIfNotExists(db_, kContactInfoTable, kLastModifierId, - "INTEGER") && - transaction.Commit(); -} - bool AutofillTable::AddFormFieldValuesTime( const std::vector<FormFieldData>& elements, std::vector<AutofillChange>* changes, @@ -3831,9 +3811,7 @@ {kUseDate, "INTEGER NOT NULL DEFAULT 0"}, {kDateModified, "INTEGER NOT NULL DEFAULT 0"}, {kLanguageCode, "VARCHAR"}, - {kLabel, "VARCHAR"}, - {kInitialCreatorId, "INTEGER"}, - {kLastModifierId, "INTEGER"}}); + {kLabel, "VARCHAR"}}); } bool AutofillTable::InitContactInfoTypeTokensTable() {
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h index 008610c..c3508c7 100644 --- a/components/autofill/core/browser/webdata/autofill_table.h +++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -465,11 +465,6 @@ // help identifying the semantics of the profile. The user // can choose an arbitrary string in principle, but the // values '$HOME$' and '$WORK$' indicate a special meaning. -// initial_creator_id The application that initially created the profile. -// Represented as an integer. See AutofillProfile. -// last_modifier_id The application that performed the last non-metadata -// modification of the profile. -// Represented as an integer. See AutofillProfile. // // contact_info_type_tokens // Contains the values for all relevant ServerFieldTypes of @@ -816,7 +811,6 @@ bool MigrateToVersion107AddContactInfoTables(); bool MigrateToVersion108AddCardIssuerIdColumn(); bool MigrateToVersion109AddVirtualCardUsageDataTable(); - bool MigrateToVersion110AddInitialCreatorIdAndLastModifierId(); // Max data length saved in the table, AKA the maximum length allowed for // form data.
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index 9da9210d..037f807 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -224,6 +224,11 @@ "AutofillEnableDependentLocalityParsing", base::FEATURE_DISABLED_BY_DEFAULT); +// Controls if Autofill emits form issues to devtools. +BASE_FEATURE(kAutofillEnableDevtoolsIssues, + "AutofillEnableDevtoolsIssues", + base::FEATURE_DISABLED_BY_DEFAULT); + // Controls whether to save the first number in a form with multiple phone // numbers instead of aborting the import. // TODO(crbug.com/1167484) Remove once launched.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index bf9992f..f77646e 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -64,6 +64,8 @@ COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillEnableDependentLocalityParsing); COMPONENT_EXPORT(AUTOFILL) +BASE_DECLARE_FEATURE(kAutofillEnableDevtoolsIssues); +COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillEnableImportWhenMultiplePhoneNumbers); COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillEnableMultiStepImports);
diff --git a/components/autofill/ios/browser/autofill_driver_ios.h b/components/autofill/ios/browser/autofill_driver_ios.h index 8dc1ec08..a328498 100644 --- a/components/autofill/ios/browser/autofill_driver_ios.h +++ b/components/autofill/ios/browser/autofill_driver_ios.h
@@ -74,6 +74,8 @@ const std::u16string& value) override; void SendFieldsEligibleForManualFillingToRenderer( const std::vector<FieldGlobalId>& fields) override; + void SetShouldSuppressKeyboard(bool suppress) override; + void TriggerReparseInAllFrames() override; AutofillClient* client() { return client_; }
diff --git a/components/autofill/ios/browser/autofill_driver_ios.mm b/components/autofill/ios/browser/autofill_driver_ios.mm index d530158..5333c13 100644 --- a/components/autofill/ios/browser/autofill_driver_ios.mm +++ b/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -141,6 +141,14 @@ void AutofillDriverIOS::SendFieldsEligibleForManualFillingToRenderer( const std::vector<FieldGlobalId>& fields) {} +void AutofillDriverIOS::SetShouldSuppressKeyboard(bool suppress) { + NOTIMPLEMENTED(); +} + +void AutofillDriverIOS::TriggerReparseInAllFrames() { + NOTIMPLEMENTED(); +} + void AutofillDriverIOS::RendererShouldClearFilledSection() {} void AutofillDriverIOS::RendererShouldClearPreviewedForm() {
diff --git a/components/bookmarks/browser/url_index.cc b/components/bookmarks/browser/url_index.cc index 1f6cdd60..9ac31d5 100644 --- a/components/bookmarks/browser/url_index.cc +++ b/components/bookmarks/browser/url_index.cc
@@ -65,6 +65,15 @@ duplicate_title_and_parent_count; } +void AddTimeStatsForBookmark(BookmarkNode* node, UrlLoadStats* stats) { + stats->avg_num_days_since_added += + (base::Time::Now() - node->date_added()).InDays(); + + if (node->date_last_used() != base::Time()) { + stats->used_url_bookmark_count += 1; + } +} + } // namespace UrlIndex::UrlIndex(std::unique_ptr<BookmarkNode> root) @@ -131,6 +140,9 @@ base::AutoLock url_lock(url_lock_); UrlLoadStats stats; stats.total_url_bookmark_count = nodes_ordered_by_url_set_.size(); + if (nodes_ordered_by_url_set_.begin() != nodes_ordered_by_url_set_.end()) { + AddTimeStatsForBookmark(*nodes_ordered_by_url_set_.begin(), &stats); + } if (stats.total_url_bookmark_count <= 1) return stats; @@ -139,14 +151,14 @@ auto prev_i = nodes_ordered_by_url_set_.begin(); for (auto i = std::next(prev_i); i != nodes_ordered_by_url_set_.end(); ++i, ++prev_i) { + // Handle duplicate URL stats. if ((*prev_i)->url() != (*i)->url()) { AddStatsForBookmarksWithSameUrl(&bookmarks_with_same_url, &stats); bookmarks_with_same_url.clear(); } - - stats.avg_num_days_since_added += - (base::Time::Now() - (*i)->date_added()).InDays(); bookmarks_with_same_url.push_back(*i); + + AddTimeStatsForBookmark(*i, &stats); } stats.avg_num_days_since_added /= nodes_ordered_by_url_set_.size();
diff --git a/components/bookmarks/common/bookmark_metrics.cc b/components/bookmarks/common/bookmark_metrics.cc index 15c956f..41ccb4a 100644 --- a/components/bookmarks/common/bookmark_metrics.cc +++ b/components/bookmarks/common/bookmark_metrics.cc
@@ -101,6 +101,24 @@ base::UmaHistogramCounts1000( "Bookmarks.Times.OnProfileLoad.TimeSinceAdded3", base::saturated_cast<int>(stats.avg_num_days_since_added)); + + int utilization; + if (stats.used_url_bookmark_count == 0) { + utilization = 0; + } else { + // Calculate the utilization as a percentage from 0 - 100. Do this without + // a float conversion by multiplying everything by 100 first. + utilization = (100 * stats.used_url_bookmark_count + + stats.total_url_bookmark_count / 2) / + stats.total_url_bookmark_count; + } + base::UmaHistogramPercentage( + "Bookmarks.Utilization.OnProfileLoad.PercentUsed", utilization); + base::UmaHistogramCounts1000("Bookmarks.Utilization.OnProfileLoad.TotalUsed", + stats.used_url_bookmark_count); + base::UmaHistogramCounts1000( + "Bookmarks.Utilization.OnProfileLoad.TotalUnused", + stats.total_url_bookmark_count - stats.used_url_bookmark_count); } void RecordCloneBookmarkNode(int num_cloned) {
diff --git a/components/bookmarks/common/url_load_stats.h b/components/bookmarks/common/url_load_stats.h index 42bf157..8db7ab6 100644 --- a/components/bookmarks/common/url_load_stats.h +++ b/components/bookmarks/common/url_load_stats.h
@@ -25,6 +25,10 @@ size_t duplicate_url_and_title_and_parent_bookmark_count = 0; // Average number of days since each bookmark was added. size_t avg_num_days_since_added = 0; + // Number of bookmarks which have a non-default value for time_since_opened. + // This hints that this bookmark has been used before, but isn't conclusive + // as this number is reset with history clear events. + size_t used_url_bookmark_count = 0; }; } // namespace bookmarks
diff --git a/components/browser_ui/settings/android/BUILD.gn b/components/browser_ui/settings/android/BUILD.gn index 2bee722..dcfc759 100644 --- a/components/browser_ui/settings/android/BUILD.gn +++ b/components/browser_ui/settings/android/BUILD.gn
@@ -113,8 +113,6 @@ "widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java", "widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java", "widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreferenceTest.java", - "widget/javatests/src/org/chromium/components/browser_ui/settings/ManagedPreferencesUtilsTest.java", - "widget/javatests/src/org/chromium/components/browser_ui/settings/Matchers.java", ] deps = [ ":java", @@ -127,31 +125,52 @@ "//content/public/test/android:content_java_test_support", "//third_party/android_deps:espresso_java", "//third_party/android_deps:guava_android_java", - "//third_party/android_support_test_runner:rules_java", - "//third_party/android_support_test_runner:runner_java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//third_party/androidx:androidx_constraintlayout_constraintlayout_java", - "//third_party/androidx:androidx_fragment_fragment_java", "//third_party/androidx:androidx_preference_preference_java", "//third_party/androidx:androidx_test_runner_java", "//third_party/hamcrest:hamcrest_java", "//third_party/junit", - "//third_party/mockito:mockito_java", "//ui/android:ui_java_test_support", - "//ui/android:ui_no_recycler_view_java", ] resources_package = "org.chromium.components.browser_ui.settings.test" } +robolectric_library("junit") { + testonly = true + + sources = [ "java/src/org/chromium/components/browser_ui/settings/ManagedPreferencesUtilsTest.java" ] + + deps = [ + ":java", + ":java_resources", + ":managed_prefs_java_resources", + ":test_support_java", + "//base:base_java", + "//base:base_java_test_support", + "//base:base_junit_test_support", + "//content/public/test/android:content_java_test_support", + "//third_party/androidx:androidx_constraintlayout_constraintlayout_java", + "//third_party/androidx:androidx_preference_preference_java", + "//third_party/androidx:androidx_test_runner_java", + "//third_party/junit", + "//ui/android:ui_java_test_support", + ] + + resources_package = "org.chromium.components.browser_ui.settings.test" +} + android_library("test_support_java") { testonly = true sources = [ "widget/javatests/src/org/chromium/components/browser_ui/settings/BlankUiTestActivitySettingsTestRule.java", + "widget/javatests/src/org/chromium/components/browser_ui/settings/ManagedPreferenceTestDelegates.java", + "widget/javatests/src/org/chromium/components/browser_ui/settings/Matchers.java", "widget/javatests/src/org/chromium/components/browser_ui/settings/PlaceholderSettingsForTest.java", ] deps = [ + ":java", + ":managed_prefs_java_resources", "//base:base_java_test_support", "//content/public/test/android:content_java_test_support", "//third_party/androidx:androidx_annotation_annotation_java", @@ -160,6 +179,8 @@ "//third_party/hamcrest:hamcrest_java", "//ui/android:ui_java_test_support", ] + + resources_package = "org.chromium.components.browser_ui.settings.test" } android_resources("java_test_resources") {
diff --git a/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/ManagedPreferencesUtilsTest.java b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/ManagedPreferencesUtilsTest.java new file mode 100644 index 0000000..00d90de --- /dev/null +++ b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/ManagedPreferencesUtilsTest.java
@@ -0,0 +1,140 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.browser_ui.settings; + +import static org.junit.Assert.assertTrue; + +import android.app.Activity; + +import androidx.preference.Preference; +import androidx.test.filters.SmallTest; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowToast; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.Batch; +import org.chromium.components.browser_ui.settings.test.R; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.ui.base.TestActivity; + +/** Tests of {@link ManagedPreferencesUtils}. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE, shadows = {ShadowToast.class}) +@Batch(Batch.PER_CLASS) +public class ManagedPreferencesUtilsTest { + private Activity mActivity; + + @Before + public void setup() { + mActivity = Robolectric.buildActivity(TestActivity.class).get(); + } + + @After + public void tearDown() { + ShadowToast.reset(); + } + + @Test + @SmallTest + public void testShowManagedByAdministratorToast() { + TestThreadUtils.runOnUiThreadBlockingNoException(() -> { + return ManagedPreferencesUtils.showManagedByAdministratorToast(mActivity); + }); + + assertTrue("Toast is not as expected", + ShadowToast.showedCustomToast( + mActivity.getResources().getString(R.string.managed_by_your_organization), + R.id.toast_text)); + } + + @Test + @SmallTest + public void testShowManagedByParentToastNullDelegate() { + TestThreadUtils.runOnUiThreadBlockingNoException(() -> { + return ManagedPreferencesUtils.showManagedByParentToast(mActivity, null); + }); + + assertTrue("Toast is not as expected", + ShadowToast.showedCustomToast( + mActivity.getResources().getString(R.string.managed_by_your_parent), + R.id.toast_text)); + } + + @Test + @SmallTest + public void testShowManagedByParentToastSingleCustodian() { + TestThreadUtils.runOnUiThreadBlockingNoException(() -> { + return ManagedPreferencesUtils.showManagedByParentToast( + mActivity, ManagedPreferenceTestDelegates.SINGLE_CUSTODIAN_DELEGATE); + }); + + assertTrue("Toast is not as expected", + ShadowToast.showedCustomToast( + mActivity.getResources().getString(R.string.managed_by_your_parent), + R.id.toast_text)); + } + + @Test + @SmallTest + public void testShowManagedByParentToastMultipleCustodians() { + TestThreadUtils.runOnUiThreadBlockingNoException(() -> { + return ManagedPreferencesUtils.showManagedByParentToast( + mActivity, ManagedPreferenceTestDelegates.MULTI_CUSTODIAN_DELEGATE); + }); + + assertTrue("Toast is not as expected", + ShadowToast.showedCustomToast( + mActivity.getResources().getString(R.string.managed_by_your_parents), + R.id.toast_text)); + } + + @Test + @SmallTest + public void testShowManagedSettingsCannotBeResetToast() { + TestThreadUtils.runOnUiThreadBlockingNoException(() -> { + return ManagedPreferencesUtils.showManagedSettingsCannotBeResetToast(mActivity); + }); + + assertTrue("Toast is not as expected", + ShadowToast.showedCustomToast(mActivity.getResources().getString( + R.string.managed_settings_cannot_be_reset), + R.id.toast_text)); + } + + @Test + @SmallTest + public void testGetManagedIconIdNull() { + Preference pref = new Preference(mActivity); + int actual = ManagedPreferencesUtils.getManagedIconResId(null, pref); + Assert.assertEquals(0, actual); + } + + @Test + @SmallTest + public void testGetManagedIconIdPolicy() { + Preference pref = new Preference(mActivity); + int expected = ManagedPreferencesUtils.getManagedByEnterpriseIconId(); + int actual = ManagedPreferencesUtils.getManagedIconResId( + ManagedPreferenceTestDelegates.POLICY_DELEGATE, pref); + Assert.assertEquals(expected, actual); + } + + @Test + @SmallTest + public void testGetManagedIconIdCustodian() { + Preference pref = new Preference(mActivity); + int expected = ManagedPreferencesUtils.getManagedByCustodianIconId(); + int actual = ManagedPreferencesUtils.getManagedIconResId( + ManagedPreferenceTestDelegates.SINGLE_CUSTODIAN_DELEGATE, pref); + Assert.assertEquals(expected, actual); + } +}
diff --git a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java index d8acbc3e..2f724d7 100644 --- a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java +++ b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeBasePreferenceTest.java
@@ -99,7 +99,7 @@ ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setSummary(SUMMARY); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.UNMANAGED_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.UNMANAGED_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertTrue(preference.isEnabled()); @@ -118,7 +118,7 @@ public void testPolicyManagedPreferenceWithoutSummary() { ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled()); @@ -145,7 +145,7 @@ ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setSummary(SUMMARY); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled()); @@ -174,7 +174,7 @@ ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate( - ManagedPreferencesUtilsTest.SINGLE_CUSTODIAN_DELEGATE); + ManagedPreferenceTestDelegates.SINGLE_CUSTODIAN_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled()); @@ -196,7 +196,7 @@ ChromeBasePreference preference = new ChromeBasePreference(mActivity); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate( - ManagedPreferencesUtilsTest.MULTI_CUSTODIAN_DELEGATE); + ManagedPreferenceTestDelegates.MULTI_CUSTODIAN_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled()); @@ -223,7 +223,8 @@ fragment.findPreference("preference_with_custom_layout"); preference.setTitle(TITLE); preference.setSummary(SUMMARY); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.UNMANAGED_DELEGATE); + preference.setManagedPreferenceDelegate( + ManagedPreferenceTestDelegates.UNMANAGED_DELEGATE); }); ChromeBasePreference preference = fragment.findPreference("preference_with_custom_layout"); @@ -248,7 +249,7 @@ fragment.findPreference("preference_with_custom_layout"); preference.setTitle(TITLE); preference.setSummary(SUMMARY); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); }); ChromeBasePreference preference = fragment.findPreference("preference_with_custom_layout"); @@ -275,7 +276,7 @@ ChromeBasePreference preference = fragment.findPreference("preference_with_custom_layout"); preference.setTitle(TITLE); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); }); ChromeBasePreference preference = fragment.findPreference("preference_with_custom_layout"); @@ -301,7 +302,7 @@ fragment.findPreference("preference_with_custom_layout"); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate( - ManagedPreferencesUtilsTest.SINGLE_CUSTODIAN_DELEGATE); + ManagedPreferenceTestDelegates.SINGLE_CUSTODIAN_DELEGATE); }); ChromeBasePreference preference = fragment.findPreference("preference_with_custom_layout");
diff --git a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java index 376ca01..586544d 100644 --- a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java +++ b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeImageViewPreferenceTest.java
@@ -82,7 +82,7 @@ ChromeImageViewPreference preference = new ChromeImageViewPreference(mActivity); preference.setTitle(TITLE); preference.setImageView(DRAWABLE_RES, CONTENT_DESCRIPTION_RES, null); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled());
diff --git a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreferenceTest.java b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreferenceTest.java index 20bb090..4223fc08 100644 --- a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreferenceTest.java +++ b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreferenceTest.java
@@ -100,7 +100,7 @@ ChromeSwitchPreference preference = new ChromeSwitchPreference(mActivity); preference.setTitle(TITLE); preference.setSummary(SUMMARY); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.UNMANAGED_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.UNMANAGED_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertTrue(preference.isEnabled()); @@ -120,7 +120,7 @@ public void testPolicyManagedPreferenceWithoutSummary() { ChromeSwitchPreference preference = new ChromeSwitchPreference(mActivity); preference.setTitle(TITLE); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled()); @@ -148,7 +148,7 @@ ChromeSwitchPreference preference = new ChromeSwitchPreference(mActivity); preference.setTitle(TITLE); preference.setSummary(SUMMARY); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled()); @@ -179,7 +179,7 @@ ChromeSwitchPreference preference = new ChromeSwitchPreference(mActivity); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate( - ManagedPreferencesUtilsTest.SINGLE_CUSTODIAN_DELEGATE); + ManagedPreferenceTestDelegates.SINGLE_CUSTODIAN_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled()); @@ -202,7 +202,7 @@ ChromeSwitchPreference preference = new ChromeSwitchPreference(mActivity); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate( - ManagedPreferencesUtilsTest.MULTI_CUSTODIAN_DELEGATE); + ManagedPreferenceTestDelegates.MULTI_CUSTODIAN_DELEGATE); mPreferenceScreen.addPreference(preference); Assert.assertFalse(preference.isEnabled()); @@ -230,7 +230,8 @@ fragment.findPreference("preference_with_custom_layout"); preference.setTitle(TITLE); preference.setSummary(SUMMARY); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.UNMANAGED_DELEGATE); + preference.setManagedPreferenceDelegate( + ManagedPreferenceTestDelegates.UNMANAGED_DELEGATE); }); ChromeSwitchPreference preference = @@ -257,7 +258,7 @@ fragment.findPreference("preference_with_custom_layout"); preference.setTitle(TITLE); preference.setSummary(SUMMARY); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); }); ChromeSwitchPreference preference = @@ -286,7 +287,7 @@ ChromeSwitchPreference preference = fragment.findPreference("preference_with_custom_layout"); preference.setTitle(TITLE); - preference.setManagedPreferenceDelegate(ManagedPreferencesUtilsTest.POLICY_DELEGATE); + preference.setManagedPreferenceDelegate(ManagedPreferenceTestDelegates.POLICY_DELEGATE); }); ChromeSwitchPreference preference = @@ -314,7 +315,7 @@ fragment.findPreference("preference_with_custom_layout"); preference.setTitle(TITLE); preference.setManagedPreferenceDelegate( - ManagedPreferencesUtilsTest.SINGLE_CUSTODIAN_DELEGATE); + ManagedPreferenceTestDelegates.SINGLE_CUSTODIAN_DELEGATE); }); ChromeSwitchPreference preference =
diff --git a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ManagedPreferenceTestDelegates.java b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ManagedPreferenceTestDelegates.java new file mode 100644 index 0000000..0b8569a --- /dev/null +++ b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ManagedPreferenceTestDelegates.java
@@ -0,0 +1,114 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.browser_ui.settings; + +import androidx.annotation.LayoutRes; +import androidx.preference.Preference; + +import org.chromium.components.browser_ui.settings.test.R; + +/** Instances of {@link ManagedPreferenceDelegate} used by tests. */ +public class ManagedPreferenceTestDelegates { + public static final ManagedPreferenceDelegate UNMANAGED_DELEGATE = + new ManagedPreferenceDelegate() { + @Override + public boolean isPreferenceControlledByPolicy(Preference preference) { + return false; + } + + @Override + public boolean isPreferenceControlledByCustodian(Preference preference) { + return false; + } + + @Override + public boolean doesProfileHaveMultipleCustodians() { + return false; + } + + @Override + public @LayoutRes int defaultPreferenceLayoutResource() { + return 0; + } + }; + + public static final ManagedPreferenceDelegate POLICY_DELEGATE = + new ManagedPreferenceDelegate() { + @Override + public boolean isPreferenceControlledByPolicy(Preference preference) { + return true; + } + + @Override + public boolean isPreferenceControlledByCustodian(Preference preference) { + return false; + } + + @Override + public boolean doesProfileHaveMultipleCustodians() { + return false; + } + + @Override + public @LayoutRes int defaultPreferenceLayoutResource() { + return SettingsFeatureList.isEnabled( + SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID) + ? R.layout.chrome_managed_preference + : 0; + } + }; + + public static final ManagedPreferenceDelegate SINGLE_CUSTODIAN_DELEGATE = + new ManagedPreferenceDelegate() { + @Override + public boolean isPreferenceControlledByPolicy(Preference preference) { + return false; + } + + @Override + public boolean isPreferenceControlledByCustodian(Preference preference) { + return true; + } + + @Override + public boolean doesProfileHaveMultipleCustodians() { + return false; + } + + @Override + public @LayoutRes int defaultPreferenceLayoutResource() { + return SettingsFeatureList.isEnabled( + SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID) + ? R.layout.chrome_managed_preference + : 0; + } + }; + + public static final ManagedPreferenceDelegate MULTI_CUSTODIAN_DELEGATE = + new ManagedPreferenceDelegate() { + @Override + public boolean isPreferenceControlledByPolicy(Preference preference) { + return false; + } + + @Override + public boolean isPreferenceControlledByCustodian(Preference preference) { + return true; + } + + @Override + public boolean doesProfileHaveMultipleCustodians() { + return true; + } + + @Override + public @LayoutRes int defaultPreferenceLayoutResource() { + return SettingsFeatureList.isEnabled( + SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID) + ? R.layout.chrome_managed_preference + : 0; + } + }; +}
diff --git a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ManagedPreferencesUtilsTest.java b/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ManagedPreferencesUtilsTest.java deleted file mode 100644 index 0d66280..0000000 --- a/components/browser_ui/settings/android/widget/javatests/src/org/chromium/components/browser_ui/settings/ManagedPreferencesUtilsTest.java +++ /dev/null
@@ -1,232 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.browser_ui.settings; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.RootMatchers.withDecorView; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import static org.hamcrest.Matchers.not; - -import android.support.test.InstrumentationRegistry; - -import androidx.annotation.LayoutRes; -import androidx.preference.Preference; -import androidx.test.filters.SmallTest; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.Batch; -import org.chromium.components.browser_ui.settings.test.R; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.test.util.BlankUiTestActivityTestCase; -import org.chromium.ui.widget.Toast; - -/** Tests of {@link ManagedPreferencesUtils}. */ -@RunWith(BaseJUnit4ClassRunner.class) -@Batch(Batch.PER_CLASS) -public class ManagedPreferencesUtilsTest extends BlankUiTestActivityTestCase { - public static final ManagedPreferenceDelegate UNMANAGED_DELEGATE = - new ManagedPreferenceDelegate() { - @Override - public boolean isPreferenceControlledByPolicy(Preference preference) { - return false; - } - - @Override - public boolean isPreferenceControlledByCustodian(Preference preference) { - return false; - } - - @Override - public boolean doesProfileHaveMultipleCustodians() { - return false; - } - - @Override - public @LayoutRes int defaultPreferenceLayoutResource() { - return 0; - } - }; - - public static final ManagedPreferenceDelegate POLICY_DELEGATE = - new ManagedPreferenceDelegate() { - @Override - public boolean isPreferenceControlledByPolicy(Preference preference) { - return true; - } - - @Override - public boolean isPreferenceControlledByCustodian(Preference preference) { - return false; - } - - @Override - public boolean doesProfileHaveMultipleCustodians() { - return false; - } - - @Override - public @LayoutRes int defaultPreferenceLayoutResource() { - return SettingsFeatureList.isEnabled( - SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID) - ? R.layout.chrome_managed_preference - : 0; - } - }; - - public static final ManagedPreferenceDelegate SINGLE_CUSTODIAN_DELEGATE = - new ManagedPreferenceDelegate() { - @Override - public boolean isPreferenceControlledByPolicy(Preference preference) { - return false; - } - - @Override - public boolean isPreferenceControlledByCustodian(Preference preference) { - return true; - } - - @Override - public boolean doesProfileHaveMultipleCustodians() { - return false; - } - - @Override - public @LayoutRes int defaultPreferenceLayoutResource() { - return SettingsFeatureList.isEnabled( - SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID) - ? R.layout.chrome_managed_preference - : 0; - } - }; - - public static final ManagedPreferenceDelegate MULTI_CUSTODIAN_DELEGATE = - new ManagedPreferenceDelegate() { - @Override - public boolean isPreferenceControlledByPolicy(Preference preference) { - return false; - } - - @Override - public boolean isPreferenceControlledByCustodian(Preference preference) { - return true; - } - - @Override - public boolean doesProfileHaveMultipleCustodians() { - return true; - } - - @Override - public @LayoutRes int defaultPreferenceLayoutResource() { - return SettingsFeatureList.isEnabled( - SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID) - ? R.layout.chrome_managed_preference - : 0; - } - }; - - @Test - @SmallTest - public void testShowManagedByAdministratorToast() { - Toast toast = TestThreadUtils.runOnUiThreadBlockingNoException(() -> { - return ManagedPreferencesUtils.showManagedByAdministratorToast(getActivity()); - }); - - onView(withText(R.string.managed_by_your_organization)) - .inRoot(withDecorView(not(getActivity().getWindow().getDecorView()))) - .check(matches(isDisplayed())); - - TestThreadUtils.runOnUiThreadBlocking(() -> toast.cancel()); - } - - @Test - @SmallTest - public void testShowManagedByParentToastNullDelegate() { - Toast toast = TestThreadUtils.runOnUiThreadBlockingNoException(() -> { - return ManagedPreferencesUtils.showManagedByParentToast(getActivity(), null); - }); - - onView(withText(R.string.managed_by_your_parent)) - .inRoot(withDecorView(not(getActivity().getWindow().getDecorView()))) - .check(matches(isDisplayed())); - - TestThreadUtils.runOnUiThreadBlocking(() -> toast.cancel()); - } - - @Test - @SmallTest - public void testShowManagedByParentToastSingleCustodian() { - Toast toast = TestThreadUtils.runOnUiThreadBlockingNoException(() -> { - return ManagedPreferencesUtils.showManagedByParentToast( - getActivity(), SINGLE_CUSTODIAN_DELEGATE); - }); - - onView(withText(R.string.managed_by_your_parent)) - .inRoot(withDecorView(not(getActivity().getWindow().getDecorView()))) - .check(matches(isDisplayed())); - - TestThreadUtils.runOnUiThreadBlocking(() -> toast.cancel()); - } - - @Test - @SmallTest - public void testShowManagedByParentToastMultipleCustodians() { - Toast toast = TestThreadUtils.runOnUiThreadBlockingNoException(() -> { - return ManagedPreferencesUtils.showManagedByParentToast( - getActivity(), MULTI_CUSTODIAN_DELEGATE); - }); - - onView(withText(R.string.managed_by_your_parents)) - .inRoot(withDecorView(not(getActivity().getWindow().getDecorView()))) - .check(matches(isDisplayed())); - - TestThreadUtils.runOnUiThreadBlocking(() -> toast.cancel()); - } - - @Test - @SmallTest - public void testShowManagedSettingsCannotBeResetToast() { - Toast toast = TestThreadUtils.runOnUiThreadBlockingNoException(() -> { - return ManagedPreferencesUtils.showManagedSettingsCannotBeResetToast(getActivity()); - }); - - onView(withText(R.string.managed_settings_cannot_be_reset)) - .inRoot(withDecorView(not(getActivity().getWindow().getDecorView()))) - .check(matches(isDisplayed())); - } - - @Test - @SmallTest - public void testGetManagedIconIdNull() { - Preference pref = new Preference(InstrumentationRegistry.getTargetContext()); - int actual = ManagedPreferencesUtils.getManagedIconResId(null, pref); - Assert.assertEquals(0, actual); - } - - @Test - @SmallTest - public void testGetManagedIconIdPolicy() { - Preference pref = new Preference(InstrumentationRegistry.getTargetContext()); - int expected = ManagedPreferencesUtils.getManagedByEnterpriseIconId(); - int actual = ManagedPreferencesUtils.getManagedIconResId(POLICY_DELEGATE, pref); - Assert.assertEquals(expected, actual); - } - - @Test - @SmallTest - public void testGetManagedIconIdCustodian() { - Preference pref = new Preference(InstrumentationRegistry.getTargetContext()); - int expected = ManagedPreferencesUtils.getManagedByCustodianIconId(); - int actual = ManagedPreferencesUtils.getManagedIconResId(SINGLE_CUSTODIAN_DELEGATE, pref); - Assert.assertEquals(expected, actual); - } -}
diff --git a/components/browser_ui/site_settings/android/java/res/xml/site_settings_preferences_with_categories.xml b/components/browser_ui/site_settings/android/java/res/xml/site_settings_preferences_with_categories.xml index 7ad3b0e..94891c6a 100644 --- a/components/browser_ui/site_settings/android/java/res/xml/site_settings_preferences_with_categories.xml +++ b/components/browser_ui/site_settings/android/java/res/xml/site_settings_preferences_with_categories.xml
@@ -20,6 +20,7 @@ android:icon="@drawable/settings_all_sites" app:iconTint="@macro/default_icon_color" /> + <!-- PERMISSIONS section --> <PreferenceCategory android:title="@string/site_settings_permission_category"/> <!-- Location --> <org.chromium.components.browser_ui.settings.ChromeBasePreference @@ -73,21 +74,8 @@ <org.chromium.components.browser_ui.settings.ChromeBasePreference android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" android:key="idle_detection" /> - <!-- Federated Identity API --> - <org.chromium.components.browser_ui.settings.ChromeBasePreference - android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" - android:key="federated_identity_api" /> - <!-- Auto-dark Web Content --> - <org.chromium.components.browser_ui.settings.ChromeBasePreference - android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" - android:key="auto_dark_web_content" /> - <!-- Request Desktop Site --> - <!-- TODO(crbug.com/1243758): Update the location of this setting once approved. - Also update site_settings_preferences.xml. --> - <org.chromium.components.browser_ui.settings.ChromeBasePreference - android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" - android:key="request_desktop_site" /> + <!-- CONTENT SETTINGS section --> <PreferenceCategory android:title="@string/site_settings_content_category"/> <!-- Third party cookies --> <org.chromium.components.browser_ui.settings.ChromeBasePreference @@ -95,10 +83,6 @@ android:icon="@drawable/permission_cookie" app:iconTint="@macro/default_icon_color" android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" /> - <!-- Site data --> - <org.chromium.components.browser_ui.settings.ChromeBasePreference - android:key="site_data" - android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" /> <!-- JavaScript --> <org.chromium.components.browser_ui.settings.ChromeBasePreference android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" @@ -107,10 +91,36 @@ <org.chromium.components.browser_ui.settings.ChromeBasePreference android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" android:key="popups" /> + <!-- Sound --> + <org.chromium.components.browser_ui.settings.ChromeBasePreference + android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" + android:key="sound" /> <!-- Ads --> <org.chromium.components.browser_ui.settings.ChromeBasePreference android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" android:key="ads" /> + <!-- Protected content --> + <org.chromium.components.browser_ui.settings.ChromeBasePreference + android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" + android:key="protected_content" /> + <!-- Federated Identity API --> + <org.chromium.components.browser_ui.settings.ChromeBasePreference + android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" + android:key="federated_identity_api" /> + <!-- Site data --> + <org.chromium.components.browser_ui.settings.ChromeBasePreference + android:key="site_data" + android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" /> + <!-- Request Desktop Site --> + <!-- TODO(crbug.com/1243758): Update the location of this setting once approved. + Also update site_settings_preferences.xml. --> + <org.chromium.components.browser_ui.settings.ChromeBasePreference + android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" + android:key="request_desktop_site" /> + <!-- Auto-dark Web Content --> + <org.chromium.components.browser_ui.settings.ChromeBasePreference + android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" + android:key="auto_dark_web_content" /> <!-- Background sync --> <org.chromium.components.browser_ui.settings.ChromeBasePreference android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" @@ -119,14 +129,7 @@ <org.chromium.components.browser_ui.settings.ChromeBasePreference android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" android:key="automatic_downloads" /> - <!-- Protected content --> - <org.chromium.components.browser_ui.settings.ChromeBasePreference - android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" - android:key="protected_content" /> - <!-- Sound --> - <org.chromium.components.browser_ui.settings.ChromeBasePreference - android:fragment="org.chromium.components.browser_ui.site_settings.SingleCategorySettings" - android:key="sound" /> + <!-- Storage --> <!-- TODO(finnur): Move this over to the new Usage screen, once it exists. Also update site_settings_preferences.xml. -->
diff --git a/components/cast_streaming/public/BUILD.gn b/components/cast_streaming/public/BUILD.gn index 19390122..2e55ea8 100644 --- a/components/cast_streaming/public/BUILD.gn +++ b/components/cast_streaming/public/BUILD.gn
@@ -4,12 +4,9 @@ import("//testing/test.gni") -visibility = [ ":*" ] - # TODO(crbug.com/1357085): Determine whether we need all these separate targets. source_set("public") { - visibility += [ "*" ] public = [ "app_ids.h", "cast_streaming_url.h", @@ -29,12 +26,10 @@ } source_set("demuxer_stream_traits") { - visibility += [ "*" ] public = [ "demuxer_stream_traits.h" ] } source_set("config_conversions") { - visibility += [ "*" ] public = [ "config_conversions.h" ] sources = [ "config_conversions.cc" ] public_deps = [ @@ -47,8 +42,22 @@ ] } +source_set("decoder_buffer_reader") { + public = [ "decoder_buffer_reader.h" ] + sources = [ "decoder_buffer_reader.cc" ] + public_deps = [ + "//base", + "//media/mojo/mojom", + "//mojo/public/cpp/system", + ] + deps = [ + "//media", + "//media/mojo/common", + "//mojo/public/cpp/system", + ] +} + source_set("remoting_utils") { - visibility += [ "*" ] public = [ "remoting_message_factories.h", "remoting_proto_enum_utils.h", @@ -74,19 +83,22 @@ source_set("unit_tests") { testonly = true - visibility += [ "//components/cast_streaming:unit_tests" ] public = [] sources = [ "config_conversions_unittest.cc", + "decoder_buffer_reader_unittest.cc", "remoting_message_factories_unittest.cc", "remoting_proto_utils_unittest.cc", "rpc_call_message_handler_unittest.cc", ] deps = [ ":config_conversions", + ":decoder_buffer_reader", ":remoting_utils", + "//base/test:test_support", "//media", "//media:test_support", + "//media/mojo/common", "//testing/gmock", "//testing/gtest", "//third_party/openscreen/src/cast/streaming:remoting_proto",
diff --git a/components/cast_streaming/public/DEPS b/components/cast_streaming/public/DEPS index 74809279..552ae39 100644 --- a/components/cast_streaming/public/DEPS +++ b/components/cast_streaming/public/DEPS
@@ -1,5 +1,7 @@ include_rules = [ "+media/base", + "+media/mojo", + "+mojo/public", "+third_party/openscreen/src/cast/common", "+third_party/openscreen/src/cast/streaming", "+ui/gfx/geometry",
diff --git a/components/cast_streaming/renderer/decoder_buffer_reader.cc b/components/cast_streaming/public/decoder_buffer_reader.cc similarity index 91% rename from components/cast_streaming/renderer/decoder_buffer_reader.cc rename to components/cast_streaming/public/decoder_buffer_reader.cc index 203e5d4..115ac40 100644 --- a/components/cast_streaming/renderer/decoder_buffer_reader.cc +++ b/components/cast_streaming/public/decoder_buffer_reader.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/cast_streaming/renderer/decoder_buffer_reader.h" +#include "components/cast_streaming/public/decoder_buffer_reader.h" #include "base/functional/bind.h" @@ -50,22 +50,25 @@ void DecoderBufferReader::CompletePendingRead() { DVLOG(3) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!is_read_pending_ || !current_buffer_) + if (!is_read_pending_ || !current_buffer_) { return; + } is_read_pending_ = false; const bool is_eos = current_buffer_->end_of_stream(); new_buffer_cb_.Run(std::move(current_buffer_)); - if (!is_eos) + if (!is_eos) { TryGetNextBuffer(); + } } void DecoderBufferReader::TryGetNextBuffer() { DVLOG(3) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (current_buffer_ || pending_buffer_metadata_.empty()) + if (current_buffer_ || pending_buffer_metadata_.empty()) { return; + } media::mojom::DecoderBufferPtr buffer = std::move(pending_buffer_metadata_.front());
diff --git a/components/cast_streaming/renderer/decoder_buffer_reader.h b/components/cast_streaming/public/decoder_buffer_reader.h similarity index 74% rename from components/cast_streaming/renderer/decoder_buffer_reader.h rename to components/cast_streaming/public/decoder_buffer_reader.h index a02e1005..300c42b 100644 --- a/components/cast_streaming/renderer/decoder_buffer_reader.h +++ b/components/cast_streaming/public/decoder_buffer_reader.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_CAST_STREAMING_RENDERER_DECODER_BUFFER_READER_H_ -#define COMPONENTS_CAST_STREAMING_RENDERER_DECODER_BUFFER_READER_H_ +#ifndef COMPONENTS_CAST_STREAMING_PUBLIC_DECODER_BUFFER_READER_H_ +#define COMPONENTS_CAST_STREAMING_PUBLIC_DECODER_BUFFER_READER_H_ #include "base/containers/circular_deque.h" #include "base/functional/callback.h" @@ -17,7 +17,13 @@ namespace cast_streaming { // This class wraps functionality around reading a media::DecoderBuffer from -// a mojo pipe. +// a mojo pipe, while providing synchronization around the following three +// operations: +// - Providing the media::mojom::DecoderBufferPtr for a pending DecoderBuffer +// read. +// - Reading the data for a DecoderBuffer from a |data_pipe| provided to the +// ctor. +// - Requesting a new buffer callback by the embedding class. class DecoderBufferReader { public: using NewBufferCb = @@ -41,7 +47,8 @@ // call to |new_buffer_cb_| is expected. void ClearReadPending(); - bool is_queue_empty() { return pending_buffer_metadata_.empty(); } + bool is_queue_empty() const { return pending_buffer_metadata_.empty(); } + bool is_read_pending() const { return is_read_pending_; } private: void TryGetNextBuffer(); @@ -63,4 +70,4 @@ } // namespace cast_streaming -#endif // COMPONENTS_CAST_STREAMING_RENDERER_DECODER_BUFFER_READER_H_ +#endif // COMPONENTS_CAST_STREAMING_PUBLIC_DECODER_BUFFER_READER_H_
diff --git a/components/cast_streaming/renderer/decoder_buffer_reader_unittest.cc b/components/cast_streaming/public/decoder_buffer_reader_unittest.cc similarity index 98% rename from components/cast_streaming/renderer/decoder_buffer_reader_unittest.cc rename to components/cast_streaming/public/decoder_buffer_reader_unittest.cc index 4dffd76..bfb758a4 100644 --- a/components/cast_streaming/renderer/decoder_buffer_reader_unittest.cc +++ b/components/cast_streaming/public/decoder_buffer_reader_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/cast_streaming/renderer/decoder_buffer_reader.h" +#include "components/cast_streaming/public/decoder_buffer_reader.h" #include "base/test/bind.h" #include "base/test/task_environment.h"
diff --git a/components/cast_streaming/renderer/BUILD.gn b/components/cast_streaming/renderer/BUILD.gn index 23e50eb..7383219 100644 --- a/components/cast_streaming/renderer/BUILD.gn +++ b/components/cast_streaming/renderer/BUILD.gn
@@ -85,11 +85,7 @@ "buffer_requester.h", "public/decoder_buffer_provider.h", ] - sources = [ - "decoder_buffer_provider_impl.h", - "decoder_buffer_reader.cc", - "decoder_buffer_reader.h", - ] + sources = [ "decoder_buffer_provider_impl.h" ] public_deps = [ "//base", "//components/cast_streaming/public:demuxer_stream_traits", @@ -100,6 +96,7 @@ ] deps = [ "//base", + "//components/cast_streaming/public:decoder_buffer_reader", "//media", "//media/mojo/common", "//mojo/public/cpp/system", @@ -134,7 +131,6 @@ sources = [ "buffer_requester_unittest.cc", "decoder_buffer_provider_impl_unittest.cc", - "decoder_buffer_reader_unittest.cc", "playback_command_forwarding_renderer_factory_unittest.cc", "playback_command_forwarding_renderer_unittest.cc", "web_codecs/delegating_decoder_buffer_provider_unittest.cc",
diff --git a/components/cast_streaming/renderer/decoder_buffer_provider_impl.h b/components/cast_streaming/renderer/decoder_buffer_provider_impl.h index 7ae10dc..93dfb81 100644 --- a/components/cast_streaming/renderer/decoder_buffer_provider_impl.h +++ b/components/cast_streaming/renderer/decoder_buffer_provider_impl.h
@@ -12,7 +12,7 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/task/sequenced_task_runner.h" -#include "components/cast_streaming/renderer/decoder_buffer_reader.h" +#include "components/cast_streaming/public/decoder_buffer_reader.h" #include "components/cast_streaming/renderer/public/decoder_buffer_provider.h" #include "media/base/decoder_buffer.h" #include "media/mojo/mojom/media_types.mojom-forward.h"
diff --git a/components/cdm/common/cdm_manifest_unittest.cc b/components/cdm/common/cdm_manifest_unittest.cc index e7f7066..cd9dd4fc 100644 --- a/components/cdm/common/cdm_manifest_unittest.cc +++ b/components/cdm/common/cdm_manifest_unittest.cc
@@ -61,14 +61,14 @@ return base::JoinString(parts, ","); } -base::Value MakeListValue(const std::string& item) { - base::Value list(base::Value::Type::LIST); +base::Value::List MakeList(const std::string& item) { + base::Value::List list; list.Append(item); return list; } -base::Value MakeListValue(const std::string& item1, const std::string& item2) { - base::Value list(base::Value::Type::LIST); +base::Value::List MakeList(const std::string& item1, const std::string& item2) { + base::Value::List list; list.Append(item1); list.Append(item2); return list; @@ -79,7 +79,7 @@ base::Value::Dict dict; dict.Set(kCdmCodecsListName, "vp8,vp09,av01"); dict.Set(kCdmPersistentLicenseSupportName, true); - dict.Set(kCdmSupportedEncryptionSchemesName, MakeListValue("cenc", "cbcs")); + dict.Set(kCdmSupportedEncryptionSchemesName, MakeList("cenc", "cbcs")); // The following are dependent on what the current code supports. EXPECT_TRUE(media::IsSupportedCdmModuleVersion(kSupportedCdmModuleVersion)); @@ -301,14 +301,14 @@ // Try each valid value individually. { CdmCapability capability; - manifest.Set(kCdmSupportedEncryptionSchemesName, MakeListValue("cenc")); + manifest.Set(kCdmSupportedEncryptionSchemesName, MakeList("cenc")); EXPECT_TRUE(ParseCdmManifest(manifest, &capability)); CheckEncryptionSchemes(capability.encryption_schemes, {media::EncryptionScheme::kCenc}); } { CdmCapability capability; - manifest.Set(kCdmSupportedEncryptionSchemesName, MakeListValue("cbcs")); + manifest.Set(kCdmSupportedEncryptionSchemesName, MakeList("cbcs")); EXPECT_TRUE(ParseCdmManifest(manifest, &capability)); CheckEncryptionSchemes(capability.encryption_schemes, {media::EncryptionScheme::kCbcs}); @@ -316,8 +316,7 @@ { // Try multiple valid entries. CdmCapability capability; - manifest.Set(kCdmSupportedEncryptionSchemesName, - MakeListValue("cenc", "cbcs")); + manifest.Set(kCdmSupportedEncryptionSchemesName, MakeList("cenc", "cbcs")); EXPECT_TRUE(ParseCdmManifest(manifest, &capability)); CheckEncryptionSchemes( capability.encryption_schemes, @@ -327,13 +326,13 @@ // Invalid encryption schemes are ignored. However, if value specified then // there must be at least 1 valid value. CdmCapability capability; - manifest.Set(kCdmSupportedEncryptionSchemesName, MakeListValue("invalid")); + manifest.Set(kCdmSupportedEncryptionSchemesName, MakeList("invalid")); EXPECT_FALSE(ParseCdmManifest(manifest, &capability)); } { CdmCapability capability; manifest.Set(kCdmSupportedEncryptionSchemesName, - MakeListValue("invalid", "cenc")); + MakeList("invalid", "cenc")); EXPECT_TRUE(ParseCdmManifest(manifest, &capability)); CheckEncryptionSchemes(capability.encryption_schemes, {media::EncryptionScheme::kCenc});
diff --git a/components/chromeos_camera/BUILD.gn b/components/chromeos_camera/BUILD.gn index 46b28b8..7bbace877 100644 --- a/components/chromeos_camera/BUILD.gn +++ b/components/chromeos_camera/BUILD.gn
@@ -193,6 +193,7 @@ ":mjpeg_decode_accelerator", ":mjpeg_decode_accelerator_service", "//base", + "//base/test:test_support", "//media:test_support", "//media/gpu", "//media/gpu:buildflags",
diff --git a/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc b/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc index ad39381..7b6fec99 100644 --- a/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc +++ b/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
@@ -33,6 +33,8 @@ #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" #include "base/task/single_thread_task_runner.h" +#include "base/test/task_environment.h" +#include "base/test/test_timeouts.h" #include "base/threading/thread.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" @@ -953,6 +955,9 @@ size_t num_concurrent_decoders = 1); void PerfDecodeByJDA(int decode_times, const std::vector<DecodeTask>& tasks); void PerfDecodeBySW(int decode_times, const std::vector<DecodeTask>& tasks); + + // This is needed to use base::ThreadPool in MjpegDecodeAccelerator. + base::test::TaskEnvironment task_environment_; }; void MjpegDecodeAcceleratorTest::TestDecode( @@ -1303,6 +1308,7 @@ testing::InitGoogleTest(&argc, argv); base::CommandLine::Init(argc, argv); mojo::core::Init(); + TestTimeouts::Initialize(); base::ShadowingAtExitManager at_exit_manager; // Needed to enable DVLOG through --vmodule.
diff --git a/components/commerce/core/BUILD.gn b/components/commerce/core/BUILD.gn index 048b68b..e024e19 100644 --- a/components/commerce/core/BUILD.gn +++ b/components/commerce/core/BUILD.gn
@@ -337,3 +337,25 @@ "//services/network/public/cpp:cpp", ] } + +source_set("account_checker_unittests") { + testonly = true + sources = [ "account_checker_unittest.cc" ] + deps = [ + ":account_checker", + ":feature_list", + ":pref_names", + "//base", + "//base/test:test_support", + "//components/endpoint_fetcher:test_support", + "//components/prefs:test_support", + "//components/signin/public/identity_manager:test_support", + "//net/traffic_annotation:test_support", + "//services/data_decoder/public/cpp:test_support", + "//services/network:test_support", + "//services/network/public/cpp:cpp", + "//testing/gmock", + "//testing/gtest", + "//url:url", + ] +}
diff --git a/components/commerce/core/account_checker.cc b/components/commerce/core/account_checker.cc index 0cc0a9b..6b62b62 100644 --- a/components/commerce/core/account_checker.cc +++ b/components/commerce/core/account_checker.cc
@@ -20,16 +20,7 @@ namespace { -const char kOAuthScope[] = "https://www.googleapis.com/auth/chromememex"; -const char kOAuthName[] = "chromememex_svc"; -const char kGetHttpMethod[] = "GET"; -const char kPostHttpMethod[] = "POST"; -const char kContentType[] = "application/json; charset=UTF-8"; -const char kEmptyPostData[] = ""; const int64_t kTimeoutMs = 10000; - -const char kNotificationsPrefUrl[] = - "https://memex-pa.googleapis.com/v1/notifications/preferences"; const char kPriceTrackEmailPref[] = "price_track_email"; const char kPreferencesKey[] = "preferences"; @@ -37,6 +28,15 @@ namespace commerce { +const char kOAuthScope[] = "https://www.googleapis.com/auth/chromememex"; +const char kOAuthName[] = "chromememex_svc"; +const char kGetHttpMethod[] = "GET"; +const char kPostHttpMethod[] = "POST"; +const char kContentType[] = "application/json; charset=UTF-8"; +const char kEmptyPostData[] = ""; +const char kNotificationsPrefUrl[] = + "https://memex-pa.googleapis.com/v1/notifications/preferences"; + AccountChecker::AccountChecker( PrefService* pref_service, signin::IdentityManager* identity_manager, @@ -56,7 +56,7 @@ pref_change_registrar_->Init(pref_service); pref_change_registrar_->Add( kPriceEmailNotificationsEnabled, - base::BindRepeating(&AccountChecker::SendPriceEmailPref, + base::BindRepeating(&AccountChecker::OnPriceEmailPrefChanged, weak_ptr_factory_.GetWeakPtr())); } } @@ -132,10 +132,10 @@ } } })"); - auto endpoint_fetcher = std::make_unique<EndpointFetcher>( - url_loader_factory_, waa_oauth_name, GURL(waa_query_url), waa_get_method, - waa_content_type, std::vector<std::string>{waa_oauth_scope}, - waa_timeout_ms, waa_post_data, traffic_annotation, identity_manager_); + auto endpoint_fetcher = CreateEndpointFetcher( + waa_oauth_name, GURL(waa_query_url), waa_get_method, waa_content_type, + std::vector<std::string>{waa_oauth_scope}, waa_timeout_ms, waa_post_data, + traffic_annotation); endpoint_fetcher.get()->Fetch(base::BindOnce( &AccountChecker::HandleFetchWaaResponse, weak_ptr_factory_.GetWeakPtr(), std::move(endpoint_fetcher))); @@ -197,10 +197,10 @@ } } })"); - auto endpoint_fetcher = std::make_unique<EndpointFetcher>( - url_loader_factory_, kOAuthName, GURL(kNotificationsPrefUrl), - kGetHttpMethod, kContentType, std::vector<std::string>{kOAuthScope}, - kTimeoutMs, kEmptyPostData, traffic_annotation, identity_manager_); + auto endpoint_fetcher = CreateEndpointFetcher( + kOAuthName, GURL(kNotificationsPrefUrl), kGetHttpMethod, kContentType, + std::vector<std::string>{kOAuthScope}, kTimeoutMs, kEmptyPostData, + traffic_annotation); endpoint_fetcher.get()->Fetch(base::BindOnce( &AccountChecker::HandleFetchPriceEmailPrefResponse, weak_ptr_factory_.GetWeakPtr(), std::move(endpoint_fetcher))); @@ -229,6 +229,7 @@ // PrefService::Preference::IsDefaultValue(). if (pref_service_->GetBoolean(kPriceEmailNotificationsEnabled) != *price_email_pref) { + ignore_next_email_pref_change_ = true; pref_service_->SetBoolean(kPriceEmailNotificationsEnabled, *price_email_pref); } @@ -238,14 +239,20 @@ is_waiting_for_pref_fetch_completion_ = false; } -void AccountChecker::SendPriceEmailPref() { +void AccountChecker::OnPriceEmailPrefChanged() { + // If users update the pref faster than we hear back from the server fetch, + // the fetched result should be discarded. + is_waiting_for_pref_fetch_completion_ = false; + if (ignore_next_email_pref_change_) { + ignore_next_email_pref_change_ = false; + return; + } + if (!IsSignedIn() || !pref_service_) { return; } - // If users update the pref faster than we hear back from the server fetch, - // the fetched result should be discarded. - is_waiting_for_pref_fetch_completion_ = false; + // Send the new value to server. base::Value preferences_map(base::Value::Type::DICTIONARY); preferences_map.SetBoolKey( kPriceTrackEmailPref, @@ -285,10 +292,10 @@ } } })"); - auto endpoint_fetcher = std::make_unique<EndpointFetcher>( - url_loader_factory_, kOAuthName, GURL(kNotificationsPrefUrl), - kPostHttpMethod, kContentType, std::vector<std::string>{kOAuthScope}, - kTimeoutMs, post_data, traffic_annotation, identity_manager_); + auto endpoint_fetcher = CreateEndpointFetcher( + kOAuthName, GURL(kNotificationsPrefUrl), kPostHttpMethod, kContentType, + std::vector<std::string>{kOAuthScope}, kTimeoutMs, post_data, + traffic_annotation); endpoint_fetcher.get()->Fetch(base::BindOnce( &AccountChecker::HandleSendPriceEmailPrefResponse, weak_ptr_factory_.GetWeakPtr(), std::move(endpoint_fetcher))); @@ -318,4 +325,18 @@ } } +std::unique_ptr<EndpointFetcher> AccountChecker::CreateEndpointFetcher( + const std::string& oauth_consumer_name, + const GURL& url, + const std::string& http_method, + const std::string& content_type, + const std::vector<std::string>& scopes, + int64_t timeout_ms, + const std::string& post_data, + const net::NetworkTrafficAnnotationTag& annotation_tag) { + return std::make_unique<EndpointFetcher>( + url_loader_factory_, oauth_consumer_name, url, http_method, content_type, + scopes, timeout_ms, post_data, annotation_tag, identity_manager_); +} + } // namespace commerce
diff --git a/components/commerce/core/account_checker.h b/components/commerce/core/account_checker.h index 169e4555..d2ddb6a 100644 --- a/components/commerce/core/account_checker.h +++ b/components/commerce/core/account_checker.h
@@ -10,14 +10,24 @@ #include "components/endpoint_fetcher/endpoint_fetcher.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/primary_account_change_event.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "services/data_decoder/public/cpp/data_decoder.h" #include "services/network/public/cpp/shared_url_loader_factory.h" +class GURL; class PrefService; class PrefChangeRegistrar; namespace commerce { +extern const char kOAuthScope[]; +extern const char kOAuthName[]; +extern const char kGetHttpMethod[]; +extern const char kPostHttpMethod[]; +extern const char kContentType[]; +extern const char kEmptyPostData[]; +extern const char kNotificationsPrefUrl[]; + // Used to check user account status. class AccountChecker : public signin::IdentityManager::Observer { public: @@ -43,6 +53,17 @@ // Fetch users' pref from server on whether to receive price tracking emails. void FetchPriceEmailPref(); + // This method could be overridden in tests. + virtual std::unique_ptr<EndpointFetcher> CreateEndpointFetcher( + const std::string& oauth_consumer_name, + const GURL& url, + const std::string& http_method, + const std::string& content_type, + const std::vector<std::string>& scopes, + int64_t timeout_ms, + const std::string& post_data, + const net::NetworkTrafficAnnotationTag& annotation_tag); + private: void OnPrimaryAccountChanged( const signin::PrimaryAccountChangeEvent& event_details) override; @@ -62,8 +83,10 @@ void OnFetchWaaJsonParsed(data_decoder::DataDecoder::ValueOrError result); - // Send users' pref to server on whether to receive price tracking emails. - void SendPriceEmailPref(); + // Called when the pref value on whether to receive price tracking emails + // changes. We need to send the new value to server unless the change is + // triggered by aligning with the server fetched value. + void OnPriceEmailPrefChanged(); void HandleSendPriceEmailPrefResponse( // Passing the endpoint_fetcher ensures the endpoint_fetcher's @@ -101,6 +124,11 @@ bool is_waiting_for_pref_fetch_completion_; + // Indicate whether we should ignore the next email pref change. This is true + // only if the change is triggered by aligning with the server fetched value, + // in which case we don't need to send the new value to the server again. + bool ignore_next_email_pref_change_{false}; + base::WeakPtrFactory<AccountChecker> weak_ptr_factory_; };
diff --git a/components/commerce/core/account_checker_unittest.cc b/components/commerce/core/account_checker_unittest.cc new file mode 100644 index 0000000..c16aef16 --- /dev/null +++ b/components/commerce/core/account_checker_unittest.cc
@@ -0,0 +1,182 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <queue> +#include <string> +#include <unordered_map> + +#include "base/check.h" +#include "base/functional/callback.h" +#include "base/run_loop.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/task_environment.h" +#include "components/commerce/core/account_checker.h" +#include "components/commerce/core/commerce_feature_list.h" +#include "components/commerce/core/pref_names.h" +#include "components/endpoint_fetcher/mock_endpoint_fetcher.h" +#include "components/prefs/testing_pref_service.h" +#include "components/signin/public/identity_manager/identity_test_environment.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +using testing::_; +using testing::InSequence; + +namespace { + +const int64_t kTimeoutMs = 10000; +const char kPostData[] = "{\"preferences\":{\"price_track_email\":true}}"; + +} // namespace + +namespace commerce { + +class SpyAccountChecker : public AccountChecker { + public: + SpyAccountChecker( + PrefService* pref_service, + signin::IdentityManager* identity_manager, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + : AccountChecker(pref_service, + identity_manager, + std::move(url_loader_factory)) {} + SpyAccountChecker(const SpyAccountChecker&) = delete; + SpyAccountChecker operator=(const SpyAccountChecker&) = delete; + ~SpyAccountChecker() override = default; + + MOCK_METHOD(std::unique_ptr<EndpointFetcher>, + CreateEndpointFetcher, + (const std::string& oauth_consumer_name, + const GURL& url, + const std::string& http_method, + const std::string& content_type, + const std::vector<std::string>& scopes, + int64_t timeout_ms, + const std::string& post_data, + const net::NetworkTrafficAnnotationTag& annotation_tag), + (override)); + + protected: + friend class AccountCheckerTest; +}; + +class AccountCheckerTest : public testing::Test { + public: + AccountCheckerTest() = default; + ~AccountCheckerTest() override = default; + + void SetUp() override { + test_features_.InitAndEnableFeature(kShoppingList); + RegisterPrefs(pref_service_.registry()); + scoped_refptr<network::SharedURLLoaderFactory> test_url_loader_factory = + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_); + fetcher_ = std::make_unique<MockEndpointFetcher>(); + account_checker_ = std::make_unique<SpyAccountChecker>( + &pref_service_, identity_test_env_.identity_manager(), + std::move(test_url_loader_factory)); + ASSERT_EQ(false, account_checker_->IsSignedIn()); + + ON_CALL(*account_checker_, CreateEndpointFetcher).WillByDefault([this]() { + return std::move(fetcher_); + }); + } + + void SetFetchResponse(std::string response) { + fetcher_.reset(); + fetcher_ = std::make_unique<MockEndpointFetcher>(); + fetcher_->SetFetchResponse(response); + } + + void FetchPriceEmailPref() { account_checker_->FetchPriceEmailPref(); } + + protected: + base::test::TaskEnvironment task_environment_; + signin::IdentityTestEnvironment identity_test_env_; + base::test::ScopedFeatureList test_features_; + TestingPrefServiceSimple pref_service_; + network::TestURLLoaderFactory test_url_loader_factory_; + data_decoder::test::InProcessDataDecoder in_process_data_decoder_; + std::unique_ptr<MockEndpointFetcher> fetcher_; + std::unique_ptr<SpyAccountChecker> account_checker_; +}; + +TEST_F(AccountCheckerTest, TestFetchWaaStatusOnAccountChanged) { + const char waa_oauth_name[] = "web_history"; + const char waa_query_url[] = + "https://history.google.com/history/api/lookup?client=web_app"; + const char waa_oauth_scope[] = "https://www.googleapis.com/auth/chromesync"; + const char waa_content_type[] = "application/json; charset=UTF-8"; + const char waa_get_method[] = "GET"; + const int64_t waa_timeout_ms = 30000; + const char waa_post_data[] = ""; + + EXPECT_CALL(*account_checker_, + CreateEndpointFetcher(waa_oauth_name, GURL(waa_query_url), + waa_get_method, waa_content_type, + std::vector<std::string>{waa_oauth_scope}, + waa_timeout_ms, waa_post_data, _)) + .Times(1); + + ASSERT_EQ(true, account_checker_->IsWebAndAppActivityEnabled()); + SetFetchResponse("{ \"history_recording_enabled\": false }"); + identity_test_env_.MakePrimaryAccountAvailable("mock_email@gmail.com", + signin::ConsentLevel::kSync); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, account_checker_->IsSignedIn()); + ASSERT_EQ(false, account_checker_->IsWebAndAppActivityEnabled()); +} + +TEST_F(AccountCheckerTest, TestFetchPriceEmailPref) { + { + InSequence s; + // Fetch Waa. + EXPECT_CALL(*account_checker_, CreateEndpointFetcher); + // Fetch email pref. + EXPECT_CALL(*account_checker_, + CreateEndpointFetcher(kOAuthName, GURL(kNotificationsPrefUrl), + kGetHttpMethod, kContentType, + std::vector<std::string>{kOAuthScope}, + kTimeoutMs, kEmptyPostData, _)); + } + + ASSERT_EQ(false, pref_service_.GetBoolean(kPriceEmailNotificationsEnabled)); + identity_test_env_.MakePrimaryAccountAvailable("mock_email@gmail.com", + signin::ConsentLevel::kSync); + SetFetchResponse("{ \"preferences\": { \"price_track_email\" : true } }"); + FetchPriceEmailPref(); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, pref_service_.GetBoolean(kPriceEmailNotificationsEnabled)); +} + +TEST_F(AccountCheckerTest, TestSendPriceEmailPrefOnPrefChange) { + { + InSequence s; + // Fetch Waa. + EXPECT_CALL(*account_checker_, CreateEndpointFetcher); + // Send email pref. + EXPECT_CALL(*account_checker_, + CreateEndpointFetcher(kOAuthName, GURL(kNotificationsPrefUrl), + kPostHttpMethod, kContentType, + std::vector<std::string>{kOAuthScope}, + kTimeoutMs, kPostData, _)); + } + + ASSERT_EQ(false, pref_service_.GetBoolean(kPriceEmailNotificationsEnabled)); + identity_test_env_.MakePrimaryAccountAvailable("mock_email@gmail.com", + signin::ConsentLevel::kSync); + SetFetchResponse("{ \"preferences\": { \"price_track_email\" : true } }"); + pref_service_.SetBoolean(kPriceEmailNotificationsEnabled, true); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(true, pref_service_.GetBoolean(kPriceEmailNotificationsEnabled)); +} + +} // namespace commerce
diff --git a/components/commerce/core/subscriptions/BUILD.gn b/components/commerce/core/subscriptions/BUILD.gn index 4ecc51b..9890a1f 100644 --- a/components/commerce/core/subscriptions/BUILD.gn +++ b/components/commerce/core/subscriptions/BUILD.gn
@@ -43,10 +43,11 @@ deps = [ ":subscriptions", "//base/test:test_support", + "//components/commerce/core:account_checker", "//components/commerce/core:account_checker_test_support", "//components/commerce/core:commerce_subscription_db_content_proto", "//components/commerce/core:feature_list", - "//components/endpoint_fetcher:endpoint_fetcher", + "//components/endpoint_fetcher:test_support", "//components/leveldb_proto", "//components/session_proto_db:core", "//components/signin/public/identity_manager:test_support",
diff --git a/components/commerce/core/subscriptions/subscriptions_server_proxy.cc b/components/commerce/core/subscriptions/subscriptions_server_proxy.cc index 3a75d75..e4c7935d 100644 --- a/components/commerce/core/subscriptions/subscriptions_server_proxy.cc +++ b/components/commerce/core/subscriptions/subscriptions_server_proxy.cc
@@ -11,6 +11,7 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/json/values_util.h" +#include "components/commerce/core/account_checker.h" #include "components/commerce/core/commerce_feature_list.h" #include "components/commerce/core/subscriptions/commerce_subscription.h" #include "components/commerce/core/subscriptions/subscriptions_server_proxy.h" @@ -23,13 +24,6 @@ namespace { // For creating endpoint fetcher. -const char kOAuthScope[] = "https://www.googleapis.com/auth/chromememex"; -const char kOAuthName[] = "subscriptions_svc"; -const char kGetHttpMethod[] = "GET"; -const char kPostHttpMethod[] = "POST"; -const char kContentType[] = "application/json; charset=UTF-8"; -const char kEmptyPostData[] = ""; - const int kDefaultTimeoutMs = 5000; const char kTimeoutParam[] = "subscriptions_server_request_timeout"; constexpr base::FeatureParam<int> kTimeoutMs{&commerce::kShoppingList,
diff --git a/components/commerce/core/subscriptions/subscriptions_server_proxy_unittest.cc b/components/commerce/core/subscriptions/subscriptions_server_proxy_unittest.cc index ec519af..d27d025 100644 --- a/components/commerce/core/subscriptions/subscriptions_server_proxy_unittest.cc +++ b/components/commerce/core/subscriptions/subscriptions_server_proxy_unittest.cc
@@ -11,11 +11,12 @@ #include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" +#include "components/commerce/core/account_checker.h" #include "components/commerce/core/commerce_feature_list.h" #include "components/commerce/core/subscriptions/commerce_subscription.h" #include "components/commerce/core/subscriptions/subscriptions_server_proxy.h" #include "components/commerce/core/subscriptions/subscriptions_storage.h" -#include "components/endpoint_fetcher/endpoint_fetcher.h" +#include "components/endpoint_fetcher/mock_endpoint_fetcher.h" #include "components/signin/public/identity_manager/identity_test_environment.h" #include "net/http/http_status_code.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" @@ -39,9 +40,6 @@ const long kMockPrice = 100; const std::string kMockCountry = "us"; -const char kGetHttpMethod[] = "GET"; -const char kPostHttpMethod[] = "POST"; -const char kEmptyPostData[] = ""; const char kServiceUrl[] = "https://memex-pa.googleapis.com/v1/shopping/subscriptions"; const char kServiceUrlForGet[] = @@ -95,33 +93,6 @@ return std::make_unique<std::vector<commerce::CommerceSubscription>>(); } -// TODO(crbug.com/1351599): Move this to the endpoint_fetcher component. -class MockEndpointFetcher : public EndpointFetcher { - public: - explicit MockEndpointFetcher( - const net::NetworkTrafficAnnotationTag& annotation_tag) - : EndpointFetcher(annotation_tag) {} - ~MockEndpointFetcher() override = default; - - MOCK_METHOD(void, Fetch, (EndpointFetcherCallback callback), (override)); - - void MockFetchResponse( - std::string response_string, - int http_status_code = net::HTTP_OK, - absl::optional<FetchErrorType> error_type = absl::nullopt) { - ON_CALL(*this, Fetch) - .WillByDefault([response_string, http_status_code, - error_type](EndpointFetcherCallback callback) { - auto response = std::make_unique<EndpointResponse>(); - response->response = std::move(response_string); - response->http_status_code = http_status_code; - if (error_type) - response->error_type = error_type; - std::move(callback).Run(std::move(response)); - }); - } -}; - } // namespace namespace commerce { @@ -153,8 +124,7 @@ ~SubscriptionsServerProxyTest() override = default; void SetUp() override { - fetcher_ = - std::make_unique<MockEndpointFetcher>(TRAFFIC_ANNOTATION_FOR_TESTS); + fetcher_ = std::make_unique<MockEndpointFetcher>(); scoped_refptr<network::SharedURLLoaderFactory> test_url_loader_factory = base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_); @@ -176,7 +146,7 @@ }; TEST_F(SubscriptionsServerProxyTest, TestCreate) { - fetcher_->MockFetchResponse(kResponseSucceeded); + fetcher_->SetFetchResponse(kResponseSucceeded); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrl), kPostHttpMethod, kExpectedPostDataForCreate, _)) @@ -195,7 +165,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestCreate_EmptyList) { - fetcher_->MockFetchResponse(kResponseSucceeded); + fetcher_->SetFetchResponse(kResponseSucceeded); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher).Times(0); base::RunLoop run_loop; @@ -211,7 +181,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestCreate_ServerFailed) { - fetcher_->MockFetchResponse(kResponseFailed); + fetcher_->SetFetchResponse(kResponseFailed); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrl), kPostHttpMethod, kExpectedPostDataForCreate, _)) @@ -230,7 +200,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestCreate_WrongHttpCode) { - fetcher_->MockFetchResponse(kResponseSucceeded, net::HTTP_NOT_FOUND); + fetcher_->SetFetchResponse(kResponseSucceeded, net::HTTP_NOT_FOUND); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrl), kPostHttpMethod, kExpectedPostDataForCreate, _)) @@ -249,7 +219,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestCreate_EmptyResponse) { - fetcher_->MockFetchResponse(""); + fetcher_->SetFetchResponse(""); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrl), kPostHttpMethod, kExpectedPostDataForCreate, _)) @@ -268,7 +238,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestDelete) { - fetcher_->MockFetchResponse(kResponseSucceeded); + fetcher_->SetFetchResponse(kResponseSucceeded); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrl), kPostHttpMethod, kExpectedPostDataForDelete, _)) @@ -287,7 +257,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestDelete_EmptyList) { - fetcher_->MockFetchResponse(kResponseSucceeded); + fetcher_->SetFetchResponse(kResponseSucceeded); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher).Times(0); base::RunLoop run_loop; @@ -303,7 +273,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestDelete_ServerFailed) { - fetcher_->MockFetchResponse(kResponseFailed); + fetcher_->SetFetchResponse(kResponseFailed); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrl), kPostHttpMethod, kExpectedPostDataForDelete, _)) @@ -322,7 +292,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestGet) { - fetcher_->MockFetchResponse(kValidGetResponse); + fetcher_->SetFetchResponse(kValidGetResponse); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrlForGet), kGetHttpMethod, kEmptyPostData, _)) @@ -351,7 +321,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestGet_WrongType) { - fetcher_->MockFetchResponse(kValidGetResponse); + fetcher_->SetFetchResponse(kValidGetResponse); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher).Times(0); base::RunLoop run_loop; @@ -369,7 +339,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestGet_WrongHttpCode) { - fetcher_->MockFetchResponse(kValidGetResponse, net::HTTP_NOT_FOUND); + fetcher_->SetFetchResponse(kValidGetResponse, net::HTTP_NOT_FOUND); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrlForGet), kGetHttpMethod, kEmptyPostData, _)) @@ -390,7 +360,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestGet_FetchError) { - fetcher_->MockFetchResponse( + fetcher_->SetFetchResponse( kValidGetResponse, net::HTTP_OK, absl::make_optional<FetchErrorType>(FetchErrorType::kNetError)); EXPECT_CALL(*server_proxy_, @@ -413,7 +383,7 @@ } TEST_F(SubscriptionsServerProxyTest, TestGet_NoSubscriptions) { - fetcher_->MockFetchResponse(""); + fetcher_->SetFetchResponse(""); EXPECT_CALL(*server_proxy_, CreateEndpointFetcher(GURL(kServiceUrlForGet), kGetHttpMethod, kEmptyPostData, _))
diff --git a/components/commerce/core/subscriptions/subscriptions_storage_unittest.cc b/components/commerce/core/subscriptions/subscriptions_storage_unittest.cc index aa20d1c5..f903c0c 100644 --- a/components/commerce/core/subscriptions/subscriptions_storage_unittest.cc +++ b/components/commerce/core/subscriptions/subscriptions_storage_unittest.cc
@@ -15,7 +15,6 @@ #include "components/commerce/core/proto/commerce_subscription_db_content.pb.h" #include "components/commerce/core/subscriptions/commerce_subscription.h" #include "components/commerce/core/subscriptions/subscriptions_storage.h" -#include "components/endpoint_fetcher/endpoint_fetcher.h" #include "components/session_proto_db/session_proto_storage.h" #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/digital_asset_links/BUILD.gn b/components/digital_asset_links/BUILD.gn index da4433d..60c4be26 100644 --- a/components/digital_asset_links/BUILD.gn +++ b/components/digital_asset_links/BUILD.gn
@@ -4,6 +4,10 @@ source_set("digital_asset_links") { sources = [ + "browser_url_loader_throttle.cc", + "browser_url_loader_throttle.h", + "digital_asset_links_constants.cc", + "digital_asset_links_constants.h", "digital_asset_links_handler.cc", "digital_asset_links_handler.h", ] @@ -11,6 +15,7 @@ deps = [ "//base", "//content/public/browser", + "//content/public/common", "//net", "//services/data_decoder/public/cpp", "//services/network/public/cpp",
diff --git a/components/digital_asset_links/DEPS b/components/digital_asset_links/DEPS index d0e5c38..0f466f3aa 100644 --- a/components/digital_asset_links/DEPS +++ b/components/digital_asset_links/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+components/embedder_support/android/java/src/org/chromium/components/embedder_support/util", "+content/public/android/java/src/org/chromium/content_public/browser", "+content/public/browser", "+content/public/test", @@ -7,6 +8,6 @@ "+services/network/public/cpp", "+services/network/public/mojom", "+services/network/test", + "+third_party/blink/public/common/loader/url_loader_throttle.h", "+third_party/blink/public/mojom", - "+components/embedder_support/android/java/src/org/chromium/components/embedder_support/util", ]
diff --git a/components/digital_asset_links/browser_url_loader_throttle.cc b/components/digital_asset_links/browser_url_loader_throttle.cc new file mode 100644 index 0000000..c30de12 --- /dev/null +++ b/components/digital_asset_links/browser_url_loader_throttle.cc
@@ -0,0 +1,80 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/digital_asset_links/browser_url_loader_throttle.h" + +#include "base/check_op.h" +#include "base/functional/bind.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_functions.h" +#include "base/trace_event/trace_event.h" +#include "components/digital_asset_links/digital_asset_links_constants.h" +#include "content/public/browser/browser_task_traits.h" +#include "net/log/net_log_event_type.h" +#include "net/url_request/redirect_info.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/mojom/fetch_api.mojom.h" +#include "services/network/public/mojom/url_response_head.mojom.h" + +namespace digital_asset_links { + +BrowserURLLoaderThrottle::OriginVerificationSchedulerBridge:: + OriginVerificationSchedulerBridge() = default; +BrowserURLLoaderThrottle::OriginVerificationSchedulerBridge:: + ~OriginVerificationSchedulerBridge() = default; + +// static +std::unique_ptr<BrowserURLLoaderThrottle> BrowserURLLoaderThrottle::Create( + OriginVerificationSchedulerBridge* bridge) { + return base::WrapUnique<BrowserURLLoaderThrottle>( + new BrowserURLLoaderThrottle(bridge)); +} + +BrowserURLLoaderThrottle::BrowserURLLoaderThrottle( + OriginVerificationSchedulerBridge* bridge) + : bridge_(bridge) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +} + +BrowserURLLoaderThrottle::~BrowserURLLoaderThrottle() = default; + +void BrowserURLLoaderThrottle::WillProcessResponse( + const GURL& response_url, + network::mojom::URLResponseHead* response_head, + bool* defer) { + // TODO(crbug.com/1376958): Check the headers in |response_head| for CSP. + + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(delegate_); + + // Do the verification here, as redirected urls are not verified, only the + // final url. + *defer = true; + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce( + &OriginVerificationSchedulerBridge::Verify, base::Unretained(bridge_), + response_url.spec(), + base::BindOnce(&BrowserURLLoaderThrottle::OnCompleteCheck, + weak_factory_.GetWeakPtr(), response_url.spec()))); +} + +void BrowserURLLoaderThrottle::OnCompleteCheck(std::string url, bool verified) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(delegate_); + + if (verified) { + delegate_->Resume(); + } else { + // TODO(crbug.com/1376958): Show an interstitial for blocked content. + delegate_->CancelWithError(kNetErrorCodeForDigitalAssetLinks, + kCustomCancelReasonForURLLoader); + } +} + +const char* BrowserURLLoaderThrottle::NameForLoggingWillProcessResponse() { + return "DigitalAssetLinksBrowserThrottle"; +} + +} // namespace digital_asset_links
diff --git a/components/digital_asset_links/browser_url_loader_throttle.h b/components/digital_asset_links/browser_url_loader_throttle.h new file mode 100644 index 0000000..b1af30c --- /dev/null +++ b/components/digital_asset_links/browser_url_loader_throttle.h
@@ -0,0 +1,77 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DIGITAL_ASSET_LINKS_BROWSER_URL_LOADER_THROTTLE_H_ +#define COMPONENTS_DIGITAL_ASSET_LINKS_BROWSER_URL_LOADER_THROTTLE_H_ + +#include <memory> + +#include "base/functional/callback.h" +#include "base/memory/ref_counted.h" +#include "base/strings/strcat.h" +#include "base/time/time.h" +#include "content/public/browser/browser_thread.h" +#include "third_party/blink/public/common/loader/url_loader_throttle.h" +#include "url/gurl.h" + +namespace digital_asset_links { + +// TODO(crbug.com/1376958): Add CSP as method to allow content access in this +// throttle and then move it to components/third_party_restrictions. + +// BrowserURLLoaderThrottle is used in the browser process to perform a +// digital asset links verification to determine whether a URL and also its +// redirect URLs are considered first party content and will be loaded. +// +// This throttle never defers starting the URL request or following redirects. +// If any of the checks for the original URL and redirect chain are not complete +// by the time the response headers are available, the request is deferred +// until all the checks are done. It cancels the load if any URLs turn out to +// be bad. +class BrowserURLLoaderThrottle : public blink::URLLoaderThrottle { + public: + // Inherited classes must not define member variables since the + // |weak_factory_| needs to be the last member. + class OriginVerificationSchedulerBridge { + public: + using OriginVerifierCallback = base::OnceCallback<void(bool /*verified*/)>; + + OriginVerificationSchedulerBridge(); + virtual ~OriginVerificationSchedulerBridge(); + + OriginVerificationSchedulerBridge( + const OriginVerificationSchedulerBridge&) = delete; + OriginVerificationSchedulerBridge& operator=( + const OriginVerificationSchedulerBridge&) = delete; + + virtual void Verify(std::string url, OriginVerifierCallback callback) = 0; + }; + + static std::unique_ptr<BrowserURLLoaderThrottle> Create( + OriginVerificationSchedulerBridge* bridge); + + BrowserURLLoaderThrottle(const BrowserURLLoaderThrottle&) = delete; + BrowserURLLoaderThrottle& operator=(const BrowserURLLoaderThrottle&) = delete; + + ~BrowserURLLoaderThrottle() override; + + // blink::URLLoaderThrottle implementation. + void WillProcessResponse(const GURL& response_url, + network::mojom::URLResponseHead* response_head, + bool* defer) override; + const char* NameForLoggingWillProcessResponse() override; + + private: + explicit BrowserURLLoaderThrottle(OriginVerificationSchedulerBridge* bridge); + + void OnCompleteCheck(std::string url, bool verified); + + OriginVerificationSchedulerBridge* bridge_; + + base::WeakPtrFactory<BrowserURLLoaderThrottle> weak_factory_{this}; +}; + +} // namespace digital_asset_links + +#endif // COMPONENTS_DIGITAL_ASSET_LINKS_BROWSER_URL_LOADER_THROTTLE_H_
diff --git a/components/digital_asset_links/digital_asset_links_constants.cc b/components/digital_asset_links/digital_asset_links_constants.cc new file mode 100644 index 0000000..3ef25ab --- /dev/null +++ b/components/digital_asset_links/digital_asset_links_constants.cc
@@ -0,0 +1,15 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/digital_asset_links/digital_asset_links_constants.h" + +#include "net/base/net_errors.h" + +namespace digital_asset_links { + +const char kCustomCancelReasonForURLLoader[] = "DigitalAssetLinks"; + +const int kNetErrorCodeForDigitalAssetLinks = net::ERR_ACCESS_DENIED; + +} // namespace digital_asset_links
diff --git a/components/digital_asset_links/digital_asset_links_constants.h b/components/digital_asset_links/digital_asset_links_constants.h new file mode 100644 index 0000000..5c34f0e --- /dev/null +++ b/components/digital_asset_links/digital_asset_links_constants.h
@@ -0,0 +1,21 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DIGITAL_ASSET_LINKS_DIGITAL_ASSET_LINKS_CONSTANTS_H_ +#define COMPONENTS_DIGITAL_ASSET_LINKS_DIGITAL_ASSET_LINKS_CONSTANTS_H_ + +namespace digital_asset_links { + +// When a network::mojom::URLLoader is cancelled because of digital asset link +// verification, this custom cancellation reason could be used to notify the +// implementation side. Please see +// network::mojom::URLLoader::kClientDisconnectReason for more details. +extern const char kCustomCancelReasonForURLLoader[]; + +// error_code to use when Safe Browsing blocks a request. +extern const int kNetErrorCodeForDigitalAssetLinks; + +} // namespace digital_asset_links + +#endif // COMPONENTS_SAFE_BROWSING_CORE_COMMON_SAFEBROWSING_CONSTANTS_H_
diff --git a/components/embedder_support/user_agent_utils_unittest.cc b/components/embedder_support/user_agent_utils_unittest.cc index e925135..25debd5 100644 --- a/components/embedder_support/user_agent_utils_unittest.cc +++ b/components/embedder_support/user_agent_utils_unittest.cc
@@ -1344,7 +1344,7 @@ scoped_feature_list.Reset(); scoped_feature_list.InitWithFeaturesAndParameters( /*enabled_features=*/{{blink::features::kReduceUserAgentMinorVersion, - {{{"build_version", "5555"}}}}}, + {{{"build_version", "0000"}}}}}, /*disabled_features=*/{ blink::features::kForceMajorVersionInMinorPositionInUserAgent}); @@ -1357,7 +1357,7 @@ &build_version, &patch_version)); EXPECT_EQ(major_version, version_info::GetMajorVersionNumber()); EXPECT_EQ(minor_version, "0"); - EXPECT_EQ(build_version, "5555"); + EXPECT_EQ(build_version, "0000"); EXPECT_EQ(patch_version, "0"); // (2b) Policies: UserAgentReduction and MajorVersionInMinor force enabled. @@ -1381,7 +1381,7 @@ &build_version)); EXPECT_EQ(major_version, version_info::GetMajorVersionNumber()); EXPECT_EQ(minor_version, "0"); - EXPECT_NE(build_version, "5555"); + EXPECT_NE(build_version, "0000"); // Patch version cannot be tested as it would be set in a release branch. // (3) Features: UserAgentReduction disabled and MajorVersionInMinor enabled.
diff --git a/components/endpoint_fetcher/BUILD.gn b/components/endpoint_fetcher/BUILD.gn index 70c61bb..3d8ee18 100644 --- a/components/endpoint_fetcher/BUILD.gn +++ b/components/endpoint_fetcher/BUILD.gn
@@ -39,3 +39,20 @@ "//testing/gtest", ] } + +source_set("test_support") { + testonly = true + + sources = [ + "mock_endpoint_fetcher.cc", + "mock_endpoint_fetcher.h", + ] + + deps = [ + ":endpoint_fetcher", + "//base", + "//net", + "//net/traffic_annotation:test_support", + "//testing/gmock", + ] +}
diff --git a/components/endpoint_fetcher/mock_endpoint_fetcher.cc b/components/endpoint_fetcher/mock_endpoint_fetcher.cc new file mode 100644 index 0000000..adbdce5 --- /dev/null +++ b/components/endpoint_fetcher/mock_endpoint_fetcher.cc
@@ -0,0 +1,51 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> +#include <vector> + +#include "base/functional/callback.h" +#include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/task/sequenced_task_runner.h" +#include "components/endpoint_fetcher/endpoint_fetcher.h" +#include "components/endpoint_fetcher/mock_endpoint_fetcher.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" + +MockEndpointFetcher::MockEndpointFetcher() + : EndpointFetcher(TRAFFIC_ANNOTATION_FOR_TESTS) {} +MockEndpointFetcher::~MockEndpointFetcher() = default; + +void MockEndpointFetcher::SetFetchResponse( + std::string response_string, + int http_status_code, + absl::optional<FetchErrorType> error_type) { + ON_CALL(*this, Fetch) + .WillByDefault([response_string, http_status_code, + error_type](EndpointFetcherCallback callback) { + std::unique_ptr<EndpointResponse> response = + std::make_unique<EndpointResponse>(); + response->response = std::move(response_string); + response->http_status_code = http_status_code; + if (error_type) { + response->error_type = error_type; + } + std::move(callback).Run(std::move(response)); + }); + + ON_CALL(*this, PerformRequest) + .WillByDefault([response_string, http_status_code, error_type]( + EndpointFetcherCallback endpoint_fetcher_callback, + const char* key) { + std::unique_ptr<EndpointResponse> response = + std::make_unique<EndpointResponse>(); + response->response = std::move(response_string); + response->http_status_code = http_status_code; + if (error_type) { + response->error_type = error_type; + } + std::move(endpoint_fetcher_callback).Run(std::move(response)); + }); +}
diff --git a/components/endpoint_fetcher/mock_endpoint_fetcher.h b/components/endpoint_fetcher/mock_endpoint_fetcher.h new file mode 100644 index 0000000..c6014f351 --- /dev/null +++ b/components/endpoint_fetcher/mock_endpoint_fetcher.h
@@ -0,0 +1,39 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_ENDPOINT_FETCHER_MOCK_ENDPOINT_FETCHER_H_ +#define COMPONENTS_ENDPOINT_FETCHER_MOCK_ENDPOINT_FETCHER_H_ + +#include <string> +#include <vector> + +#include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "components/endpoint_fetcher/endpoint_fetcher.h" +#include "net/http/http_status_code.h" +#include "testing/gmock/include/gmock/gmock.h" + +// Used to mock endpoint fetcher in tests. +class MockEndpointFetcher : public EndpointFetcher { + public: + MockEndpointFetcher(); + MockEndpointFetcher(const MockEndpointFetcher&) = delete; + MockEndpointFetcher& operator=(const MockEndpointFetcher&) = delete; + ~MockEndpointFetcher() override; + + MOCK_METHOD(void, Fetch, (EndpointFetcherCallback callback), (override)); + MOCK_METHOD(void, + PerformRequest, + (EndpointFetcherCallback endpoint_fetcher_callback, + const char* key), + (override)); + + void SetFetchResponse( + std::string response_string, + int http_status_code = net::HTTP_OK, + absl::optional<FetchErrorType> error_type = absl::nullopt); +}; + +#endif // COMPONENTS_ENDPOINT_FETCHER_MOCK_ENDPOINT_FETCHER_H_
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc index caf2986b..399c134 100644 --- a/components/exo/wayland/server.cc +++ b/components/exo/wayland/server.cc
@@ -405,7 +405,7 @@ xdg_shell_data_ = std::make_unique<WaylandXdgShell>(display_, serial_tracker_.get()); - wl_global_create(wl_display_.get(), &xdg_wm_base_interface, 1, + wl_global_create(wl_display_.get(), &xdg_wm_base_interface, 3, xdg_shell_data_.get(), bind_xdg_shell); wl_global_create(wl_display_.get(), &zcr_touchpad_haptics_v1_interface, 1,
diff --git a/components/exo/wayland/xdg_shell.cc b/components/exo/wayland/xdg_shell.cc index 97529ca..2313b832 100644 --- a/components/exo/wayland/xdg_shell.cc +++ b/components/exo/wayland/xdg_shell.cc
@@ -91,11 +91,27 @@ GetUserDataAs<WaylandPositioner>(resource)->SetOffset(gfx::Vector2d(x, y)); } +// Version 3 xdg_positioner +// Empty since Weston doesn't implement this. +// Ref: +// https://gitlab.freedesktop.org/wayland/weston/-/blob/main/libweston/desktop/xdg-shell.c#L312 +void xdg_positioner_set_reactive(wl_client* client, wl_resource* resource) {} + +void xdg_positioner_set_parent_size(wl_client* client, + wl_resource* resource, + int32_t parent_width, + int32_t parent_height) {} + +void xdg_positioner_set_parent_configure(wl_client* client, + wl_resource* resource, + uint32_t serial) {} + const struct xdg_positioner_interface xdg_positioner_implementation = { xdg_positioner_destroy, xdg_positioner_set_size, xdg_positioner_set_anchor_rect, xdg_positioner_set_anchor, xdg_positioner_set_gravity, xdg_positioner_set_constraint_adjustment, - xdg_positioner_set_offset}; + xdg_positioner_set_offset, xdg_positioner_set_reactive, + xdg_positioner_set_parent_size, xdg_positioner_set_parent_configure}; //////////////////////////////////////////////////////////////////////////////// // xdg_toplevel_interface: @@ -456,6 +472,7 @@ public: WaylandPopup(wl_resource* resource, wl_resource* surface_resource) : resource_(resource), + surface_resource_(surface_resource), shell_surface_data_( GetUserDataAs<WaylandXdgSurface>(surface_resource)) { shell_surface_data_->shell_surface->host_window()->AddObserver(this); @@ -495,6 +512,39 @@ shell_surface_data_->shell_surface->Grab(); } + void Reposition(WaylandPositioner* positioner, uint32_t token) { + xdg_popup_send_repositioned(resource_, token); + + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestWindow( + shell_surface_data_->shell_surface->GetWidget() + ->parent() + ->GetNativeWindow()); + gfx::Rect work_area = display.work_area(); + wm::ConvertRectFromScreen(shell_surface_data_->shell_surface->GetWidget() + ->parent() + ->GetNativeWindow(), + &work_area); + WaylandPositioner::Result position = positioner->CalculateBounds(work_area); + gfx::Point origin = position.origin; + views::View::ConvertPointToScreen( + shell_surface_data_->shell_surface->GetWidget() + ->parent() + ->widget_delegate() + ->GetContentsView(), + &origin); + + shell_surface_data_->shell_surface->SetOrigin(origin); + shell_surface_data_->shell_surface->SetSize(position.size); + + xdg_popup_send_configure(resource_, position.origin.x(), + position.origin.y(), position.size.width(), + position.size.height()); + xdg_surface_send_configure( + surface_resource_, shell_surface_data_->serial_tracker->GetNextSerial( + SerialTracker::EventType::OTHER_EVENT)); + } + // Overridden from aura::WindowObserver: void OnWindowDestroying(aura::Window* window) override { shell_surface_data_ = nullptr; @@ -514,6 +564,7 @@ } wl_resource* const resource_; + wl_resource* const surface_resource_; WaylandXdgSurface* shell_surface_data_; base::WeakPtrFactory<WaylandPopup> weak_ptr_factory_{this}; }; @@ -529,8 +580,16 @@ GetUserDataAs<WaylandPopup>(resource)->Grab(); } -const struct xdg_popup_interface xdg_popup_implementation = {xdg_popup_destroy, - xdg_popup_grab}; +void xdg_popup_reposition(wl_client* client, + wl_resource* resource, + wl_resource* positioner, + uint32_t token) { + GetUserDataAs<WaylandPopup>(resource)->Reposition( + GetUserDataAs<WaylandPositioner>(positioner), token); +} + +const struct xdg_popup_interface xdg_popup_implementation = { + xdg_popup_destroy, xdg_popup_grab, xdg_popup_reposition}; //////////////////////////////////////////////////////////////////////////////// // xdg_surface_interface: @@ -622,8 +681,8 @@ shell_surface_data->shell_surface->SetPopup(); shell_surface_data->shell_surface->SetEnabled(true); - wl_resource* xdg_popup_resource = - wl_resource_create(client, &xdg_popup_interface, 1, id); + wl_resource* xdg_popup_resource = wl_resource_create( + client, &xdg_popup_interface, wl_resource_get_version(resource), id); SetImplementation( xdg_popup_resource, &xdg_popup_implementation, @@ -667,8 +726,8 @@ void xdg_wm_base_create_positioner(wl_client* client, wl_resource* resource, uint32_t id) { - wl_resource* positioner_resource = - wl_resource_create(client, &xdg_positioner_interface, 1, id); + wl_resource* positioner_resource = wl_resource_create( + client, &xdg_positioner_interface, wl_resource_get_version(resource), id); SetImplementation( positioner_resource, &xdg_positioner_implementation, @@ -698,8 +757,8 @@ std::make_unique<WaylandXdgSurface>(std::move(shell_surface), data->serial_tracker); - wl_resource* xdg_surface_resource = - wl_resource_create(client, &xdg_surface_interface, 1, id); + wl_resource* xdg_surface_resource = wl_resource_create( + client, &xdg_surface_interface, wl_resource_get_version(resource), id); SetImplementation(xdg_surface_resource, &xdg_surface_implementation, std::move(wayland_shell_surface)); @@ -797,8 +856,8 @@ void* data, uint32_t version, uint32_t id) { - wl_resource* resource = - wl_resource_create(client, &xdg_wm_base_interface, 1, id); + wl_resource* resource = wl_resource_create(client, &xdg_wm_base_interface, + std::min(3u, version), id); wl_resource_set_implementation(resource, &xdg_wm_base_implementation, data, nullptr);
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc index a39299db..7de5d48 100644 --- a/components/feature_engagement/public/feature_constants.cc +++ b/components/feature_engagement/public/feature_constants.cc
@@ -11,8 +11,6 @@ // Features used by the In-Product Help system. BASE_FEATURE(kIPHDemoMode, "IPH_DemoMode", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kIPHSnooze, "IPH_Snooze", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kEnableIPH, "EnableIPH", base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kUseClientConfigIPH, "UseClientConfigIPH", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h index f393a0d7..7568774f 100644 --- a/components/feature_engagement/public/feature_constants.h +++ b/components/feature_engagement/public/feature_constants.h
@@ -13,9 +13,6 @@ // A feature for enabling a demonstration mode for In-Product Help (IPH). BASE_DECLARE_FEATURE(kIPHDemoMode); -// A feature for enabling a snooze mode for In-Product Help (IPH). -BASE_DECLARE_FEATURE(kIPHSnooze); - // A feature for enabling In-Product Help (IPH) to use client side // configuration. When this flag is enabled, finch config will be ignored for // all IPHs. @@ -24,8 +21,6 @@ // A feature to ensure all arrays can contain at least one feature. BASE_DECLARE_FEATURE(kIPHDummyFeature); -BASE_DECLARE_FEATURE(kEnableIPH); - #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) BASE_DECLARE_FEATURE(kIPHBatterySaverModeFeature);
diff --git a/components/flags_ui/flags_test_helpers.cc b/components/flags_ui/flags_test_helpers.cc index 99faaa3..3802cd61 100644 --- a/components/flags_ui/flags_test_helpers.cc +++ b/components/flags_ui/flags_test_helpers.cc
@@ -69,14 +69,16 @@ base::Value metadata_json = FileContents(FlagFile::kFlagMetadata); FlagMetadataMap metadata; - for (const auto& entry : metadata_json.GetList()) { - std::string name = entry.FindKey("name")->GetString(); + for (const auto& entry_val : metadata_json.GetList()) { + const base::Value::Dict& entry = entry_val.GetDict(); + std::string name = *entry.FindString("name"); std::vector<std::string> owners; - if (const base::Value* e = entry.FindKey("owners")) { - for (const auto& owner : e->GetList()) + if (const base::Value::List* e = entry.FindList("owners")) { + for (const auto& owner : *e) { owners.push_back(owner.GetString()); + } } - int expiry_milestone = entry.FindKey("expiry_milestone")->GetInt(); + int expiry_milestone = entry.FindInt("expiry_milestone").value(); metadata[name] = FlagMetadataEntry{owners, expiry_milestone}; } @@ -275,10 +277,10 @@ std::vector<std::string> normalized_names; std::vector<std::string> names; - for (const auto& entry : metadata_json.GetList()) { - normalized_names.push_back( - NormalizeName(entry.FindKey("name")->GetString())); - names.push_back(entry.FindKey("name")->GetString()); + for (const auto& entry_val : metadata_json.GetList()) { + const base::Value::Dict& entry = entry_val.GetDict(); + normalized_names.push_back(NormalizeName(*entry.FindString("name"))); + names.push_back(*entry.FindString("name")); } EnsureNamesAreAlphabetical(normalized_names, names, FlagFile::kFlagMetadata);
diff --git a/components/gcm_driver/fake_gcm_profile_service.cc b/components/gcm_driver/fake_gcm_profile_service.cc index 6437627..fa81e44 100644 --- a/components/gcm_driver/fake_gcm_profile_service.cc +++ b/components/gcm_driver/fake_gcm_profile_service.cc
@@ -11,12 +11,10 @@ #include "base/location.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "components/gcm_driver/crypto/gcm_encryption_result.h" -#include "components/gcm_driver/fake_gcm_client_factory.h" #include "components/gcm_driver/gcm_driver.h" #include "components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h" @@ -25,7 +23,10 @@ class FakeGCMProfileService::CustomFakeGCMDriver : public instance_id::FakeGCMDriverForInstanceID { public: - explicit CustomFakeGCMDriver(FakeGCMProfileService* service); + CustomFakeGCMDriver(); + + // Must be called before any other methods. + void SetService(FakeGCMProfileService* service); CustomFakeGCMDriver(const CustomFakeGCMDriver&) = delete; CustomFakeGCMDriver& operator=(const CustomFakeGCMDriver&) = delete; @@ -39,9 +40,6 @@ const std::string& message_id, GCMClient::Result result); - void OnDispatchMessage(const std::string& app_id, - const IncomingMessage& message); - // GCMDriver overrides: void EncryptMessage(const std::string& app_id, const std::string& authorized_entity, @@ -80,7 +78,7 @@ const std::string& receiver_id, const OutgoingMessage& message); - raw_ptr<FakeGCMProfileService> service_; + raw_ptr<FakeGCMProfileService> service_ = nullptr; // Used to give each registration a unique registration id. Does not decrease // when unregister is called. @@ -90,11 +88,9 @@ this}; // Must be last. }; -FakeGCMProfileService::CustomFakeGCMDriver::CustomFakeGCMDriver( - FakeGCMProfileService* service) - : service_(service) {} +FakeGCMProfileService::CustomFakeGCMDriver::CustomFakeGCMDriver() = default; -FakeGCMProfileService::CustomFakeGCMDriver::~CustomFakeGCMDriver() {} +FakeGCMProfileService::CustomFakeGCMDriver::~CustomFakeGCMDriver() = default; void FakeGCMProfileService::CustomFakeGCMDriver::RegisterImpl( const std::string& app_id, @@ -171,6 +167,11 @@ std::move(callback).Run(GCMEncryptionResult::ENCRYPTED_DRAFT_08, message); } +void FakeGCMProfileService::CustomFakeGCMDriver::SetService( + FakeGCMProfileService* service) { + service_ = service; +} + void FakeGCMProfileService::CustomFakeGCMDriver::DoSend( const std::string& app_id, const std::string& receiver_id, @@ -207,24 +208,22 @@ app_id, authorized_entity, scope, std::move(callback)); } -void FakeGCMProfileService::CustomFakeGCMDriver::OnDispatchMessage( - const std::string& app_id, - const IncomingMessage& message) { - DispatchMessage(app_id, message); -} - // static std::unique_ptr<KeyedService> FakeGCMProfileService::Build( content::BrowserContext* context) { - std::unique_ptr<FakeGCMProfileService> service = - std::make_unique<FakeGCMProfileService>(); - service->SetDriverForTesting( - std::make_unique<CustomFakeGCMDriver>(service.get())); + auto custom_driver = std::make_unique<CustomFakeGCMDriver>(); + CustomFakeGCMDriver* custom_driver_ptr = custom_driver.get(); + std::unique_ptr<FakeGCMProfileService> service = + std::make_unique<FakeGCMProfileService>(std::move(custom_driver)); + + custom_driver_ptr->SetService(service.get()); return service; } -FakeGCMProfileService::FakeGCMProfileService() = default; +FakeGCMProfileService::FakeGCMProfileService( + std::unique_ptr<instance_id::FakeGCMDriverForInstanceID> fake_gcm_driver) + : GCMProfileService(std::move(fake_gcm_driver)) {} FakeGCMProfileService::~FakeGCMProfileService() = default; @@ -235,9 +234,12 @@ void FakeGCMProfileService::DispatchMessage(const std::string& app_id, const IncomingMessage& message) { - CustomFakeGCMDriver* custom_driver = - static_cast<CustomFakeGCMDriver*>(driver()); - custom_driver->OnDispatchMessage(app_id, message); + GetFakeGCMDriver()->DispatchMessage(app_id, message); +} + +instance_id::FakeGCMDriverForInstanceID* +FakeGCMProfileService::GetFakeGCMDriver() { + return static_cast<instance_id::FakeGCMDriverForInstanceID*>(driver()); } } // namespace gcm
diff --git a/components/gcm_driver/fake_gcm_profile_service.h b/components/gcm_driver/fake_gcm_profile_service.h index d53777c..0adf038 100644 --- a/components/gcm_driver/fake_gcm_profile_service.h +++ b/components/gcm_driver/fake_gcm_profile_service.h
@@ -18,6 +18,10 @@ class BrowserContext; } // namespace content +namespace instance_id { +class FakeGCMDriverForInstanceID; +} // namespace instance_id + namespace gcm { // Acts as a bridge between GCM API and GCM Client layer for testing purposes. @@ -26,7 +30,8 @@ // Helper function to be used with KeyedServiceFactory::SetTestingFactory(). static std::unique_ptr<KeyedService> Build(content::BrowserContext* context); - FakeGCMProfileService(); + explicit FakeGCMProfileService( + std::unique_ptr<instance_id::FakeGCMDriverForInstanceID> fake_gcm_driver); FakeGCMProfileService(const FakeGCMProfileService&) = delete; FakeGCMProfileService& operator=(const FakeGCMProfileService&) = delete; @@ -38,6 +43,8 @@ void DispatchMessage(const std::string& app_id, const IncomingMessage& message); + instance_id::FakeGCMDriverForInstanceID* GetFakeGCMDriver(); + const OutgoingMessage& last_sent_message() const { return last_sent_message_; }
diff --git a/components/gcm_driver/gcm_profile_service.cc b/components/gcm_driver/gcm_profile_service.cc index addd858..0f2be5a 100644 --- a/components/gcm_driver/gcm_profile_service.cc +++ b/components/gcm_driver/gcm_profile_service.cc
@@ -184,9 +184,17 @@ } #endif // BUILDFLAG(USE_GCM_FROM_PLATFORM) -GCMProfileService::GCMProfileService() {} +GCMProfileService::GCMProfileService(std::unique_ptr<GCMDriver> gcm_driver) + : driver_(std::move(gcm_driver)) { +#if !BUILDFLAG(USE_GCM_FROM_PLATFORM) + if (identity_observer_) { + identity_observer_ = std::make_unique<IdentityObserver>( + identity_manager_, url_loader_factory_, driver_.get()); + } +#endif // !BUILDFLAG(USE_GCM_FROM_PLATFORM) +} -GCMProfileService::~GCMProfileService() {} +GCMProfileService::~GCMProfileService() = default; void GCMProfileService::Shutdown() { #if !BUILDFLAG(USE_GCM_FROM_PLATFORM) @@ -198,15 +206,4 @@ } } -void GCMProfileService::SetDriverForTesting(std::unique_ptr<GCMDriver> driver) { - driver_ = std::move(driver); - -#if !BUILDFLAG(USE_GCM_FROM_PLATFORM) - if (identity_observer_) { - identity_observer_ = std::make_unique<IdentityObserver>( - identity_manager_, url_loader_factory_, driver.get()); - } -#endif // !BUILDFLAG(USE_GCM_FROM_PLATFORM) -} - } // namespace gcm
diff --git a/components/gcm_driver/gcm_profile_service.h b/components/gcm_driver/gcm_profile_service.h index 81a282cc..aeead5c 100644 --- a/components/gcm_driver/gcm_profile_service.h +++ b/components/gcm_driver/gcm_profile_service.h
@@ -78,14 +78,11 @@ // KeyedService: void Shutdown() override; - // For testing purposes. - void SetDriverForTesting(std::unique_ptr<GCMDriver> driver); - GCMDriver* driver() const { return driver_.get(); } protected: // Used for constructing fake GCMProfileService for testing purpose. - GCMProfileService(); + explicit GCMProfileService(std::unique_ptr<GCMDriver> driver); private: std::unique_ptr<GCMDriver> driver_;
diff --git a/components/gcm_driver/instance_id/BUILD.gn b/components/gcm_driver/instance_id/BUILD.gn index fc71330..f9bfee62f 100644 --- a/components/gcm_driver/instance_id/BUILD.gn +++ b/components/gcm_driver/instance_id/BUILD.gn
@@ -53,6 +53,7 @@ deps = [ "//base", "//components/gcm_driver", + "//net", "//testing/gtest", ]
diff --git a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc index 22b64453..1a4be74 100644 --- a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc +++ b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc
@@ -11,12 +11,18 @@ #include "base/location.h" #include "base/logging.h" #include "base/rand_util.h" +#include "base/ranges/algorithm.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" +#include "base/task/task_runner.h" #include "base/threading/thread_restrictions.h" +#include "base/time/time.h" +#include "components/gcm_driver/common/gcm_message.h" #include "components/gcm_driver/gcm_client.h" +#include "components/gcm_driver/gcm_connection_observer.h" +#include "net/base/ip_endpoint.h" namespace instance_id { @@ -53,10 +59,10 @@ << "Failed to read data from stored FCM tokens file"; for (const auto [key, value] : data.value().GetDict()) { + DVLOG(1) << "Loaded FCM token from file, key: " << key + << ", value: " << value.GetString(); tokens_[key] = value.GetString(); } - - DVLOG(1) << "Loaded tokens from file: " << tokens_.size(); } FakeGCMDriverForInstanceID::~FakeGCMDriverForInstanceID() = default; @@ -66,6 +72,48 @@ return this; } +void FakeGCMDriverForInstanceID::AddConnectionObserver( + gcm::GCMConnectionObserver* observer) { + connection_observers_.AddObserver(observer); +} + +void FakeGCMDriverForInstanceID::RemoveConnectionObserver( + gcm::GCMConnectionObserver* observer) { + connection_observers_.RemoveObserver(observer); +} + +void FakeGCMDriverForInstanceID::AddAppHandler(const std::string& app_id, + gcm::GCMAppHandler* handler) { + FakeGCMDriver::AddAppHandler(app_id, handler); + + DVLOG(1) << "GCMAppHandler was added: " << app_id; + + if (app_id_for_connection_.empty() || app_id == app_id_for_connection_) { + ConnectIfNeeded(); + } +} + +bool FakeGCMDriverForInstanceID::HasTokenForAppId( + const std::string& app_id, + const std::string& token) const { +#if BUILDFLAG(IS_ANDROID) + // FCM registration tokens on Android should be handled by + // FakeInstanceIDWithSubtype. + NOTREACHED(); +#endif // BUILDFLAG(IS_ANDROID) + for (const auto& [key, stored_token] : tokens_) { + if (token == stored_token && base::StartsWith(key, app_id)) { + return true; + } + } + return false; +} + +void FakeGCMDriverForInstanceID::WaitForAppIdBeforeConnection( + const std::string& app_id) { + app_id_for_connection_ = app_id; +} + void FakeGCMDriverForInstanceID::AddInstanceIDData( const std::string& app_id, const std::string& instance_id, @@ -183,4 +231,16 @@ DCHECK(success) << "Failed to store FCM tokens"; } +void FakeGCMDriverForInstanceID::ConnectIfNeeded() { + if (connected_) { + return; + } + + DVLOG(1) << "GCMDriver connected."; + connected_ = true; + for (gcm::GCMConnectionObserver& observer : connection_observers_) { + observer.OnConnected(net::IPEndPoint()); + } +} + } // namespace instance_id
diff --git a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h index 8e2f7bf..d3263a8a 100644 --- a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h +++ b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h
@@ -10,6 +10,8 @@ #include <utility> #include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" #include "components/gcm_driver/fake_gcm_driver.h" namespace base { @@ -34,6 +36,21 @@ // FakeGCMDriver overrides: gcm::InstanceIDHandler* GetInstanceIDHandlerInternal() override; + void AddConnectionObserver(gcm::GCMConnectionObserver* observer) override; + void RemoveConnectionObserver(gcm::GCMConnectionObserver* observer) override; + void AddAppHandler(const std::string& app_id, + gcm::GCMAppHandler* handler) override; + + // Expose protected method for testing. + using gcm::FakeGCMDriver::DispatchMessage; + + // Returns true if the given |app_id| has the expected |token|. Note that + // tokens may be loaded before GCMDriver is connected. + bool HasTokenForAppId(const std::string& app_id, + const std::string& token) const; + + // GCMDriver will not connect until the given |app_id| is added. + void WaitForAppIdBeforeConnection(const std::string& app_id); const std::string& last_gettoken_app_id() const { return last_gettoken_app_id_; @@ -69,8 +86,14 @@ GetInstanceIDDataCallback callback) override; private: + // Stores generated FCM registration tokens to a file, to keep the same tokens + // across browser restarts in tests. void StoreTokensIfNeeded(); + // Used to simulate connection of GCMDriver after adding the first + // GCMAppHandler. + void ConnectIfNeeded(); + std::string GenerateTokenImpl(const std::string& app_id, const std::string& authorized_entity, const std::string& scope); @@ -83,6 +106,20 @@ std::string last_gettoken_app_id_; std::string last_gettoken_authorized_entity_; std::string last_deletetoken_app_id_; + + // Simulate a connection to the server only after the given AppHandler has + // been added. This is required to prevent message loss in GCMDriver while + // dispatching a message. + // TODO(crbug.com/1408769): remove once GCMDriver fixes it. + std::string app_id_for_connection_; + bool connected_ = false; + + base::ObserverList<gcm::GCMConnectionObserver, + /*check_empty=*/false, + /*allow_reentrancy=*/false>::Unchecked + connection_observers_; + + base::WeakPtrFactory<FakeGCMDriverForInstanceID> weak_ptr_factory_{this}; }; } // namespace instance_id
diff --git a/components/heap_profiling/multi_process/client_connection_manager.cc b/components/heap_profiling/multi_process/client_connection_manager.cc index a010c35..16759b3 100644 --- a/components/heap_profiling/multi_process/client_connection_manager.cc +++ b/components/heap_profiling/multi_process/client_connection_manager.cc
@@ -115,6 +115,8 @@ void ClientConnectionManager::Start() { Add(this); + registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, + content::NotificationService::AllBrowserContextsAndSources()); registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, content::NotificationService::AllBrowserContextsAndSources()); registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, @@ -244,13 +246,6 @@ std::move(client), data.GetProcess().Pid(), process_type)); } -void ClientConnectionManager::OnRenderProcessHostCreated( - content::RenderProcessHost* host) { - if (ShouldProfileNewRenderer(host)) { - StartProfilingRenderer(host); - } -} - void ClientConnectionManager::Observe( int type, const content::NotificationSource& source, @@ -268,6 +263,11 @@ type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED)) { profiled_renderers_.erase(host); } + + if (type == content::NOTIFICATION_RENDERER_PROCESS_CREATED && + ShouldProfileNewRenderer(host)) { + StartProfilingRenderer(host); + } } bool ClientConnectionManager::ShouldProfileNewRenderer(
diff --git a/components/heap_profiling/multi_process/client_connection_manager.h b/components/heap_profiling/multi_process/client_connection_manager.h index 113b13f..a62b9a7c 100644 --- a/components/heap_profiling/multi_process/client_connection_manager.h +++ b/components/heap_profiling/multi_process/client_connection_manager.h
@@ -13,7 +13,6 @@ #include "content/public/browser/child_process_data.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" -#include "content/public/browser/render_process_host_creation_observer.h" namespace content { class RenderProcessHost; @@ -42,10 +41,8 @@ // This class can be subclassed for exactly one reason: to allow embedders to // override AllowedToProfileRenderer in order to prevent incognito renderers // from being profiled. -class ClientConnectionManager - : public content::BrowserChildProcessObserver, - public content::RenderProcessHostCreationObserver, - content::NotificationObserver { +class ClientConnectionManager : public content::BrowserChildProcessObserver, + content::NotificationObserver { public: // The owner of this instance must guarantee that |controller_| outlives this // class. @@ -89,9 +86,6 @@ void StartProfilingNonRendererChild(const content::ChildProcessData& data); - // content::RenderProcessHostCreationObserver - void OnRenderProcessHostCreated(content::RenderProcessHost* host) override; - // NotificationObserver // Observe connection of renderer child processes. void Observe(int type, @@ -114,11 +108,11 @@ // only be accessed on the UI thread and their values should be considered // opaque. // - // Semantically, the elements must be something that identifies which specific - // RenderProcess is being profiled. When the underlying RenderProcess goes - // away, the element must be removed. The RenderProcessHost pointer and the - // RenderProcessHostCreationObserver notification can be used to provide these - // semantics. + // Semantically, the elements must be something that identifies which + // specific RenderProcess is being profiled. When the underlying RenderProcess + // goes away, the element must be removed. The RenderProcessHost + // pointer and the NOTIFICATION_RENDERER_PROCESS_CREATED notification can be + // used to provide these semantics. // // This variable represents renderers that have been instructed to start // profiling - it does not reflect whether a renderer is currently still being
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc index 390119a..f2f86d50c 100644 --- a/components/history/core/browser/history_backend.cc +++ b/components/history/core/browser/history_backend.cc
@@ -16,7 +16,6 @@ #include "base/compiler_specific.h" #include "base/containers/flat_set.h" -#include "base/debug/dump_without_crashing.h" #include "base/feature_list.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" @@ -32,7 +31,6 @@ #include "base/observer_list.h" #include "base/rand_util.h" #include "base/strings/escape.h" -#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" @@ -42,7 +40,6 @@ #include "base/trace_event/typed_macros.h" #include "base/tracing/protos/chrome_track_event.pbzero.h" #include "build/build_config.h" -#include "components/crash/core/common/crash_key.h" #include "components/favicon/core/favicon_backend.h" #include "components/history/core/browser/download_constants.h" #include "components/history/core/browser/download_row.h" @@ -241,27 +238,6 @@ void DoneRunOnMainThread() override {} }; -// Does base::debug::DumpWithoutCrashing(), but on Canary/Dev only, and at a -// throttled rate. This is because our dump volume is high, and that can mask -// OTHER crashes. This is similar to ReportUnrecoverableError() in Sync code. -// https://crbug.com/1377512 -void SelectiveDumpWithoutCrashing(version_info::Channel channel) { - if (channel != version_info::Channel::CANARY && - channel != version_info::Channel::DEV) { - return; - } - - // We only want to upload |kErrorUploadRatio| ratio of errors. - const double kErrorUploadRatio = 0.1; - if (kErrorUploadRatio <= 0.0) - return; // We are not allowed to upload errors. - double random_number = base::RandDouble(); - if (random_number > kErrorUploadRatio) - return; - - base::debug::DumpWithoutCrashing(); -} - } // namespace std::u16string FormatUrlForRedirectComparison(const GURL& url) { @@ -2989,66 +2965,57 @@ void HistoryBackend::BeginSingletonTransaction() { TRACE_EVENT0("browser", "HistoryBackend::BeginSingletonTransaction"); - // TODO(crbug.com/1321483): Convert to DCHECKs after sussing out all the - // transaction bugs in History. - CHECK(!singleton_transaction_); + DCHECK(!singleton_transaction_); - CHECK_EQ(db_->transaction_nesting(), 0); + DCHECK_EQ(db_->transaction_nesting(), 0); singleton_transaction_ = db_->CreateTransaction(); bool success = singleton_transaction_->Begin(); UMA_HISTOGRAM_BOOLEAN("History.Backend.TransactionBeginSuccess", success); if (success) { - CHECK_EQ(db_->transaction_nesting(), 1); + DCHECK_EQ(db_->transaction_nesting(), 1); } else { - // Failing to begin the transaction is weird but it's not the end of the - // world. History can operate (slowly) without the long-running transaction, - // and we'll try to start one again at the next commit interval. Clear out + // Failing to begin the transaction happens very occasionally in the wild, + // at about 1 failure per million, almost exclusively on Windows. Previous + // analysis showed SQLITE_BUSY to be the main cause, which could suggest + // some other process (could be malware) trying to read Chrome history. + // See https://crbug.com/1377512 for more discussion. + // + // In any case, failing here is not a big deal, because Chrome will try to + // start another transaction again at the next commit interval. Clear out // the `singleton_transaction_` pointer, because it's only kept around if // it was successfully begun. + sql::UmaHistogramSqliteResult("History.Backend.TransactionBeginError", + diagnostics_.reported_sqlite_error_code); singleton_transaction_.reset(); - - // TODO(crbug.com/1321483): Remove DumpWithoutCrashing after fixing - // transaction related bugs in History. - SelectiveDumpWithoutCrashing(channel_); } } void HistoryBackend::CommitSingletonTransactionIfItExists() { TRACE_EVENT0("browser", "HistoryBackend::CommitSingletonTransactionIfItExists"); - // This can happen if the transaction was not successfully started. - // TODO(crbug.com/1321483): Convert to DCHECKs after sussing out all the - // transaction bugs in History. + if (!singleton_transaction_) { - CHECK_EQ(db_->transaction_nesting(), 0) + DCHECK_EQ(db_->transaction_nesting(), 0) << "There should not be any transactions other than the singleton one."; return; } - CHECK_EQ(db_->transaction_nesting(), 1) + DCHECK_EQ(db_->transaction_nesting(), 1) << "Someone opened multiple transactions."; bool success = singleton_transaction_->Commit(); UMA_HISTOGRAM_BOOLEAN("History.Backend.TransactionCommitSuccess", success); if (success) { - CHECK_EQ(db_->transaction_nesting(), 0) + DCHECK_EQ(db_->transaction_nesting(), 0) << "Someone left a transaction open."; } else { - // These diagnostic codes don't contain PII, and have already been cleared - // by Privacy to be used for error telemetry. - static crash_reporter::CrashKeyString<8> error_code_key( - "sql_diagnostics_error_code"); - error_code_key.Set(base::NumberToString(diagnostics_.error_code)); - static crash_reporter::CrashKeyString<8> version_key( - "sql_diagnostics_version"); - version_key.Set(base::NumberToString(diagnostics_.version)); - static crash_reporter::CrashKeyString<256> error_message_key( - "sql_diagnostics_error_message"); - error_message_key.Set(diagnostics_.error_message); - // TODO(crbug.com/1321483): Remove DumpWithoutCrashing after fixing - // transaction related bugs in History. - SelectiveDumpWithoutCrashing(channel_); + // The long-running transaction fails to commit about 1 per 100,000 times. + // The crash reports are again predominantly on Windows. The exact breakdown + // is less clear here compared to BEGIN, but some logs show "no transaction + // is active" and some show SQLITE_BUSY. Maybe this UMA will reveal things. + sql::UmaHistogramSqliteResult("History.Backend.TransactionCommitError", + diagnostics_.reported_sqlite_error_code); } singleton_transaction_.reset(); }
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h index a3f5101..b73ffcb9 100644 --- a/components/infobars/core/infobar_delegate.h +++ b/components/infobars/core/infobar_delegate.h
@@ -184,6 +184,7 @@ AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_DELEGATE_MOBILE = 110, TAILORED_SECURITY_SERVICE_INFOBAR_DELEGATE = 111, CHROME_FOR_TESTING_INFOBAR_DELEGATE = 112, + EXTENSIONS_WEB_AUTH_FLOW_INFOBAR_DELEGATE = 113, }; // Describes navigation events, used to decide whether infobars should be
diff --git a/components/metrics/content/content_stability_metrics_provider.cc b/components/metrics/content/content_stability_metrics_provider.cc index 7e6881a..611dd2c 100644 --- a/components/metrics/content/content_stability_metrics_provider.cc +++ b/components/metrics/content/content_stability_metrics_provider.cc
@@ -36,6 +36,8 @@ content::NotificationService::AllSources()); registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, content::NotificationService::AllSources()); + registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, + content::NotificationService::AllSources()); #if BUILDFLAG(IS_ANDROID) auto* crash_manager = crash_reporter::CrashMetricsReporter::GetInstance(); @@ -64,13 +66,6 @@ } #endif // BUILDFLAG(IS_ANDROID) -void ContentStabilityMetricsProvider::OnRenderProcessHostCreated( - content::RenderProcessHost* host) { - bool was_extension_process = - extensions_helper_ && extensions_helper_->IsExtensionProcess(host); - helper_.LogRendererLaunched(was_extension_process); -} - void ContentStabilityMetricsProvider::Observe( int type, const content::NotificationSource& source, @@ -96,9 +91,17 @@ break; } - case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: { + case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: helper_.LogRendererHang(); break; + + case content::NOTIFICATION_RENDERER_PROCESS_CREATED: { + bool was_extension_process = + extensions_helper_ && + extensions_helper_->IsExtensionProcess( + content::Source<content::RenderProcessHost>(source).ptr()); + helper_.LogRendererLaunched(was_extension_process); + break; } default:
diff --git a/components/metrics/content/content_stability_metrics_provider.h b/components/metrics/content/content_stability_metrics_provider.h index 8a5560c..ea40566 100644 --- a/components/metrics/content/content_stability_metrics_provider.h +++ b/components/metrics/content/content_stability_metrics_provider.h
@@ -15,7 +15,6 @@ #include "content/public/browser/browser_child_process_observer.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" -#include "content/public/browser/render_process_host_creation_observer.h" #if BUILDFLAG(IS_ANDROID) #include "components/crash/content/browser/crash_metrics_reporter_android.h" @@ -35,7 +34,6 @@ #if BUILDFLAG(IS_ANDROID) public crash_reporter::CrashMetricsReporter::Observer, #endif - public content::RenderProcessHostCreationObserver, public content::NotificationObserver { public: // |extensions_helper| is used to determine if a process corresponds to an @@ -72,9 +70,6 @@ FRIEND_TEST_ALL_PREFIXES(ContentStabilityMetricsProviderTest, ExtensionsNotificationObserver); - // content::RenderProcessHostCreationObserver: - void OnRenderProcessHostCreated(content::RenderProcessHost* host) override; - // content::NotificationObserver: void Observe(int type, const content::NotificationSource& source,
diff --git a/components/metrics/generate_expired_histograms_array.gni b/components/metrics/generate_expired_histograms_array.gni index caf777d..c360738 100644 --- a/components/metrics/generate_expired_histograms_array.gni +++ b/components/metrics/generate_expired_histograms_array.gni
@@ -132,6 +132,7 @@ "//tools/metrics/histograms/metadata/plugin_vm/histograms.xml", "//tools/metrics/histograms/metadata/power/histograms.xml", "//tools/metrics/histograms/metadata/prefetch/histograms.xml", + "//tools/metrics/histograms/metadata/preloading/histograms.xml", "//tools/metrics/histograms/metadata/print/histograms.xml", "//tools/metrics/histograms/metadata/printing/histograms.xml", "//tools/metrics/histograms/metadata/privacy/histograms.xml",
diff --git a/components/mirroring/service/BUILD.gn b/components/mirroring/service/BUILD.gn index 2702fe3..7541f1fe 100644 --- a/components/mirroring/service/BUILD.gn +++ b/components/mirroring/service/BUILD.gn
@@ -49,6 +49,7 @@ deps = [ "//build:chromeos_buildflags", "//components/cast_streaming/public:config_conversions", + "//components/cast_streaming/public:decoder_buffer_reader", "//components/mirroring/mojom:service", "//components/openscreen_platform", "//components/version_info", @@ -117,6 +118,7 @@ "//media/cast:net", "//media/cast:sender", "//media/cast:test_support", + "//media/mojo/common", "//media/mojo/mojom", "//media/mojo/mojom:remoting", "//mojo/public/cpp/bindings",
diff --git a/components/mirroring/service/remoting_sender.cc b/components/mirroring/service/remoting_sender.cc index 64b53216..6344337 100644 --- a/components/mirroring/service/remoting_sender.cc +++ b/components/mirroring/service/remoting_sender.cc
@@ -13,19 +13,51 @@ #include "base/time/default_tick_clock.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" +#include "components/cast_streaming/public/decoder_buffer_reader.h" +#include "media/base/decoder_buffer.h" #include "media/base/media_switches.h" #include "media/cast/common/openscreen_conversion_helpers.h" #include "media/cast/common/rtp_time.h" #include "media/cast/common/sender_encoded_frame.h" #include "media/cast/constants.h" #include "media/cast/sender/openscreen_frame_sender.h" -#include "media/mojo/common/mojo_data_pipe_read_write.h" #include "third_party/openscreen/src/cast/streaming/encoded_frame.h" #include "third_party/openscreen/src/cast/streaming/sender.h" using Dependency = openscreen::cast::EncodedFrame::Dependency; namespace mirroring { +namespace { + +std::unique_ptr<media::cast::SenderEncodedFrame> CreateEncodedFrame( + const media::DecoderBuffer& decoder_buffer, + media::cast::FrameId frame_id) { + auto remoting_frame = std::make_unique<media::cast::SenderEncodedFrame>(); + remoting_frame->frame_id = frame_id; + remoting_frame->dependency = decoder_buffer.is_key_frame() + ? Dependency::kKeyFrame + : Dependency::kDependent; + remoting_frame->referenced_frame_id = + remoting_frame->dependency == Dependency::kKeyFrame ? frame_id + : frame_id - 1; + remoting_frame->data = + std::string(reinterpret_cast<const char*>(decoder_buffer.data()), + decoder_buffer.data_size()); + + // TODO(crbug.com/1409620): Use duration for reference_time and + // encode_completion_time instead of timestamp. + const auto timestamp = base::TimeTicks() + decoder_buffer.timestamp(); + remoting_frame->reference_time = timestamp; + remoting_frame->encode_completion_time = timestamp; + remoting_frame->rtp_timestamp = + media::cast::RtpTimeTicks() + + ToRtpTimeDelta(decoder_buffer.timestamp(), + media::cast::kRemotingRtpTimebase); + + return remoting_frame; +} + +} // namespace RemotingSender::RemotingSender( scoped_refptr<media::cast::CastEnvironment> cast_environment, @@ -73,35 +105,47 @@ : frame_sender_(std::move(frame_sender)), clock_(cast_environment->Clock()), error_callback_(std::move(error_callback)), - data_pipe_reader_(new media::MojoDataPipeReader(std::move(pipe))), - stream_sender_(this, std::move(stream_sender)), - input_queue_discards_remaining_(0), - is_reading_(false), - flow_restart_pending_(true) { + decoder_buffer_reader_( + std::make_unique<cast_streaming::DecoderBufferReader>( + base::BindRepeating(&RemotingSender::OnFrameRead, + base::Unretained(this)), + std::move(pipe))), + stream_sender_(this, std::move(stream_sender)) { stream_sender_.set_disconnect_handler(base::BindOnce( &RemotingSender::OnRemotingDataStreamError, base::Unretained(this))); + + // Eventually calls OnBufferRead(). + decoder_buffer_reader_->ReadBufferAsync(); } RemotingSender::~RemotingSender() {} -void RemotingSender::SendFrame(uint32_t frame_size) { +void RemotingSender::SendFrame(media::mojom::DecoderBufferPtr buffer, + SendFrameCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - const bool need_to_start_processing = input_queue_.empty(); - input_queue_.push(base::BindRepeating(&RemotingSender::ReadFrame, - base::Unretained(this), frame_size)); - input_queue_.push(base::BindRepeating(&RemotingSender::TrySendFrame, - base::Unretained(this))); - if (need_to_start_processing) - ProcessNextInputTask(); + DCHECK(decoder_buffer_reader_); + + if (read_complete_cb_ || next_frame_) { + // This should never occur if the API is being used as intended, as only + // one SendFrame() call should be ongoing at a time. + mojo::ReportBadMessage( + "Multiple calls made to RemotingDataStreamSender::SendFrame()"); + return; + } + + read_complete_cb_ = std::move(callback); + decoder_buffer_reader_->ProvideBuffer(std::move(buffer)); } void RemotingSender::CancelInFlightData() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // Flag that all pending input operations should discard data. - input_queue_discards_remaining_ = input_queue_.size(); flow_restart_pending_ = true; - VLOG(1) << "Now restarting because in-flight data was just canceled."; + if (next_frame_) { + DCHECK(read_complete_cb_); + next_frame_.reset(); + std::move(read_complete_cb_).Run(); + } } int RemotingSender::GetNumberOfFramesInEncoder() const { @@ -115,51 +159,15 @@ } void RemotingSender::OnFrameCanceled(media::cast::FrameId frame_id) { - // The frame cancellation may allow for the next input task to complete. - ProcessNextInputTask(); -} - -void RemotingSender::ProcessNextInputTask() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (input_queue_.empty() || is_reading_) - return; - - input_queue_.front().Run(); -} - -void RemotingSender::ReadFrame(uint32_t size) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!is_reading_); - - if (HadError()) { - return; - } - if (!data_pipe_reader_->IsPipeValid()) { - VLOG(1) << "Data pipe handle no longer valid."; - OnRemotingDataStreamError(); - return; - } - - is_reading_ = true; - if (input_queue_discards_remaining_ > 0) { - data_pipe_reader_->Read( - nullptr, size, - base::BindOnce(&RemotingSender::OnFrameRead, base::Unretained(this))); - } else { - next_frame_data_.resize(size); - data_pipe_reader_->Read( - reinterpret_cast<uint8_t*>(std::data(next_frame_data_)), size, - base::BindOnce(&RemotingSender::OnFrameRead, base::Unretained(this))); + if (next_frame_) { + TrySendFrame(); } } void RemotingSender::TrySendFrame() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!is_reading_); - if (input_queue_discards_remaining_ > 0) { - OnInputTaskComplete(); - return; - } + DCHECK(next_frame_); + DCHECK(read_complete_cb_); // If there would be too many frames in-flight, do not proceed. if (frame_sender_->GetUnacknowledgedFrameCount() >= @@ -168,45 +176,17 @@ return; } - const bool is_first_frame = (next_frame_id_ == media::cast::FrameId::first()); - auto remoting_frame = std::make_unique<media::cast::SenderEncodedFrame>(); - remoting_frame->frame_id = next_frame_id_; + DCHECK(flow_restart_pending_ || + (next_frame_id_ != media::cast::FrameId::first())); + + auto remoting_frame = CreateEncodedFrame(*next_frame_, next_frame_id_); if (flow_restart_pending_) { remoting_frame->dependency = Dependency::kKeyFrame; + remoting_frame->referenced_frame_id = remoting_frame->frame_id; flow_restart_pending_ = false; - } else { - DCHECK(!is_first_frame); - remoting_frame->dependency = Dependency::kDependent; - } - remoting_frame->referenced_frame_id = - remoting_frame->dependency == Dependency::kKeyFrame ? next_frame_id_ - : next_frame_id_ - 1; - remoting_frame->reference_time = clock_->NowTicks(); - remoting_frame->encode_completion_time = remoting_frame->reference_time; - - base::TimeTicks last_frame_reference_time; - media::cast::RtpTimeTicks last_frame_rtp_timestamp; - if (is_first_frame) { - last_frame_reference_time = remoting_frame->reference_time; - last_frame_rtp_timestamp = - media::cast::RtpTimeTicks() - media::cast::RtpTimeDelta::FromTicks(1); - } else { - last_frame_reference_time = frame_sender_->LastSendTime(); - last_frame_rtp_timestamp = - frame_sender_->GetRecordedRtpTimestamp(next_frame_id_ - 1); } - // Ensure each successive frame's RTP timestamp is unique, but otherwise just - // base it on the reference time. - const media::cast::RtpTimeTicks rtp_timestamp = - last_frame_rtp_timestamp + - std::max(media::cast::RtpTimeDelta::FromTicks(1), - ToRtpTimeDelta( - remoting_frame->reference_time - last_frame_reference_time, - media::cast::kRemotingRtpTimebase)); - remoting_frame->rtp_timestamp = rtp_timestamp; - remoting_frame->data.swap(next_frame_data_); - + const auto rtp_timestamp = remoting_frame->rtp_timestamp; if (frame_sender_->EnqueueFrame(std::move(remoting_frame))) { // Only increment if we successfully enqueued. next_frame_id_++; @@ -216,44 +196,34 @@ rtp_timestamp.lower_32_bits(), "reason", "openscreen sender did not accept the frame"); } - OnInputTaskComplete(); + + next_frame_.reset(); + decoder_buffer_reader_->ReadBufferAsync(); + std::move(read_complete_cb_).Run(); } -void RemotingSender::OnFrameRead(bool success) { +void RemotingSender::OnFrameRead(scoped_refptr<media::DecoderBuffer> buffer) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(is_reading_); - is_reading_ = false; - if (!success) { - OnRemotingDataStreamError(); - return; - } - OnInputTaskComplete(); -} + DCHECK(!next_frame_); + DCHECK(read_complete_cb_); + DCHECK(decoder_buffer_reader_); -void RemotingSender::OnInputTaskComplete() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!input_queue_.empty()); - input_queue_.pop(); - if (input_queue_discards_remaining_ > 0) - --input_queue_discards_remaining_; + next_frame_ = std::move(buffer); - // Always force a post task to prevent the stack from growing too deep. - base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, base::BindOnce(&RemotingSender::ProcessNextInputTask, - weak_factory_.GetWeakPtr())); + TrySendFrame(); } void RemotingSender::OnRemotingDataStreamError() { // NOTE: This method must be idemptotent as it may be called more than once. - data_pipe_reader_.reset(); + decoder_buffer_reader_.reset(); stream_sender_.reset(); if (!error_callback_.is_null()) std::move(error_callback_).Run(); } bool RemotingSender::HadError() const { - DCHECK_EQ(!data_pipe_reader_, !stream_sender_.is_bound()); - return !data_pipe_reader_; + DCHECK_EQ(!decoder_buffer_reader_, !stream_sender_.is_bound()); + return !decoder_buffer_reader_; } } // namespace mirroring
diff --git a/components/mirroring/service/remoting_sender.h b/components/mirroring/service/remoting_sender.h index 083afcf8..f16dcfb 100644 --- a/components/mirroring/service/remoting_sender.h +++ b/components/mirroring/service/remoting_sender.h
@@ -22,8 +22,12 @@ class TickClock; } // namespace base +namespace cast_streaming { +class DecoderBufferReader; +} // namespace cast_streaming + namespace media { -class MojoDataPipeReader; +class DecoderBuffer; } // namespace media namespace openscreen::cast { @@ -85,7 +89,8 @@ // available or the CastTransport can accept more frames. CancelInFlightData() // is processed immediately, and will cause all pending operations to discard // data when they are processed later. - void SendFrame(uint32_t frame_size) override; + void SendFrame(media::mojom::DecoderBufferPtr buffer, + SendFrameCallback callback) override; void CancelInFlightData() override; // FrameSender::Client overrides. @@ -97,14 +102,11 @@ // as each task succeeds. void ProcessNextInputTask(); - // These are called via callbacks run from the input queue. - // Consumes a frame of |size| from the associated Mojo data pipe. - void ReadFrame(uint32_t size); // Sends out the frame to the receiver over network. void TrySendFrame(); // Called when a frame is completely read/discarded from the data pipe. - void OnFrameRead(bool success); + void OnFrameRead(scoped_refptr<media::DecoderBuffer> buffer); // Called when an input task completes. void OnInputTaskComplete(); @@ -124,30 +126,25 @@ // Callback that is run to notify when a fatal error occurs. base::OnceClosure error_callback_; - std::unique_ptr<media::MojoDataPipeReader> data_pipe_reader_; + // Reads media::DecoderBuffer instances and passes them to OnFrameRead(). + std::unique_ptr<cast_streaming::DecoderBufferReader> decoder_buffer_reader_; // Mojo receiver for this instance. Implementation at the other end of the // message pipe uses the RemotingDataStreamSender remote to control when // this RemotingSender consumes from |pipe_|. mojo::Receiver<media::mojom::RemotingDataStreamSender> stream_sender_; - // The next frame's payload data. Populated by call to OnFrameRead() when - // reading succeeded. - std::string next_frame_data_; + // The next frame. Populated by call to OnFrameRead() when reading succeeded. + scoped_refptr<media::DecoderBuffer> next_frame_; - // Queue of pending input operations. |input_queue_discards_remaining_| - // indicates the number of operations where data should be discarded (due to - // CancelInFlightData()). - base::queue<base::RepeatingClosure> input_queue_; - size_t input_queue_discards_remaining_; - - // Indicates whether the |data_pipe_reader_| is processing a reading request. - bool is_reading_; + // To be called once a frame has been successfully read and this instance is + // ready to process a new one. + SendFrameCallback read_complete_cb_; // Set to true if the first frame has not yet been sent, or if a // CancelInFlightData() operation just completed. This causes TrySendFrame() // to mark the next frame as the start of a new sequence. - bool flow_restart_pending_; + bool flow_restart_pending_ = true; // The next frame's ID. Before any frames are sent, this will be the ID of // the first frame.
diff --git a/components/mirroring/service/remoting_sender_unittest.cc b/components/mirroring/service/remoting_sender_unittest.cc index 25f6c255..e60e080 100644 --- a/components/mirroring/service/remoting_sender_unittest.cc +++ b/components/mirroring/service/remoting_sender_unittest.cc
@@ -8,606 +8,285 @@ #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" +#include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/test/task_environment.h" #include "base/time/default_tick_clock.h" #include "media/cast/common/encoded_frame.h" +#include "media/cast/common/frame_id.h" +#include "media/cast/common/sender_encoded_frame.h" #include "media/cast/constants.h" -#include "media/cast/net/cast_transport.h" +#include "media/cast/sender/frame_sender.h" #include "media/cast/test/utility/default_config.h" +#include "media/mojo/common/media_type_converters.h" +#include "media/mojo/common/mojo_data_pipe_read_write.h" #include "media/mojo/mojom/remoting.mojom.h" #include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/system/data_pipe.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using Dependency = openscreen::cast::EncodedFrame::Dependency; -namespace mirroring { +using ::testing::_; +using ::testing::Return; +using ::testing::StrictMock; +namespace mirroring { namespace { +void AreEqualExceptKeyframeImpl(const media::cast::SenderEncodedFrame& frame, + const media::DecoderBuffer& buffer) { + if (buffer.is_key_frame()) { + EXPECT_EQ(frame.dependency, Dependency::kKeyFrame); + } + + EXPECT_EQ(std::string(reinterpret_cast<const char*>(buffer.data()), + buffer.data_size()), + frame.data); + const auto timestamp = base::TimeTicks() + buffer.timestamp(); + EXPECT_EQ(frame.reference_time, timestamp); + EXPECT_EQ(frame.encode_completion_time, timestamp); +} + +ACTION_P(AreEqualNotFirstFrame, buffer) { + AreEqualExceptKeyframeImpl(*arg0, *buffer); + return true; +} + +ACTION_P(AreEqualFirstFrame, buffer) { + EXPECT_EQ(arg0->dependency, Dependency::kKeyFrame); + AreEqualExceptKeyframeImpl(*arg0, *buffer); + return true; +} + // Data pipe capacity is 1KB. constexpr int kDataPipeCapacity = 1024; -// Implements the CastTransport interface to capture output from the -// RemotingSender. -class FakeTransport final : public media::cast::CastTransport { +class FakeSender : public media::cast::FrameSender { public: - FakeTransport() = default; + ~FakeSender() override = default; - FakeTransport(const FakeTransport&) = delete; - FakeTransport& operator=(const FakeTransport&) = delete; + MOCK_METHOD1(SetTargetPlayoutDelay, void(base::TimeDelta)); + MOCK_CONST_METHOD0(GetTargetPlayoutDelay, base::TimeDelta()); + MOCK_CONST_METHOD0(NeedsKeyFrame, bool()); + MOCK_CONST_METHOD1(ShouldDropNextFrame, bool(base::TimeDelta)); + MOCK_METHOD1(GetRecordedRtpTimestamp, + media::cast::RtpTimeTicks(media::cast::FrameId)); + MOCK_CONST_METHOD0(GetUnacknowledgedFrameCount, int()); + MOCK_METHOD2(GetSuggestedBitrate, int(base::TimeTicks, base::TimeDelta)); + MOCK_CONST_METHOD0(MaxFrameRate, double()); + MOCK_METHOD1(SetMaxFrameRate, void(double)); + MOCK_CONST_METHOD0(TargetPlayoutDelay, base::TimeDelta()); + MOCK_CONST_METHOD0(CurrentRoundTripTime, base::TimeDelta()); + MOCK_CONST_METHOD0(LastSendTime, base::TimeTicks()); + MOCK_CONST_METHOD0(LastAckedFrameId, media::cast::FrameId()); + MOCK_METHOD1(OnReceivedCastFeedback, + void(const media::cast::RtcpCastMessage&)); + MOCK_METHOD0(OnReceivedPli, void()); + MOCK_METHOD1(OnMeasuredRoundTripTime, void(base::TimeDelta)); + MOCK_CONST_METHOD1(GetRecordedRtpTimestamp, + media::cast::RtpTimeTicks(media::cast::FrameId)); + MOCK_METHOD1(EnqueueFrame, + bool(std::unique_ptr<media::cast::SenderEncodedFrame>)); +}; - ~FakeTransport() override = default; +class MojoSenderWrapper { + public: + MojoSenderWrapper( + mojo::ScopedDataPipeProducerHandle handle, + mojo::PendingRemote<media::mojom::RemotingDataStreamSender> sender) + : data_pipe_writer_(std::move(handle)), + stream_sender_(std::move(sender)) {} - void TakeSentFrames(std::vector<media::cast::EncodedFrame>* frames) { - frames->swap(sent_frames_); - sent_frames_.clear(); + void SendFrame(scoped_refptr<media::DecoderBuffer> buffer) { + SendFrame(std::move(buffer), base::OnceCallback<void()>{}); } - void TakeCanceledFrameIds(std::vector<media::cast::FrameId>* frame_ids) { - frame_ids->swap(canceled_frame_ids_); - canceled_frame_ids_.clear(); + void SendFrame(scoped_refptr<media::DecoderBuffer> buffer, + base::OnceCallback<void()> on_read_complete) { + ASSERT_FALSE(is_frame_in_flight_); + is_frame_in_flight_ = true; + + data_pipe_writer_.Write( + buffer->data(), buffer->data_size(), + base::BindOnce(&MojoSenderWrapper::OnPipeWriteComplete, + weak_factory_.GetWeakPtr())); + stream_sender_->SendFrame( + media::mojom::DecoderBuffer::From(*buffer), + base::BindOnce(&MojoSenderWrapper::OnFrameReadComplete, + weak_factory_.GetWeakPtr(), + std::move(on_read_complete))); } - media::cast::FrameId WaitForKickstart() { - base::RunLoop run_loop; - kickstarted_callback_ = run_loop.QuitClosure(); - run_loop.Run(); - return kickstarted_frame_id_; - } + void CancelInFlightData() { stream_sender_->CancelInFlightData(); } - protected: - void InsertFrame(uint32_t ssrc, - const media::cast::EncodedFrame& frame) override { - sent_frames_.push_back(frame); - } - - void CancelSendingFrames( - uint32_t ssrc, - const std::vector<media::cast::FrameId>& frame_ids) override { - for (media::cast::FrameId frame_id : frame_ids) - canceled_frame_ids_.push_back(frame_id); - } - - void ResendFrameForKickstart(uint32_t ssrc, - media::cast::FrameId frame_id) override { - kickstarted_frame_id_ = frame_id; - if (!kickstarted_callback_.is_null()) - std::move(kickstarted_callback_).Run(); - } - - // The rest of the interface is not used for these tests. - void SendSenderReport( - uint32_t ssrc, - base::TimeTicks current_time, - media::cast::RtpTimeTicks current_time_as_rtp_timestamp) override {} - void AddValidRtpReceiver(uint32_t rtp_sender_ssrc, - uint32_t rtp_receiver_ssrc) override {} - void InitializeRtpReceiverRtcpBuilder( - uint32_t rtp_receiver_ssrc, - const media::cast::RtcpTimeData& time_data) override {} - void AddCastFeedback(const media::cast::RtcpCastMessage& cast_message, - base::TimeDelta target_delay) override {} - void AddPli(const media::cast::RtcpPliMessage& pli_message) override {} - void AddRtcpEvents( - const media::cast::ReceiverRtcpEventSubscriber::RtcpEvents& e) override {} - void AddRtpReceiverReport(const media::cast::RtcpReportBlock& b) override {} - void SendRtcpFromRtpReceiver() override {} - void SetOptions(const base::Value::Dict& options) override {} + bool is_frame_in_flight() const { return is_frame_in_flight_; } private: - std::vector<media::cast::EncodedFrame> sent_frames_; - std::vector<media::cast::FrameId> canceled_frame_ids_; + void OnFrameReadComplete(base::OnceCallback<void()> on_read_complete) { + is_frame_in_flight_ = false; + if (on_read_complete) { + std::move(on_read_complete).Run(); + } + } - base::RepeatingClosure kickstarted_callback_; - media::cast::FrameId kickstarted_frame_id_; + void OnPipeWriteComplete(bool success) { ASSERT_TRUE(success); } + + bool is_frame_in_flight_ = false; + + media::MojoDataPipeWriter data_pipe_writer_; + mojo::Remote<media::mojom::RemotingDataStreamSender> stream_sender_; + + base::WeakPtrFactory<MojoSenderWrapper> weak_factory_{this}; }; } // namespace class RemotingSenderTest : public ::testing::Test { public: - RemotingSenderTest(const RemotingSenderTest&) = delete; - RemotingSenderTest& operator=(const RemotingSenderTest&) = delete; - - protected: RemotingSenderTest() : cast_environment_(new media::cast::CastEnvironment( base::DefaultTickClock::GetInstance(), task_environment_.GetMainThreadTaskRunner(), task_environment_.GetMainThreadTaskRunner(), - task_environment_.GetMainThreadTaskRunner())), - expecting_error_callback_run_(false), - receiver_ssrc_(-1) { + task_environment_.GetMainThreadTaskRunner())) { + media::cast::FrameSenderConfig video_config = + media::cast::GetDefaultVideoSenderConfig(); + std::unique_ptr<testing::StrictMock<FakeSender>> fake_sender = + std::make_unique<testing::StrictMock<FakeSender>>(); + sender_ = fake_sender.get(); + + mojo::PendingRemote<media::mojom::RemotingDataStreamSender> sender; const MojoCreateDataPipeOptions data_pipe_options{ sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, kDataPipeCapacity}; + mojo::ScopedDataPipeProducerHandle producer_end; mojo::ScopedDataPipeConsumerHandle consumer_end; CHECK_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&data_pipe_options, - producer_end_, consumer_end)); + producer_end, consumer_end)); - media::cast::FrameSenderConfig video_config = - media::cast::GetDefaultVideoSenderConfig(); - video_config.rtp_payload_type = media::cast::RtpPayloadType::REMOTE_VIDEO; - video_config.codec = media::cast::CODEC_VIDEO_REMOTE; - receiver_ssrc_ = video_config.receiver_ssrc; - remoting_sender_ = std::make_unique<RemotingSender>( - cast_environment_, &transport_, video_config, std::move(consumer_end), - sender_.BindNewPipeAndPassReceiver(), + remoting_sender_ = base::WrapUnique(new RemotingSender( + cast_environment_, std::move(fake_sender), video_config, + std::move(consumer_end), sender.InitWithNewPipeAndPassReceiver(), base::BindOnce( [](bool expecting_error_callback_run) { CHECK(expecting_error_callback_run); }, - expecting_error_callback_run_)); + expecting_error_callback_run_))); - // Give CastRemotingSender a small RTT measurement to prevent kickstart - // testing from taking too long. - remoting_sender_->frame_sender_->OnMeasuredRoundTripTime( - base::Milliseconds(1)); - RunPendingTasks(); + mojo_sender_wrapper_ = std::make_unique<MojoSenderWrapper>( + std::move(producer_end), std::move(sender)); + + std::vector<uint8_t> data = {1, 2, 3}; + first_buffer_ = media::DecoderBuffer::CopyFrom(data.data(), 3); + first_buffer_->set_duration(base::Seconds(1)); + first_buffer_->set_timestamp(base::Seconds(2)); + first_buffer_->set_is_key_frame(false); + + data = {42, 43, 44}; + second_buffer_ = media::DecoderBuffer::CopyFrom(data.data(), 3); + second_buffer_->set_duration(base::Seconds(32)); + second_buffer_->set_timestamp(base::Seconds(42)); + second_buffer_->set_is_key_frame(false); + + data = {7, 8, 9}; + third_buffer_ = media::DecoderBuffer::CopyFrom(data.data(), 3); + third_buffer_->set_duration(base::Seconds(10)); + third_buffer_->set_timestamp(base::Seconds(11)); + third_buffer_->set_is_key_frame(true); } - ~RemotingSenderTest() override {} - void TearDown() final { remoting_sender_.reset(); + // Allow any pending tasks to run before destruction. RunPendingTasks(); } + protected: // Allow pending tasks, such as Mojo method calls, to execute. void RunPendingTasks() { task_environment_.RunUntilIdle(); } - protected: - media::cast::FrameId last_acked_frame_id() const { - return remoting_sender_->frame_sender_->LastAckedFrameId(); + void SendFrameCancelled(media::cast::FrameId id) { + remoting_sender_->OnFrameCanceled(id); } - int NumberOfFramesInFlight() { - return remoting_sender_->frame_sender_->GetUnacknowledgedFrameCount(); - } - - size_t GetSizeOfNextFrameData() { - return remoting_sender_->next_frame_data_.size(); - } - - bool IsFlowRestartPending() const { - return remoting_sender_->flow_restart_pending_; - } - - [[nodiscard]] bool ProduceDataChunk(size_t offset, size_t size) { - std::vector<uint8_t> fake_chunk(size); - for (size_t i = 0; i < size; ++i) - fake_chunk[i] = static_cast<uint8_t>(offset + i); - uint32_t num_bytes = fake_chunk.size(); - return producer_end_->WriteData(fake_chunk.data(), &num_bytes, - MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) == - MOJO_RESULT_OK; - } - - void SendFrame(uint32_t size) { remoting_sender_->SendFrame(size); } - - void CancelInFlightData() { remoting_sender_->CancelInFlightData(); } - - void TakeSentFrames(std::vector<media::cast::EncodedFrame>* frames) { - transport_.TakeSentFrames(frames); - } - - bool ExpectOneFrameWasSent(size_t expected_payload_size) { - std::vector<media::cast::EncodedFrame> frames; - transport_.TakeSentFrames(&frames); - EXPECT_EQ(1u, frames.size()); - if (frames.empty()) - return false; - return ExpectCorrectFrameData(expected_payload_size, frames.front()); - } - - void AckUpToAndIncluding(media::cast::FrameId frame_id) { - media::cast::RtcpCastMessage cast_feedback(receiver_ssrc_); - cast_feedback.ack_frame_id = frame_id; - remoting_sender_->frame_sender_->OnReceivedCastFeedback(cast_feedback); - } - - void AckOldestInFlightFrames(int count) { - AckUpToAndIncluding(last_acked_frame_id() + count); - } - - // Blocks the caller indefinitely, until a kickstart frame is sent, and then - // returns the FrameId of the kickstarted-frame. - media::cast::FrameId WaitForKickstart() { - return transport_.WaitForKickstart(); - } - - bool ExpectNoFramesCanceled() { - std::vector<media::cast::FrameId> frame_ids; - transport_.TakeCanceledFrameIds(&frame_ids); - return frame_ids.empty(); - } - - bool ExpectFramesCanceled(media::cast::FrameId first_frame_id, - media::cast::FrameId last_frame_id) { - std::vector<media::cast::FrameId> frame_ids; - transport_.TakeCanceledFrameIds(&frame_ids); - auto begin = frame_ids.begin(); - auto end = frame_ids.end(); - for (auto fid = first_frame_id; fid <= last_frame_id; ++fid) { - auto new_end = std::remove(begin, end, fid); - if (new_end == end) - return false; - end = new_end; - } - return begin == end; - } - - static bool ExpectCorrectFrameData(size_t expected_payload_size, - const media::cast::EncodedFrame& frame) { - if (expected_payload_size != frame.data.size()) { - ADD_FAILURE() << "Expected frame data size != frame.data.size(): " - << expected_payload_size << " vs " << frame.data.size(); - return false; - } - for (size_t i = 0; i < expected_payload_size; ++i) { - if (static_cast<uint8_t>(frame.data[i]) != static_cast<uint8_t>(i)) { - ADD_FAILURE() << "Frame data byte mismatch at offset " << i; - return false; - } - } - return true; - } - - private: base::test::TaskEnvironment task_environment_; const scoped_refptr<media::cast::CastEnvironment> cast_environment_; - FakeTransport transport_; + + testing::StrictMock<FakeSender>* sender_; + bool expecting_error_callback_run_ = false; + + std::unique_ptr<MojoSenderWrapper> mojo_sender_wrapper_; + std::unique_ptr<RemotingSender> remoting_sender_; - mojo::Remote<media::mojom::RemotingDataStreamSender> sender_; - mojo::ScopedDataPipeProducerHandle producer_end_; - bool expecting_error_callback_run_; - uint32_t receiver_ssrc_; + + scoped_refptr<media::DecoderBuffer> first_buffer_; + scoped_refptr<media::DecoderBuffer> second_buffer_; + scoped_refptr<media::DecoderBuffer> third_buffer_; + + media::cast::FrameId first_frame_id_ = media::cast::FrameId::first(); }; TEST_F(RemotingSenderTest, SendsFramesViaMojoDataPipe) { - // One 256-byte chunk pushed through the data pipe to make one frame. - ASSERT_TRUE(ProduceDataChunk(0, 256)); - SendFrame(256); + EXPECT_CALL(*sender_, GetUnacknowledgedFrameCount).WillOnce(Return(0)); + EXPECT_CALL(*sender_, EnqueueFrame(_)) + .WillOnce(AreEqualFirstFrame(first_buffer_)); + mojo_sender_wrapper_->SendFrame(first_buffer_); + EXPECT_TRUE(mojo_sender_wrapper_->is_frame_in_flight()); RunPendingTasks(); - EXPECT_TRUE(ExpectOneFrameWasSent(256)); - AckOldestInFlightFrames(1); - EXPECT_EQ(media::cast::FrameId::first(), last_acked_frame_id()); + EXPECT_FALSE(mojo_sender_wrapper_->is_frame_in_flight()); - // Four 256-byte chunks pushed through the data pipe to make one frame. - SendFrame(1024); - for (int i = 0; i < 4; ++i) { - ASSERT_TRUE(ProduceDataChunk(i * 256, 256)); - } + EXPECT_CALL(*sender_, GetUnacknowledgedFrameCount).WillOnce(Return(0)); + EXPECT_CALL(*sender_, EnqueueFrame(_)) + .WillOnce(AreEqualNotFirstFrame(second_buffer_)); + mojo_sender_wrapper_->SendFrame(second_buffer_); + EXPECT_TRUE(mojo_sender_wrapper_->is_frame_in_flight()); RunPendingTasks(); - EXPECT_TRUE(ExpectOneFrameWasSent(1024)); - AckOldestInFlightFrames(1); - EXPECT_EQ(media::cast::FrameId::first() + 1, last_acked_frame_id()); + EXPECT_FALSE(mojo_sender_wrapper_->is_frame_in_flight()); - // 10 differently-sized chunks pushed through the data pipe to make one frame - // that is larger than the data pipe's total capacity. - SendFrame(6665); - size_t offset = 0; - for (int i = 0; i < 10; ++i) { - const size_t chunk_size = 500 + i * 37; - ASSERT_TRUE(ProduceDataChunk(offset, chunk_size)); - RunPendingTasks(); - offset += chunk_size; - } + EXPECT_CALL(*sender_, GetUnacknowledgedFrameCount).WillOnce(Return(0)); + EXPECT_CALL(*sender_, EnqueueFrame(_)) + .WillOnce(AreEqualNotFirstFrame(third_buffer_)); + mojo_sender_wrapper_->SendFrame(third_buffer_); + EXPECT_TRUE(mojo_sender_wrapper_->is_frame_in_flight()); RunPendingTasks(); - EXPECT_TRUE(ExpectOneFrameWasSent(6665)); - AckOldestInFlightFrames(1); - EXPECT_EQ(media::cast::FrameId::first() + 2, last_acked_frame_id()); -} - -TEST_F(RemotingSenderTest, SendsMultipleFramesWithDelayedAcks) { - // Send 4 frames. - for (int i = 0; i < 4; ++i) { - ASSERT_TRUE(ProduceDataChunk(0, 16)); - SendFrame(16); - } - RunPendingTasks(); - EXPECT_EQ(4, NumberOfFramesInFlight()); - EXPECT_TRUE(ExpectNoFramesCanceled()); - - // Ack one frame. - AckOldestInFlightFrames(1); - EXPECT_EQ(3, NumberOfFramesInFlight()); - EXPECT_TRUE(ExpectFramesCanceled(media::cast::FrameId::first(), - media::cast::FrameId::first())); - - // Ack all. - AckOldestInFlightFrames(3); - EXPECT_EQ(0, NumberOfFramesInFlight()); - EXPECT_TRUE(ExpectFramesCanceled(media::cast::FrameId::first() + 1, - media::cast::FrameId::first() + 3)); -} - -TEST_F(RemotingSenderTest, KickstartsIfAckNotTimely) { - // Send first frame and don't Ack it. Expect the first frame to be - // kickstarted. - ASSERT_TRUE(ProduceDataChunk(0, 16)); - SendFrame(16); - EXPECT_EQ(media::cast::FrameId::first(), WaitForKickstart()); - EXPECT_EQ(1, NumberOfFramesInFlight()); - - // Send 3 more frames and don't Ack them either. Expect the 4th frame to be - // kickstarted. - for (int i = 0; i < 3; ++i) { - ASSERT_TRUE(ProduceDataChunk(0, 16)); - SendFrame(16); - } - EXPECT_EQ(media::cast::FrameId::first() + 3, WaitForKickstart()); - EXPECT_EQ(4, NumberOfFramesInFlight()); - - // Ack the first two frames and wait for another kickstart (for the 4th frame - // again). - AckOldestInFlightFrames(2); - EXPECT_EQ(2, NumberOfFramesInFlight()); - EXPECT_EQ(media::cast::FrameId::first() + 3, WaitForKickstart()); + EXPECT_FALSE(mojo_sender_wrapper_->is_frame_in_flight()); } TEST_F(RemotingSenderTest, CancelsUnsentFrame) { - EXPECT_EQ(0u, GetSizeOfNextFrameData()); - SendFrame(16); - SendFrame(32); - CancelInFlightData(); - - // Provide the data. Both frames should not be sent out. - ASSERT_TRUE(ProduceDataChunk(0, 16)); + EXPECT_CALL(*sender_, GetUnacknowledgedFrameCount) + .WillOnce(Return(media::cast::kMaxUnackedFrames)); + mojo_sender_wrapper_->SendFrame(first_buffer_); + EXPECT_TRUE(mojo_sender_wrapper_->is_frame_in_flight()); RunPendingTasks(); - ASSERT_TRUE(ProduceDataChunk(0, 32)); - RunPendingTasks(); - EXPECT_EQ(0, NumberOfFramesInFlight()); + EXPECT_TRUE(mojo_sender_wrapper_->is_frame_in_flight()); - // Since no frames were sent, none should have been passed to the - // CastTransport, and none should have been canceled. - std::vector<media::cast::EncodedFrame> frames; - TakeSentFrames(&frames); - EXPECT_TRUE(frames.empty()); - EXPECT_TRUE(ExpectNoFramesCanceled()); + mojo_sender_wrapper_->CancelInFlightData(); + RunPendingTasks(); + EXPECT_FALSE(mojo_sender_wrapper_->is_frame_in_flight()); + + SendFrameCancelled(first_frame_id_); + RunPendingTasks(); + EXPECT_FALSE(mojo_sender_wrapper_->is_frame_in_flight()); } -TEST_F(RemotingSenderTest, CancelsFramesInFlight) { - EXPECT_TRUE(IsFlowRestartPending()); - - // Send 10 frames. - for (int i = 0; i < 10; ++i) { - ASSERT_TRUE(ProduceDataChunk(0, 16)); - SendFrame(16); - } +TEST_F(RemotingSenderTest, CancelsOrAcksFramesInFlight) { + EXPECT_CALL(*sender_, GetUnacknowledgedFrameCount) + .WillOnce(Return(media::cast::kMaxUnackedFrames)); + mojo_sender_wrapper_->SendFrame(first_buffer_); + EXPECT_TRUE(mojo_sender_wrapper_->is_frame_in_flight()); RunPendingTasks(); - EXPECT_FALSE(IsFlowRestartPending()); - EXPECT_EQ(10, NumberOfFramesInFlight()); + EXPECT_TRUE(mojo_sender_wrapper_->is_frame_in_flight()); - // Ack the first frame. - AckOldestInFlightFrames(1); - EXPECT_FALSE(IsFlowRestartPending()); - EXPECT_EQ(9, NumberOfFramesInFlight()); - EXPECT_TRUE(ExpectFramesCanceled(media::cast::FrameId::first(), - media::cast::FrameId::first())); - - // Despite the name, this does not actually cancel in-flight frames, as that - // capability was never implemented. - CancelInFlightData(); + EXPECT_CALL(*sender_, EnqueueFrame(_)) + .WillOnce(AreEqualFirstFrame(first_buffer_)); + EXPECT_CALL(*sender_, GetUnacknowledgedFrameCount) + .WillOnce(Return(media::cast::kMaxUnackedFrames - 1)); + SendFrameCancelled(first_frame_id_); RunPendingTasks(); - EXPECT_TRUE(IsFlowRestartPending()); - EXPECT_EQ(9, NumberOfFramesInFlight()); - - // Send one more frame and ack it. - ASSERT_TRUE(ProduceDataChunk(0, 16)); - SendFrame(16); - RunPendingTasks(); - EXPECT_FALSE(IsFlowRestartPending()); - EXPECT_EQ(10, NumberOfFramesInFlight()); - AckOldestInFlightFrames(1); - EXPECT_EQ(9, NumberOfFramesInFlight()); - - // Check that the dependency metadata was set correctly to indicate a frame - // that immediately follows a CancelInFlightData() operation. - std::vector<media::cast::EncodedFrame> frames; - TakeSentFrames(&frames); - ASSERT_EQ(11u, frames.size()); - for (size_t i = 0; i < 11; ++i) { - const media::cast::EncodedFrame& frame = frames[i]; - EXPECT_EQ(media::cast::FrameId::first() + i, frame.frame_id); - if (i == 0 || i == 10) - EXPECT_EQ(Dependency::kKeyFrame, frame.dependency); - else - EXPECT_EQ(Dependency::kDependent, frame.dependency); - } -} - -TEST_F(RemotingSenderTest, WaitsForDataBeforeConsumingFromDataPipe) { - // Queue up and issue Mojo calls to consume three frames. Since no data has - // been pushed into the pipe yet no frames should be sent. - for (int i = 0; i < 3; ++i) { - SendFrame(4); - } - RunPendingTasks(); - EXPECT_TRUE(IsFlowRestartPending()); - EXPECT_EQ(0, NumberOfFramesInFlight()); - - // Push the data for one frame into the data pipe. This should trigger input - // processing and allow one frame to be sent. - ASSERT_TRUE(ProduceDataChunk(0, 4)); - RunPendingTasks(); // Allow Mojo Watcher to signal CastRemotingSender. - EXPECT_FALSE(IsFlowRestartPending()); - EXPECT_EQ(1, NumberOfFramesInFlight()); - - // Now push the data for the other two frames into the data pipe and expect - // two more frames to be sent. - ASSERT_TRUE(ProduceDataChunk(0, 4)); - ASSERT_TRUE(ProduceDataChunk(0, 4)); - RunPendingTasks(); // Allow Mojo Watcher to signal CastRemotingSender. - EXPECT_FALSE(IsFlowRestartPending()); - EXPECT_EQ(3, NumberOfFramesInFlight()); -} - -TEST_F(RemotingSenderTest, WaitsForDataThenDiscardsCanceledData) { - // Queue up and issue Mojo calls to consume data chunks and send three - // frames. Since no data has been pushed into the pipe yet no frames should be - // sent. - for (int i = 0; i < 3; ++i) { - SendFrame(4); - } - RunPendingTasks(); - EXPECT_EQ(0, NumberOfFramesInFlight()); - - // Cancel all in-flight data. - CancelInFlightData(); - RunPendingTasks(); - - // Now, push the data for one frame into the data pipe. Because of the - // cancellation, no frames should be sent. - ASSERT_TRUE(ProduceDataChunk(0, 4)); - RunPendingTasks(); // Allow Mojo Watcher to signal CastRemotingSender. - EXPECT_EQ(0, NumberOfFramesInFlight()); - - // Now push the data for the other two frames into the data pipe and still no - // frames should be sent. - ASSERT_TRUE(ProduceDataChunk(0, 4)); - ASSERT_TRUE(ProduceDataChunk(0, 4)); - RunPendingTasks(); // Allow Mojo Watcher to signal CastRemotingSender. - EXPECT_EQ(0, NumberOfFramesInFlight()); - - // Now issue calls to send another frame and then push the data for it into - // the data pipe. Expect to see the frame gets sent since it was provided - // after the CancelInFlightData(). - SendFrame(4); - RunPendingTasks(); - EXPECT_EQ(0, NumberOfFramesInFlight()); - ASSERT_TRUE(ProduceDataChunk(0, 4)); - RunPendingTasks(); // Allow Mojo Watcher to signal CastRemotingSender. - EXPECT_EQ(1, NumberOfFramesInFlight()); -} - -TEST_F(RemotingSenderTest, StopsConsumingWhileTooManyFramesAreInFlight) { - EXPECT_TRUE(IsFlowRestartPending()); - - // Send out the maximum possible number of unacked frames, but don't ack any - // yet. - for (int i = 0; i < media::cast::kMaxUnackedFrames; ++i) { - ASSERT_TRUE(ProduceDataChunk(0, 4)); - SendFrame(4); - } - RunPendingTasks(); - EXPECT_FALSE(IsFlowRestartPending()); - EXPECT_EQ(media::cast::kMaxUnackedFrames, NumberOfFramesInFlight()); - // Note: All frames should have been sent to the Transport, and so - // CastRemotingSender's single-frame data buffer should be empty. - EXPECT_EQ(0u, GetSizeOfNextFrameData()); - - // When the client provides one more frame, CastRemotingSender will begin - // queuing input operations instead of sending the the frame to the - // CastTransport. - ASSERT_TRUE(ProduceDataChunk(0, 4)); - SendFrame(4); - RunPendingTasks(); - EXPECT_EQ(media::cast::kMaxUnackedFrames, NumberOfFramesInFlight()); - // Note: The unsent frame resides in CastRemotingSender's single-frame data - // buffer. - EXPECT_EQ(4u, GetSizeOfNextFrameData()); - - // Ack the the first frame and expect sending to resume, with one more frame - // being sent to the CastTransport. - AckOldestInFlightFrames(1); - EXPECT_EQ(media::cast::kMaxUnackedFrames, NumberOfFramesInFlight()); - // Note: Only one frame was backlogged, and so CastRemotingSender's - // single-frame data buffer should be empty. - EXPECT_EQ(0u, GetSizeOfNextFrameData()); - - // Attempting to send another frame will once again cause CastRemotingSender - // to queue input operations. - ASSERT_TRUE(ProduceDataChunk(0, 4)); - SendFrame(4); - RunPendingTasks(); - EXPECT_EQ(media::cast::kMaxUnackedFrames, NumberOfFramesInFlight()); - // Note: Once again, CastRemotingSender's single-frame data buffer contains an - // unsent frame. - EXPECT_EQ(4u, GetSizeOfNextFrameData()); - - // Send more frames: Some number of frames will queue-up inside the Mojo data - // pipe (the exact number depends on the data pipe's capacity, and how Mojo - // manages memory internally). At some point, attempting to produce and push - // another frame will fail because the data pipe is full. - int num_frames_in_data_pipe = 0; - while (ProduceDataChunk(0, 768)) { - ++num_frames_in_data_pipe; - SendFrame(768); - RunPendingTasks(); - EXPECT_EQ(media::cast::kMaxUnackedFrames, NumberOfFramesInFlight()); - // Note: CastRemotingSender's single-frame data buffer should still contain - // the unsent 4-byte frame. - EXPECT_EQ(4u, GetSizeOfNextFrameData()); - } - EXPECT_LT(0, num_frames_in_data_pipe); - - // Ack one frame at a time until the backlog in the Mojo data pipe has - // cleared. - int remaining_frames_in_data_pipe = num_frames_in_data_pipe; - while (remaining_frames_in_data_pipe > 0) { - AckOldestInFlightFrames(1); - RunPendingTasks(); - --remaining_frames_in_data_pipe; - EXPECT_EQ(media::cast::kMaxUnackedFrames, NumberOfFramesInFlight()); - EXPECT_EQ(768u, GetSizeOfNextFrameData()); - } - - // Ack one more frame. There should no longer be a backlog on the input side - // of things. - AckOldestInFlightFrames(1); - RunPendingTasks(); // No additional Mojo method calls should be made here. - EXPECT_EQ(media::cast::kMaxUnackedFrames, NumberOfFramesInFlight()); - // The single-frame data buffer should be empty to indicate no input backlog. - EXPECT_EQ(0u, GetSizeOfNextFrameData()); - - // Ack all but one frame. - AckOldestInFlightFrames(NumberOfFramesInFlight() - 1); - EXPECT_EQ(1, NumberOfFramesInFlight()); - // ..and one more frame can be sent immediately. - ASSERT_TRUE(ProduceDataChunk(0, 4)); - SendFrame(4); - RunPendingTasks(); - EXPECT_EQ(2, NumberOfFramesInFlight()); - // ...and ack these last two frames. - AckOldestInFlightFrames(2); - EXPECT_EQ(0, NumberOfFramesInFlight()); - - // Finally, examine all frames that were sent to the CastTransport, and - // confirm their metadata and data is valid. - std::vector<media::cast::EncodedFrame> frames; - TakeSentFrames(&frames); - const size_t total_frames_sent = - media::cast::kMaxUnackedFrames + 2 + num_frames_in_data_pipe + 1; - ASSERT_EQ(total_frames_sent, frames.size()); - media::cast::RtpTimeTicks last_rtp_timestamp = - media::cast::RtpTimeTicks() - media::cast::RtpTimeDelta::FromTicks(1); - for (size_t i = 0; i < total_frames_sent; ++i) { - const media::cast::EncodedFrame& frame = frames[i]; - EXPECT_EQ(media::cast::FrameId::first() + i, frame.frame_id); - if (i == 0) { - EXPECT_EQ(Dependency::kKeyFrame, frame.dependency); - EXPECT_EQ(media::cast::FrameId::first() + i, frame.referenced_frame_id); - } else { - EXPECT_EQ(Dependency::kDependent, frame.dependency); - EXPECT_EQ(media::cast::FrameId::first() + i - 1, - frame.referenced_frame_id); - } - - // RTP timestamp must be monotonically increasing. - EXPECT_GT(frame.rtp_timestamp, last_rtp_timestamp); - last_rtp_timestamp = frame.rtp_timestamp; - - size_t expected_frame_size = 4; - if ((i >= media::cast::kMaxUnackedFrames + 2u) && - (i < media::cast::kMaxUnackedFrames + 2u + num_frames_in_data_pipe)) { - expected_frame_size = 768; - } - EXPECT_TRUE(ExpectCorrectFrameData(expected_frame_size, frame)); - } + EXPECT_FALSE(mojo_sender_wrapper_->is_frame_in_flight()); } } // namespace mirroring
diff --git a/components/no_state_prefetch/browser/no_state_prefetch_manager.cc b/components/no_state_prefetch/browser/no_state_prefetch_manager.cc index 0793c0b..5edb176 100644 --- a/components/no_state_prefetch/browser/no_state_prefetch_manager.cc +++ b/components/no_state_prefetch/browser/no_state_prefetch_manager.cc
@@ -246,9 +246,9 @@ // Create PreloadingPrediction and PreloadingAttempt for NoStatePrefetch. preloading_data->AddPreloadingPrediction( - content::PreloadingPredictor::kLinkRel, confidence, same_url_matcher); + content::preloading_predictor::kLinkRel, confidence, same_url_matcher); attempt = preloading_data->AddPreloadingAttempt( - content::PreloadingPredictor::kLinkRel, + content::preloading_predictor::kLinkRel, content::PreloadingType::kNoStatePrefetch, same_url_matcher); } return StartPrefetchingWithPreconnectFallback(
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn index 52bd944..00aad3b 100644 --- a/components/omnibox/browser/BUILD.gn +++ b/components/omnibox/browser/BUILD.gn
@@ -178,9 +178,9 @@ "omnibox_client.h", "omnibox_controller.cc", "omnibox_controller.h", - "omnibox_edit_controller.h", "omnibox_edit_model.cc", "omnibox_edit_model.h", + "omnibox_edit_model_delegate.h", "omnibox_event_global_tracker.cc", "omnibox_event_global_tracker.h", "omnibox_field_trial.cc", @@ -574,10 +574,10 @@ "test_location_bar_model.h", "test_omnibox_client.cc", "test_omnibox_client.h", - "test_omnibox_edit_controller.cc", - "test_omnibox_edit_controller.h", "test_omnibox_edit_model.cc", "test_omnibox_edit_model.h", + "test_omnibox_edit_model_delegate.cc", + "test_omnibox_edit_model_delegate.h", "test_omnibox_view.cc", "test_omnibox_view.h", "test_scheme_classifier.cc",
diff --git a/components/omnibox/browser/actions/omnibox_action.cc b/components/omnibox/browser/actions/omnibox_action.cc index 90b76be2..33825542 100644 --- a/components/omnibox/browser/actions/omnibox_action.cc +++ b/components/omnibox/browser/actions/omnibox_action.cc
@@ -8,7 +8,6 @@ #include "base/trace_event/memory_usage_estimator.h" #include "build/build_config.h" #include "components/omnibox/browser/omnibox_client.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/components/omnibox/browser/actions/omnibox_pedal.cc b/components/omnibox/browser/actions/omnibox_pedal.cc index 51d47b0..2ef5e754 100644 --- a/components/omnibox/browser/actions/omnibox_pedal.cc +++ b/components/omnibox/browser/actions/omnibox_pedal.cc
@@ -14,7 +14,6 @@ #include "build/build_config.h" #include "components/omnibox/browser/buildflags.h" #include "components/omnibox/browser/omnibox_client.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/resources/grit/omnibox_pedal_synonyms.h" #include "components/strings/grit/components_strings.h"
diff --git a/components/omnibox/browser/omnibox_client.cc b/components/omnibox/browser/omnibox_client.cc index e497a7a..cd26f4e 100644 --- a/components/omnibox/browser/omnibox_client.cc +++ b/components/omnibox/browser/omnibox_client.cc
@@ -87,6 +87,8 @@ return false; } +void OmniboxClient::OnUserPastedInOmniboxResultingInValidURL() {} + gfx::Image OmniboxClient::GetFaviconForPageUrl( const GURL& page_url, FaviconFetchedCallback on_favicon_fetched) {
diff --git a/components/omnibox/browser/omnibox_client.h b/components/omnibox/browser/omnibox_client.h index 6325b64..5a718de 100644 --- a/components/omnibox/browser/omnibox_client.h +++ b/components/omnibox/browser/omnibox_client.h
@@ -135,6 +135,10 @@ virtual void OnFocusChanged(OmniboxFocusState state, OmniboxFocusChangeReason reason) {} + // Called to notify the clients that the user has pasted into the omnibox, and + // the resulting string in the omnibox is a valid URL. + virtual void OnUserPastedInOmniboxResultingInValidURL(); + // Called when the autocomplete result has changed. Implementations that // support preloading (currently, prefetching or prerendering) of search // results pages should preload only if `should_preload` is true. If the
diff --git a/components/omnibox/browser/omnibox_controller.cc b/components/omnibox/browser/omnibox_controller.cc index 72b100f..b8428516 100644 --- a/components/omnibox/browser/omnibox_controller.cc +++ b/components/omnibox/browser/omnibox_controller.cc
@@ -10,7 +10,6 @@ #include "components/omnibox/browser/autocomplete_controller_emitter.h" #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/omnibox_client.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" #include "components/omnibox/browser/omnibox_edit_model.h" #include "components/omnibox/browser/omnibox_popup_selection.h" #include "components/omnibox/browser/omnibox_popup_view.h"
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index b49ff91b..29786834 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -41,7 +41,7 @@ #include "components/omnibox/browser/location_bar_model.h" #include "components/omnibox/browser/omnibox.mojom-shared.h" #include "components/omnibox/browser/omnibox_client.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" +#include "components/omnibox/browser/omnibox_edit_model_delegate.h" #include "components/omnibox/browser/omnibox_event_global_tracker.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/omnibox_log.h" @@ -236,12 +236,13 @@ // OmniboxEditModel ----------------------------------------------------------- -OmniboxEditModel::OmniboxEditModel(OmniboxView* view, - OmniboxEditController* controller, - std::unique_ptr<OmniboxClient> client) +OmniboxEditModel::OmniboxEditModel( + OmniboxView* view, + OmniboxEditModelDelegate* edit_model_delegate, + std::unique_ptr<OmniboxClient> client) : client_(std::move(client)), view_(view), - controller_(controller), + edit_model_delegate_(edit_model_delegate), focus_state_(OMNIBOX_FOCUS_NONE), user_input_in_progress_(false), user_input_since_focus_(true), @@ -276,7 +277,7 @@ metrics::OmniboxEventProto::PageClassification OmniboxEditModel::GetPageClassification() const { - return controller()->GetLocationBarModel()->GetPageClassification( + return delegate()->GetLocationBarModel()->GetPageClassification( focus_source_); } @@ -374,7 +375,7 @@ bool OmniboxEditModel::ResetDisplayTexts() { const std::u16string old_display_text = GetPermanentDisplayText(); - LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); + LocationBarModel* location_bar_model = delegate()->GetLocationBarModel(); url_for_editing_ = location_bar_model->GetFormattedFullURL(); #if BUILDFLAG(IS_IOS) @@ -421,7 +422,7 @@ return false; // No need to unelide if we are already displaying the full URL. - LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); + LocationBarModel* location_bar_model = delegate()->GetLocationBarModel(); if (view_->GetText() == location_bar_model->GetFormattedFullURL()) return false; @@ -446,7 +447,7 @@ client_->OnTextChanged(current_match, user_input_in_progress_, user_text_, result(), has_focus()); - controller_->OnChanged(); + edit_model_delegate_->OnChanged(); } void OmniboxEditModel::GetDataForURLExport(GURL* url, @@ -485,7 +486,7 @@ // contents as a hyperlink to the current page. if (!user_input_in_progress_ && (*text == display_text_ || *text == url_for_editing_)) { - *url_from_text = controller()->GetLocationBarModel()->GetURL(); + *url_from_text = delegate()->GetLocationBarModel()->GetURL(); *write_url = true; // Don't let users copy Reader Mode page URLs. @@ -518,7 +519,7 @@ *url_from_text = match_from_text.destination_url; // Get the current page GURL (or the GURL of the currently selected match). - GURL current_page_url = controller()->GetLocationBarModel()->GetURL(); + GURL current_page_url = delegate()->GetLocationBarModel()->GetURL(); if (PopupIsOpen()) { AutocompleteMatch current_match = CurrentMatch(nullptr); if (!AutocompleteMatch::IsSearchType(current_match.type) && @@ -693,7 +694,7 @@ void OmniboxEditModel::StartPrefetch() { auto page_classification = - controller()->GetLocationBarModel()->GetPageClassification( + delegate()->GetLocationBarModel()->GetPageClassification( OmniboxFocusSource::OMNIBOX, /*is_prefetch=*/true); if (!OmniboxFieldTrial::IsZeroSuggestPrefetchingEnabledInContext( page_classification)) { @@ -814,8 +815,7 @@ if (ui::PageTransitionCoreTypeIs(match.transition, ui::PAGE_TRANSITION_TYPED) && - (match.destination_url == - controller()->GetLocationBarModel()->GetURL())) { + (match.destination_url == delegate()->GetLocationBarModel()->GetURL())) { // When the user hit enter on the existing permanent URL, treat it like a // reload for scoring purposes. We could detect this by just checking // user_input_in_progress_, but it seems better to treat "edits" that end @@ -879,8 +879,8 @@ RecordActionShownForAllActions(result(), match_position); OmniboxAction::ExecutionContext context( *(autocomplete_controller()->autocomplete_provider_client()), - base::BindOnce(&OmniboxEditController::OnAutocompleteAccept, - controller_->AsWeakPtr()), + base::BindOnce(&OmniboxEditModelDelegate::OnAutocompleteAccept, + edit_model_delegate_->AsWeakPtr()), match_selection_timestamp, disposition); match.action->Execute(context); @@ -1135,7 +1135,7 @@ // This calls RevertAll again. base::AutoReset<bool> tmp(&in_revert_, true); - controller_->OnAutocompleteAccept( + edit_model_delegate_->OnAutocompleteAccept( match.destination_url, match.post_content.get(), disposition, ui::PageTransitionFromInt(match.transition | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR), @@ -1693,15 +1693,10 @@ if (paste_state_ == PASTING) { paste_state_ = PASTED; -#if BUILDFLAG(IS_IOS) GURL url = GURL(*(state_changes.new_text)); - if (url.is_valid()) { - base::RecordAction( - base::UserMetricsAction("Mobile.Omnibox.iOS.PastedValidURL")); + client_->OnUserPastedInOmniboxResultingInValidURL(); } -#endif - } else if (state_changes.text_differs) paste_state_ = NONE; @@ -1939,7 +1934,7 @@ } bool OmniboxEditModel::ShouldPreventElision() const { - return controller()->GetLocationBarModel()->ShouldPreventElision(); + return delegate()->GetLocationBarModel()->ShouldPreventElision(); } bool OmniboxEditModel::IsStarredMatch(const AutocompleteMatch& match) const { @@ -2354,7 +2349,7 @@ bool popup_was_open = popup_view_->IsOpen(); popup_view_->UpdatePopupAppearance(); if (popup_view_->IsOpen() != popup_was_open) { - controller()->OnPopupVisibilityChanged(); + delegate()->OnPopupVisibilityChanged(); } } } @@ -2472,7 +2467,7 @@ } void OmniboxEditModel::NotifyObserversInputInProgress(bool in_progress) { - controller_->OnInputInProgress(in_progress); + edit_model_delegate_->OnInputInProgress(in_progress); if (user_input_in_progress_ || !in_revert_) client_->OnInputStateChanged();
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h index 1a860f8..e388f5a 100644 --- a/components/omnibox/browser/omnibox_edit_model.h +++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -33,7 +33,7 @@ class AutocompleteResult; class OmniboxClient; -class OmniboxEditController; +class OmniboxEditModelDelegate; class OmniboxPopupView; namespace gfx { @@ -68,7 +68,7 @@ }; OmniboxEditModel(OmniboxView* view, - OmniboxEditController* controller, + OmniboxEditModelDelegate* edit_model_delegate, std::unique_ptr<OmniboxClient> client); virtual ~OmniboxEditModel(); OmniboxEditModel(const OmniboxEditModel&) = delete; @@ -89,7 +89,7 @@ void set_popup_view(OmniboxPopupView* popup_view); OmniboxPopupView* get_popup_view(); - OmniboxEditController* controller() const { return controller_; } + OmniboxEditModelDelegate* delegate() const { return edit_model_delegate_; } OmniboxClient* client() const { return client_.get(); } @@ -620,7 +620,7 @@ raw_ptr<OmniboxView> view_; - raw_ptr<OmniboxEditController> controller_; + raw_ptr<OmniboxEditModelDelegate> edit_model_delegate_; OmniboxFocusState focus_state_;
diff --git a/components/omnibox/browser/omnibox_edit_controller.h b/components/omnibox/browser/omnibox_edit_model_delegate.h similarity index 82% rename from components/omnibox/browser/omnibox_edit_controller.h rename to components/omnibox/browser/omnibox_edit_model_delegate.h index 3cba0f3..153bd7d3 100644 --- a/components/omnibox/browser/omnibox_edit_controller.h +++ b/components/omnibox/browser/omnibox_edit_model_delegate.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_EDIT_CONTROLLER_H_ -#define COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_EDIT_CONTROLLER_H_ +#ifndef COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_EDIT_MODEL_DELEGATE_H_ +#define COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_EDIT_MODEL_DELEGATE_H_ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" @@ -17,13 +17,13 @@ class LocationBarModel; -class OmniboxEditController - : public base::SupportsWeakPtr<OmniboxEditController> { +class OmniboxEditModelDelegate + : public base::SupportsWeakPtr<OmniboxEditModelDelegate> { public: - OmniboxEditController() = default; - OmniboxEditController(const OmniboxEditController&) = delete; - OmniboxEditController& operator=(const OmniboxEditController&) = delete; - virtual ~OmniboxEditController() = default; + OmniboxEditModelDelegate() = default; + OmniboxEditModelDelegate(const OmniboxEditModelDelegate&) = delete; + OmniboxEditModelDelegate& operator=(const OmniboxEditModelDelegate&) = delete; + virtual ~OmniboxEditModelDelegate() = default; virtual void OnAutocompleteAccept( const GURL& destination_url, @@ -73,4 +73,4 @@ bool destination_url_entered_without_scheme_; }; -#endif // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_EDIT_CONTROLLER_H_ +#endif // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_EDIT_MODEL_DELEGATE_H_
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc index 83c77b12..d6cd726a 100644 --- a/components/omnibox/browser/omnibox_edit_model_unittest.cc +++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -25,8 +25,8 @@ #include "components/omnibox/browser/search_provider.h" #include "components/omnibox/browser/test_location_bar_model.h" #include "components/omnibox/browser/test_omnibox_client.h" -#include "components/omnibox/browser/test_omnibox_edit_controller.h" #include "components/omnibox/browser/test_omnibox_edit_model.h" +#include "components/omnibox/browser/test_omnibox_edit_model_delegate.h" #include "components/omnibox/browser/test_omnibox_view.h" #include "components/omnibox/browser/test_scheme_classifier.h" #include "components/omnibox/common/omnibox_features.h" @@ -81,15 +81,15 @@ base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(omnibox::kSiteSearchStarterPack); - controller_ = std::make_unique<TestOmniboxEditController>(); - view_ = std::make_unique<TestOmniboxView>(controller_.get()); + edit_model_delegate_ = std::make_unique<TestOmniboxEditModelDelegate>(); + view_ = std::make_unique<TestOmniboxView>(edit_model_delegate_.get()); view_->SetModel(std::make_unique<TestOmniboxEditModel>( - view_.get(), controller_.get(), nullptr)); + view_.get(), edit_model_delegate_.get(), nullptr)); } TestOmniboxView* view() { return view_.get(); } TestLocationBarModel* location_bar_model() { - return controller_->GetLocationBarModel(); + return edit_model_delegate_->GetLocationBarModel(); } TestOmniboxEditModel* model() { return static_cast<TestOmniboxEditModel*>(view_->model()); @@ -97,7 +97,7 @@ protected: base::test::TaskEnvironment task_environment_; - std::unique_ptr<TestOmniboxEditController> controller_; + std::unique_ptr<TestOmniboxEditModelDelegate> edit_model_delegate_; std::unique_ptr<TestOmniboxView> view_; }; @@ -371,13 +371,13 @@ model()->OpenMatch(match, WindowOpenDisposition::CURRENT_TAB, alternate_nav_url, std::u16string(), 0); EXPECT_TRUE(AutocompleteInput::HasHTTPScheme( - controller_->alternate_nav_match().fill_into_edit)); + edit_model_delegate_->alternate_nav_match().fill_into_edit)); model()->SetUserText(u"abcd"); model()->OpenMatch(match, WindowOpenDisposition::CURRENT_TAB, alternate_nav_url, std::u16string(), 0); EXPECT_TRUE(AutocompleteInput::HasHTTPScheme( - controller_->alternate_nav_match().fill_into_edit)); + edit_model_delegate_->alternate_nav_match().fill_into_edit)); } TEST_F(OmniboxEditModelTest, CurrentMatch) { @@ -628,7 +628,8 @@ class OmniboxEditModelPopupTest : public ::testing::Test { public: OmniboxEditModelPopupTest() - : view_(&controller_), model_(&view_, &controller_, &pref_service_) { + : view_(&edit_model_delegate_), + model_(&view_, &edit_model_delegate_, &pref_service_) { omnibox::RegisterProfilePrefs(pref_service_.registry()); model_.set_popup_view(&popup_view_); model_.SetPopupIsOpen(true); @@ -642,7 +643,7 @@ private: base::test::TaskEnvironment task_environment_; - TestOmniboxEditController controller_; + TestOmniboxEditModelDelegate edit_model_delegate_; TestingPrefServiceSimple pref_service_; TestOmniboxView view_; @@ -1328,19 +1329,22 @@ model()->SetUserText(u"http://abcd"); model()->OpenMatch(match, WindowOpenDisposition::CURRENT_TAB, GURL(), std::u16string(), 0); - EXPECT_EQ(controller_->disposition(), WindowOpenDisposition::SWITCH_TO_TAB); + EXPECT_EQ(edit_model_delegate_->disposition(), + WindowOpenDisposition::SWITCH_TO_TAB); // Suggestions not from the Open Tab Provider or not from keyword mode should // not change the disposition. match.from_keyword = false; model()->OpenMatch(match, WindowOpenDisposition::CURRENT_TAB, GURL(), std::u16string(), 0); - EXPECT_EQ(controller_->disposition(), WindowOpenDisposition::CURRENT_TAB); + EXPECT_EQ(edit_model_delegate_->disposition(), + WindowOpenDisposition::CURRENT_TAB); match.provider = model()->autocomplete_controller()->search_provider(); match.from_keyword = true; model()->OpenMatch(match, WindowOpenDisposition::CURRENT_TAB, GURL(), std::u16string(), 0); - EXPECT_EQ(controller_->disposition(), WindowOpenDisposition::CURRENT_TAB); + EXPECT_EQ(edit_model_delegate_->disposition(), + WindowOpenDisposition::CURRENT_TAB); } #endif // !(BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID))
diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc index 28ba370..a1bfffe 100644 --- a/components/omnibox/browser/omnibox_view.cc +++ b/components/omnibox/browser/omnibox_view.cc
@@ -22,8 +22,8 @@ #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_match_type.h" #include "components/omnibox/browser/location_bar_model.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" #include "components/omnibox/browser/omnibox_edit_model.h" +#include "components/omnibox/browser/omnibox_edit_model_delegate.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/common/omnibox_features.h" #include "extensions/buildflags/buildflags.h" @@ -208,7 +208,8 @@ } if (model_->ShouldShowCurrentPageIcon()) { - LocationBarModel* location_bar_model = controller_->GetLocationBarModel(); + LocationBarModel* location_bar_model = + edit_model_delegate_->GetLocationBarModel(); return ui::ImageModel::FromVectorIcon(location_bar_model->GetVectorIcon(), color_current_page_icon, dip_size); } @@ -334,13 +335,13 @@ return state_changes; } -OmniboxView::OmniboxView(OmniboxEditController* controller, +OmniboxView::OmniboxView(OmniboxEditModelDelegate* edit_model_delegate, std::unique_ptr<OmniboxClient> client) - : controller_(controller) { + : edit_model_delegate_(edit_model_delegate) { // |client| can be null in tests. if (client) { - model_ = - std::make_unique<OmniboxEditModel>(this, controller, std::move(client)); + model_ = std::make_unique<OmniboxEditModel>(this, edit_model_delegate, + std::move(client)); } }
diff --git a/components/omnibox/browser/omnibox_view.h b/components/omnibox/browser/omnibox_view.h index eff5d30..6db9619 100644 --- a/components/omnibox/browser/omnibox_view.h +++ b/components/omnibox/browser/omnibox_view.h
@@ -30,7 +30,7 @@ #include "ui/gfx/range/range.h" class GURL; -class OmniboxEditController; +class OmniboxEditModelDelegate; class OmniboxViewMacTest; class OmniboxEditModel; @@ -282,7 +282,7 @@ State(const State& state); }; - OmniboxView(OmniboxEditController* controller, + OmniboxView(OmniboxEditModelDelegate* edit_model_delegate, std::unique_ptr<OmniboxClient> client); // Fills |state| with the current text state. @@ -302,8 +302,12 @@ // Try to parse the current text as a URL and colorize the components. virtual void EmphasizeURLComponents() = 0; - OmniboxEditController* controller() { return controller_; } - const OmniboxEditController* controller() const { return controller_; } + OmniboxEditModelDelegate* edit_model_delegate() { + return edit_model_delegate_; + } + const OmniboxEditModelDelegate* edit_model_delegate() const { + return edit_model_delegate_; + } // Marks part (or, if |range| is invalid, all) of the current text as // emphasized or de-emphasized, by changing its color. @@ -330,7 +334,7 @@ // |model_| can be NULL in tests. std::unique_ptr<OmniboxEditModel> model_; - raw_ptr<OmniboxEditController> controller_; + raw_ptr<OmniboxEditModelDelegate> edit_model_delegate_; }; #endif // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_VIEW_H_
diff --git a/components/omnibox/browser/omnibox_view_unittest.cc b/components/omnibox/browser/omnibox_view_unittest.cc index 6fa71767..4f53b8a 100644 --- a/components/omnibox/browser/omnibox_view_unittest.cc +++ b/components/omnibox/browser/omnibox_view_unittest.cc
@@ -19,8 +19,8 @@ #include "components/bookmarks/test/test_bookmark_client.h" #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/test_omnibox_client.h" -#include "components/omnibox/browser/test_omnibox_edit_controller.h" #include "components/omnibox/browser/test_omnibox_edit_model.h" +#include "components/omnibox/browser/test_omnibox_edit_model_delegate.h" #include "components/omnibox/browser/test_omnibox_view.h" #include "components/omnibox/common/omnibox_features.h" #include "testing/gtest/include/gtest/gtest.h" @@ -39,10 +39,10 @@ class OmniboxViewTest : public testing::Test { public: OmniboxViewTest() { - controller_ = std::make_unique<TestOmniboxEditController>(); - view_ = std::make_unique<TestOmniboxView>(controller_.get()); + edit_model_delegate_ = std::make_unique<TestOmniboxEditModelDelegate>(); + view_ = std::make_unique<TestOmniboxView>(edit_model_delegate_.get()); view_->SetModel(std::make_unique<TestOmniboxEditModel>( - view_.get(), controller_.get(), nullptr)); + view_.get(), edit_model_delegate_.get(), nullptr)); bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel(); client()->SetBookmarkModel(bookmark_model_.get()); @@ -62,7 +62,7 @@ private: base::test::TaskEnvironment task_environment_; - std::unique_ptr<TestOmniboxEditController> controller_; + std::unique_ptr<TestOmniboxEditModelDelegate> edit_model_delegate_; std::unique_ptr<TestOmniboxView> view_; std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_; };
diff --git a/components/omnibox/browser/test_omnibox_edit_model.cc b/components/omnibox/browser/test_omnibox_edit_model.cc index d7368cb3..f24fc2b 100644 --- a/components/omnibox/browser/test_omnibox_edit_model.cc +++ b/components/omnibox/browser/test_omnibox_edit_model.cc
@@ -7,10 +7,13 @@ #include "components/omnibox/browser/test_omnibox_client.h" #include "components/omnibox/browser/test_omnibox_edit_model.h" -TestOmniboxEditModel::TestOmniboxEditModel(OmniboxView* view, - OmniboxEditController* controller, - PrefService* pref_service) - : OmniboxEditModel(view, controller, std::make_unique<TestOmniboxClient>()), +TestOmniboxEditModel::TestOmniboxEditModel( + OmniboxView* view, + OmniboxEditModelDelegate* edit_model_delegate, + PrefService* pref_service) + : OmniboxEditModel(view, + edit_model_delegate, + std::make_unique<TestOmniboxClient>()), popup_is_open_(false), pref_service_(pref_service) {}
diff --git a/components/omnibox/browser/test_omnibox_edit_model.h b/components/omnibox/browser/test_omnibox_edit_model.h index 1c625800..eacdf2b 100644 --- a/components/omnibox/browser/test_omnibox_edit_model.h +++ b/components/omnibox/browser/test_omnibox_edit_model.h
@@ -14,7 +14,7 @@ class TestOmniboxEditModel : public OmniboxEditModel { public: TestOmniboxEditModel(OmniboxView* view, - OmniboxEditController* controller, + OmniboxEditModelDelegate* edit_model_delegate, PrefService* pref_service); ~TestOmniboxEditModel() override; TestOmniboxEditModel(const TestOmniboxEditModel&) = delete;
diff --git a/components/omnibox/browser/test_omnibox_edit_controller.cc b/components/omnibox/browser/test_omnibox_edit_model_delegate.cc similarity index 77% rename from components/omnibox/browser/test_omnibox_edit_controller.cc rename to components/omnibox/browser/test_omnibox_edit_model_delegate.cc index 0699c09..9c69817d 100644 --- a/components/omnibox/browser/test_omnibox_edit_controller.cc +++ b/components/omnibox/browser/test_omnibox_edit_model_delegate.cc
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/omnibox/browser/test_omnibox_edit_controller.h" +#include "components/omnibox/browser/test_omnibox_edit_model_delegate.h" -TestLocationBarModel* TestOmniboxEditController::GetLocationBarModel() { +TestLocationBarModel* TestOmniboxEditModelDelegate::GetLocationBarModel() { return &location_bar_model_; } -const TestLocationBarModel* TestOmniboxEditController::GetLocationBarModel() +const TestLocationBarModel* TestOmniboxEditModelDelegate::GetLocationBarModel() const { return &location_bar_model_; } -void TestOmniboxEditController::OnAutocompleteAccept( +void TestOmniboxEditModelDelegate::OnAutocompleteAccept( const GURL& destination_url, TemplateURLRef::PostContent* post_content, WindowOpenDisposition disposition,
diff --git a/components/omnibox/browser/test_omnibox_edit_controller.h b/components/omnibox/browser/test_omnibox_edit_model_delegate.h similarity index 69% rename from components/omnibox/browser/test_omnibox_edit_controller.h rename to components/omnibox/browser/test_omnibox_edit_model_delegate.h index d22399a..6e44eed1 100644 --- a/components/omnibox/browser/test_omnibox_edit_controller.h +++ b/components/omnibox/browser/test_omnibox_edit_model_delegate.h
@@ -2,22 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_CONTROLLER_H_ -#define COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_CONTROLLER_H_ +#ifndef COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_MODEL_DELEGATE_H_ +#define COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_MODEL_DELEGATE_H_ #include "components/omnibox/browser/autocomplete_match.h" -#include "components/omnibox/browser/omnibox_edit_controller.h" +#include "components/omnibox/browser/omnibox_edit_model_delegate.h" #include "components/omnibox/browser/test_location_bar_model.h" #include "ui/base/window_open_disposition.h" -class TestOmniboxEditController : public OmniboxEditController { +class TestOmniboxEditModelDelegate : public OmniboxEditModelDelegate { public: - TestOmniboxEditController() = default; - TestOmniboxEditController(const TestOmniboxEditController&) = delete; - TestOmniboxEditController& operator=(const TestOmniboxEditController&) = + TestOmniboxEditModelDelegate() = default; + TestOmniboxEditModelDelegate(const TestOmniboxEditModelDelegate&) = delete; + TestOmniboxEditModelDelegate& operator=(const TestOmniboxEditModelDelegate&) = delete; - // OmniboxEditController: + // OmniboxEditModelDelegate: TestLocationBarModel* GetLocationBarModel() override; const TestLocationBarModel* GetLocationBarModel() const override; void OnAutocompleteAccept( @@ -46,4 +46,4 @@ AutocompleteMatch alternate_nav_match_; }; -#endif // COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_CONTROLLER_H_ +#endif // COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_MODEL_DELEGATE_H_
diff --git a/components/omnibox/browser/test_omnibox_view.h b/components/omnibox/browser/test_omnibox_view.h index b740f2c..d8bc506 100644 --- a/components/omnibox/browser/test_omnibox_view.h +++ b/components/omnibox/browser/test_omnibox_view.h
@@ -14,13 +14,13 @@ #include "ui/gfx/range/range.h" struct AutocompleteMatch; -class OmniboxEditController; +class OmniboxEditModelDelegate; // Fake implementation of OmniboxView for use in tests. class TestOmniboxView : public OmniboxView { public: - explicit TestOmniboxView(OmniboxEditController* controller) - : OmniboxView(controller, nullptr) {} + explicit TestOmniboxView(OmniboxEditModelDelegate* edit_model_delegate) + : OmniboxView(edit_model_delegate, nullptr) {} TestOmniboxView(const TestOmniboxView&) = delete; TestOmniboxView& operator=(const TestOmniboxView&) = delete;
diff --git a/components/optimization_guide/proto/models.proto b/components/optimization_guide/proto/models.proto index a01a0fc..ec35430 100644 --- a/components/optimization_guide/proto/models.proto +++ b/components/optimization_guide/proto/models.proto
@@ -215,7 +215,7 @@ MODEL_ENGINE_VERSION_TFLITE_2_10 = 9; // A model using only operations that are supported by TensorflowLite 2.11.0. MODEL_ENGINE_VERSION_TFLITE_2_11 = 10; - // A model using only operations that are supported by TensorflowLite 2.11.0. + // A model using only operations that are supported by TensorflowLite 2.12.0. MODEL_ENGINE_VERSION_TFLITE_2_12 = 11; }
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn index eae9f11..c48d5b1 100644 --- a/components/password_manager/core/browser/BUILD.gn +++ b/components/password_manager/core/browser/BUILD.gn
@@ -368,15 +368,19 @@ sources += [ "password_strength_calculation.cc", "password_strength_calculation.h", + ] + deps += + [ "//components/password_manager/services/password_strength:service" ] + } + + if (!is_android) { + sources += [ "ui/reuse_check_utility.cc", "ui/reuse_check_utility.h", "ui/weak_check_utility.cc", "ui/weak_check_utility.h", ] - deps += [ - "//components/password_manager/services/password_strength:service", - "//third_party/zxcvbn-cpp", - ] + deps += [ "//third_party/zxcvbn-cpp" ] } if ((is_posix && !is_apple) || is_fuchsia) { @@ -807,12 +811,15 @@ ] if (!is_android && !is_ios) { + sources += [ "password_strength_calculation_unittest.cc" ] + deps += [ "//components/password_manager/services/password_strength:lib" ] + } + + if (!is_android) { sources += [ - "password_strength_calculation_unittest.cc", "ui/reuse_check_utility_unittest.cc", "ui/weak_check_utility_unittest.cc", ] - deps += [ "//components/password_manager/services/password_strength:lib" ] } if (!is_ios) {
diff --git a/components/password_manager/core/browser/password_change_success_tracker.h b/components/password_manager/core/browser/password_change_success_tracker.h index 324e88c..a9c6021 100644 --- a/components/password_manager/core/browser/password_change_success_tracker.h +++ b/components/password_manager/core/browser/password_change_success_tracker.h
@@ -36,9 +36,8 @@ static constexpr base::TimeDelta kFlowTypeRefinementTimeout = base::Seconds(30); - // Start and end events for automated (i.e. Autofill Assistant-driven) and - // manual flows (i.e. Chrome opens a CCT and a user updates a password on - // their own). + // Start and end events for flows (i.e. Chrome opens a CCT and a user updates + // a password on their own). // These values are persisted to prefs and used in enums.xml; do not reorder // or renumber entries! enum class StartEvent {
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index f4d1593..f34721f 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -747,13 +747,6 @@ IsCredentialAPISave()); } -void PasswordFormManager::ResetState() { - parsed_submitted_form_.reset(); - submitted_form_ = FormData(); - password_save_manager_->ResetPendingCredentials(); - is_submitted_ = false; -} - bool PasswordFormManager::ProvisionallySave( const FormData& submitted_form, const PasswordManagerDriver* driver, @@ -768,10 +761,12 @@ bool have_password_to_save = parsed_submitted_form && parsed_submitted_form->HasNonEmptyPasswordValue(); - if (!have_password_to_save) { // In case of error during parsing, reset the state. - ResetState(); + parsed_submitted_form_.reset(); + submitted_form_ = FormData(); + password_save_manager_->ResetPendingCredentials(); + is_submitted_ = false; return false; }
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h index 5fd567f..c10e91a 100644 --- a/components/password_manager/core/browser/password_form_manager.h +++ b/components/password_manager/core/browser/password_form_manager.h
@@ -84,10 +84,6 @@ // for success detection. bool IsEqualToSubmittedForm(const autofill::FormData& form) const; - // Clears potentially submitted or pending form. Used to forget the state when - // Autofill Assistant has handled a submission. - void ResetState(); - // If |submitted_form| is managed by *this (i.e. DoesManage returns true for // |submitted_form| and |driver|) then saves |submitted_form| to // |submitted_form_| field, sets |is_submitted| = true and returns true.
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc index 5bb97f3..7c411c4 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -717,20 +717,6 @@ EXPECT_EQ(PasswordForm(), form_manager_->GetPendingCredentials()); } -TEST_P(PasswordFormManagerTest, ResetState) { - EXPECT_TRUE( - form_manager_->ProvisionallySave(submitted_form_, &driver_, nullptr)); - EXPECT_TRUE(form_manager_->is_submitted()); - EXPECT_TRUE(form_manager_->GetSubmittedForm()); - EXPECT_NE(PasswordForm(), form_manager_->GetPendingCredentials()); - - form_manager_->ResetState(); - - EXPECT_FALSE(form_manager_->is_submitted()); - EXPECT_FALSE(form_manager_->GetSubmittedForm()); - EXPECT_EQ(PasswordForm(), form_manager_->GetPendingCredentials()); -} - // Tests that when PasswordFormManager receives saved matches it waits for // server predictions and fills on receiving them. TEST_P(PasswordFormManagerTest, ServerPredictionsWithinDelay) {
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager.cc b/components/password_manager/core/browser/ui/insecure_credentials_manager.cc index ce470915..e9dbc234 100644 --- a/components/password_manager/core/browser/ui/insecure_credentials_manager.cc +++ b/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
@@ -28,7 +28,7 @@ #include "components/password_manager/core/browser/ui/saved_passwords_presenter.h" #include "components/password_manager/core/common/password_manager_features.h" -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#if !BUILDFLAG(IS_ANDROID) #include "components/password_manager/core/browser/ui/reuse_check_utility.h" #include "components/password_manager/core/browser/ui/weak_check_utility.h" #endif @@ -42,8 +42,7 @@ insecure_type == InsecureType::kPhished); } -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) -// The function is only used by the weak check. +#if !BUILDFLAG(IS_ANDROID) base::flat_set<std::u16string> ExtractPasswords( const std::vector<CredentialUIEntry>& credentials) { return base::MakeFlatSet<std::u16string>(credentials, {}, @@ -51,10 +50,27 @@ } bool IsCheckForReusedPasswordsEnabled() { +#if BUILDFLAG(IS_IOS) + // Weak and reused checks are controlled by the Password Checkup feature. + return base::FeatureList::IsEnabled( + password_manager::features::kIOSPasswordCheckup); +#else return base::FeatureList::IsEnabled( password_manager::features::kPasswordManagerRedesign); +#endif } -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) + +bool IsCheckForWeakPasswordsEnabled() { +#if BUILDFLAG(IS_IOS) + // Weak and reused checks are controlled by the Password Checkup feature. + return base::FeatureList::IsEnabled( + password_manager::features::kIOSPasswordCheckup); +#else + return true; +#endif +} + +#endif // !BUILDFLAG(IS_ANDROID) } // namespace InsecureCredentialsManager::InsecureCredentialsManager( @@ -69,7 +85,7 @@ InsecureCredentialsManager::~InsecureCredentialsManager() = default; -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#if !BUILDFLAG(IS_ANDROID) void InsecureCredentialsManager::StartReuseCheck( base::OnceClosure on_check_done) { base::ThreadPool::PostTaskAndReplyWithResult( @@ -90,7 +106,7 @@ weak_ptr_factory_.GetWeakPtr(), base::ElapsedTimer()) .Then(std::move(on_check_done))); } -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#endif // !BUILDFLAG(IS_ANDROID) void InsecureCredentialsManager::SaveInsecureCredential( const LeakCheckCredential& leak) { @@ -142,7 +158,8 @@ DCHECK(presenter_); std::vector<CredentialUIEntry> credentials = presenter_->GetSavedCredentials(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) + +#if BUILDFLAG(IS_ANDROID) // Otherwise erase entries which aren't leaked and phished. base::EraseIf(credentials, [](const auto& credential) { return !credential.IsLeaked() && !credential.IsPhished(); @@ -163,6 +180,7 @@ base::Time(), password_manager::IsMuted(false))}); } } + base::EraseIf(credentials, [](const auto& credential) { return credential.password_issues.empty(); }); @@ -195,23 +213,25 @@ } void InsecureCredentialsManager::OnEdited(const CredentialUIEntry& credential) { - // The WeakCheck is a Desktop only feature for now. Disable on Mobile to - // avoid pulling in a big dependency on zxcvbn. -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) + // The WeakCheck feature is not available on Android yet. Disable on Android + // to avoid pulling in a big dependency on zxcvbn. +#if !BUILDFLAG(IS_ANDROID) if (IsCheckForReusedPasswordsEnabled()) { // Re-run reused check since user might have changed reused password. StartReuseCheck(); } - const std::u16string& password = credential.password; - if (weak_passwords_.contains(password) || !IsWeak(password)) { - // Either the password is already known to be weak, or it is not weak at - // all. In both cases there is nothing to do. - return; - } + if (IsCheckForWeakPasswordsEnabled()) { + const std::u16string& password = credential.password; + if (weak_passwords_.contains(password) || !IsWeak(password)) { + // Either the password is already known to be weak, or it is not weak at + // all. In both cases there is nothing to do. + return; + } - weak_passwords_.insert(password); - NotifyInsecureCredentialsChanged(); + weak_passwords_.insert(password); + NotifyInsecureCredentialsChanged(); + } #endif }
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager.h b/components/password_manager/core/browser/ui/insecure_credentials_manager.h index 0be924cc..d2ede14 100644 --- a/components/password_manager/core/browser/ui/insecure_credentials_manager.h +++ b/components/password_manager/core/browser/ui/insecure_credentials_manager.h
@@ -55,7 +55,7 @@ scoped_refptr<PasswordStoreInterface> account_store); ~InsecureCredentialsManager() override; -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#if !BUILDFLAG(IS_ANDROID) // Computes reused credentials in a separate thread and then passes the result // to OnReuseCheckDone. void StartReuseCheck(base::OnceClosure on_check_done = base::DoNothing());
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc b/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc index ae5a4bc..f4dc749 100644 --- a/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc +++ b/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
@@ -37,13 +37,13 @@ constexpr char16_t kPassword216[] = u"pmsFlsnoab4nsl#losb@skpfnsbkjb^klsnbs!cns"; -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#if !BUILDFLAG(IS_ANDROID) constexpr char16_t kWeakPassword1[] = u"123456"; constexpr char16_t kWeakPassword216[] = u"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcda"; // Delay in milliseconds. constexpr int kDelay = 2; -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#endif // !BUILDFLAG(IS_ANDROID) using ::testing::ElementsAre; using ::testing::ElementsAreArray; @@ -320,7 +320,7 @@ ElementsAre(CredentialUIEntry(password1))); } -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#if !BUILDFLAG(IS_ANDROID) TEST_F(InsecureCredentialsManagerTest, StartWeakCheckNotifiesOnCompletion) { base::MockOnceClosure closure; provider().StartWeakCheck(closure.Get()); @@ -535,7 +535,7 @@ histogram_tester().ExpectUniqueSample( "PasswordManager.WeakCheck.PasswordScore", 0, 1); } -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#endif // !BUILDFLAG(IS_ANDROID) // Test verifies that saving LeakCheckCredential via provider adds expected // compromised credential. @@ -886,8 +886,8 @@ store().AddLogin(password); RunUntilIdle(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - // Weak passwords are filtered on Android and iOS. +#if BUILDFLAG(IS_ANDROID) + // Weak passwords are filtered on Android. ASSERT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); #else ASSERT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1)); @@ -897,8 +897,8 @@ RunUntilIdle(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - // Weak passwords are filtered on Android and iOS. +#if BUILDFLAG(IS_ANDROID) + // Weak passwords are filtered on Android. EXPECT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); #else EXPECT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1)); @@ -921,8 +921,8 @@ store().AddLogin(password); RunUntilIdle(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - // Weak passwords are filtered on Android and iOS. +#if BUILDFLAG(IS_ANDROID) + // Weak passwords are filtered on Android. ASSERT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); #else ASSERT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1)); @@ -932,8 +932,8 @@ RunUntilIdle(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - // Weak passwords are filtered on Android and iOS. +#if BUILDFLAG(IS_ANDROID) + // Weak passwords are filtered on Android. EXPECT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); #else EXPECT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1)); @@ -958,8 +958,8 @@ store().AddLogin(password); RunUntilIdle(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - // Reused passwords are filtered on Android and iOS. +#if BUILDFLAG(IS_ANDROID) + // Reused passwords are filtered on Android. ASSERT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); #else ASSERT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1)); @@ -969,8 +969,8 @@ RunUntilIdle(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - // Reused passwords are filtered on Android and iOS. +#if BUILDFLAG(IS_ANDROID) + // Reused passwords are filtered on Android. EXPECT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); #else EXPECT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1)); @@ -993,8 +993,8 @@ store().AddLogin(password); RunUntilIdle(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - // Reused passwords are filtered on Android and iOS. +#if BUILDFLAG(IS_ANDROID) + // Reused passwords are filtered on Android. ASSERT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); #else ASSERT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1)); @@ -1004,8 +1004,8 @@ RunUntilIdle(); -#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) - // Reused passwords are filtered on Android and iOS. +#if BUILDFLAG(IS_ANDROID) + // Reused passwords are filtered on Android. EXPECT_THAT(provider().GetInsecureCredentialEntries(), IsEmpty()); #else EXPECT_THAT(provider().GetInsecureCredentialEntries(), SizeIs(1)); @@ -1038,10 +1038,14 @@ EXPECT_TRUE(provider().GetInsecureCredentialEntries().empty()); } -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#if !BUILDFLAG(IS_ANDROID) // Test verifies that editing a weak credential to another weak credential // continues to be treated weak. TEST_F(InsecureCredentialsManagerTest, UpdatedWeakPasswordBecomesStrong) { +#if BUILDFLAG(IS_IOS) + base::test::ScopedFeatureList feature_list( + password_manager::features::kIOSPasswordCheckup); +#endif PasswordForm password_form = MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1); @@ -1065,6 +1069,10 @@ // Test verifies that editing a weak credential to another weak credential // continues to be treated weak. TEST_F(InsecureCredentialsManagerTest, UpdatedWeakPasswordRemainsWeak) { +#if BUILDFLAG(IS_IOS) + base::test::ScopedFeatureList feature_list( + password_manager::features::kIOSPasswordCheckup); +#endif PasswordForm password_form = MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1); @@ -1145,8 +1153,13 @@ } TEST_F(InsecureCredentialsManagerTest, UpdatingReusedPasswordFixesTheIssue) { +#if BUILDFLAG(IS_IOS) + base::test::ScopedFeatureList scoped_feature_list( + password_manager::features::kIOSPasswordCheckup); +#else base::test::ScopedFeatureList scoped_feature_list( password_manager::features::kPasswordManagerRedesign); +#endif PasswordForm form1 = MakeSavedPassword(kExampleCom, kUsername1, kPassword1); PasswordForm form2 = MakeSavedPassword(kExampleCom, kUsername2, kPassword1); @@ -1190,7 +1203,7 @@ ElementsAre(CredentialUIEntry(password1))); } -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#endif // !BUILDFLAG(IS_ANDROID) TEST_F(InsecureCredentialsManagerTest, GetInsecureCredentialsFiltersDuplicates) { @@ -1316,7 +1329,7 @@ .password_issues.size()); } -#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#if !BUILDFLAG(IS_ANDROID) TEST_F(InsecureCredentialsManagerWithTwoStoresTest, GetInsecureCredentialsWeak) { profile_store().AddLogin( @@ -1336,6 +1349,6 @@ ElementsAre(CredentialUIEntry(expected_form))); } -#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) +#endif // !BUILDFLAG(IS_ANDROID) } // namespace password_manager
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn index 788824a..76794b2 100644 --- a/components/performance_manager/BUILD.gn +++ b/components/performance_manager/BUILD.gn
@@ -11,6 +11,7 @@ static_library("performance_manager") { sources = [ "binders.cc", + "browser_child_process_host_proxy.cc", "decorators/frame_visibility_decorator.cc", "decorators/frame_visibility_decorator.h", "decorators/freezing_vote_decorator.cc", @@ -112,6 +113,8 @@ "power/battery_level_provider_creator.cc", "process_node_source.cc", "process_node_source.h", + "public/browser_child_process_host_id.h", + "public/browser_child_process_host_proxy.h", "public/decorators/page_live_state_decorator.h", "public/decorators/page_load_tracker_decorator_helper.h", "public/decorators/process_metrics_decorator.h",
diff --git a/components/performance_manager/browser_child_process_host_proxy.cc b/components/performance_manager/browser_child_process_host_proxy.cc new file mode 100644 index 0000000..2abd8ca --- /dev/null +++ b/components/performance_manager/browser_child_process_host_proxy.cc
@@ -0,0 +1,35 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/performance_manager/public/browser_child_process_host_proxy.h" + +#include "content/public/browser/browser_child_process_host.h" + +namespace performance_manager { + +BrowserChildProcessHostProxy::BrowserChildProcessHostProxy() = default; +BrowserChildProcessHostProxy::~BrowserChildProcessHostProxy() = default; +BrowserChildProcessHostProxy::BrowserChildProcessHostProxy( + const BrowserChildProcessHostProxy& other) = default; +BrowserChildProcessHostProxy& BrowserChildProcessHostProxy::operator=( + const BrowserChildProcessHostProxy& other) = default; + +content::BrowserChildProcessHost* BrowserChildProcessHostProxy::Get() const { + return content::BrowserChildProcessHost::FromID( + browser_child_process_host_id_.value()); +} + +BrowserChildProcessHostProxy::BrowserChildProcessHostProxy( + BrowserChildProcessHostId browser_child_process_host_id) + : browser_child_process_host_id_(browser_child_process_host_id) { + DCHECK_GE(browser_child_process_host_id.value(), 0); +} + +// static +BrowserChildProcessHostProxy BrowserChildProcessHostProxy::CreateForTesting( + BrowserChildProcessHostId browser_child_process_host_id) { + return BrowserChildProcessHostProxy(browser_child_process_host_id); +} + +} // namespace performance_manager
diff --git a/components/performance_manager/graph/process_node_impl.cc b/components/performance_manager/graph/process_node_impl.cc index 01791d99..d819b393 100644 --- a/components/performance_manager/graph/process_node_impl.cc +++ b/components/performance_manager/graph/process_node_impl.cc
@@ -57,13 +57,16 @@ ProcessNodeImpl::ProcessNodeImpl( RenderProcessHostProxy render_process_host_proxy) : process_type_(content::PROCESS_TYPE_RENDERER), - render_process_host_proxy_(std::move(render_process_host_proxy)) { + child_process_host_proxy_(std::move(render_process_host_proxy)) { weak_this_ = weak_factory_.GetWeakPtr(); DETACH_FROM_SEQUENCE(sequence_checker_); } -ProcessNodeImpl::ProcessNodeImpl(content::ProcessType process_type) - : process_type_(process_type) { +ProcessNodeImpl::ProcessNodeImpl( + content::ProcessType process_type, + BrowserChildProcessHostProxy browser_child_process_host_proxy) + : process_type_(process_type), + child_process_host_proxy_(std::move(browser_child_process_host_proxy)) { DCHECK_NE(process_type, content::PROCESS_TYPE_BROWSER); DCHECK_NE(process_type, content::PROCESS_TYPE_RENDERER); weak_this_ = weak_factory_.GetWeakPtr(); @@ -225,7 +228,7 @@ RenderProcessHostId ProcessNodeImpl::GetRenderProcessId() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return RenderProcessHostId( - render_process_host_proxy_.render_process_host_id()); + render_process_host_proxy().render_process_host_id()); } void ProcessNodeImpl::AddFrame(FrameNodeImpl* frame_node) { @@ -378,6 +381,14 @@ return render_process_host_proxy(); } +const BrowserChildProcessHostProxy& +ProcessNodeImpl::GetBrowserChildProcessHostProxy() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_NE(process_type_, content::PROCESS_TYPE_BROWSER); + DCHECK_NE(process_type_, content::PROCESS_TYPE_RENDERER); + return browser_child_process_host_proxy(); +} + base::TaskPriority ProcessNodeImpl::GetPriority() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return priority();
diff --git a/components/performance_manager/graph/process_node_impl.h b/components/performance_manager/graph/process_node_impl.h index eeb6b28..cdcace6d 100644 --- a/components/performance_manager/graph/process_node_impl.h +++ b/components/performance_manager/graph/process_node_impl.h
@@ -17,6 +17,7 @@ #include "components/performance_manager/graph/node_attached_data.h" #include "components/performance_manager/graph/node_base.h" #include "components/performance_manager/graph/properties.h" +#include "components/performance_manager/public/browser_child_process_host_proxy.h" #include "components/performance_manager/public/graph/process_node.h" #include "components/performance_manager/public/mojom/coordination_unit.mojom.h" #include "components/performance_manager/public/mojom/v8_contexts.mojom.h" @@ -25,6 +26,7 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/abseil-cpp/absl/types/variant.h" #include "third_party/blink/public/common/tokens/tokens.h" namespace performance_manager { @@ -62,7 +64,9 @@ explicit ProcessNodeImpl(RenderProcessHostProxy render_process_host_proxy); // Constructor for a non-renderer child process. - explicit ProcessNodeImpl(content::ProcessType process_type); + ProcessNodeImpl( + content::ProcessType process_type, + BrowserChildProcessHostProxy browser_child_process_host_proxy); ProcessNodeImpl(const ProcessNodeImpl&) = delete; ProcessNodeImpl& operator=(const ProcessNodeImpl&) = delete; @@ -157,7 +161,11 @@ } const RenderProcessHostProxy& render_process_host_proxy() const { - return render_process_host_proxy_; + return absl::get<RenderProcessHostProxy>(child_process_host_proxy_); + } + + const BrowserChildProcessHostProxy& browser_child_process_host_proxy() const { + return absl::get<BrowserChildProcessHostProxy>(child_process_host_proxy_); } base::TaskPriority priority() const { @@ -223,6 +231,8 @@ uint64_t GetResidentSetKb() const override; RenderProcessHostId GetRenderProcessHostId() const override; const RenderProcessHostProxy& GetRenderProcessHostProxy() const override; + const BrowserChildProcessHostProxy& GetBrowserChildProcessHostProxy() + const override; base::TaskPriority GetPriority() const override; ContentTypes GetHostedContentTypes() const override; @@ -252,9 +262,11 @@ const content::ProcessType process_type_ GUARDED_BY_CONTEXT(sequence_checker_); - // This is used during frame node initialization. - // TODO(siggi): It seems unnecessary to initialize this at creation time? - const RenderProcessHostProxy render_process_host_proxy_; + // The proxy that allows access to either the RenderProcessHost or the + // BrowserChildProcessHost associated with this process, if `this` is a + // process node for a child process (process_type() != PROCESS_TYPE_BROWSER). + const absl::variant<RenderProcessHostProxy, BrowserChildProcessHostProxy> + child_process_host_proxy_; ObservedProperty::NotifiesOnlyOnChanges< bool,
diff --git a/components/performance_manager/graph/process_node_impl_unittest.cc b/components/performance_manager/graph/process_node_impl_unittest.cc index e8f1c49..6cd3e58 100644 --- a/components/performance_manager/graph/process_node_impl_unittest.cc +++ b/components/performance_manager/graph/process_node_impl_unittest.cc
@@ -227,12 +227,20 @@ } TEST_F(ProcessNodeImplTest, ConstructionArguments_NonRenderer) { - auto process_node = CreateNode<ProcessNodeImpl>(content::PROCESS_TYPE_GPU); + constexpr BrowserChildProcessHostId kBrowserChildProcessHostId = + BrowserChildProcessHostId(0xF0B); + auto process_node = CreateNode<ProcessNodeImpl>( + content::PROCESS_TYPE_GPU, BrowserChildProcessHostProxy::CreateForTesting( + kBrowserChildProcessHostId)); const ProcessNode* public_process_node = process_node.get(); EXPECT_EQ(content::PROCESS_TYPE_GPU, process_node->process_type()); EXPECT_EQ(content::PROCESS_TYPE_GPU, public_process_node->GetProcessType()); + + EXPECT_EQ(kBrowserChildProcessHostId, + public_process_node->GetBrowserChildProcessHostProxy() + .browser_child_process_host_id()); } TEST_F(ProcessNodeImplTest, PublicInterface) {
diff --git a/components/performance_manager/performance_manager_impl.cc b/components/performance_manager/performance_manager_impl.cc index ad5b0d6..e9a75f04 100644 --- a/components/performance_manager/performance_manager_impl.cc +++ b/components/performance_manager/performance_manager_impl.cc
@@ -164,14 +164,17 @@ std::unique_ptr<ProcessNodeImpl> PerformanceManagerImpl::CreateProcessNode( RenderProcessHostProxy render_process_host_proxy) { return CreateNodeImpl<ProcessNodeImpl>( - base::OnceCallback<void(ProcessNodeImpl*)>(), render_process_host_proxy); + base::OnceCallback<void(ProcessNodeImpl*)>(), + std::move(render_process_host_proxy)); } // static std::unique_ptr<ProcessNodeImpl> PerformanceManagerImpl::CreateProcessNode( - content::ProcessType process_type) { + content::ProcessType process_type, + BrowserChildProcessHostProxy browser_child_process_host_proxy) { return CreateNodeImpl<ProcessNodeImpl>( - base::OnceCallback<void(ProcessNodeImpl*)>(), process_type); + base::OnceCallback<void(ProcessNodeImpl*)>(), process_type, + std::move(browser_child_process_host_proxy)); } // static
diff --git a/components/performance_manager/performance_manager_impl.h b/components/performance_manager/performance_manager_impl.h index 8e83e75..daa8e2d 100644 --- a/components/performance_manager/performance_manager_impl.h +++ b/components/performance_manager/performance_manager_impl.h
@@ -16,6 +16,7 @@ #include "base/sequence_checker.h" #include "base/task/sequenced_task_runner.h" #include "components/performance_manager/graph/graph_impl.h" +#include "components/performance_manager/public/browser_child_process_host_proxy.h" #include "components/performance_manager/public/graph/frame_node.h" #include "components/performance_manager/public/graph/page_node.h" #include "components/performance_manager/public/graph/worker_node.h" @@ -116,7 +117,8 @@ static std::unique_ptr<ProcessNodeImpl> CreateProcessNode( RenderProcessHostProxy proxy); static std::unique_ptr<ProcessNodeImpl> CreateProcessNode( - content::ProcessType process_type); + content::ProcessType process_type, + BrowserChildProcessHostProxy proxy); static std::unique_ptr<WorkerNodeImpl> CreateWorkerNode( const std::string& browser_context_id, WorkerNode::WorkerType worker_type,
diff --git a/components/performance_manager/public/browser_child_process_host_id.h b/components/performance_manager/public/browser_child_process_host_id.h new file mode 100644 index 0000000..538fb73 --- /dev/null +++ b/components/performance_manager/public/browser_child_process_host_id.h
@@ -0,0 +1,40 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_BROWSER_CHILD_PROCESS_HOST_ID_H_ +#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_BROWSER_CHILD_PROCESS_HOST_ID_H_ + +#include "base/types/id_type.h" +#include "content/public/browser/child_process_host.h" + +namespace performance_manager { + +using BrowserChildProcessHostIdBase = + base::IdType<class BrowserChildProcessHostIdTag, + int32_t, + content::ChildProcessHost::kInvalidUniqueID, + 1>; + +// A strongly typed wrapper for the id returned by +// BrowserChildProcessHost::GetData().id. +// +// This uses ChildProcessHost::kInvalidUniqueId (-1) as the default invalid id, +// but also recognizes 0 as an invalid id because there is existing code that +// uses 0 as an invalid value. It starts generating id's at 1. +class BrowserChildProcessHostId : public BrowserChildProcessHostIdBase { + public: + using BrowserChildProcessHostIdBase::BrowserChildProcessHostIdBase; + + // 0 is also an invalid value. + constexpr bool is_null() const { + return BrowserChildProcessHostIdBase::is_null() || this->value() == 0; + } + + // Override operator bool() to call the overridden is_null(). + constexpr explicit operator bool() const { return !is_null(); } +}; + +} // namespace performance_manager + +#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_BROWSER_CHILD_PROCESS_HOST_ID_H_
diff --git a/components/performance_manager/public/browser_child_process_host_proxy.h b/components/performance_manager/public/browser_child_process_host_proxy.h new file mode 100644 index 0000000..69a783e --- /dev/null +++ b/components/performance_manager/public/browser_child_process_host_proxy.h
@@ -0,0 +1,59 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_BROWSER_CHILD_PROCESS_HOST_PROXY_H_ +#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_BROWSER_CHILD_PROCESS_HOST_PROXY_H_ + +#include "components/performance_manager/public/browser_child_process_host_id.h" +#include "content/public/browser/child_process_host.h" + +namespace content { +class BrowserChildProcessHost; +} // namespace content + +namespace performance_manager { + +// A BrowserChildProcessHostProxy is used to post messages out of the +// performance manager sequence that are bound for a BrowserChildProcessHost +// running on the UI thread. The object is bound to the UI thread. A +// BrowserChildProcessHostProxy is conceputally equivalent to a +// WeakPtr<BrowserChildProcessHost>. Copy and assignment are explicitly allowed +// for this object. +class BrowserChildProcessHostProxy { + public: + BrowserChildProcessHostProxy(); + BrowserChildProcessHostProxy(const BrowserChildProcessHostProxy& other); + ~BrowserChildProcessHostProxy(); + BrowserChildProcessHostProxy& operator=( + const BrowserChildProcessHostProxy& other); + + // Allows resolving this proxy to the underlying BrowserChildProcessHost. This + // must only be called on the UI thread. Returns nullptr if the + // BrowserChildProcessHost no longer exists. + content::BrowserChildProcessHost* Get() const; + + // Returns the routing id of the BrowserChildProcessHost (from + // BrowserChildProcessHost::GetID). Can be ChildProcessHost::kInvalidUniqueID + // in unit tests. + BrowserChildProcessHostId browser_child_process_host_id() const { + return browser_child_process_host_id_; + } + + static BrowserChildProcessHostProxy CreateForTesting( + BrowserChildProcessHostId browser_child_process_host_id); + + protected: + friend class BrowserChildProcessWatcher; + + explicit BrowserChildProcessHostProxy( + BrowserChildProcessHostId browser_child_process_host_id); + + private: + BrowserChildProcessHostId browser_child_process_host_id_ = + BrowserChildProcessHostId(content::ChildProcessHost::kInvalidUniqueID); +}; + +} // namespace performance_manager + +#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_BROWSER_CHILD_PROCESS_HOST_PROXY_H_
diff --git a/components/performance_manager/public/graph/process_node.h b/components/performance_manager/public/graph/process_node.h index fccd209..5d43df03 100644 --- a/components/performance_manager/public/graph/process_node.h +++ b/components/performance_manager/public/graph/process_node.h
@@ -24,6 +24,7 @@ class WorkerNode; class ProcessNodeObserver; class RenderProcessHostProxy; +class BrowserChildProcessHostProxy; // A process node follows the lifetime of a RenderProcessHost. // It may reference zero or one processes at a time, but during its lifetime, it @@ -133,9 +134,16 @@ virtual RenderProcessHostId GetRenderProcessHostId() const = 0; // Returns a proxy to the RenderProcessHost associated with this node. The - // proxy may only be dereferenced on the UI thread. + // proxy may only be dereferenced on the UI thread. The proxy is only valid + // for renderer processes. virtual const RenderProcessHostProxy& GetRenderProcessHostProxy() const = 0; + // Returns a proxy to the BrowserChildProcessHost associated with this node. + // The proxy may only be dereferenced on the UI thread. The proxy is only + // valid for non-renderer child processes. + virtual const BrowserChildProcessHostProxy& GetBrowserChildProcessHostProxy() + const = 0; + // Returns the current priority of the process. virtual base::TaskPriority GetPriority() const = 0;
diff --git a/components/performance_manager/public/render_frame_host_proxy.h b/components/performance_manager/public/render_frame_host_proxy.h index a4cdd705..547b228 100644 --- a/components/performance_manager/public/render_frame_host_proxy.h +++ b/components/performance_manager/public/render_frame_host_proxy.h
@@ -16,7 +16,7 @@ class FrameNodeImpl; // A RenderFrameHostProxy is used to post messages out of the performance -// manager sequence that are bound for a RenderFrameHostProxy running on the UI +// manager sequence that are bound for a RenderFrameHost running on the UI // thread. The object is bound to the UI thread. A RenderFrameHostProxy is // conceptually equivalent to a WeakPtr<RenderFrameHost>. Copy and assignment // are explicitly allowed for this object.
diff --git a/components/performance_manager/public/render_process_host_proxy.h b/components/performance_manager/public/render_process_host_proxy.h index 8715676..5092d84 100644 --- a/components/performance_manager/public/render_process_host_proxy.h +++ b/components/performance_manager/public/render_process_host_proxy.h
@@ -32,8 +32,8 @@ content::RenderProcessHost* Get() const; // Returns the routing id of the render process (from - // RenderProcessHost::GetID), or ChildProcessHost::kInvalidUniqueID if this is - // not a renderer. + // RenderProcessHost::GetID). Can be ChildProcessHost::kInvalidUniqueID + // in unit tests. RenderProcessHostId render_process_host_id() const { return render_process_host_id_; }
diff --git a/components/performance_manager/render_process_host_proxy.cc b/components/performance_manager/render_process_host_proxy.cc index bb713370..b1ab8d1c 100644 --- a/components/performance_manager/render_process_host_proxy.cc +++ b/components/performance_manager/render_process_host_proxy.cc
@@ -22,7 +22,7 @@ RenderProcessHostProxy::RenderProcessHostProxy( RenderProcessHostId render_process_host_id) : render_process_host_id_(render_process_host_id) { - DCHECK(render_process_host_id_.value() >= 0); + DCHECK_GE(render_process_host_id_.value(), 0); } // static
diff --git a/components/performance_manager/test_support/graph_test_harness.h b/components/performance_manager/test_support/graph_test_harness.h index df9f52f..6ed1e4d 100644 --- a/components/performance_manager/test_support/graph_test_harness.h +++ b/components/performance_manager/test_support/graph_test_harness.h
@@ -104,8 +104,10 @@ return std::make_unique<ProcessNodeImpl>(std::move(proxy)); } static std::unique_ptr<ProcessNodeImpl> Create( - content::ProcessType process_type) { - return std::make_unique<ProcessNodeImpl>(process_type); + content::ProcessType process_type, + BrowserChildProcessHostProxy proxy = BrowserChildProcessHostProxy()) { + // Provide an empty BrowserChildProcessHostProxy by default. + return std::make_unique<ProcessNodeImpl>(process_type, std::move(proxy)); } };
diff --git a/components/policy/core/common/features.cc b/components/policy/core/common/features.cc index 87c463c5..2c90e95 100644 --- a/components/policy/core/common/features.cc +++ b/components/policy/core/common/features.cc
@@ -34,6 +34,12 @@ "DmTokenDeletion", base::FEATURE_ENABLED_BY_DEFAULT); +#if BUILDFLAG(IS_ANDROID) +BASE_FEATURE(kPolicyLogsPageAndroid, + "PolicyLogsPageAndroid", + base::FEATURE_DISABLED_BY_DEFAULT); +#endif // BUILDFLAG(IS_ANDROID) + } // namespace features } // namespace policy
diff --git a/components/policy/core/common/features.h b/components/policy/core/common/features.h index e3c31d8..a4eb8e60 100644 --- a/components/policy/core/common/features.h +++ b/components/policy/core/common/features.h
@@ -39,6 +39,11 @@ // deleted from CBCM. POLICY_EXPORT BASE_DECLARE_FEATURE(kDmTokenDeletion); +#if BUILDFLAG(IS_ANDROID) +// Enable logging and chrome://policy/logs page on Android. +POLICY_EXPORT BASE_DECLARE_FEATURE(kPolicyLogsPageAndroid); +#endif // BUILDFLAG(IS_ANDROID) + } // namespace features } // namespace policy
diff --git a/components/policy/core/common/policy_logger.cc b/components/policy/core/common/policy_logger.cc index 19c230c..45e292359 100644 --- a/components/policy/core/common/policy_logger.cc +++ b/components/policy/core/common/policy_logger.cc
@@ -1,17 +1,52 @@ // Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - #include "components/policy/core/common/policy_logger.h" - #include <utility> - #include "base/no_destructor.h" #include "base/notreached.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" +#include "components/policy/core/common/features.h" #include "components/version_info/version_info.h" +namespace { + +// The base format for the Chromium Code Search URLs. +constexpr char kChromiumCSUrlFormat[] = + "https://source.chromium.org/chromium/chromium/src/+/main:%s;l=%i;drc:%s"; + +// Gets the string value for the log source. +std::string GetLogSourceValue( + const policy::PolicyLogger::Log::LogSource log_source) { + switch (log_source) { + case policy::PolicyLogger::Log::LogSource::kCBCMEnrollment: + return "CBCM Enrollment"; + case policy::PolicyLogger::Log::LogSource::kPlatformPolicy: + return "Platform Policy"; + case policy::PolicyLogger::Log::LogSource::kPolicyFetching: + return "Policy Fetching"; + default: + NOTREACHED(); + } +} + +// Constructs the URL for Chromium Code Search that points to the line of code +// that generated the log and the Chromium git revision hash. +std::string GetLineURL(const base::Location location) { + std::string last_change = version_info::GetLastChange(); + + // The substring separates the last change commit hash from the branch name on + // the '-'. + return base::StringPrintf( + kChromiumCSUrlFormat, location.file_name(), location.line_number(), + last_change.substr(0, last_change.find('-')).c_str()); +} + +} // namespace + namespace policy { + PolicyLogger::Log::Log(const LogSource log_source, const std::string& message, const base::Location location) @@ -19,48 +54,47 @@ message_(message), location_(location), timestamp_(base::Time::Now()) {} - PolicyLogger* PolicyLogger::GetInstance() { static base::NoDestructor<PolicyLogger> instance; return instance.get(); } -PolicyLogger::PolicyLogger() = default; +base::Value PolicyLogger::Log::GetAsValue() const { + base::Value log_value(base::Value::Type::DICT); + log_value.SetStringPath("message", message_); + log_value.SetStringPath("log_source", GetLogSourceValue(log_source_)); + log_value.SetStringPath("location", GetLineURL(location_)); + log_value.SetStringPath("timestamp", base::TimeFormatHTTP(timestamp_)); + return log_value; +} +PolicyLogger::PolicyLogger() = default; PolicyLogger::~PolicyLogger() = default; void PolicyLogger::AddLog(PolicyLogger::Log&& new_log) { if (IsPolicyLoggingEnabled()) { logs_.emplace_back(std::move(new_log)); - NotifyChanged(); } } -void PolicyLogger::AddObserver(Observer* observer) { - if (IsPolicyLoggingEnabled()) { - observers_.AddObserver(observer); - observer->OnLogsChanged(logs_); +base::Value PolicyLogger::GetAsValue() const { + base::Value all_logs_value(base::Value::Type::LIST); + for (const Log& log : logs_) { + all_logs_value.Append(log.GetAsValue()); } -} - -void PolicyLogger::RemoveObserver(Observer* observer) { - if (IsPolicyLoggingEnabled()) { - observers_.RemoveObserver(observer); - } -} - -void PolicyLogger::NotifyChanged() { - for (Observer& observer : observers_) { - observer.OnLogsChanged(logs_); - } + return all_logs_value; } bool PolicyLogger::IsPolicyLoggingEnabled() { #if BUILDFLAG(IS_ANDROID) - return true; + return base::FeatureList::IsEnabled(policy::features::kPolicyLogsPageAndroid); #else return false; #endif // BUILDFLAG(IS_ANDROID) } +int PolicyLogger::GetPolicyLogsSizeForTesting() { + return logs_.size(); +} + } // namespace policy
diff --git a/components/policy/core/common/policy_logger.h b/components/policy/core/common/policy_logger.h index a1da5434..5fe8732 100644 --- a/components/policy/core/common/policy_logger.h +++ b/components/policy/core/common/policy_logger.h
@@ -39,6 +39,8 @@ base::Location location() const { return location_; } base::Time timestamp() const { return timestamp_; } + base::Value GetAsValue() const; + private: LogSource log_source_; std::string message_; @@ -46,15 +48,6 @@ base::Time timestamp_; }; - // Observer interface to be implemented by page handlers. Handler will need to - // observe changes in the logs and notify the chrome://policy-logs tabs opened - // to update UI. - class Observer : public base::CheckedObserver { - public: - // Called to inform observers when logs are added or deleted. - virtual void OnLogsChanged(const std::vector<Log>& logs) = 0; - }; - static PolicyLogger* GetInstance(); PolicyLogger(); @@ -65,22 +58,21 @@ // Adds a new log and calls OnLogsChanged for observers. void AddLog(Log&& new_log); - // Adds observer to the list and calls its OnLogsChanged. - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); + // Returns the logs list as base::Value to send to UI. + base::Value GetAsValue() const; - // Notifies all observers in observers list when logs are added or deleted. - void NotifyChanged(); + // Checks if browser is running on Android. + bool IsPolicyLoggingEnabled(); + + // Returns the logs size for testing purposes. + int GetPolicyLogsSizeForTesting(); // TODO(b/251799119): delete logs after an expiry period of ~30 minutes. private: std::vector<Log> logs_; - base::ObserverList<Observer> observers_; - - // Checks if browser is running on Android. - bool IsPolicyLoggingEnabled(); }; } // namespace policy + #endif // COMPONENTS_POLICY_CORE_COMMON_POLICY_LOGGER_H_
diff --git a/components/policy/core/common/policy_logger_unittest.cc b/components/policy/core/common/policy_logger_unittest.cc index 1fb6987..1b8e740b 100644 --- a/components/policy/core/common/policy_logger_unittest.cc +++ b/components/policy/core/common/policy_logger_unittest.cc
@@ -3,7 +3,8 @@ // found in the LICENSE file. #include "components/policy/core/common/policy_logger.h" - +#include "base/test/scoped_feature_list.h" +#include "components/policy/core/common/features.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -16,14 +17,6 @@ namespace { -class MockObserver : public policy::PolicyLogger::Observer { - public: - MOCK_METHOD(void, - OnLogsChanged, - (const std::vector<policy::PolicyLogger::Log>& logs), - (override)); -}; - void AddLogs(const std::string& message, PolicyLogger* policy_logger) { policy_logger->AddLog(policy::PolicyLogger::Log( policy::PolicyLogger::Log::LogSource::kPolicyFetching, message, @@ -32,35 +25,30 @@ } // namespace -TEST(PolicyLoggerTest, ObserverRegistered) { - PolicyLogger policy_logger; - MockObserver mock_observer; +TEST(PolicyLoggerTest, PolicyLoggingEnabled) { + base::test::ScopedFeatureList scoped_feature_list_; + scoped_feature_list_.InitWithFeatureState( + policy::features::kPolicyLogsPageAndroid, true); - // Ensure OnLogsChanged is called when the observer is added to the logger. - EXPECT_CALL(mock_observer, - OnLogsChanged(ElementsAre( - Property(&PolicyLogger::Log::message, - Eq("Element Added Before Observer Creation"))))) - .Times(1); + PolicyLogger* policy_logger = policy::PolicyLogger::GetInstance(); - AddLogs("Element Added Before Observer Creation", &policy_logger); + int logs_size_before_adding = policy_logger->GetPolicyLogsSizeForTesting(); + AddLogs("Element added when the feature is enabled.", policy_logger); + EXPECT_EQ(policy_logger->GetPolicyLogsSizeForTesting(), + logs_size_before_adding + 1); +} - policy_logger.AddObserver(&mock_observer); +TEST(PolicyLoggerTest, PolicyLoggingDisabled) { + base::test::ScopedFeatureList scoped_feature_list_; + scoped_feature_list_.InitWithFeatureState( + policy::features::kPolicyLogsPageAndroid, false); - // Ensure OnLogsChanged is called when a log is added after registration. - EXPECT_CALL(mock_observer, - OnLogsChanged(ElementsAre( - Property(&PolicyLogger::Log::message, - Eq("Element Added Before Observer Creation")), - Property(&PolicyLogger::Log::message, - Eq("Element Added After Observer Creation"))))) - .Times(1); - AddLogs("Element Added After Observer Creation", &policy_logger); + PolicyLogger* policy_logger = policy::PolicyLogger::GetInstance(); - // Ensure OnLogsChanged is not called when observer is removed. - EXPECT_CALL(mock_observer, OnLogsChanged(_)).Times(0); - policy_logger.RemoveObserver(&mock_observer); - AddLogs("Element Added After Observer Removal", &policy_logger); + int logs_size_before_adding = policy_logger->GetPolicyLogsSizeForTesting(); + AddLogs("Element added when the feature is disabled.", policy_logger); + EXPECT_EQ(policy_logger->GetPolicyLogsSizeForTesting(), + logs_size_before_adding); } } // namespace policy \ No newline at end of file
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto index 8f19fb1f..b29b453a 100644 --- a/components/policy/proto/device_management_backend.proto +++ b/components/policy/proto/device_management_backend.proto
@@ -4009,6 +4009,14 @@ optional bytes signature = 1; } +// The client should try again later. +message CertProvTryLaterInstruction { + // The delay after which the client should retry on its own. + // It should also be observing the invalidation for the certificate + // provisioning process. + optional int64 delay_ms = 1; +} + // The client should perform an authorization step. message CertProvAuthorizeInstruction { // The verified access challenge. @@ -4018,15 +4026,14 @@ // The client should provide a proof-of-possession signature generated using // the private key. message CertProvProofOfPossessionInstruction { - // Algorithm to sign data with for CSR creation. - optional SigningAlgorithm signing_algorithm = 1; + reserved 1; // Data to sign for CSR creation. - // For SigningAlgorithm RSA_PKCS1_V1_5, the client will perform PKCS#1 v1.5 - // padding on `data_to_sign`. `data_to_sign` is expected to already contain a - // PKCS#1 DigestInfo prefix - the client will not attempt to add such a - // prefix. Also `data_to_sign` must be shorter than (key_size-11) bytes. If no - // other key size was specified in the + // The signing algorithm is currently RSA_PKCS1_V1_5. The client will perform + // PKCS#1 v1.5 padding on `data_to_sign`. `data_to_sign` is expected to + // already contain a PKCS#1 DigestInfo prefix - the client will not attempt to + // add such a prefix. Also `data_to_sign` must be shorter than (key_size-11) + // bytes. If no other key size was specified in the // RequiredClientCertificateFor{User,Device} policy, 2048 bits is assumed. optional bytes data_to_sign = 2; } @@ -4048,8 +4055,12 @@ // One of the instructions must be filled. // If no instruction is available yet, the server should fill - // `ClientCertificateProvisioningResponse.try_again_later instead`. + // `try_again_later_ms`. oneof instruction { + // If filled, the request can currently not be processed and the client + // is supposed to continue later using StartOrContinueRequest. + CertProvTryLaterInstruction try_later_instruction = 5; + CertProvAuthorizeInstruction authorize_instruction = 2; CertProvProofOfPossessionInstruction proof_of_possession_instruction = 3; CertProvImportCertificateInstruction import_certificate_instruction = 4; @@ -4131,6 +4142,8 @@ // is supposed to try again later using the same data. // The value is the number of milliseconds when the client should // automatically retry. + // Used in "Static" flow only. The "Dynamic" flow uses the + // `try_again_later_ms` field in `CertProvNextActionResponse`. optional int64 try_again_later = 1; oneof response {
diff --git a/components/policy/resources/templates/policies.yaml b/components/policy/resources/templates/policies.yaml index 0c00b3b..60d31a8 100644 --- a/components/policy/resources/templates/policies.yaml +++ b/components/policy/resources/templates/policies.yaml
@@ -1057,6 +1057,10 @@ 1056: KioskTroubleshootingToolsEnabled 1057: ForceEnablePepperVideoDecoderDevAPI 1058: DomainReliabilityAllowed + 1059: ScreensaverEnabled + 1060: ScreensaverIdleTimeoutSeconds + 1061: ScreensaverImageDisplayIntervalSeconds + 1062: ScreensaverImages atomic_groups: 1: Homepage 2: RemoteAccess
diff --git a/components/policy/resources/templates/policy_definitions/Extensions/ExtensionAllowedTypes.yaml b/components/policy/resources/templates/policy_definitions/Extensions/ExtensionAllowedTypes.yaml index dd8c8f1..f7f6039 100644 --- a/components/policy/resources/templates/policy_definitions/Extensions/ExtensionAllowedTypes.yaml +++ b/components/policy/resources/templates/policy_definitions/Extensions/ExtensionAllowedTypes.yaml
@@ -51,7 +51,6 @@ value: platform_app label: Types of extensions/apps that are allowed to be installed owners: -- benwells@chromium.org - file://extensions/OWNERS schema: $ref: ExtensionAllowedTypes
diff --git a/components/policy/resources/templates/policy_definitions/Printing/DevicePrintingClientNameTemplate.yaml b/components/policy/resources/templates/policy_definitions/Printing/DevicePrintingClientNameTemplate.yaml index c75ab16f..c3a32ea5 100644 --- a/components/policy/resources/templates/policy_definitions/Printing/DevicePrintingClientNameTemplate.yaml +++ b/components/policy/resources/templates/policy_definitions/Printing/DevicePrintingClientNameTemplate.yaml
@@ -1,39 +1,46 @@ caption: Template for the <ph name="CLIENT_NAME_IPP_ATTRIBUTE">'client-name'</ph> <ph name="INTERNET_PRINTING_PROTOCOL">Internet Printing Protocol</ph> <ph name="IPP_ATTRIBUTE">attribute</ph> -desc: "This policy controls the value of the <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\"\ - >'client-info'</ph> <ph name=\"IPP_PROTOCOL\">IPP</ph> (<ph name=\"INTERNET_PRINTING_PROTOCOL\"\ - >Internet Printing Protocol</ph>) <ph name=\"IPP_ATTRIBUTE\">attribute</ph> in print\ - \ jobs.\n\n Setting the policy to a string has the effect of adding an additional\ - \ <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\">'client-info'</ph> item to every print\ - \ job. The <ph name=\"CLIENT_NAME_IPP_ATTRIBUTE\">'client-name'</ph> member of the\ - \ added <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\">'client-info'</ph> item will be set\ - \ to the value of the policy after substitution of variables.\n\n Supported\ - \ variables are <ph name=\"DIRECTORY_ID_PLACEHOLDER\">${DEVICE_DIRECTORY_ID}</ph>,\ - \ <ph name=\"SERIAL_NUMBER_PLACEHOLDER\">${DEVICE_SERIAL_NUMBER}</ph>, <ph name=\"\ - ASSET_ID_PLACEHOLDER\">${DEVICE_ASSET_ID}</ph>, <ph name=\"ANNOTATED_LOCATION_PLACEHOLDER\"\ - >${DEVICE_ANNOTATED_LOCATION}</ph>. Unsupported placeholder variables will not be\ - \ substituted.\n\n The resulting value after substitution of variables is considered\ - \ valid if it consists only of <ph name=\"ASCII\">ASCII</ph> printable characters\ - \ and its length does not exceed 255.\n\n Note that, for privacy reasons, this\ - \ policy applies only when communicating with a printer using <ph name=\"IPPS_PROTOCOL\"\ - >IPPS</ph>, <ph name=\"HTTPS_PROTOCOL\">HTTPS</ph>, <ph name=\"USB_PROTOCOL\">USB</ph>\ - \ or <ph name=\"IPP_USB_PROTOCOL\">IPP-over-USB</ph> protocols. Also, note that\ - \ this policy only applies to printers that support <ph name=\"CLIENT_NAME_IPP_ATTRIBUTE\"\ - >'client-name'</ph>.\n\n The policy only applies to affiliated users.\n\n \ - \ If the policy is unset, set to an empty or invalid value, an additional <ph\ - \ name=\"CLIENT_INFO_PLACEHOLDER\">'client-info'</ph> will not be added to print\ - \ job requests.\n " +desc: "This policy controls the value of the <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\">'client-info'</ph>\ + \ <ph name=\"INTERNET_PRINTING_PROTOCOL\">Internet Printing Protocol</ph> (<ph name=\"IPP_PROTOCOL\">IPP</ph>)\ + \ <ph name=\"IPP_ATTRIBUTE\">attribute</ph> in print jobs.\n\n\ + \ Setting the policy has the effect of sending an additional\ + \ <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\">'client-info'</ph> value to print jobs submitted to\ + \ <ph name=\"IPP_PROTOCOL\">IPP</ph> printers.\ + \ The <ph name=\"CLIENT_TYPE_IPP_ATTRIBUTE\">'client-type'</ph> member of the\ + \ added <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\">'client-info'</ph> value will be set\ + \ to <ph name=\"CLIENT_TYPE_OTHER\">'other'</ph>.\ + \ The <ph name=\"CLIENT_NAME_IPP_ATTRIBUTE\">'client-name'</ph> member of the\ + \ added <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\">'client-info'</ph> value will be set\ + \ to the value of the policy after substitution of placeholder variables.\ + \ Supported placeholder variables are\ + \ <ph name=\"DIRECTORY_ID_PLACEHOLDER\">${DEVICE_DIRECTORY_API_ID}</ph>,\ + \ <ph name=\"SERIAL_NUMBER_PLACEHOLDER\">${DEVICE_SERIAL_NUMBER}</ph>,\ + \ <ph name=\"ASSET_ID_PLACEHOLDER\">${DEVICE_ASSET_ID}</ph>,\ + \ <ph name=\"ANNOTATED_LOCATION_PLACEHOLDER\">${DEVICE_ANNOTATED_LOCATION}</ph>.\ + \ Unsupported placeholder variables will not be substituted.\n\n\ + \ The resulting value after substitution of placeholder variables is considered\ + \ valid if it is not longer than 127 characters and only contains the following characters:\ + \ lowercase and uppercase letters of the English alphabet, digits, dashes ('-'), dots ('.')\ + \ and underscores ('_').\n\n\ + \ Note that, for privacy reasons, this policy takes effect only when the connection to the\ + \ printer is secure (<ph name=\"IPPS_SCHEME\">ipps://</ph> URI scheme) and the user\ + \ submitting the print job is affiliated.\ + \ Also, note that this policy only applies to printers that support\ + \ <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\">'client-info'</ph>.\n\n\ + \ If the policy is unset, set to an empty or invalid value, an additional\ + \ <ph name=\"CLIENT_INFO_IPP_ATTRIBUTE\">'client-info'</ph> value will not be added to print\ + \ job requests.\n" device_only: true example_value: chromebook-${DEVICE_ASSET_ID} features: dynamic_refresh: true per_profile: false -future_on: -- chrome_os owners: - ust@google.com - srad@google.com schema: type: string +supported_on: +- chrome_os:111- tags: [] type: string
diff --git a/components/policy/resources/templates/policy_definitions/Screensaver/.group.details.yaml b/components/policy/resources/templates/policy_definitions/Screensaver/.group.details.yaml new file mode 100644 index 0000000..55e6af0 --- /dev/null +++ b/components/policy/resources/templates/policy_definitions/Screensaver/.group.details.yaml
@@ -0,0 +1,2 @@ +caption: Screensaver Settings +desc: Controls the screensaver settings for the device sign-in screen, and user lock screen. \ No newline at end of file
diff --git a/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverEnabled.yaml b/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverEnabled.yaml new file mode 100644 index 0000000..7e763e9 --- /dev/null +++ b/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverEnabled.yaml
@@ -0,0 +1,33 @@ +caption: User screensaver enabled. +default: false +desc: |- + Configures the user screensaver for the lock screen. + + If this policy is set to true, the <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph> device will show a screensaver when it is idle in the lock screen. + + If this policy is set to false, or unset, the screensaver will not be displayed in the lock screen. + + The user screensaver displays the images referenced by the <ph name="SCREENSAVER_IMAGES_POLICY_NAME">ScreensaverImages</ph> policy. If <ph name="SCREENSAVER_IMAGES_POLICY_NAME">ScreensaverImages</ph> is unset, or it is set to an empty list, or to a list without any valid images, the screensaver for the lock screen will not be displayed. + + The idle timeout to start the screensaver, and the interval that an image is displayed can be modified with the <ph name="SCREENSAVER_IDLE_TIMEOUT_SECONDS_POLICY_NAME">ScreensaverIdleTimeoutSeconds</ph>, and the <ph name="SCREENSAVER_DISPLAY_INTERVAL_SECONDS_POLICY_NAME">ScreensaverDisplayIntervalSeconds</ph> policies respectively. If any of these policies are unset, their default values will be use instead. + +example_value: true +features: + can_be_recommended: false + dynamic_refresh: true + per_profile: true +items: +- caption: Enable the screensaver in the lock screen. + value: true +- caption: Do not enable the screensaver in the lock screen. + value: false +owners: +- mpetrisor@google.com +- eariassoto@google.com +- imprivata-eng@google.com +schema: + type: boolean +future_on: +- chrome_os +tags: [] +type: main
diff --git a/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverIdleTimeoutSeconds.yaml b/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverIdleTimeoutSeconds.yaml new file mode 100644 index 0000000..69f248b4 --- /dev/null +++ b/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverIdleTimeoutSeconds.yaml
@@ -0,0 +1,26 @@ +caption: User screensaver idle timeout. +desc: |- + Configures the time in seconds that the device will wait idle before showing the screensaver for the lock screen. + + Valid values range from 1 second to 9999 seconds. Leaving the policy unset means <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph> uses the default value of 7 seconds. + + This policy will not have any effect when the <ph name="SCREENSAVER_ENABLED_POLICY_NAME">ScreensaverEnabled</ph> policy is set to false. + +default: 7 +example_value: 7 +features: + can_be_recommended: false + dynamic_refresh: true + per_profile: true +owners: +- mpetrisor@google.com +- eariassoto@google.com +- imprivata-eng@google.com +schema: + minimum: 1 + maximum: 9999 + type: integer +future_on: +- chrome_os +tags: [] +type: int
diff --git a/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverImageDisplayIntervalSeconds.yaml b/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverImageDisplayIntervalSeconds.yaml new file mode 100644 index 0000000..581e871 --- /dev/null +++ b/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverImageDisplayIntervalSeconds.yaml
@@ -0,0 +1,26 @@ +caption: User screensaver image display interval. +desc: |- + Configures the interval in seconds to display an image when the screensaver for the lock screen has multiple images to display. + + Valid values range from 1 second to 9999 seconds. Leaving the policy unset means <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph> uses the default value of 60 seconds. + + This policy will not have any effect when the <ph name="SCREENSAVER_ENABLED_POLICY_NAME">ScreensaverEnabled</ph> policy is set to false. + +default: 60 +example_value: 60 +features: + can_be_recommended: false + dynamic_refresh: true + per_profile: true +owners: +- mpetrisor@google.com +- eariassoto@google.com +- imprivata-eng@google.com +schema: + minimum: 1 + maximum: 9999 + type: integer +future_on: +- chrome_os +tags: [] +type: int
diff --git a/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverImages.yaml b/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverImages.yaml new file mode 100644 index 0000000..8415079 --- /dev/null +++ b/components/policy/resources/templates/policy_definitions/Screensaver/ScreensaverImages.yaml
@@ -0,0 +1,44 @@ +caption: User screensaver image source. +desc: |- + Configures the list of images to display in the screensaver for the lock screen. + + Each list item references an image to be displayed in the screensaver. The item must have as members a URL to the image, and the SHA-256 hash value of the image file for verification. The image format must be JPEG. The <ph name="PRODUCT_OS_NAME">$2<ex>Google ChromeOS</ex></ph> device will download these images, and maintain a local cache of these references. + + This policy will not have any effect if the <ph name="SCREENSAVER_ENABLED_POLICY_NAME">ScreensaverEnabled</ph> policy is set to false. + + If this policy is unset, or the list does not contain any valid image references, the screensaver for the lock screen will not be displayed, regardless of the value set in the <ph name="SCREENSAVER_ENABLED_POLICY_NAME">ScreensaverEnabled</ph> policy. + +default: [] +example_value: +- url: https://www.example.com/img_1.jpg + hash: 38aae2b1647f1f37729c4f3632c297ceb901a130bf5881d72c3a19e16ff97e7a +- url: https://www.example.com/img_2.jpg + hash: 439189aabe4fb024450ca7f0f5a7bc06841200e14b286db87e820d8674e316cd +- url: https://www.example.com/img_3.jpg + hash: b6d9d35eb4d2957dbb78ba82f47c94727b8563ee7e3030c3c56be227c4ef4f78 +features: + can_be_recommended: false + dynamic_refresh: true + per_profile: true +owners: +- mpetrisor@google.com +- eariassoto@google.com +- imprivata-eng@google.com +schema: + items: + properties: + hash: + description: The SHA-256 hash of the image. + type: string + url: + description: The URL from which the screensaver image can be downloaded. + type: string + required: + - url + - hash + type: object + type: array +future_on: +- chrome_os +tags: [] +type: dict
diff --git a/components/policy/resources/webui/BUILD.gn b/components/policy/resources/webui/BUILD.gn index 1b4e247..fa8b028 100644 --- a/components/policy/resources/webui/BUILD.gn +++ b/components/policy/resources/webui/BUILD.gn
@@ -16,6 +16,10 @@ "policy.html", ] +if (is_android) { + static_files += [ "logs/policy_logs.html" ] +} + # TODO(b/265198461): Migrate to TypeScript and then simplify the build setup by # leveraging build_webui(). web_component_files = [ @@ -41,6 +45,13 @@ "policy.js", ] +if (is_android) { + non_web_component_files += [ + "logs/types.ts", + "logs/policy_logs.ts", + ] +} + preprocess_if_expr("preprocess_static_files") { in_folder = "." out_folder = preprocess_dir
diff --git a/components/policy/resources/webui/logs/policy_logs.html b/components/policy/resources/webui/logs/policy_logs.html new file mode 100644 index 0000000..f8256c59 --- /dev/null +++ b/components/policy/resources/webui/logs/policy_logs.html
@@ -0,0 +1,71 @@ +<!DOCTYPE html> +<html lang="en" dir="ltr"> +<head> + <meta charset="utf-8"> + <title>Policy Logs</title> + <meta name="viewport" content="width=device-width"> + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> + + <style> + h2, + ul, + .version-info-table-data { + word-break: break-all; + } + + .buttons-row { + align-items: center; + display: flex; + height: 56px; + } + + ul { + list-style-type: none; + } + </style> +</head> + +<body> + + <section id="logs-disabled-container" hidden> + <h2>This page is not available on your browser</h2> + </section> + + <section id="logs-enabled-container"> + <h1>Policy Logs</h1> + + <div class="buttons-row"> + <button id="logs-dump">Export Logs to JSON</button> + <button id="logs-refresh">Refresh Logs</button> + </div> + + <h2>Version Information</h2> + + <table id="version-info" aria-label="Version Information"> + <tr> + <td>Chrome Version: </td> + <td id="chrome-version-value" class="version-info-table-data">-</td> + </tr> + + <tr> + <td>Chrome Revision: </td> + <td id="chrome-revision-value" class="version-info-table-data">-</td> + </tr> + + <tr> + <td id="os-version-label">OS: </td> + <td id="os-version-value" class="version-info-table-data">-</td> + </tr> + </table> + + <h2>Logs</h2> + + <ul id="logs-container" aria-label="Logs List"></ul> + + <h2>Active Variations</h2> + + <ul id="active-variations-container" aria-label="Active Variations List"></ul> + </section> + <script type="module" src="/logs/policy_logs.js"></script> +</body> +</html> \ No newline at end of file
diff --git a/components/policy/resources/webui/logs/policy_logs.ts b/components/policy/resources/webui/logs/policy_logs.ts new file mode 100644 index 0000000..7226ad68 --- /dev/null +++ b/components/policy/resources/webui/logs/policy_logs.ts
@@ -0,0 +1,86 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../strings.m.js'; + +import {sendWithPromise} from 'chrome://resources/js/cr.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {getRequiredElement} from 'chrome://resources/js/util_ts.js'; + +import {Log, VersionInfo} from './types.js'; + +let logs: Log[]; +let versionInfo: VersionInfo; + +// Dumps file with JSON contents to filename. +function dumpFileWithJsonContents() { + const dumpObject = {versionInfo, logs}; + + const data = JSON.stringify(dumpObject); + const filename = 'policy_logs_dump.json'; + + const blob = new Blob([data], {'type': 'application/json'}); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.setAttribute('href', url); + a.setAttribute('download', filename); + a.click(); +} + +function displayList() { + logs = logs; + + const logMessageContainer = getRequiredElement('logs-container'); + logMessageContainer.innerHTML = window.trustedTypes!.emptyHTML; + logs.forEach(log => { + const logMessage = document.createElement('li'); + logMessage.textContent = log.message; + logMessageContainer.appendChild(logMessage); + }); +} + +function displayVersionInfo() { + versionInfo = JSON.parse(loadTimeData.getString('versionInfo')); + + getRequiredElement('chrome-version-value').textContent = versionInfo.version; + + getRequiredElement('chrome-revision-value').textContent = + versionInfo.revision; + + getRequiredElement('os-version-value').textContent = versionInfo.deviceOs; + + const activeVariationsDiv = getRequiredElement('active-variations-container'); + versionInfo.variations.forEach((variation) => { + const activeVariationItem = document.createElement('li'); + activeVariationItem.textContent = variation; + activeVariationsDiv.appendChild(activeVariationItem); + }); +} + +function fetchLogs() { + return sendWithPromise('getPolicyLogs').then(logsFetched => { + logs = logsFetched; + }); +} + +function initialize() { + // TODO(b/251799119): Add instructions on how to enable the page. + if (!loadTimeData.getBoolean('loggingEnabled')) { + getRequiredElement('logs-disabled-container').hidden = false; + getRequiredElement('logs-enabled-container').hidden = true; + return; + } + + displayVersionInfo(); + + const fetchLogsAndDisplay = () => fetchLogs().then(displayList); + fetchLogsAndDisplay(); + + getRequiredElement('logs-dump') + .addEventListener('click', dumpFileWithJsonContents); + getRequiredElement('logs-refresh') + .addEventListener('click', fetchLogsAndDisplay); +} + +document.addEventListener('DOMContentLoaded', initialize); \ No newline at end of file
diff --git a/components/policy/resources/webui/logs/types.ts b/components/policy/resources/webui/logs/types.ts new file mode 100644 index 0000000..adf8e93 --- /dev/null +++ b/components/policy/resources/webui/logs/types.ts
@@ -0,0 +1,29 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Types for objects sent from C++ to chrome://policy/logs. + */ + +/** + * The type of the policy log result object. The definition is based on + * components/policy/core/common/policy_logger.cc Log::GetAsValue() + */ +export interface Log { + logSource: string; + message: string; + location: string; + timestamp: string; +} + +/** + * The type of the version info result object. The definition is based on + * chrome/browser/ui/webui/policy/policy_ui_handler.cc: GetVersionInfo() + */ +export interface VersionInfo { + version: string; + revision: string; + deviceOs: string; + variations: string[]; +} \ No newline at end of file
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py index fe8d8eab..8552e881 100755 --- a/components/policy/tools/syntax_check_policy_template_json.py +++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -828,6 +828,28 @@ return False + # Checks if the policy supported on a specific platform via 'supported_on' + # field. Does not take into account the 'future_on' field. + def _SupportedOnPlatformPolicy(self, policy, current_version, platform): + for s in policy.get('supported_on', []): + ( + supported_on_platform, + supported_on_from, + supported_on_to, + ) = _GetSupportedVersionPlatformAndRange(s) + + # Skip other platforms. + if supported_on_platform != platform: + continue + + # If supported_on_to isn't given, this policy is still supported. + if supported_on_to is None: + return True + + return current_version <= int(supported_on_to) + + return False + def _CheckPolicyDefinition(self, policy, current_version, @@ -1568,4 +1590,39 @@ self._PolicyError( 'Schema compatible errors.\n' f' {schema_compatible_error_message}', policy) + + # Check that defaults have not changed for a launched policy. + if policy_change['old_policy'] is not None: + old_policy = policy_change['old_policy'] + supported_on = self._CheckContains(policy, + 'supported_on', + list, + optional=True) + for key in [ + 'default', 'default_for_enterprise_users', 'default_policy_level' + ]: + # Nothing changed. + if old_policy.get(key) == policy.get(key): + continue + if key == 'default': + if not supported_on: + continue + self._Warning( + 'You seem to change a default value for a launched policy ' + '\'%s\'. This will certainly break the contract if the policy ' + 'is already supported in the Admin Console. Please consider ' + 'contacting cros-policy-muc-eng@google.com for guidance.' % + policy['name']) + continue + + # Handle default_for_enterprise_users and default_policy_level + if self._SupportedOnPlatformPolicy(old_policy, current_version, + 'chrome_os'): + self._Warning( + 'You seem to change defaults for enterprise users on ChromeOS ' + 'for a launched policy \'%s\'. This will certainly break the ' + ' contract if the policy is already supported in the Admin ' + 'Console. Please consider contacting ' + 'cros-policy-muc-eng@google.com for guidance' % policy['name']) + return self.errors, self.warnings
diff --git a/components/power_bookmarks/common/power.h b/components/power_bookmarks/common/power.h index 56905ae..37c6e8d 100644 --- a/components/power_bookmarks/common/power.h +++ b/components/power_bookmarks/common/power.h
@@ -30,6 +30,8 @@ const base::GUID& guid() const { return guid_; } void set_guid(base::GUID guid) { guid_ = guid; } + std::string guid_string() const { return guid_.AsLowercaseString(); } + const GURL& url() const { return url_; } void set_url(GURL url) { url_ = url; }
diff --git a/components/power_bookmarks/storage/BUILD.gn b/components/power_bookmarks/storage/BUILD.gn index 5b42a52..c056491 100644 --- a/components/power_bookmarks/storage/BUILD.gn +++ b/components/power_bookmarks/storage/BUILD.gn
@@ -34,6 +34,7 @@ sources = [ "power_bookmark_database_impl_unittest.cc", + "power_bookmark_sync_bridge_unittest.cc", "power_bookmark_sync_metadata_database_unittest.cc", ] @@ -42,6 +43,7 @@ "//base", "//base/test:test_support", "//components/power_bookmarks/common", + "//components/sync:test_support", "//components/sync/model", "//components/sync/protocol", "//sql",
diff --git a/components/power_bookmarks/storage/empty_power_bookmark_database.cc b/components/power_bookmarks/storage/empty_power_bookmark_database.cc index 11a854a..fce67fe0 100644 --- a/components/power_bookmarks/storage/empty_power_bookmark_database.cc +++ b/components/power_bookmarks/storage/empty_power_bookmark_database.cc
@@ -10,6 +10,17 @@ namespace power_bookmarks { +namespace { +class EmptyDatabaseTransaction : public Transaction { + public: + bool Commit() override; +}; + +bool EmptyDatabaseTransaction::Commit() { + return true; +} +} // namespace + EmptyPowerBookmarkDatabase::EmptyPowerBookmarkDatabase() = default; EmptyPowerBookmarkDatabase::~EmptyPowerBookmarkDatabase() = default; @@ -50,8 +61,9 @@ return false; } -bool EmptyPowerBookmarkDatabase::UpdatePower(std::unique_ptr<Power> power) { - return false; +std::unique_ptr<Power> EmptyPowerBookmarkDatabase::UpdatePower( + std::unique_ptr<Power> power) { + return nullptr; } bool EmptyPowerBookmarkDatabase::DeletePower(const base::GUID& guid) { @@ -60,7 +72,8 @@ bool EmptyPowerBookmarkDatabase::DeletePowersForURL( const GURL& url, - const sync_pb::PowerBookmarkSpecifics::PowerType& power_type) { + const sync_pb::PowerBookmarkSpecifics::PowerType& power_type, + std::vector<std::string>* deleted_guids) { return false; } @@ -79,4 +92,22 @@ return nullptr; } +bool EmptyPowerBookmarkDatabase::CreateOrMergePowerFromSync( + const Power& power) { + return false; +} + +bool EmptyPowerBookmarkDatabase::DeletePowerFromSync(const std::string& guid) { + return false; +} + +syncer::SyncMetadataStore* +EmptyPowerBookmarkDatabase::GetSyncMetadataDatabase() { + return nullptr; +} + +std::unique_ptr<Transaction> EmptyPowerBookmarkDatabase::BeginTransaction() { + return std::make_unique<EmptyDatabaseTransaction>(); +} + } // namespace power_bookmarks
diff --git a/components/power_bookmarks/storage/empty_power_bookmark_database.h b/components/power_bookmarks/storage/empty_power_bookmark_database.h index 49b24a69..fe54cf88d 100644 --- a/components/power_bookmarks/storage/empty_power_bookmark_database.h +++ b/components/power_bookmarks/storage/empty_power_bookmark_database.h
@@ -37,15 +37,20 @@ std::vector<std::unique_ptr<PowerOverview>> GetPowerOverviewsForSearchParams( const SearchParams& search_params) override; bool CreatePower(std::unique_ptr<Power> power) override; - bool UpdatePower(std::unique_ptr<Power> power) override; + std::unique_ptr<Power> UpdatePower(std::unique_ptr<Power> power) override; bool DeletePower(const base::GUID& guid) override; bool DeletePowersForURL( const GURL& url, - const sync_pb::PowerBookmarkSpecifics::PowerType& power_type) override; + const sync_pb::PowerBookmarkSpecifics::PowerType& power_type, + std::vector<std::string>* deleted_guids) override; std::vector<std::unique_ptr<Power>> GetAllPowers() override; std::vector<std::unique_ptr<Power>> GetPowersForGUIDs( const std::vector<std::string>& guids) override; std::unique_ptr<Power> GetPowerForGUID(const std::string& guid) override; + bool CreateOrMergePowerFromSync(const Power& power) override; + bool DeletePowerFromSync(const std::string& guid) override; + syncer::SyncMetadataStore* GetSyncMetadataDatabase() override; + std::unique_ptr<Transaction> BeginTransaction() override; }; } // namespace power_bookmarks
diff --git a/components/power_bookmarks/storage/power_bookmark_backend.cc b/components/power_bookmarks/storage/power_bookmark_backend.cc index ef6f6d3..b8995f58 100644 --- a/components/power_bookmarks/storage/power_bookmark_backend.cc +++ b/components/power_bookmarks/storage/power_bookmark_backend.cc
@@ -90,49 +90,58 @@ bool PowerBookmarkBackend::CreatePower(std::unique_ptr<Power> power) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - sync_pb::PowerBookmarkSpecifics::PowerType power_type = power->power_type(); - bool success = db_->CreatePower(std::move(power)); - metrics::RecordPowerCreated(power_type, success); - if (success) { - // TODO(crbug.com/1406371): Posting a task here causes the observer method - // to be called before the callback. This behavior is pretty strange, but - // not a problem right now. Eventually we should stop using SequenceBound - // for the backend and post tasks directly to ensure proper ordering. - frontend_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&PowerBookmarkObserver::OnPowersChanged, - base::Unretained(service_observer_))); + auto transaction = db_->BeginTransaction(); + if (!transaction) { + return false; } - - return success; + sync_pb::PowerBookmarkSpecifics::PowerType power_type = power->power_type(); + bool success = db_->CreatePower(power->Clone()); + metrics::RecordPowerCreated(power_type, success); + if (!success) { + return false; + } + if (bridge_) { + bridge_->SendPowerToSync(*power); + } + return CommitAndNotify(*transaction); } bool PowerBookmarkBackend::UpdatePower(std::unique_ptr<Power> power) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - sync_pb::PowerBookmarkSpecifics::PowerType power_type = power->power_type(); - bool success = db_->UpdatePower(std::move(power)); - metrics::RecordPowerUpdated(power_type, success); - if (success) { - frontend_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&PowerBookmarkObserver::OnPowersChanged, - base::Unretained(service_observer_))); + auto transaction = db_->BeginTransaction(); + if (!transaction) { + return false; } - - return success; + sync_pb::PowerBookmarkSpecifics::PowerType power_type = power->power_type(); + auto updated_power = db_->UpdatePower(std::move(power)); + bool success = updated_power != nullptr; + metrics::RecordPowerUpdated(power_type, success); + if (!success) { + return false; + } + if (bridge_) { + bridge_->SendPowerToSync(*updated_power); + } + return CommitAndNotify(*transaction); } bool PowerBookmarkBackend::DeletePower(const base::GUID& guid) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto transaction = db_->BeginTransaction(); + if (!transaction) { + return false; + } bool success = db_->DeletePower(guid); metrics::RecordPowerDeleted(success); - if (success) { - frontend_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&PowerBookmarkObserver::OnPowersChanged, - base::Unretained(service_observer_))); + if (!success) { + return false; } - - return success; + if (bridge_) { + bridge_->NotifySyncForDeletion(guid.AsLowercaseString()); + } + return CommitAndNotify(*transaction); } bool PowerBookmarkBackend::DeletePowersForURL( @@ -140,15 +149,22 @@ const sync_pb::PowerBookmarkSpecifics::PowerType& power_type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - bool success = db_->DeletePowersForURL(url, power_type); - metrics::RecordPowersDeletedForURL(power_type, success); - if (success) { - frontend_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&PowerBookmarkObserver::OnPowersChanged, - base::Unretained(service_observer_))); + auto transaction = db_->BeginTransaction(); + if (!transaction) { + return false; } - - return success; + std::vector<std::string> deleted_guids; + bool success = db_->DeletePowersForURL(url, power_type, &deleted_guids); + metrics::RecordPowersDeletedForURL(power_type, success); + if (!success) { + return false; + } + if (bridge_) { + for (auto const& guid : deleted_guids) { + bridge_->NotifySyncForDeletion(guid); + } + } + return CommitAndNotify(*transaction); } std::vector<std::unique_ptr<Power>> PowerBookmarkBackend::GetAllPowers() { @@ -168,4 +184,47 @@ return db_->GetPowerForGUID(guid); } +bool PowerBookmarkBackend::CreateOrMergePowerFromSync(const Power& power) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return db_->CreateOrMergePowerFromSync(power); +} + +bool PowerBookmarkBackend::DeletePowerFromSync(const std::string& guid) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return db_->DeletePowerFromSync(guid); +} + +syncer::SyncMetadataStore* PowerBookmarkBackend::GetSyncMetadataDatabase() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return db_->GetSyncMetadataDatabase(); +} + +std::unique_ptr<Transaction> PowerBookmarkBackend::BeginTransaction() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return db_->BeginTransaction(); +} + +bool PowerBookmarkBackend::CommitAndNotify(Transaction& transaction) { + if (transaction.Commit()) { + NotifyPowersChanged(); + return true; + } else { + if (bridge_) { + bridge_->change_processor()->ReportError(syncer::ModelError( + FROM_HERE, "PowerBookmark database fails to persist data.")); + } + return false; + } +} + +void PowerBookmarkBackend::NotifyPowersChanged() { + // TODO(crbug.com/1406371): Posting a task here causes the observer method + // to be called before the callback. This behavior is pretty strange, but + // not a problem right now. Eventually we should stop using SequenceBound + // for the backend and post tasks directly to ensure proper ordering. + frontend_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&PowerBookmarkObserver::OnPowersChanged, + base::Unretained(service_observer_))); +} + } // namespace power_bookmarks
diff --git a/components/power_bookmarks/storage/power_bookmark_backend.h b/components/power_bookmarks/storage/power_bookmark_backend.h index 9700e7d..3f4ce90 100644 --- a/components/power_bookmarks/storage/power_bookmark_backend.h +++ b/components/power_bookmarks/storage/power_bookmark_backend.h
@@ -80,8 +80,17 @@ std::vector<std::unique_ptr<Power>> GetPowersForGUIDs( const std::vector<std::string>& guids) override; std::unique_ptr<Power> GetPowerForGUID(const std::string& guid) override; + bool CreateOrMergePowerFromSync(const Power& power) override; + bool DeletePowerFromSync(const std::string& guid) override; + syncer::SyncMetadataStore* GetSyncMetadataDatabase() override; + std::unique_ptr<Transaction> BeginTransaction() override; + void NotifyPowersChanged() override; private: + // Commit the change. If success then notify the observer, otherwise report + // error to sync. + bool CommitAndNotify(Transaction& transaction); + const base::FilePath database_dir_; std::unique_ptr<PowerBookmarkDatabase> db_
diff --git a/components/power_bookmarks/storage/power_bookmark_database.h b/components/power_bookmarks/storage/power_bookmark_database.h index ad7ef52b..e0bf464e 100644 --- a/components/power_bookmarks/storage/power_bookmark_database.h +++ b/components/power_bookmarks/storage/power_bookmark_database.h
@@ -52,8 +52,9 @@ virtual bool CreatePower(std::unique_ptr<Power> power) = 0; // Update the given `power` in the database. If it doesn't exist, then it - // will be created instead. Returns whether the operation was successful. - virtual bool UpdatePower(std::unique_ptr<Power> power) = 0; + // will be created instead. Returns the updated power if the operation was + // successful or nullptr otherwise. + virtual std::unique_ptr<Power> UpdatePower(std::unique_ptr<Power> power) = 0; // Delete the given `guid` in the database, if it exists. Returns whether // the operation was successful. @@ -61,9 +62,12 @@ // Delete all powers for the given `url`. Use `power_type` to restrict which // type is deleted or use POWER_TYPE_UNSPECIFIED to delete everything. + // Returns whether the operation was successfaul and all deleted guids in + // deleted_guids as output if provided. virtual bool DeletePowersForURL( const GURL& url, - const sync_pb::PowerBookmarkSpecifics::PowerType& power_type) = 0; + const sync_pb::PowerBookmarkSpecifics::PowerType& power_type, + std::vector<std::string>* deleted_guids = nullptr) = 0; }; } // namespace power_bookmarks
diff --git a/components/power_bookmarks/storage/power_bookmark_database_impl.cc b/components/power_bookmarks/storage/power_bookmark_database_impl.cc index e14105db..d6ac2b9 100644 --- a/components/power_bookmarks/storage/power_bookmark_database_impl.cc +++ b/components/power_bookmarks/storage/power_bookmark_database_impl.cc
@@ -103,6 +103,38 @@ } return true; } + +class SqliteDatabaseTransaction : public Transaction { + public: + explicit SqliteDatabaseTransaction(sql::Database& db); + ~SqliteDatabaseTransaction() override; + bool Begin(); + bool Commit() override; + + private: + sql::Transaction transaction_; + bool committed_ = false; +}; + +SqliteDatabaseTransaction::SqliteDatabaseTransaction(sql::Database& db) + : transaction_(&db) {} + +SqliteDatabaseTransaction::~SqliteDatabaseTransaction() { + if (!committed_) { + transaction_.Rollback(); + } +} + +bool SqliteDatabaseTransaction::Begin() { + return transaction_.Begin(); +} + +bool SqliteDatabaseTransaction::Commit() { + DCHECK(!committed_); + committed_ = true; + return transaction_.Commit(); +} + } // namespace PowerBookmarkDatabaseImpl::PowerBookmarkDatabaseImpl( @@ -461,107 +493,26 @@ return false; } - sql::Transaction transaction(&db_); - if (!transaction.Begin()) - return false; - - static constexpr char kCreatePowerSaveSql[] = - // clang-format off - "INSERT INTO saves(" - "id, url, origin, power_type, " - "time_added, time_modified)" - "VALUES(?,?,?,?,?,?)"; - // clang-format on - DCHECK(db_.IsSQLValid(kCreatePowerSaveSql)); - - sql::Statement save_statement( - db_.GetCachedStatement(SQL_FROM_HERE, kCreatePowerSaveSql)); - save_statement.BindString(0, power->guid().AsLowercaseString()); - save_statement.BindString(1, power->url().spec()); - save_statement.BindString(2, url::Origin::Create(power->url()).Serialize()); - save_statement.BindInt(3, power->power_type()); - save_statement.BindTime(4, power->time_added()); - save_statement.BindTime(5, power->time_modified()); - if (!save_statement.Run()) - return false; - - static constexpr char kCreatePowerBlobSql[] = - // clang-format off - "INSERT INTO blobs(id, specifics) VALUES(?, ?)"; - // clang-format on - DCHECK(db_.IsSQLValid(kCreatePowerBlobSql)); - - sql::Statement blob_statement( - db_.GetCachedStatement(SQL_FROM_HERE, kCreatePowerBlobSql)); - blob_statement.BindString(0, power->guid().AsLowercaseString()); - - std::string data; - sync_pb::PowerBookmarkSpecifics specifics; - power->ToPowerBookmarkSpecifics(&specifics); - specifics.SerializeToString(&data); - blob_statement.BindString(1, data); - if (!blob_statement.Run()) - return false; - - return transaction.Commit(); + return CreatePowerInternal(*power); } -bool PowerBookmarkDatabaseImpl::UpdatePower(std::unique_ptr<Power> power) { +std::unique_ptr<Power> PowerBookmarkDatabaseImpl::UpdatePower( + std::unique_ptr<Power> power) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - auto existing_power = GetPowerForGUID(power->guid().AsLowercaseString()); + auto existing_power = GetPowerForGUID(power->guid_string()); if (!existing_power) { DLOG(ERROR) << "Failed to update power because the current power does not exist."; - return false; + return nullptr; } existing_power->Merge(*power); - sql::Transaction transaction(&db_); - if (!transaction.Begin()) - return false; + if (!UpdatePowerInternal(*existing_power)) { + return nullptr; + } - static constexpr char kUpdatePowerSaveSql[] = - // clang-format off - "UPDATE saves SET " - "url=?, origin=?, power_type=?, time_added=?, " - "time_modified=?" - "WHERE id=?"; - // clang-format on - DCHECK(db_.IsSQLValid(kUpdatePowerSaveSql)); - - sql::Statement save_statement( - db_.GetCachedStatement(SQL_FROM_HERE, kUpdatePowerSaveSql)); - - save_statement.BindString(0, existing_power->url().spec()); - save_statement.BindString( - 1, url::Origin::Create(existing_power->url()).Serialize()); - save_statement.BindInt(2, existing_power->power_type()); - save_statement.BindTime(3, existing_power->time_added()); - save_statement.BindTime(4, existing_power->time_modified()); - if (!save_statement.Run()) - return false; - - static constexpr char kUpdatePowerBlobSql[] = - // clang-format off - "UPDATE blobs SET specifics=? WHERE id=?"; - // clang-format on - DCHECK(db_.IsSQLValid(kUpdatePowerBlobSql)); - - sql::Statement blob_statement( - db_.GetCachedStatement(SQL_FROM_HERE, kUpdatePowerBlobSql)); - - std::string data; - sync_pb::PowerBookmarkSpecifics specifics; - existing_power->ToPowerBookmarkSpecifics(&specifics); - bool success = specifics.SerializeToString(&data); - DCHECK(success); - blob_statement.BindBlob(0, data); - blob_statement.BindString(1, existing_power->guid().AsLowercaseString()); - if (!blob_statement.Run()) - return false; - - return transaction.Commit(); + return existing_power; } bool PowerBookmarkDatabaseImpl::DeletePower(const base::GUID& guid) { @@ -571,45 +522,19 @@ return true; } - sql::Transaction transaction(&db_); - if (!transaction.Begin()) - return false; - - static constexpr char kDeletePowerSaveSql[] = - // clang-format off - "DELETE FROM saves WHERE id=?"; - // clang-format on - DCHECK(db_.IsSQLValid(kDeletePowerSaveSql)); - - sql::Statement save_statement( - db_.GetCachedStatement(SQL_FROM_HERE, kDeletePowerSaveSql)); - save_statement.BindString(0, guid.AsLowercaseString()); - if (!save_statement.Run()) - return false; - - static constexpr char kDeletePowerBlobSql[] = - // clang-format off - "DELETE FROM blobs WHERE id=?"; - // clang-format on - DCHECK(db_.IsSQLValid(kDeletePowerBlobSql)); - - sql::Statement blob_statement( - db_.GetCachedStatement(SQL_FROM_HERE, kDeletePowerBlobSql)); - blob_statement.BindString(0, guid.AsLowercaseString()); - if (!blob_statement.Run()) - return false; - - return transaction.Commit(); + return DeletePowerInternal(guid); } bool PowerBookmarkDatabaseImpl::DeletePowersForURL( const GURL& url, - const sync_pb::PowerBookmarkSpecifics::PowerType& power_type) { + const sync_pb::PowerBookmarkSpecifics::PowerType& power_type, + std::vector<std::string>* deleted_guids) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - sql::Transaction transaction(&db_); - if (!transaction.Begin()) - return false; + std::vector<std::string> guids = GetGUIDsForURL(url, power_type); + if (guids.empty()) { + return true; + } static constexpr char kDeletePowersBlobsForURLSql[] = // clang-format off @@ -645,7 +570,12 @@ if (!save_statement.Run()) return false; - return transaction.Commit(); + if (deleted_guids) { + for (const auto& guid : guids) { + deleted_guids->push_back(guid); + } + } + return true; } std::vector<std::unique_ptr<Power>> @@ -746,6 +676,28 @@ return nullptr; } +bool PowerBookmarkDatabaseImpl::CreateOrMergePowerFromSync(const Power& power) { + auto existing_power = GetPowerForGUID(power.guid_string()); + if (existing_power) { + // The merged data is not sent back to sync in order to prevent sending data + // back and forth between two clients. Usually sync data from the server + // should override local data, which make it unnecessary to send data back. + existing_power->Merge(power); + return UpdatePowerInternal(*existing_power); + } else { + return CreatePowerInternal(power); + } +} + +bool PowerBookmarkDatabaseImpl::DeletePowerFromSync(const std::string& guid) { + return DeletePower(base::GUID::ParseLowercase(guid)); +} + +syncer::SyncMetadataStore* +PowerBookmarkDatabaseImpl::GetSyncMetadataDatabase() { + return sync_db_.get(); +} + absl::optional<sync_pb::PowerBookmarkSpecifics> PowerBookmarkDatabaseImpl::DeserializeOrDelete(const std::string& data, const base::GUID& id) { @@ -760,4 +712,163 @@ return absl::nullopt; } +std::vector<std::string> PowerBookmarkDatabaseImpl::GetGUIDsForURL( + const GURL& url, + const sync_pb::PowerBookmarkSpecifics::PowerType& power_type) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + static constexpr char kGetGUIDsForURLSql[] = + // clang-format off + "SELECT id FROM saves WHERE (url=?) AND (power_type=? OR ?=?)"; + // clang-format on + DCHECK(db_.IsSQLValid(kGetGUIDsForURLSql)); + + sql::Statement statement( + db_.GetCachedStatement(SQL_FROM_HERE, kGetGUIDsForURLSql)); + statement.BindString(0, url.spec()); + statement.BindInt(1, power_type); + statement.BindInt(2, power_type); + statement.BindInt(3, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_UNSPECIFIED); + + std::vector<std::string> guids; + while (statement.Step()) { + DCHECK_EQ(1, statement.ColumnCount()); + guids.push_back(statement.ColumnString(0)); + } + + return guids; +} + +bool PowerBookmarkDatabaseImpl::CreatePowerInternal(const Power& power) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + static constexpr char kCreatePowerSaveSql[] = + // clang-format off + "INSERT INTO saves(" + "id, url, origin, power_type, " + "time_added, time_modified)" + "VALUES(?,?,?,?,?,?)"; + // clang-format on + DCHECK(db_.IsSQLValid(kCreatePowerSaveSql)); + + sql::Statement save_statement( + db_.GetCachedStatement(SQL_FROM_HERE, kCreatePowerSaveSql)); + save_statement.BindString(0, power.guid_string()); + save_statement.BindString(1, power.url().spec()); + save_statement.BindString(2, url::Origin::Create(power.url()).Serialize()); + save_statement.BindInt(3, power.power_type()); + save_statement.BindTime(4, power.time_added()); + save_statement.BindTime(5, power.time_modified()); + if (!save_statement.Run()) { + return false; + } + + static constexpr char kCreatePowerBlobSql[] = + // clang-format off + "INSERT INTO blobs(id, specifics) VALUES(?, ?)"; + // clang-format on + DCHECK(db_.IsSQLValid(kCreatePowerBlobSql)); + + sql::Statement blob_statement( + db_.GetCachedStatement(SQL_FROM_HERE, kCreatePowerBlobSql)); + blob_statement.BindString(0, power.guid_string()); + + std::string data; + sync_pb::PowerBookmarkSpecifics specifics; + power.ToPowerBookmarkSpecifics(&specifics); + specifics.SerializeToString(&data); + blob_statement.BindString(1, data); + if (!blob_statement.Run()) { + return false; + } + + return true; +} + +bool PowerBookmarkDatabaseImpl::UpdatePowerInternal(const Power& power) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + static constexpr char kUpdatePowerSaveSql[] = + // clang-format off + "UPDATE saves SET " + "url=?, origin=?, power_type=?, time_added=?, " + "time_modified=?" + "WHERE id=?"; + // clang-format on + DCHECK(db_.IsSQLValid(kUpdatePowerSaveSql)); + + sql::Statement save_statement( + db_.GetCachedStatement(SQL_FROM_HERE, kUpdatePowerSaveSql)); + + save_statement.BindString(0, power.url().spec()); + save_statement.BindString(1, url::Origin::Create(power.url()).Serialize()); + save_statement.BindInt(2, power.power_type()); + save_statement.BindTime(3, power.time_added()); + save_statement.BindTime(4, power.time_modified()); + if (!save_statement.Run()) { + return false; + } + + static constexpr char kUpdatePowerBlobSql[] = + // clang-format off + "UPDATE blobs SET specifics=? WHERE id=?"; + // clang-format on + DCHECK(db_.IsSQLValid(kUpdatePowerBlobSql)); + + sql::Statement blob_statement( + db_.GetCachedStatement(SQL_FROM_HERE, kUpdatePowerBlobSql)); + + std::string data; + sync_pb::PowerBookmarkSpecifics specifics; + power.ToPowerBookmarkSpecifics(&specifics); + bool success = specifics.SerializeToString(&data); + DCHECK(success); + blob_statement.BindBlob(0, data); + blob_statement.BindString(1, power.guid_string()); + if (!blob_statement.Run()) { + return false; + } + + return true; +} + +bool PowerBookmarkDatabaseImpl::DeletePowerInternal(const base::GUID& guid) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + static constexpr char kDeletePowerSaveSql[] = + // clang-format off + "DELETE FROM saves WHERE id=?"; + // clang-format on + DCHECK(db_.IsSQLValid(kDeletePowerSaveSql)); + + sql::Statement save_statement( + db_.GetCachedStatement(SQL_FROM_HERE, kDeletePowerSaveSql)); + save_statement.BindString(0, guid.AsLowercaseString()); + if (!save_statement.Run()) { + return false; + } + + static constexpr char kDeletePowerBlobSql[] = + // clang-format off + "DELETE FROM blobs WHERE id=?"; + // clang-format on + DCHECK(db_.IsSQLValid(kDeletePowerBlobSql)); + + sql::Statement blob_statement( + db_.GetCachedStatement(SQL_FROM_HERE, kDeletePowerBlobSql)); + blob_statement.BindString(0, guid.AsLowercaseString()); + if (!blob_statement.Run()) { + return false; + } + + return true; +} + +std::unique_ptr<Transaction> PowerBookmarkDatabaseImpl::BeginTransaction() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto transaction = std::make_unique<SqliteDatabaseTransaction>(db_); + if (transaction->Begin()) { + return transaction; + } else { + return nullptr; + } +} + } // namespace power_bookmarks
diff --git a/components/power_bookmarks/storage/power_bookmark_database_impl.h b/components/power_bookmarks/storage/power_bookmark_database_impl.h index 68cb2ad..a9b1aba8 100644 --- a/components/power_bookmarks/storage/power_bookmark_database_impl.h +++ b/components/power_bookmarks/storage/power_bookmark_database_impl.h
@@ -44,19 +44,20 @@ std::vector<std::unique_ptr<PowerOverview>> GetPowerOverviewsForSearchParams( const SearchParams& search_params) override; bool CreatePower(std::unique_ptr<Power> power) override; - bool UpdatePower(std::unique_ptr<Power> power) override; + std::unique_ptr<Power> UpdatePower(std::unique_ptr<Power> power) override; bool DeletePower(const base::GUID& guid) override; bool DeletePowersForURL( const GURL& url, - const sync_pb::PowerBookmarkSpecifics::PowerType& power_type) override; + const sync_pb::PowerBookmarkSpecifics::PowerType& power_type, + std::vector<std::string>* deleted_guids = nullptr) override; std::vector<std::unique_ptr<Power>> GetAllPowers() override; std::vector<std::unique_ptr<Power>> GetPowersForGUIDs( const std::vector<std::string>& guids) override; std::unique_ptr<Power> GetPowerForGUID(const std::string& guid) override; - - PowerBookmarkSyncMetadataDatabase* GetSyncMetadataDatabase() { - return sync_db_.get(); - } + bool CreateOrMergePowerFromSync(const Power& power) override; + bool DeletePowerFromSync(const std::string& guid) override; + syncer::SyncMetadataStore* GetSyncMetadataDatabase() override; + std::unique_ptr<Transaction> BeginTransaction() override; private: FRIEND_TEST_ALL_PREFIXES(PowerBookmarkDatabaseImplTest, @@ -73,6 +74,16 @@ const std::string& data, const base::GUID& id); + std::vector<std::string> GetGUIDsForURL( + const GURL& url, + const sync_pb::PowerBookmarkSpecifics::PowerType& power_type); + + bool CreatePowerInternal(const Power& power); + + bool UpdatePowerInternal(const Power& power); + + bool DeletePowerInternal(const base::GUID& guid); + sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_); sql::MetaTable meta_table_ GUARDED_BY_CONTEXT(sequence_checker_); std::unique_ptr<PowerBookmarkSyncMetadataDatabase> sync_db_;
diff --git a/components/power_bookmarks/storage/power_bookmark_database_impl_unittest.cc b/components/power_bookmarks/storage/power_bookmark_database_impl_unittest.cc index 3010c461..a03d733 100644 --- a/components/power_bookmarks/storage/power_bookmark_database_impl_unittest.cc +++ b/components/power_bookmarks/storage/power_bookmark_database_impl_unittest.cc
@@ -77,7 +77,7 @@ std::string WritePower(PowerBookmarkDatabaseImpl* pbdb, std::unique_ptr<Power> power) { - std::string guid = power->guid().AsLowercaseString(); + std::string guid = power->guid_string(); EXPECT_TRUE(pbdb->CreatePower(std::move(power))); return guid; } @@ -153,7 +153,7 @@ std::make_unique<sync_pb::PowerEntity>(); std::unique_ptr<Power> power = std::make_unique<Power>(std::move(power_specifics)); - save_statement.BindString(0, power->guid().AsLowercaseString()); + save_statement.BindString(0, power->guid_string()); save_statement.BindString(1, power->url().spec()); save_statement.BindString(2, url::Origin::Create(power->url()).Serialize()); save_statement.BindInt(3, power->power_type()); @@ -171,7 +171,7 @@ sql::Statement blob_statement( db.GetCachedStatement(SQL_FROM_HERE, kCreatePowerBlobSql)); - blob_statement.BindString(0, power->guid().AsLowercaseString()); + blob_statement.BindString(0, power->guid_string()); std::string data = "badprotofortesting"; blob_statement.BindBlob(1, data); EXPECT_TRUE(blob_statement.Run()); @@ -532,21 +532,21 @@ EXPECT_EQ(5u, example_power_overview->count()); const Power* example_power = example_power_overview->power(); EXPECT_EQ(kExampleUrl, example_power->url()); - EXPECT_EQ(exampleGuid, example_power->guid().AsLowercaseString()); + EXPECT_EQ(exampleGuid, example_power->guid_string()); EXPECT_EQ(EpochAndSeconds(9), example_power->time_modified()); const PowerOverview* google_power_overview = power_overviews[1].get(); EXPECT_EQ(3u, google_power_overview->count()); const Power* google_power = google_power_overview->power(); EXPECT_EQ(kGoogleUrl, google_power->url()); - EXPECT_EQ(googleGuid, google_power->guid().AsLowercaseString()); + EXPECT_EQ(googleGuid, google_power->guid_string()); EXPECT_EQ(EpochAndSeconds(3), google_power->time_modified()); const PowerOverview* boogle_power_overview = power_overviews[2].get(); EXPECT_EQ(1u, boogle_power_overview->count()); const Power* boogle_power = boogle_power_overview->power(); EXPECT_EQ(kBoogleUrl, boogle_power->url()); - EXPECT_EQ(boogleGuid, boogle_power->guid().AsLowercaseString()); + EXPECT_EQ(boogleGuid, boogle_power->guid_string()); EXPECT_EQ(EpochAndSeconds(4), boogle_power->time_modified()); } @@ -830,7 +830,9 @@ std::make_unique<PowerBookmarkDatabaseImpl>(db_dir()); EXPECT_TRUE(pbdb->Init()); - EXPECT_TRUE(pbdb->CreatePower(MakePower(kGoogleUrl, kMockType))); + auto power = MakePower(kGoogleUrl, kMockType); + auto guid = power->guid_string(); + EXPECT_TRUE(pbdb->CreatePower(std::move(power))); std::vector<std::unique_ptr<Power>> stored_powers = pbdb->GetPowersForURL(kGoogleUrl, kMockType); @@ -838,8 +840,14 @@ EXPECT_EQ(kGoogleUrl, stored_powers[0]->url()); EXPECT_EQ(kMockType, stored_powers[0]->power_type()); - EXPECT_TRUE(pbdb->DeletePowersForURL(kGoogleUrl, kMockType)); - stored_powers = pbdb->GetPowersForURL(kGoogleUrl, kMockType); + std::vector<std::string> guids; + EXPECT_TRUE(pbdb->DeletePowersForURL(kGoogleUrl, kMockType, &guids)); + EXPECT_EQ(1u, guids.size()); + EXPECT_EQ(guid, guids[0]); + + stored_powers = + pbdb->GetPowersForURL(GURL("https://google.com"), + sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK); EXPECT_EQ(0u, stored_powers.size()); } @@ -856,9 +864,12 @@ EXPECT_EQ(kGoogleUrl, stored_powers[0]->url()); EXPECT_EQ(kMockType, stored_powers[0]->power_type()); + std::vector<std::string> guids; EXPECT_TRUE(pbdb->DeletePowersForURL( - kGoogleUrl, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_UNSPECIFIED)); - stored_powers = pbdb->GetPowersForURL(kGoogleUrl, kMockType); + kGoogleUrl, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_UNSPECIFIED, + &guids)); + stored_powers = pbdb->GetPowersForURL( + kGoogleUrl, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK); EXPECT_EQ(0u, stored_powers.size()); } @@ -884,8 +895,8 @@ auto power1 = MakePower(kGoogleUrl, kMockType); auto power2 = MakePower(kGoogleUrl, kMockType); auto power3 = MakePower(GURL("https://bing.com"), kMockType); - auto guid1 = power1->guid().AsLowercaseString(); - auto guid2 = power2->guid().AsLowercaseString(); + auto guid1 = power1->guid_string(); + auto guid2 = power2->guid_string(); EXPECT_TRUE(pbdb->CreatePower(std::move(power1))); EXPECT_TRUE(pbdb->CreatePower(std::move(power2))); @@ -905,7 +916,7 @@ auto power1 = MakePower(kGoogleUrl, kMockType); auto power2 = MakePower(GURL("https://bing.com"), kMockType); - auto guid1 = power1->guid().AsLowercaseString(); + auto guid1 = power1->guid_string(); EXPECT_TRUE(pbdb->CreatePower(std::move(power1))); EXPECT_TRUE(pbdb->CreatePower(std::move(power2)));
diff --git a/components/power_bookmarks/storage/power_bookmark_sync_bridge.cc b/components/power_bookmarks/storage/power_bookmark_sync_bridge.cc index b708d19..76136d686 100644 --- a/components/power_bookmarks/storage/power_bookmark_sync_bridge.cc +++ b/components/power_bookmarks/storage/power_bookmark_sync_bridge.cc
@@ -6,6 +6,7 @@ #include "components/power_bookmarks/common/power.h" #include "components/power_bookmarks/storage/power_bookmark_sync_metadata_database.h" +#include "components/sync/model/in_memory_metadata_change_list.h" #include "components/sync/model/metadata_batch.h" #include "components/sync/model/metadata_change_list.h" #include "components/sync/model/model_type_change_processor.h" @@ -19,7 +20,7 @@ PowerBookmarkSyncBridge::DataCallback callback) { auto batch = std::make_unique<syncer::MutableDataBatch>(); for (const auto& power : powers) { - std::string guid = power->guid().AsLowercaseString(); + std::string guid = power->guid_string(); auto entity_data = std::make_unique<syncer::EntityData>(); entity_data->name = guid; power->ToPowerBookmarkSpecifics( @@ -31,7 +32,7 @@ } // namespace PowerBookmarkSyncBridge::PowerBookmarkSyncBridge( - PowerBookmarkSyncMetadataDatabase* meta_db, + syncer::SyncMetadataStore* meta_db, Delegate* delegate, std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor) : syncer::ModelTypeSyncBridge(std::move(change_processor)), @@ -42,24 +43,21 @@ std::unique_ptr<syncer::MetadataChangeList> PowerBookmarkSyncBridge::CreateMetadataChangeList() { - return std::make_unique<syncer::SyncMetadataStoreChangeList>( - meta_db_, syncer::POWER_BOOKMARK, - base::BindRepeating(&syncer::ModelTypeChangeProcessor::ReportError, - change_processor()->GetWeakPtr())); + return std::make_unique<syncer::InMemoryMetadataChangeList>(); } absl::optional<syncer::ModelError> PowerBookmarkSyncBridge::MergeSyncData( std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, syncer::EntityChangeList entity_changes) { - NOTIMPLEMENTED(); - return {}; + return ApplyChanges(std::move(metadata_change_list), entity_changes, + /*is_initial_merge=*/true); } absl::optional<syncer::ModelError> PowerBookmarkSyncBridge::ApplySyncChanges( std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, syncer::EntityChangeList entity_changes) { - NOTIMPLEMENTED(); - return {}; + return ApplyChanges(std::move(metadata_change_list), entity_changes, + /*is_initial_merge=*/false); } std::string PowerBookmarkSyncBridge::GetStorageKey( @@ -82,4 +80,91 @@ WritePowersToSyncData(delegate_->GetAllPowers(), std::move(callback)); } +void PowerBookmarkSyncBridge::SendPowerToSync(const Power& power) { + if (!change_processor()->IsTrackingMetadata()) { + return; + } + auto entity_data = std::make_unique<syncer::EntityData>(); + power.ToPowerBookmarkSpecifics( + entity_data->specifics.mutable_power_bookmark()); + entity_data->name = power.guid_string(); + + change_processor()->Put(power.guid_string(), std::move(entity_data), + CreateMetadataChangeListInTransaction().get()); +} + +void PowerBookmarkSyncBridge::NotifySyncForDeletion(const std::string& guid) { + if (!change_processor()->IsTrackingMetadata()) { + return; + } + change_processor()->Delete(guid, + CreateMetadataChangeListInTransaction().get()); +} + +std::unique_ptr<syncer::MetadataChangeList> +PowerBookmarkSyncBridge::CreateMetadataChangeListInTransaction() { + // TODO(crbug.com/1392502): Add a DCHECK to make sure this is called inside a + // transaction. + return std::make_unique<syncer::SyncMetadataStoreChangeList>( + meta_db_, syncer::POWER_BOOKMARK, + base::BindRepeating(&syncer::ModelTypeChangeProcessor::ReportError, + change_processor()->GetWeakPtr())); +} + +absl::optional<syncer::ModelError> PowerBookmarkSyncBridge::ApplyChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList& entity_changes, + bool is_initial_merge) { + std::set<std::string> synced_entries; + std::unique_ptr<Transaction> transaction = delegate_->BeginTransaction(); + if (!transaction) { + return syncer::ModelError( + FROM_HERE, "Failed to begin transaction for PowerBookmarks."); + } + + for (const std::unique_ptr<syncer::EntityChange>& change : entity_changes) { + switch (change->type()) { + case syncer::EntityChange::ACTION_ADD: + case syncer::EntityChange::ACTION_UPDATE: + if (!delegate_->CreateOrMergePowerFromSync(*std::make_unique<Power>( + change->data().specifics.power_bookmark()))) { + return syncer::ModelError( + FROM_HERE, "Failed to merge local powers for PowerBookmarks."); + } + if (is_initial_merge) { + synced_entries.insert(change->storage_key()); + } + break; + case syncer::EntityChange::ACTION_DELETE: + if (!delegate_->DeletePowerFromSync(change->storage_key())) { + return syncer::ModelError( + FROM_HERE, "Failed to delete local powers for PowerBookmarks."); + } + break; + } + } + + if (is_initial_merge) { + // Send local only powers to sync. + for (const std::unique_ptr<Power>& power : delegate_->GetAllPowers()) { + if (synced_entries.count(power->guid_string()) == 0) { + SendPowerToSync(*power); + } + } + } + + std::unique_ptr<syncer::MetadataChangeList> power_bookmark_change_list = + CreateMetadataChangeListInTransaction(); + static_cast<syncer::InMemoryMetadataChangeList*>(metadata_change_list.get()) + ->TransferChangesTo(power_bookmark_change_list.get()); + + if (!transaction->Commit()) { + return syncer::ModelError( + FROM_HERE, "Failed to commit transaction for PowerBookmarks."); + } + + delegate_->NotifyPowersChanged(); + return {}; +} + } // namespace power_bookmarks
diff --git a/components/power_bookmarks/storage/power_bookmark_sync_bridge.h b/components/power_bookmarks/storage/power_bookmark_sync_bridge.h index 93c4fa7..30883c7 100644 --- a/components/power_bookmarks/storage/power_bookmark_sync_bridge.h +++ b/components/power_bookmarks/storage/power_bookmark_sync_bridge.h
@@ -5,31 +5,63 @@ #ifndef COMPONENTS_POWER_BOOKMARKS_STORAGE_POWER_BOOKMARK_SYNC_BRIDGE_H_ #define COMPONENTS_POWER_BOOKMARKS_STORAGE_POWER_BOOKMARK_SYNC_BRIDGE_H_ +#include "base/guid.h" #include "components/sync/model/model_type_sync_bridge.h" namespace syncer { class ModelError; +class SyncMetadataStore; } // namespace syncer namespace power_bookmarks { class Power; -class PowerBookmarkSyncMetadataDatabase; + +// Transaction wraps a database transaction. When it's out of scope the +// underlying transaction will be cancelled if not committed. +// TODO(crbug.com/1392502): Find a better layout for this class. +class Transaction { + public: + virtual bool Commit() = 0; + virtual ~Transaction() = default; +}; // PowerBookmarkSyncBridge is responsible for syncing all powers to different // devices. It runs on the same thread as the power bookmark database // implementation. class PowerBookmarkSyncBridge : public syncer::ModelTypeSyncBridge { public: + // Delegate interface PowerBookmarkSyncBridge needs from the backend. class Delegate { public: + // Get all the powers from the database. virtual std::vector<std::unique_ptr<Power>> GetAllPowers() = 0; + + // Get powers for the given guids. virtual std::vector<std::unique_ptr<Power>> GetPowersForGUIDs( const std::vector<std::string>& guids) = 0; + + // Get power for the given guid. virtual std::unique_ptr<Power> GetPowerForGUID(const std::string& guid) = 0; + + // Create a power if not exists or merge existing the power in the database. + virtual bool CreateOrMergePowerFromSync(const Power& power) = 0; + + // Delete a power from the database. + virtual bool DeletePowerFromSync(const std::string& guid) = 0; + + // Get the database to store power bookmarks metadata. + virtual syncer::SyncMetadataStore* GetSyncMetadataDatabase() = 0; + + // Start a transaction. This is used to make sure power bookmark data + // and metadata are stored atomically. + virtual std::unique_ptr<Transaction> BeginTransaction() = 0; + + // Notify the backend if powers are changed. + virtual void NotifyPowersChanged() {} }; PowerBookmarkSyncBridge( - PowerBookmarkSyncMetadataDatabase* meta_db, + syncer::SyncMetadataStore* meta_db, Delegate* delegate, std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor); @@ -52,8 +84,27 @@ void GetData(StorageKeyList storage_keys, DataCallback callback) override; void GetAllDataForDebugging(DataCallback callback) override; + void SendPowerToSync(const Power& power); + void NotifySyncForDeletion(const std::string& guid); + private: - const raw_ptr<PowerBookmarkSyncMetadataDatabase> meta_db_; + // Create a change list to store metadata inside the power bookmark database. + // This method should be called inside a transaction because Chrome sync + // requires saving data and metadata atomically. Also need to transfer the + // meta_data_change_list from the InMemoryMetadataChangeList created by + // CreateMetadataChangeList() within the transaction created in + // MergeSyncData() and ApplySyncChanges(). + std::unique_ptr<syncer::MetadataChangeList> + CreateMetadataChangeListInTransaction(); + + // Helper function called by both `MergeSyncData` with is_initial_merge=true + // and `ApplySyncChanges` with is_initial_merge=false. + absl::optional<syncer::ModelError> ApplyChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList& entity_changes, + bool is_initial_merge); + + const raw_ptr<syncer::SyncMetadataStore> meta_db_; const raw_ptr<Delegate> delegate_; };
diff --git a/components/power_bookmarks/storage/power_bookmark_sync_bridge_unittest.cc b/components/power_bookmarks/storage/power_bookmark_sync_bridge_unittest.cc new file mode 100644 index 0000000..1de5edd0 --- /dev/null +++ b/components/power_bookmarks/storage/power_bookmark_sync_bridge_unittest.cc
@@ -0,0 +1,239 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/power_bookmarks/storage/power_bookmark_sync_bridge.h" +#include "base/files/scoped_temp_dir.h" +#include "base/test/task_environment.h" +#include "components/power_bookmarks/common/power.h" +#include "components/power_bookmarks/storage/power_bookmark_backend.h" +#include "components/power_bookmarks/storage/power_bookmark_sync_metadata_database.h" +#include "components/sync/model/sync_metadata_store.h" +#include "components/sync/test/mock_model_type_change_processor.h" +#include "components/sync/test/model_type_store_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::Return; +using testing::SizeIs; + +namespace power_bookmarks { + +namespace { + +std::unique_ptr<Power> MakePower( + GURL url, + sync_pb::PowerBookmarkSpecifics::PowerType power_type, + std::unique_ptr<sync_pb::PowerEntity> power_specifics) { + std::unique_ptr<Power> power = + std::make_unique<Power>(std::move(power_specifics)); + power->set_guid(base::GUID::GenerateRandomV4()); + power->set_url(url); + power->set_power_type(power_type); + return power; +} + +std::unique_ptr<Power> MakePower( + GURL url, + sync_pb::PowerBookmarkSpecifics::PowerType power_type) { + return MakePower(url, power_type, std::make_unique<sync_pb::PowerEntity>()); +} + +MATCHER_P(MatchesPowerByGUID, expected_guid, "") { + return arg.guid() == expected_guid; +} + +class MockTransaction : public Transaction { + bool Commit() override { return true; } +}; + +class MockDelegate : public PowerBookmarkSyncBridge::Delegate { + public: + void CreatePower(std::unique_ptr<Power> power) { + power_map_[power->guid_string()] = std::move(power); + } + + std::vector<std::unique_ptr<Power>> GetAllPowers() override { + std::vector<std::unique_ptr<Power>> powers; + for (auto const& pair : power_map_) { + powers.push_back(pair.second->Clone()); + } + return powers; + } + + std::vector<std::unique_ptr<Power>> GetPowersForGUIDs( + const std::vector<std::string>& guids) override { + std::vector<std::unique_ptr<Power>> powers; + return powers; + } + + std::unique_ptr<Power> GetPowerForGUID(const std::string& guid) override { + if (power_map_.count(guid)) { + return power_map_[guid]->Clone(); + } + return nullptr; + } + + std::unique_ptr<Transaction> BeginTransaction() override { + return std::make_unique<MockTransaction>(); + } + + MOCK_METHOD1(CreateOrMergePowerFromSync, bool(const Power& power)); + MOCK_METHOD1(DeletePowerFromSync, bool(const std::string&)); + MOCK_METHOD0(GetSyncMetadataDatabase, syncer::SyncMetadataStore*()); + MOCK_METHOD0(NotifyPowersChanged, void()); + + private: + std::map<std::string, std::unique_ptr<Power>> power_map_; +}; + +class PowerBookmarkSyncBridgeTest : public ::testing::Test { + public: + PowerBookmarkSyncBridgeTest() = default; + ~PowerBookmarkSyncBridgeTest() override = default; + + protected: + void SetUp() override { + EXPECT_TRUE(temp_directory_.CreateUniqueTempDir()); + ON_CALL(processor_, IsTrackingMetadata()) + .WillByDefault(testing::Return(true)); + bridge_ = std::make_unique<PowerBookmarkSyncBridge>( + delegate_.GetSyncMetadataDatabase(), &delegate_, + processor_.CreateForwardingProcessor()); + task_environment_.RunUntilIdle(); + } + + base::test::TaskEnvironment task_environment_; + testing::NiceMock<syncer::MockModelTypeChangeProcessor> processor_; + testing::NiceMock<MockDelegate> delegate_; + + base::ScopedTempDir temp_directory_; + + std::unique_ptr<PowerBookmarkSyncBridge> bridge_; +}; + +TEST_F(PowerBookmarkSyncBridgeTest, MergeSyncDataAdd) { + auto power = MakePower(GURL("https://google.com"), + sync_pb::PowerBookmarkSpecifics::PowerType:: + PowerBookmarkSpecifics_PowerType_POWER_TYPE_MOCK); + auto guid = power->guid_string(); + delegate_.CreatePower(std::move(power)); + + auto power2 = MakePower(GURL("https://google.com"), + sync_pb::PowerBookmarkSpecifics::PowerType:: + PowerBookmarkSpecifics_PowerType_POWER_TYPE_MOCK); + syncer::EntityChangeList entity_changes; + syncer::EntityData data; + power2->ToPowerBookmarkSpecifics(data.specifics.mutable_power_bookmark()); + entity_changes.push_back( + syncer::EntityChange::CreateAdd(power2->guid_string(), std::move(data))); + + EXPECT_CALL(delegate_, + CreateOrMergePowerFromSync(MatchesPowerByGUID(power2->guid()))) + .WillRepeatedly(Return(true)); + EXPECT_CALL(processor_, Put(guid, _, _)); + EXPECT_CALL(delegate_, NotifyPowersChanged()); + + ASSERT_FALSE(bridge_ + ->MergeSyncData(bridge_->CreateMetadataChangeList(), + std::move(entity_changes)) + .has_value()); +} + +TEST_F(PowerBookmarkSyncBridgeTest, ApplySyncChangesAdd) { + delegate_.CreatePower( + MakePower(GURL("https://google.com"), + sync_pb::PowerBookmarkSpecifics::PowerType:: + PowerBookmarkSpecifics_PowerType_POWER_TYPE_MOCK)); + + auto power2 = MakePower(GURL("https://google.com"), + sync_pb::PowerBookmarkSpecifics::PowerType:: + PowerBookmarkSpecifics_PowerType_POWER_TYPE_MOCK); + syncer::EntityChangeList entity_changes; + syncer::EntityData data; + power2->ToPowerBookmarkSpecifics(data.specifics.mutable_power_bookmark()); + entity_changes.push_back( + syncer::EntityChange::CreateAdd(power2->guid_string(), std::move(data))); + + EXPECT_CALL(delegate_, + CreateOrMergePowerFromSync(MatchesPowerByGUID(power2->guid()))) + .WillRepeatedly(Return(true)); + EXPECT_CALL(delegate_, NotifyPowersChanged()); + + ASSERT_FALSE(bridge_ + ->ApplySyncChanges(bridge_->CreateMetadataChangeList(), + std::move(entity_changes)) + .has_value()); +} + +TEST_F(PowerBookmarkSyncBridgeTest, ApplySyncChangesUpdate) { + auto power1 = MakePower(GURL("https://google.com"), + sync_pb::PowerBookmarkSpecifics::PowerType:: + PowerBookmarkSpecifics_PowerType_POWER_TYPE_MOCK); + auto guid = power1->guid(); + auto power2 = power1->Clone(); + delegate_.CreatePower(std::move(power1)); + + syncer::EntityChangeList entity_changes; + syncer::EntityData data; + power2->ToPowerBookmarkSpecifics(data.specifics.mutable_power_bookmark()); + entity_changes.push_back( + syncer::EntityChange::CreateAdd(power2->guid_string(), std::move(data))); + + EXPECT_CALL(delegate_, CreateOrMergePowerFromSync(MatchesPowerByGUID(guid))) + .WillRepeatedly(Return(true)); + EXPECT_CALL(delegate_, NotifyPowersChanged()); + + ASSERT_FALSE(bridge_ + ->ApplySyncChanges(bridge_->CreateMetadataChangeList(), + std::move(entity_changes)) + .has_value()); +} + +TEST_F(PowerBookmarkSyncBridgeTest, ApplySyncChangesDelete) { + auto power1 = MakePower(GURL("https://google.com"), + sync_pb::PowerBookmarkSpecifics::PowerType:: + PowerBookmarkSpecifics_PowerType_POWER_TYPE_MOCK); + auto guid = power1->guid_string(); + delegate_.CreatePower(std::move(power1)); + + EXPECT_CALL(delegate_, DeletePowerFromSync(guid)) + .WillRepeatedly(Return(true)); + EXPECT_CALL(delegate_, NotifyPowersChanged()); + + syncer::EntityChangeList entity_changes; + syncer::EntityData data; + entity_changes.push_back(syncer::EntityChange::CreateDelete(guid)); + + ASSERT_FALSE(bridge_ + ->ApplySyncChanges(bridge_->CreateMetadataChangeList(), + std::move(entity_changes)) + .has_value()); +} + +TEST_F(PowerBookmarkSyncBridgeTest, ApplySyncChangesFail) { + auto power = MakePower(GURL("https://google.com"), + sync_pb::PowerBookmarkSpecifics::PowerType:: + PowerBookmarkSpecifics_PowerType_POWER_TYPE_MOCK); + syncer::EntityChangeList entity_changes; + syncer::EntityData data; + power->ToPowerBookmarkSpecifics(data.specifics.mutable_power_bookmark()); + entity_changes.push_back( + syncer::EntityChange::CreateAdd(power->guid_string(), std::move(data))); + + // When `CreateOrMergePowerFromSync` call fails, `ApplySyncChanges` will + // return an error. + EXPECT_CALL(delegate_, + CreateOrMergePowerFromSync(MatchesPowerByGUID(power->guid()))) + .WillRepeatedly(Return(false)); + + ASSERT_TRUE(bridge_ + ->ApplySyncChanges(bridge_->CreateMetadataChangeList(), + std::move(entity_changes)) + .has_value()); +} + +} // namespace + +} // namespace power_bookmarks
diff --git a/components/power_bookmarks/storage/power_bookmark_sync_metadata_database_unittest.cc b/components/power_bookmarks/storage/power_bookmark_sync_metadata_database_unittest.cc index 13e140be..40d27c7 100644 --- a/components/power_bookmarks/storage/power_bookmark_sync_metadata_database_unittest.cc +++ b/components/power_bookmarks/storage/power_bookmark_sync_metadata_database_unittest.cc
@@ -40,10 +40,13 @@ } PowerBookmarkSyncMetadataDatabase* sync_db() { - return power_bookmark_db_->GetSyncMetadataDatabase(); + return static_cast<PowerBookmarkSyncMetadataDatabase*>( + power_bookmark_db_->GetSyncMetadataDatabase()); } sql::Database* sql_db() { - return power_bookmark_db_->GetSyncMetadataDatabase()->db_; + return static_cast<PowerBookmarkSyncMetadataDatabase*>( + power_bookmark_db_->GetSyncMetadataDatabase()) + ->db_; } private:
diff --git a/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc b/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc index 3fed5c34..3fdb4670 100644 --- a/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc +++ b/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.cc
@@ -5,6 +5,7 @@ #include "components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.h" #include "base/base64url.h" +#include "base/containers/contains.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/escape.h" @@ -192,6 +193,11 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(url.is_valid()); + // If |Shutdown| has been called, return early. + if (is_shutdown_) { + return; + } + // Search local cache. std::vector<std::string> hash_prefixes_to_request; std::vector<V5::FullHash> cached_full_hashes; @@ -259,7 +265,8 @@ response_code); auto response = ParseResponseAndUpdateBackoff(net_error, response_code, - std::move(response_body)); + std::move(response_body), + hash_prefixes_in_request); absl::optional<SBThreatType> sb_threat_type; if (response.has_value()) { if (cache_manager_) { @@ -291,9 +298,11 @@ HashRealTimeService::ParseResponseAndUpdateBackoff( int net_error, int response_code, - std::unique_ptr<std::string> response_body) const { + std::unique_ptr<std::string> response_body, + const std::vector<std::string>& requested_hash_prefixes) const { auto response = - ParseResponse(net_error, response_code, std::move(response_body)); + ParseResponse(net_error, response_code, std::move(response_body), + requested_hash_prefixes); LogOperationResult(response.has_value() ? OperationResult::kSuccess : response.error()); if (response.has_value()) { @@ -304,6 +313,28 @@ return response; } +void HashRealTimeService::RemoveUnmatchedFullHashes( + std::unique_ptr<V5::SearchHashesResponse>& response, + const std::vector<std::string>& requested_hash_prefixes) const { + size_t initial_full_hashes_count = response->full_hashes_size(); + std::set<std::string> requested_hash_prefixes_set( + requested_hash_prefixes.begin(), requested_hash_prefixes.end()); + auto* mutable_full_hashes = response->mutable_full_hashes(); + mutable_full_hashes->erase( + std::remove_if( + mutable_full_hashes->begin(), mutable_full_hashes->end(), + [requested_hash_prefixes_set](const V5::FullHash& full_hash) { + return !base::Contains( + requested_hash_prefixes_set, + hash_realtime_utils::GetHashPrefix(full_hash.full_hash())); + }), + mutable_full_hashes->end()); + size_t final_full_hashes_count = response->full_hashes_size(); + base::UmaHistogramBoolean( + "SafeBrowsing.HPRT.FoundUnmatchedFullHashes", + initial_full_hashes_count != final_full_hashes_count); +} + void HashRealTimeService::RemoveFullHashDetailsWithInvalidEnums( std::unique_ptr<V5::SearchHashesResponse>& response) const { for (int i = 0; i < response->full_hashes_size(); ++i) { @@ -331,7 +362,8 @@ HashRealTimeService::ParseResponse( int net_error, int response_code, - std::unique_ptr<std::string> response_body) const { + std::unique_ptr<std::string> response_body, + const std::vector<std::string>& requested_hash_prefixes) const { auto response = std::make_unique<V5::SearchHashesResponse>(); bool net_and_http_ok = net_error == net::OK && response_code == net::HTTP_OK; if (net_and_http_ok && response->ParseFromString(*response_body)) { @@ -344,6 +376,7 @@ return base::unexpected(OperationResult::kIncorrectFullHashLengthError); } } + RemoveUnmatchedFullHashes(response, requested_hash_prefixes); RemoveFullHashDetailsWithInvalidEnums(response); return std::move(response); } else if (net_and_http_ok) { @@ -387,6 +420,7 @@ } void HashRealTimeService::Shutdown() { + is_shutdown_ = true; for (auto& pending : pending_requests_) { // Pending requests are not posted back to the IO thread during shutdown, // because it is too late to post a task to the IO thread when the UI
diff --git a/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.h b/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.h index 4cb26b3..785340f0 100644 --- a/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.h +++ b/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service.h
@@ -168,15 +168,25 @@ ParseResponseAndUpdateBackoff( int net_error, int http_error, - std::unique_ptr<std::string> response_body) const; + std::unique_ptr<std::string> response_body, + const std::vector<std::string>& requested_hash_prefixes) const; // Tries to parse the |response_body| into a |SearchHashesResponse|, and // returns either the response proto or an |OperationResult| with details on - // why the parsing was unsuccessful. + // why the parsing was unsuccessful. |requested_hash_prefixes| is used for a + // sanitization call into |RemoveUnmatchedFullHashes|. base::expected<std::unique_ptr<V5::SearchHashesResponse>, OperationResult> ParseResponse(int net_error, int http_error, - std::unique_ptr<std::string> response_body) const; + std::unique_ptr<std::string> response_body, + const std::vector<std::string>& requested_hash_prefixes) const; + + // Removes any |FullHash| within the |response| whose hash prefix is not found + // within |requested_hash_prefixes|. This is not expected to occur, but is + // handled out of caution. + void RemoveUnmatchedFullHashes( + std::unique_ptr<V5::SearchHashesResponse>& response, + const std::vector<std::string>& requested_hash_prefixes) const; // Removes any |FullHashDetail| within the |response| that has invalid // |ThreatType| or |ThreatAttribute| enums. This is for forward compatibility, @@ -211,6 +221,10 @@ // Helper object that manages backoff state. std::unique_ptr<BackoffOperator> backoff_operator_; + // Indicates whether |Shutdown| has been called. If so, |StartLookup| returns + // early. + bool is_shutdown_ = false; + base::WeakPtrFactory<HashRealTimeService> weak_factory_{this}; };
diff --git a/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service_unittest.cc b/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service_unittest.cc index 6f5903f..a8ff91f 100644 --- a/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service_unittest.cc +++ b/components/safe_browsing/core/browser/hashprefix_realtime/hash_realtime_service_unittest.cc
@@ -153,7 +153,8 @@ void CheckRequestMetrics( int expected_prefix_count, int expected_network_result, - HashRealTimeService::OperationResult expected_operation_result) { + HashRealTimeService::OperationResult expected_operation_result, + absl::optional<bool> expected_found_unmatched_full_hashes) { histogram_tester_->ExpectUniqueSample( /*name=*/"SafeBrowsing.HPRT.Request.CountOfPrefixes", /*sample=*/expected_prefix_count, @@ -168,6 +169,16 @@ /*name=*/"SafeBrowsing.HPRT.OperationResult", /*sample=*/expected_operation_result, /*expected_bucket_count=*/1); + if (expected_found_unmatched_full_hashes.has_value()) { + histogram_tester_->ExpectUniqueSample( + /*name=*/"SafeBrowsing.HPRT.FoundUnmatchedFullHashes", + /*sample=*/expected_found_unmatched_full_hashes.value(), + /*expected_bucket_count=*/1); + } else { + histogram_tester_->ExpectTotalCount( + /*name=*/"SafeBrowsing.HPRT.FoundUnmatchedFullHashes", + /*expected_count=*/0); + } } V5::FullHash CreateFullHashProto( std::vector<V5::ThreatType> threat_types, @@ -233,7 +244,8 @@ std::vector<V5::FullHash> response_full_hashes, SBThreatType expected_threat_type, int expected_prefix_count, - int expected_threat_info_size) { + int expected_threat_info_size, + bool expected_found_unmatched_full_hashes) { auto num_requests = test_url_loader_factory_->total_requests(); base::MockCallback<HPRTLookupResponseCallback> response_callback; StartSuccessRequest(url, cached_hash_prefixes, response_callback, @@ -245,7 +257,9 @@ /*expected_prefix_count=*/expected_prefix_count, /*expected_network_result=*/200, /*expected_operation_result=*/ - HashRealTimeService::OperationResult::kSuccess); + HashRealTimeService::OperationResult::kSuccess, + /*expected_found_unmatched_full_hashes=*/ + expected_found_unmatched_full_hashes); CheckPostRequestMetrics(expected_threat_info_size); ResetMetrics(); @@ -296,7 +310,8 @@ /*expected_prefix_count=*/expected_prefix_count, /*expected_network_result=*/status, /*expected_operation_result=*/ - expected_operation_result); + expected_operation_result, /*expected_found_unmatched_full_hashes=*/ + absl::nullopt); ResetMetrics(); EXPECT_EQ(test_url_loader_factory_->total_requests(), num_requests + 1u); @@ -411,7 +426,8 @@ /*url=*/url, /*cached_hash_prefixes=*/{}, /*response_full_hashes=*/{}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_SAFE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/0); + /*expected_threat_info_size=*/0, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_OneHash_Phishing) { @@ -422,7 +438,8 @@ UrlToSingleFullHash(url))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_PHISHING, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/1); + /*expected_threat_info_size=*/1, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_OneHash_Malware) { @@ -433,7 +450,8 @@ UrlToSingleFullHash(url))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_MALWARE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/1); + /*expected_threat_info_size=*/1, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_OneHash_UnwantedSoftware) { @@ -444,7 +462,8 @@ UrlToSingleFullHash(url))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_UNWANTED, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/1); + /*expected_threat_info_size=*/1, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_OneHash_Suspicious) { @@ -455,7 +474,8 @@ UrlToSingleFullHash(url))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_SUSPICIOUS_SITE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/1); + /*expected_threat_info_size=*/1, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_OneHash_Billing) { @@ -466,7 +486,8 @@ UrlToSingleFullHash(url))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_BILLING, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/1); + /*expected_threat_info_size=*/1, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_OneHash_IrrelevantThreatType) { @@ -477,7 +498,8 @@ UrlToSingleFullHash(url))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_SAFE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/0); + /*expected_threat_info_size=*/0, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_OverlappingHashPrefixes) { @@ -492,7 +514,8 @@ UrlToSingleFullHash(url2))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_SAFE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/0); + /*expected_threat_info_size=*/0, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_MaxHashes_Phishing) { @@ -508,7 +531,8 @@ UrlToFullHashes(url)[15])}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_PHISHING, /*expected_prefix_count=*/30, - /*expected_threat_info_size=*/2); + /*expected_threat_info_size=*/2, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, @@ -542,7 +566,8 @@ non_matching_full_hash)}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_PHISHING, /*expected_prefix_count=*/30, - /*expected_threat_info_size=*/9); + /*expected_threat_info_size=*/9, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_MaxHashes_OnlyIrrelevant) { @@ -572,7 +597,8 @@ UrlToHashPrefixes(url)[15] + rest_of_hash)}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_SAFE, /*expected_prefix_count=*/30, - /*expected_threat_info_size=*/0); + /*expected_threat_info_size=*/0, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_CompetingSeverities) { @@ -585,7 +611,8 @@ UrlToSingleFullHash(url))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_MALWARE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/3); + /*expected_threat_info_size=*/3, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_Attributes) { @@ -603,7 +630,8 @@ UrlToSingleFullHash(url), attributes)}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_MALWARE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/3); + /*expected_threat_info_size=*/3, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_InvalidThreatTypes) { @@ -615,7 +643,8 @@ {CreateFullHashProto(threat_types, UrlToSingleFullHash(url))}, /*expected_threat_type=*/expected_threat_type, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/expected_threat_info_size); + /*expected_threat_info_size=*/expected_threat_info_size, + /*expected_found_unmatched_full_hashes=*/false); }; // Sanity check the static casting on a valid threat type is not filtered out. run_test(GURL("https://example.test1"), {static_cast<V5::ThreatType>(2)}, @@ -658,7 +687,8 @@ UrlToSingleFullHash(url), attributes)}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_UNWANTED, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/1); + /*expected_threat_info_size=*/1, + /*expected_found_unmatched_full_hashes=*/false); } // Threat types are the same. { @@ -678,7 +708,41 @@ UrlToSingleFullHash(url), attributes)}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_UNWANTED, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/2); + /*expected_threat_info_size=*/2, + /*expected_found_unmatched_full_hashes=*/false); + } +} + +TEST_F(HashRealTimeServiceTest, TestLookup_UnmatchedFullHashesInResponse) { + // The code should still function properly even if the server sends back + // FullHash objects that don't match the requested hash prefixes. + { + GURL url = GURL("https://example.test1"); + GURL other_url = GURL("https://example.test2"); + RunRequestSuccessTest( + /*url=*/url, + /*cached_hash_prefixes=*/{}, /*response_full_hashes=*/ + {CreateFullHashProto({V5::ThreatType::MALWARE}, + UrlToSingleFullHash(other_url))}, + /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_SAFE, + /*expected_prefix_count=*/1, + /*expected_threat_info_size=*/0, + /*expected_found_unmatched_full_hashes=*/true); + } + { + GURL url = GURL("https://example.test3"); + GURL other_url = GURL("https://example.test4"); + RunRequestSuccessTest( + /*url=*/url, + /*cached_hash_prefixes=*/{}, /*response_full_hashes=*/ + {CreateFullHashProto({V5::ThreatType::MALWARE}, + UrlToSingleFullHash(other_url)), + CreateFullHashProto({V5::ThreatType::UNWANTED_SOFTWARE}, + UrlToSingleFullHash(url))}, + /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_UNWANTED, + /*expected_prefix_count=*/1, + /*expected_threat_info_size=*/1, + /*expected_found_unmatched_full_hashes=*/true); } } @@ -695,7 +759,8 @@ UrlToSingleFullHash(url1))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_MALWARE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/2); + /*expected_threat_info_size=*/2, + /*expected_found_unmatched_full_hashes=*/false); // Run it with the server responses backwards as well to confirm order doesn't // matter. GURL url2 = GURL("https://example.test2"); @@ -708,7 +773,8 @@ UrlToSingleFullHash(url2))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_MALWARE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/2); + /*expected_threat_info_size=*/2, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookup_DuplicateFullHashDetailsInResponse) { @@ -724,7 +790,8 @@ UrlToSingleFullHash(url))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_MALWARE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/4); + /*expected_threat_info_size=*/4, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestLookupFailure_Error) { @@ -827,7 +894,8 @@ {CreateFullHashProto({V5::ThreatType::SOCIAL_ENGINEERING}, UrlToSingleFullHash(url1))}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_PHISHING, - /*expected_prefix_count=*/1, /*expected_threat_info_size=*/1); + /*expected_prefix_count=*/1, /*expected_threat_info_size=*/1, + /*expected_found_unmatched_full_hashes=*/false); ResetMetrics(); // Start a lookup for url2. This has the same hash prefix as url1, so the // results are fully cached, and no request is sent. @@ -844,16 +912,17 @@ RunSimpleRequest( /*url=*/url1, /*response_full_hashes=*/ {CreateFullHashProto({V5::ThreatType::UNWANTED_SOFTWARE}, - UrlToFullHashes(url1)[0])}); + UrlToFullHashes(url1).back())}); ResetMetrics(); GURL url2 = GURL("https://a.b.c.d.e.f.g/1/2/3/4/5/6?param=x"); RunRequestSuccessTest( /*url=*/url2, /*cached_hash_prefixes=*/UrlToHashPrefixesAsSet(url1), /*response_full_hashes=*/ {CreateFullHashProto({V5::ThreatType::SOCIAL_ENGINEERING}, - UrlToFullHashes(url2)[0])}, + UrlToFullHashes(url2).back())}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_PHISHING, - /*expected_prefix_count=*/24, /*expected_threat_info_size=*/2); + /*expected_prefix_count=*/24, /*expected_threat_info_size=*/2, + /*expected_found_unmatched_full_hashes=*/false); } // Since phishing is more severe than unwanted software, the cached results @@ -863,16 +932,17 @@ RunSimpleRequest( /*url=*/url1, /*response_full_hashes=*/ {CreateFullHashProto({V5::ThreatType::SOCIAL_ENGINEERING}, - UrlToFullHashes(url1)[0])}); + UrlToFullHashes(url1).back())}); ResetMetrics(); GURL url2 = GURL("https://a.b.c.d.e.f.g/1/2/3/4/5/6?param=x"); RunRequestSuccessTest( /*url=*/url2, /*cached_hash_prefixes=*/UrlToHashPrefixesAsSet(url1), /*response_full_hashes=*/ {CreateFullHashProto({V5::ThreatType::UNWANTED_SOFTWARE}, - UrlToFullHashes(url2)[0])}, + UrlToFullHashes(url2).back())}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_URL_PHISHING, - /*expected_prefix_count=*/24, /*expected_threat_info_size=*/2); + /*expected_prefix_count=*/24, /*expected_threat_info_size=*/2, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestCacheDuration) { @@ -893,7 +963,8 @@ /*url=*/url, /*cached_hash_prefixes=*/{}, /*response_full_hashes=*/{}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_SAFE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/0); + /*expected_threat_info_size=*/0, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceNoCacheManagerTest, TestNoCaching) { @@ -907,26 +978,46 @@ /*url=*/url, /*cached_hash_prefixes=*/{}, /*response_full_hashes=*/{}, /*expected_threat_type=*/SBThreatType::SB_THREAT_TYPE_SAFE, /*expected_prefix_count=*/1, - /*expected_threat_info_size=*/0); + /*expected_threat_info_size=*/0, + /*expected_found_unmatched_full_hashes=*/false); } TEST_F(HashRealTimeServiceTest, TestShutdown) { - GURL url = GURL("https://example.test"); - // Set up request response. - auto request = std::make_unique<V5::SearchHashesRequest>(); - for (const auto& hash_prefix : UrlToHashPrefixesAsSet(url)) { - request->add_hash_prefixes(hash_prefix); + { + GURL url = GURL("https://example.test"); + // Set up request response. + auto request = std::make_unique<V5::SearchHashesRequest>(); + for (const auto& hash_prefix : UrlToHashPrefixesAsSet(url)) { + request->add_hash_prefixes(hash_prefix); + } + std::string expected_url = GetExpectedRequestUrl(request); + SetUpLookupResponse(/*request_url=*/expected_url, + /*full_hashes=*/{}); + // Start lookup, setting up the expectation that the response_callback is + // not called due to shutdown. It should still send the initial request + // since it happens before Shutdown. + base::MockCallback<HPRTLookupResponseCallback> response_callback; + EXPECT_CALL(response_callback, Run(testing::_, testing::_)).Times(0); + service_->StartLookup(url, response_callback.Get(), + base::SequencedTaskRunner::GetCurrentDefault()); + histogram_tester_->ExpectTotalCount( + /*name=*/"SafeBrowsing.HPRT.Request.CountOfPrefixes", + /*expected_count=*/1); } - std::string expected_url = GetExpectedRequestUrl(request); - SetUpLookupResponse(/*request_url=*/expected_url, - /*full_hashes=*/{}); - // Start lookup, setting up the expectation that the response_callback is - // not called due to shutdown. - base::MockCallback<HPRTLookupResponseCallback> response_callback; - EXPECT_CALL(response_callback, Run(testing::_, testing::_)).Times(0); - service_->StartLookup(url, response_callback.Get(), - base::SequencedTaskRunner::GetCurrentDefault()); + ResetMetrics(); service_->Shutdown(); + { + // A new lookup should also not have the response_callback called (due to + // shutdown). It should not even trigger a request. + GURL url = GURL("https://example.test"); + base::MockCallback<HPRTLookupResponseCallback> response_callback; + EXPECT_CALL(response_callback, Run(testing::_, testing::_)).Times(0); + service_->StartLookup(url, response_callback.Get(), + base::SequencedTaskRunner::GetCurrentDefault()); + histogram_tester_->ExpectTotalCount( + /*name=*/"SafeBrowsing.HPRT.Request.CountOfPrefixes", + /*expected_count=*/0); + } task_environment_.RunUntilIdle(); }
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc index 3b210e94..4f01b98 100644 --- a/components/safe_browsing/core/common/features.cc +++ b/components/safe_browsing/core/common/features.cc
@@ -104,6 +104,10 @@ "SafeBrowsingExtensionTelemetryPersistence", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kExtensionTelemetryConfiguration, + "SafeBrowsingExtensionTelemetryConfiguration", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kExtensionTelemetryPotentialPasswordTheft, "SafeBrowsingExtensionTelemetryPotentialPasswordTheft", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h index 6f1b217..529afc1c 100644 --- a/components/safe_browsing/core/common/features.h +++ b/components/safe_browsing/core/common/features.h
@@ -85,6 +85,10 @@ // of telemetry reports to SB servers. BASE_DECLARE_FEATURE(kExtensionTelemetry); +// Allows the Extension Telemetry Service to accept and use configurations +// sent by the server. +BASE_DECLARE_FEATURE(kExtensionTelemetryConfiguration); + // Enables data collected by the kExtensionTelemetry to be written and read to // disk. This data will be uploaded for analysis. BASE_DECLARE_FEATURE(kExtensionTelemetryPersistence);
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.cc b/components/safe_browsing/core/common/safe_browsing_prefs.cc index 2c44c3d9..df8eb09 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.cc +++ b/components/safe_browsing/core/common/safe_browsing_prefs.cc
@@ -114,6 +114,8 @@ "safebrowsing.esb_enabled_via_tailored_security"; const char kExtensionTelemetryLastUploadTime[] = "safebrowsing.extension_telemetry_last_upload_time"; +const char kExtensionTelemetryConfig[] = + "safebrowsing.extension_telemetry_configuration"; } // namespace prefs namespace safe_browsing { @@ -234,6 +236,17 @@ prefs::kEnhancedProtectionEnabledViaTailoredSecurity, false); registry->RegisterTimePref(prefs::kExtensionTelemetryLastUploadTime, base::Time::Now()); + registry->RegisterDictionaryPref(prefs::kExtensionTelemetryConfig, + base::Value::Dict()); +} + +const base::Value::Dict& GetExtensionTelemetryConfig(const PrefService& prefs) { + return prefs.GetDict(prefs::kExtensionTelemetryConfig); +} + +void SetExtensionTelemetryConfig(PrefService& prefs, + const base::Value::Dict& config) { + prefs.SetDict(prefs::kExtensionTelemetryConfig, config.Clone()); } base::Time GetLastUploadTimeForExtensionTelemetry(PrefService& prefs) {
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.h b/components/safe_browsing/core/common/safe_browsing_prefs.h index c1aff82..f58528b 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.h +++ b/components/safe_browsing/core/common/safe_browsing_prefs.h
@@ -131,6 +131,9 @@ // uploaded its data. extern const char kExtensionTelemetryLastUploadTime[]; +// The saved copy of the current configuration that will be used by +// the Extension Telemetry Service. +extern const char kExtensionTelemetryConfig[]; } // namespace prefs namespace safe_browsing { @@ -259,6 +262,13 @@ // This variant is used to simplify test code by omitting the location. void SetExtendedReportingPrefForTests(PrefService* prefs, bool value); +// Set the current configuration being used by the Extension Telemetry Service +void SetExtensionTelemetryConfig(PrefService& prefs, + const base::Value::Dict& config); + +// Get the current configuration being used by the Extension Telemetry Service +const base::Value::Dict& GetExtensionTelemetryConfig(const PrefService& prefs); + // Sets the last time the Extension Telemetry Service successfully uploaded // its data. void SetLastUploadTimeForExtensionTelemetry(PrefService& prefs,
diff --git a/components/saved_tab_groups/saved_tab_group.cc b/components/saved_tab_groups/saved_tab_group.cc index 9ac8a2e..bd83a48 100644 --- a/components/saved_tab_groups/saved_tab_group.cc +++ b/components/saved_tab_groups/saved_tab_group.cc
@@ -122,21 +122,36 @@ return *this; } -SavedTabGroup& SavedTabGroup::AddTab(size_t index, SavedTabGroupTab tab) { - CHECK_GE(index, 0u); - CHECK_LE(index, saved_tabs_.size()); +SavedTabGroup& SavedTabGroup::AddTab(SavedTabGroupTab tab, + bool update_tab_positions) { CHECK(!ContainsTab(tab.saved_tab_guid())); - saved_tabs_.emplace(saved_tabs_.begin() + index, std::move(tab)); + + if (tab.position() == SavedTabGroupTab::kUnsetPosition) { + tab.SetPosition(saved_tabs_.size()); + } + + InsertTabImpl(tab); + + if (update_tab_positions) { + UpdateTabPositionsImpl(); + } + SetUpdateTimeWindowsEpochMicros(base::Time::Now()); return *this; } -SavedTabGroup& SavedTabGroup::RemoveTab(const base::GUID& saved_tab_guid) { +SavedTabGroup& SavedTabGroup::RemoveTab(const base::GUID& saved_tab_guid, + bool update_tab_positions) { absl::optional<size_t> index = GetIndexOfTab(saved_tab_guid); CHECK(index.has_value()); CHECK_GE(index.value(), 0u); CHECK_LT(index.value(), saved_tabs_.size()); saved_tabs_.erase(saved_tabs_.begin() + index.value()); + + if (update_tab_positions) { + UpdateTabPositionsImpl(); + } + SetUpdateTimeWindowsEpochMicros(base::Time::Now()); return *this; } @@ -161,6 +176,7 @@ CHECK(!ContainsTab(tab.saved_tab_guid())); saved_tabs_.erase(saved_tabs_.begin() + index.value()); saved_tabs_.insert(saved_tabs_.begin() + index.value(), std::move(tab)); + UpdateTabPositionsImpl(); SetUpdateTimeWindowsEpochMicros(base::Time::Now()); return *this; } @@ -185,10 +201,52 @@ saved_tabs_.rbegin() + ((saved_tabs_.size() - 1) - curr_index.value()) + 1); } + UpdateTabPositionsImpl(); SetUpdateTimeWindowsEpochMicros(base::Time::Now()); return *this; } +void SavedTabGroup::UpdateTabPositionsImpl() { + for (size_t i = 0; i < saved_tabs_.size(); ++i) { + saved_tabs_[i].SetPosition(i); + } +} + +void SavedTabGroup::InsertTabImpl(const SavedTabGroupTab& tab) { + // We can always safely insert the first tab at the end. We can also safely + // insert `tab` if its position is larger than the position at the end of + // `saved_tabs_`. + if (saved_tabs_.empty() || + saved_tabs_[saved_tabs_.size() - 1].position() < tab.position()) { + saved_tabs_.emplace_back(std::move(tab)); + return; + } + + // Insert `tab` in front of an element if one of these criteria + // are met: + // 1. The current index is larger than `tab`. + // 2. The current index has the same position as `tab` and is not + // the most recently updated position. + for (size_t index = 0; index < saved_tabs_.size(); ++index) { + const SavedTabGroupTab& curr_tab = saved_tabs_[index]; + bool curr_position_larger = curr_tab.position() > tab.position(); + bool curr_position_same = curr_tab.position() == tab.position(); + bool curr_position_least_recently_updated = + curr_tab.update_time_windows_epoch_micros() < + tab.update_time_windows_epoch_micros(); + + if (curr_position_larger || + (curr_position_same && curr_position_least_recently_updated)) { + saved_tabs_.insert(saved_tabs_.begin() + index, std::move(tab)); + return; + } + } + + // This can happen when the last element of the vector has the same position + // as `group` and was more recently updated. + saved_tabs_.push_back(std::move(tab)); +} + bool SavedTabGroup::ShouldMergeGroup( const sync_pb::SavedTabGroupSpecifics& sync_specific) { bool sync_update_is_latest =
diff --git a/components/saved_tab_groups/saved_tab_group.h b/components/saved_tab_groups/saved_tab_group.h index dc03c74c3..ce50577 100644 --- a/components/saved_tab_groups/saved_tab_group.h +++ b/components/saved_tab_groups/saved_tab_group.h
@@ -24,6 +24,7 @@ // tab_group_editor_bubble_view. class SavedTabGroup { public: + // Used to denote groups that have not been given a position. static constexpr int kUnsetPosition = -1; SavedTabGroup( @@ -83,15 +84,22 @@ SavedTabGroup& SetPosition(int position); // Tab mutators. - // Adds `tab` to `saved_tabs_` at the specified `index` unless the added tab - // already exists. In this case we CHECK. - SavedTabGroup& AddTab(size_t index, SavedTabGroupTab tab); - // Removes the tab denoted by `tab_id` from `saved_tabs_`. This function will - // remove the last tab: crbug/1371959. - SavedTabGroup& RemoveTab(const base::GUID& tab_id); + // Add `tab` into its position in `saved_tabs_` if it is set. Otherwise add it + // to the end. If the tab already exists, CHECK. If `update_tab_positions` is + // true, update the positions of all tabs in the group. + SavedTabGroup& AddTab(SavedTabGroupTab tab, + bool update_tab_positions = false); + // Updates the tab with with `tab_id` tab.guid() with a value of `tab`. If // there is no tab, this function will CHECK. SavedTabGroup& UpdateTab(SavedTabGroupTab tab); + + // Removes a tab from `saved_tabs_` denoted by `saved_tab_guid` even if that + // was the last tab in the group: crbug/1371959. If `update_tab_positions` is + // true, update the positions of all tabs in the group. + SavedTabGroup& RemoveTab(const base::GUID& saved_tab_guid, + bool update_tab_positions = false); + // Replaces that tab denoted by `tab_id` with value of `tab` unless the // replacement tab already exists. In this case we CHECK. SavedTabGroup& ReplaceTabAt(const base::GUID& saved_tab_guid, @@ -110,6 +118,17 @@ // 2. The `sync_specific` has the oldest (smallest) creation time. bool ShouldMergeGroup(const sync_pb::SavedTabGroupSpecifics& sync_specific); + // Insert `tab` into sorted order based on its position compared to already + // stored tabs in its group. It should be noted that the list of tabs in each + // group must already be in sorted order for this function to work as + // intended. To do this, UpdateTabPositionsImpl() can be called before calling + // this method. + void InsertTabImpl(const SavedTabGroupTab& tab); + + // Updates all tab positions to match the index they are currently stored at + // in the group at `group_index`. Does not call observers. + void UpdateTabPositionsImpl(); + // Converts a `SavedTabGroupSpecifics` retrieved from sync into a // `SavedTabGroupTab`. static SavedTabGroup FromSpecifics( @@ -146,8 +165,8 @@ std::vector<SavedTabGroupTab> saved_tabs_; // The current position of the group in relation to all other saved groups. - // A value of -1 means that the group was not assigned a position and will be - // assigned one when it is added into the SavedTabGroupModel. + // A value of kUnsetPosition means that the group was not assigned a position + // and will be assigned one when it is added into the SavedTabGroupModel. int position_; // Timestamp for when the tab was created using windows epoch microseconds.
diff --git a/components/saved_tab_groups/saved_tab_group_model.cc b/components/saved_tab_groups/saved_tab_group_model.cc index eadf818..6694210 100644 --- a/components/saved_tab_groups/saved_tab_group_model.cc +++ b/components/saved_tab_groups/saved_tab_group_model.cc
@@ -88,8 +88,9 @@ InsertGroupImpl(std::move(saved_group)); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupAddedLocally(Get(group_guid)->saved_guid()); + } } void SavedTabGroupModel::Remove(const tab_groups::TabGroupId tab_group_id) { @@ -99,9 +100,10 @@ const int index = GetIndexOf(tab_group_id).value(); base::GUID removed_guid = Get(tab_group_id)->saved_guid(); std::unique_ptr<SavedTabGroup> removed_group = RemoveImpl(index); - UpdatePositionsImpl(); - for (auto& observer : observers_) + UpdateGroupPositionsImpl(); + for (auto& observer : observers_) { observer.SavedTabGroupRemovedLocally(removed_group.get()); + } } void SavedTabGroupModel::Remove(const base::GUID& id) { @@ -111,9 +113,10 @@ const int index = GetIndexOf(id).value(); base::GUID removed_guid = Get(id)->saved_guid(); std::unique_ptr<SavedTabGroup> removed_group = RemoveImpl(index); - UpdatePositionsImpl(); - for (auto& observer : observers_) + UpdateGroupPositionsImpl(); + for (auto& observer : observers_) { observer.SavedTabGroupRemovedLocally(removed_group.get()); + } } void SavedTabGroupModel::UpdateVisualData( @@ -125,8 +128,9 @@ const absl::optional<int> index = GetIndexOf(tab_group_id); UpdateVisualDataImpl(index.value(), visual_data); base::GUID updated_guid = Get(tab_group_id)->saved_guid(); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedLocally(updated_guid); + } } void SavedTabGroupModel::UpdateVisualData( @@ -137,8 +141,9 @@ const absl::optional<int> index = GetIndexOf(id); UpdateVisualDataImpl(index.value(), visual_data); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedLocally(id); + } } void SavedTabGroupModel::AddedFromSync(SavedTabGroup saved_group) { @@ -148,8 +153,9 @@ InsertGroupImpl(std::move(saved_group)); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupAddedFromSync(Get(group_guid)->saved_guid()); + } } void SavedTabGroupModel::RemovedFromSync( @@ -160,8 +166,9 @@ const absl::optional<int> index = GetIndexOf(tab_group_id); base::GUID removed_guid = Get(tab_group_id)->saved_guid(); std::unique_ptr<SavedTabGroup> removed_group = RemoveImpl(index.value()); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupRemovedFromSync(removed_group.get()); + } } void SavedTabGroupModel::RemovedFromSync(const base::GUID& id) { @@ -171,8 +178,9 @@ const absl::optional<int> index = GetIndexOf(id); base::GUID removed_guid = Get(id)->saved_guid(); std::unique_ptr<SavedTabGroup> removed_group = RemoveImpl(index.value()); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupRemovedFromSync(removed_group.get()); + } } void SavedTabGroupModel::UpdatedVisualDataFromSync( @@ -184,8 +192,9 @@ const absl::optional<int> index = GetIndexOf(tab_group_id); UpdateVisualDataImpl(index.value(), visual_data); base::GUID updated_guid = Get(tab_group_id)->saved_guid(); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedFromSync(updated_guid); + } } void SavedTabGroupModel::UpdatedVisualDataFromSync( @@ -196,8 +205,9 @@ const absl::optional<int> index = GetIndexOf(id); UpdateVisualDataImpl(index.value(), visual_data); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedFromSync(id); + } } SavedTabGroup* SavedTabGroupModel::GetGroupContainingTab( @@ -222,16 +232,23 @@ void SavedTabGroupModel::AddTabToGroup(const base::GUID& group_id, SavedTabGroupTab tab, - int index) { + bool update_tab_positions) { if (!Contains(group_id)) return; const base::GUID tab_id = tab.saved_tab_guid(); absl::optional<int> group_index = GetIndexOf(group_id); - saved_tab_groups_[group_index.value()].AddTab(index, tab); + saved_tab_groups_[group_index.value()].AddTab(tab, update_tab_positions); - for (auto& observer : observers_) - observer.SavedTabGroupUpdatedLocally(group_id, tab_id); + if (!update_tab_positions) { + for (auto& observer : observers_) { + observer.SavedTabGroupUpdatedFromSync(group_id); + } + } else { + for (auto& observer : observers_) { + observer.SavedTabGroupUpdatedLocally(group_id, tab_id); + } + } } void SavedTabGroupModel::UpdateTabInGroup(const base::GUID& group_id, @@ -246,7 +263,8 @@ } void SavedTabGroupModel::RemoveTabFromGroup(const base::GUID& group_id, - const base::GUID& tab_id) { + const base::GUID& tab_id, + bool update_tab_positions) { if (!Contains(group_id)) return; @@ -264,11 +282,20 @@ } // Copy `tab_id` to prevent uaf when ungrouping a saved tab: crbug/1401965. - base::GUID copy_tab_id = tab_id; - saved_tab_groups_[index.value()].RemoveTab(tab_id); + const base::GUID copy_tab_id = tab_id; + saved_tab_groups_[index.value()].RemoveTab(tab_id, update_tab_positions); - for (auto& observer : observers_) - observer.SavedTabGroupUpdatedLocally(group_id, copy_tab_id); + // TODO(dljames): Update to use SavedTabGroupRemoveLocally and update the API + // to pass a group_id and an optional tab_id. + if (!update_tab_positions) { + for (auto& observer : observers_) { + observer.SavedTabGroupUpdatedFromSync(group_id); + } + } else { + for (auto& observer : observers_) { + observer.SavedTabGroupUpdatedLocally(group_id, copy_tab_id); + } + } } void SavedTabGroupModel::ReplaceTabInGroupAt(const base::GUID& group_id, @@ -277,10 +304,10 @@ if (!Contains(group_id)) return; + // Copy `tab_id` to prevent uaf when ungrouping a saved tab: crbug/1401965. + const base::GUID copy_tab_id = tab_id; const base::GUID guid = new_tab.saved_tab_guid(); absl::optional<int> index = GetIndexOf(group_id); - // Copy `tab_id` to prevent uaf when ungrouping a saved tab: crbug/1401965. - base::GUID copy_tab_id = tab_id; saved_tab_groups_[index.value()].ReplaceTabAt(tab_id, new_tab); for (auto& observer : observers_) { @@ -295,13 +322,14 @@ if (!Contains(group_id)) return; - absl::optional<int> index = GetIndexOf(group_id); // Copy `tab_id` to prevent uaf when ungrouping a saved tab: crbug/1401965. - base::GUID copy_tab_id = tab_id; + const base::GUID copy_tab_id = tab_id; + absl::optional<int> index = GetIndexOf(group_id); saved_tab_groups_[index.value()].MoveTab(tab_id, new_index); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedLocally(group_id, copy_tab_id); + } } std::unique_ptr<sync_pb::SavedTabGroupSpecifics> SavedTabGroupModel::MergeGroup( @@ -318,8 +346,9 @@ Reorder(group_id, preferred_index); } - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedFromSync(group_id); + } return Get(group_id)->ToSpecifics(); } @@ -337,8 +366,9 @@ tab->MergeTab(std::move(sync_specific)); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedFromSync(group_id, tab->saved_group_guid()); + } return tab->ToSpecifics(); } @@ -357,13 +387,14 @@ saved_tab_groups_.emplace(saved_tab_groups_.begin() + new_index, std::move(group)); - UpdatePositionsImpl(); + UpdateGroupPositionsImpl(); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupReorderedLocally(); + } } -void SavedTabGroupModel::UpdatePositionsImpl() { +void SavedTabGroupModel::UpdateGroupPositionsImpl() { for (size_t i = 0; i < saved_tab_groups_.size(); ++i) saved_tab_groups_[i].SetPosition(i); } @@ -426,7 +457,7 @@ tabs.emplace_back(SavedTabGroupTab::FromSpecifics(proto)); } - UpdatePositionsImpl(); + UpdateGroupPositionsImpl(); for (const SavedTabGroupTab& tab : tabs) { absl::optional<int> index = GetIndexOf(tab.saved_group_guid()); @@ -434,7 +465,7 @@ tabs_missing_groups.emplace_back(std::move(*tab.ToSpecifics())); } else { base::GUID group_id = tab.saved_group_guid(); - AddTabToGroup(group_id, std::move(tab), 0); + AddTabToGroup(group_id, std::move(tab), /*update_tab_positions=*/false); } } @@ -450,8 +481,9 @@ SavedTabGroup& saved_group = saved_tab_groups_[index.value()]; saved_group.SetLocalGroupId(absl::nullopt); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedLocally(saved_group.saved_guid()); + } } void SavedTabGroupModel::OnGroupOpenedInTabStrip( @@ -464,8 +496,9 @@ SavedTabGroup& saved_group = saved_tab_groups_[index.value()]; saved_group.SetLocalGroupId(tab_group_id); - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.SavedTabGroupUpdatedLocally(saved_group.saved_guid()); + } } std::unique_ptr<SavedTabGroup> SavedTabGroupModel::RemoveImpl(int index) {
diff --git a/components/saved_tab_groups/saved_tab_group_model.h b/components/saved_tab_groups/saved_tab_group_model.h index 46936393..8191843 100644 --- a/components/saved_tab_groups/saved_tab_group_model.h +++ b/components/saved_tab_groups/saved_tab_group_model.h
@@ -90,18 +90,23 @@ SavedTabGroup* GetGroupContainingTab(const base::Token& local_tab_id); // Adds a saved tab to `index` in the specified group denoted by `group_id` if - // it exists. + // it exists. If `update_tab_positions` is true, update the positions of all + // tabs in the group. void AddTabToGroup(const base::GUID& group_id, SavedTabGroupTab tab, - int index); + bool update_tab_positions = false); // Calls the UpdateTab method on a group found by group id in the model. // Calls the observer function SavedTabGroupUpdatedLocally. void UpdateTabInGroup(const base::GUID& group_id, SavedTabGroupTab tab); - // Removes a saved tab from `index` in the specified group denoted by - // `group_id` if it exists. - void RemoveTabFromGroup(const base::GUID& group_id, const base::GUID& tab_id); + // Removes saved tab `tab_id` in the specified group denoted by + // `group_id` if it exists. We delete the group instead if the last tab is + // removed from it. If `update_tab_positions` is true, update the positions of + // all tabs in the group and notify sync of the changes. + void RemoveTabFromGroup(const base::GUID& group_id, + const base::GUID& tab_id, + bool update_tab_positions = false); // Replaces a saved tab `tab_id` in the specified group denoted by // `group_id` if it exists with `new_tab`. @@ -147,7 +152,7 @@ private: // Updates all group positions to match the index they are currently stored // at. - void UpdatePositionsImpl(); + void UpdateGroupPositionsImpl(); // Insert `group` into sorted order based on its position compared to already // stored groups in `saved_tab_groups_`. It should be noted that
diff --git a/components/saved_tab_groups/saved_tab_group_model_unittest.cc b/components/saved_tab_groups/saved_tab_group_model_unittest.cc index 8b28dc4..2ddc09b 100644 --- a/components/saved_tab_groups/saved_tab_group_model_unittest.cc +++ b/components/saved_tab_groups/saved_tab_group_model_unittest.cc
@@ -78,8 +78,10 @@ SavedTabGroupTab CreateSavedTabGroupTab(const std::string& url, const std::u16string& title, - const base::GUID& group_guid) { - SavedTabGroupTab tab(GURL(url), title, group_guid); + const base::GUID& group_guid, + absl::optional<int> position) { + SavedTabGroupTab tab(GURL(url), title, group_guid, nullptr, absl::nullopt, + absl::nullopt, position); tab.SetFavicon(gfx::Image()); return tab; } @@ -90,9 +92,9 @@ const tab_groups::TabGroupColorId& color = tab_groups::TabGroupColorId::kBlue; SavedTabGroupTab tab1 = - CreateSavedTabGroupTab("www.google.com", u"Google", id); + CreateSavedTabGroupTab("www.google.com", u"Google", id, absl::nullopt); SavedTabGroupTab tab2 = - CreateSavedTabGroupTab("chrome://newtab", u"new tab", id); + CreateSavedTabGroupTab("chrome://newtab", u"new tab", id, absl::nullopt); tab1.SetFavicon(gfx::Image()); tab2.SetFavicon(gfx::Image()); @@ -209,14 +211,14 @@ tab_groups::TabGroupColorId::kGreen; std::vector<SavedTabGroupTab> group_1_tabs = { - CreateSavedTabGroupTab("A_Link", u"Only Tab", id_1_)}; + CreateSavedTabGroupTab("A_Link", u"Only Tab", id_1_, 0)}; std::vector<SavedTabGroupTab> group_2_tabs = { - CreateSavedTabGroupTab("One_Link", u"One Of Two", id_2_), - CreateSavedTabGroupTab("Two_Link", u"Second", id_2_)}; + CreateSavedTabGroupTab("One_Link", u"One Of Two", id_2_, 0), + CreateSavedTabGroupTab("Two_Link", u"Second", id_2_, 1)}; std::vector<SavedTabGroupTab> group_3_tabs = { - CreateSavedTabGroupTab("Athos", u"All For One", id_3_), - CreateSavedTabGroupTab("Porthos", u"And", id_3_), - CreateSavedTabGroupTab("Aramis", u"One For All", id_3_)}; + CreateSavedTabGroupTab("Athos", u"All For One", id_3_, 0), + CreateSavedTabGroupTab("Porthos", u"And", id_3_, 1), + CreateSavedTabGroupTab("Aramis", u"One For All", id_3_, 2)}; saved_tab_group_model_->Add( CreateSavedTabGroup(title_1, color_1, group_1_tabs, id_1_)); @@ -304,9 +306,9 @@ tab_groups::TabGroupColorId::kBlue; SavedTabGroupTab tab1 = - CreateSavedTabGroupTab("4th group", u"First Tab 4th Group", id_4); + CreateSavedTabGroupTab("4th group", u"First Tab 4th Group", id_4, 0); SavedTabGroupTab tab2 = - CreateSavedTabGroupTab("2nd link", u"Second Tab 4th Group", id_4); + CreateSavedTabGroupTab("2nd link", u"Second Tab 4th Group", id_4, 1); std::vector<SavedTabGroupTab> group_4_tabs = {tab1, tab2}; SavedTabGroup group_4(title_4, color_4, group_4_tabs, id_4); @@ -378,21 +380,23 @@ // Tests that the correct tabs are added to the correct position in group 1. TEST_F(SavedTabGroupModelTest, AddTabToGroup) { SavedTabGroupTab tab1 = - CreateSavedTabGroupTab("4th group", u"First Tab 4th Group", id_1_); + CreateSavedTabGroupTab("4th group", u"First Tab 4th Group", id_1_, 0); SavedTabGroupTab tab2 = - CreateSavedTabGroupTab("2nd link", u"Second Tab 4th Group", id_1_); + CreateSavedTabGroupTab("2nd link", u"Second Tab 4th Group", id_1_, 2); SavedTabGroup* group = saved_tab_group_model_->Get(id_1_); ASSERT_EQ(group->saved_tabs().size(), size_t(1)); - saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab1, 0); + saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab1, + /*update_tab_positions=*/true); EXPECT_EQ(group->saved_tabs().size(), size_t(2)); EXPECT_EQ(0, group->GetIndexOfTab(tab1.saved_tab_guid())); EXPECT_TRUE(group->ContainsTab(tab1.saved_tab_guid())); ASSERT_TRUE(group->GetTab(tab1.saved_tab_guid())); CompareSavedTabGroupTabs({*group->GetTab(tab1.saved_tab_guid())}, {tab1}); - saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab2, 2); + saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab2, + /*update_tab_positions=*/true); EXPECT_EQ(group->saved_tabs().size(), size_t(3)); EXPECT_EQ(2, group->GetIndexOfTab(tab2.saved_tab_guid())); EXPECT_TRUE(group->ContainsTab(tab2.saved_tab_guid())); @@ -405,24 +409,28 @@ // Tests that the correct tabs are removed from the correct position in group 1. TEST_F(SavedTabGroupModelTest, RemoveTabFromGroup) { SavedTabGroupTab tab1 = - CreateSavedTabGroupTab("4th group", u"First Tab 4th Group", id_1_); + CreateSavedTabGroupTab("4th group", u"First Tab 4th Group", id_1_, 0); SavedTabGroupTab tab2 = - CreateSavedTabGroupTab("2nd link", u"Second Tab 4th Group", id_1_); + CreateSavedTabGroupTab("2nd link", u"Second Tab 4th Group", id_1_, 2); SavedTabGroup* group = saved_tab_group_model_->Get(id_1_); ASSERT_EQ(group->saved_tabs().size(), size_t(1)); - saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab1, 0); - saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab2, 2); + saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab1, + /*update_tab_positions=*/true); + saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab2, + /*update_tab_positions=*/true); EXPECT_EQ(group->saved_tabs().size(), size_t(3)); saved_tab_group_model_->RemoveTabFromGroup(group->saved_guid(), - tab1.saved_tab_guid()); + tab1.saved_tab_guid(), + /*update_tab_positions=*/true); EXPECT_EQ(group->saved_tabs().size(), size_t(2)); CompareSavedTabGroupTabs(group->saved_tabs(), {group->saved_tabs()[0], tab2}); saved_tab_group_model_->RemoveTabFromGroup(group->saved_guid(), - tab2.saved_tab_guid()); + tab2.saved_tab_guid(), + /*update_tab_positions=*/true); EXPECT_EQ(group->saved_tabs().size(), size_t(1)); CompareSavedTabGroupTabs(group->saved_tabs(), {group->saved_tabs()[0]}); } @@ -434,23 +442,28 @@ ASSERT_EQ(group->saved_tabs().size(), size_t(1)); saved_tab_group_model_->RemoveTabFromGroup( - group->saved_guid(), group->saved_tabs()[0].saved_tab_guid()); + group->saved_guid(), group->saved_tabs()[0].saved_tab_guid(), + /*update_tab_positions=*/true); EXPECT_FALSE(saved_tab_group_model_->Contains(id_1_)); } // Tests that the correct tabs are replaced in group 1. TEST_F(SavedTabGroupModelTest, ReplaceTabInGroup) { - SavedTabGroupTab tab1 = CreateSavedTabGroupTab("first", u"First Tab", id_1_); + SavedTabGroupTab tab1 = + CreateSavedTabGroupTab("first", u"First Tab", id_1_, 0); SavedTabGroupTab tab2 = - CreateSavedTabGroupTab("second", u"Second Tab", id_1_); - SavedTabGroupTab tab3 = CreateSavedTabGroupTab("third", u"Third Tab", id_1_); + CreateSavedTabGroupTab("second", u"Second Tab", id_1_, 2); + SavedTabGroupTab tab3 = + CreateSavedTabGroupTab("third", u"Third Tab", id_1_, absl::nullopt); SavedTabGroup* group = saved_tab_group_model_->Get(id_1_); ASSERT_EQ(group->saved_tabs().size(), size_t(1)); - saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab1, 0); - saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab2, 2); + saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab1, + /*update_tab_positions=*/true); + saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab2, + /*update_tab_positions=*/true); EXPECT_EQ(group->saved_tabs().size(), size_t(3)); saved_tab_group_model_->ReplaceTabInGroupAt(group->saved_guid(), @@ -471,15 +484,17 @@ // Tests that the correct tabs are moved in group 1. TEST_F(SavedTabGroupModelTest, MoveTabInGroup) { SavedTabGroupTab tab1 = - CreateSavedTabGroupTab("4th group", u"First Tab 4th Group", id_1_); + CreateSavedTabGroupTab("4th group", u"First Tab 4th Group", id_1_, 0); SavedTabGroupTab tab2 = - CreateSavedTabGroupTab("2nd link", u"Second Tab 4th Group", id_1_); + CreateSavedTabGroupTab("2nd link", u"Second Tab 4th Group", id_1_, 2); SavedTabGroup* group = saved_tab_group_model_->Get(id_1_); ASSERT_EQ(group->saved_tabs().size(), size_t(1)); - saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab1, 0); - saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab2, 2); + saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab1, + /*update_tab_positions=*/true); + saved_tab_group_model_->AddTabToGroup(group->saved_guid(), tab2, + /*update_tab_positions=*/true); EXPECT_EQ(group->saved_tabs().size(), size_t(3)); saved_tab_group_model_->MoveTabInGroupTo(group->saved_guid(), @@ -524,8 +539,9 @@ EXPECT_EQ(saved_group->saved_guid(), id_3_); EXPECT_EQ(saved_group->title(), group->title()); EXPECT_EQ(saved_group->color(), group->color()); - // TODO(dljames): Use CompareSavedTabGroupTabs when we can ensure the order of - // tabs and groups are maintained. + + // We can not use CompareSavedTabGroupTabs because the favicons are not loaded + // until the tab is opened through the saved group button. EXPECT_EQ(saved_group->saved_tabs().size(), group->saved_tabs().size()); } @@ -989,7 +1005,7 @@ SavedTabGroupTab tab(GURL(url::kAboutBlankURL), std::u16string(u"title"), matching_group.saved_guid(), &matching_group, matching_tab_guid, matching_local_tab_id); - matching_group.AddTab(0, std::move(tab)); + matching_group.AddTab(std::move(tab)); saved_tab_group_model_->Add(std::move(matching_group)); // Add another non matching SavedTabGroup.
diff --git a/components/saved_tab_groups/saved_tab_group_proto_conversion_unittest.cc b/components/saved_tab_groups/saved_tab_group_proto_conversion_unittest.cc index 25411b2..55306fc 100644 --- a/components/saved_tab_groups/saved_tab_group_proto_conversion_unittest.cc +++ b/components/saved_tab_groups/saved_tab_group_proto_conversion_unittest.cc
@@ -95,8 +95,8 @@ // Create a tab. SavedTabGroupTab tab(GURL("chrome://hidden_link"), u"Hidden Title", base::GUID::GenerateRandomV4(), nullptr, - base::GUID::GenerateRandomV4(), absl::nullopt, time_, - time_); + base::GUID::GenerateRandomV4(), absl::nullopt, + absl::nullopt, time_, time_); // Create a STGSpecific using `tab`. std::unique_ptr<sync_pb::SavedTabGroupSpecifics> specific = tab.ToSpecifics();
diff --git a/components/saved_tab_groups/saved_tab_group_sync_bridge.cc b/components/saved_tab_groups/saved_tab_group_sync_bridge.cc index 6632945..703728a9 100644 --- a/components/saved_tab_groups/saved_tab_group_sync_bridge.cc +++ b/components/saved_tab_groups/saved_tab_group_sync_bridge.cc
@@ -31,8 +31,6 @@ #include "components/sync/protocol/entity_data.h" #include "components/sync/protocol/saved_tab_group_specifics.pb.h" -#include "base/logging.h" - namespace { constexpr base::TimeDelta discard_orphaned_tabs_threshold = base::Microseconds(base::Time::kMicrosecondsPerDay * 90); @@ -355,7 +353,8 @@ if (existing_group) { // We do not have this tab. Add the tab from sync into local storage. model_->AddTabToGroup(existing_group->saved_guid(), - SavedTabGroupTab::FromSpecifics(specifics), 0); + SavedTabGroupTab::FromSpecifics(specifics), + /*update_tab_positions=*/false); } else { // We reach this case if we were unable to find a group for this tab. This // can happen when sync sends the tab data before the group data. In this @@ -382,7 +381,8 @@ if (!group.ContainsTab(guid)) continue; - model_->RemoveTabFromGroup(group.saved_guid(), guid); + model_->RemoveTabFromGroup(group.saved_guid(), guid, + /*update_tab_positions=*/false); return; } } @@ -410,7 +410,8 @@ write_batch->WriteData(tab_iterator->guid(), tab_iterator->SerializeAsString()); model_->AddTabToGroup(group->saved_guid(), - SavedTabGroupTab::FromSpecifics(*tab_iterator), 0); + SavedTabGroupTab::FromSpecifics(*tab_iterator), + /*update_tab_positions=*/false); tab_iterator = tabs_missing_groups_.erase(tab_iterator); } }
diff --git a/components/saved_tab_groups/saved_tab_group_sync_bridge_unittest.cc b/components/saved_tab_groups/saved_tab_group_sync_bridge_unittest.cc index fe37bfc..4e10eea 100644 --- a/components/saved_tab_groups/saved_tab_group_sync_bridge_unittest.cc +++ b/components/saved_tab_groups/saved_tab_group_sync_bridge_unittest.cc
@@ -158,7 +158,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Google", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); group.SetPosition(0); // Note: Here the change type does not matter. The initial merge will add @@ -196,7 +196,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Google", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); base::GUID group_guid = group.saved_guid(); base::GUID tab_1_guid = tab_1.saved_tab_guid(); @@ -216,8 +216,8 @@ group_creation_time); SavedTabGroupTab updated_tab_1(GURL("https://support.google.com"), u"Support", group_guid, nullptr, tab_1_guid, absl::nullopt, - tab_1_creation_time); - updated_group.AddTab(0, updated_tab_1); + absl::nullopt, tab_1_creation_time); + updated_group.AddTab(updated_tab_1); updated_group.SetPosition(0); syncer::EntityChangeList entity_change_list = CreateEntityChangeListFromGroup( @@ -240,7 +240,7 @@ // Ensure tab_2 was left untouched. SavedTabGroupTab tab_2_replica(GURL("https://google.com"), u"Google", group_guid, nullptr, tab_2_guid, absl::nullopt, - tab_2_creation_time); + absl::nullopt, tab_2_creation_time); EXPECT_TRUE(AreTabSpecificsEqual( *tab_2_replica.ToSpecifics(), *group_from_model->GetTab(tab_2_guid)->ToSpecifics())); @@ -404,7 +404,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Google", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); group.SetPosition(0); bridge_->ApplySyncChanges( @@ -470,7 +470,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Google", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); group.SetPosition(0); bridge_->ApplySyncChanges( @@ -512,7 +512,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Google", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); EXPECT_EQ(group.saved_tabs().size(), 2u); @@ -562,7 +562,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Google", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); base::GUID group_guid = group.saved_guid(); base::GUID tab_1_guid = tab_1.saved_tab_guid(); @@ -584,7 +584,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Google", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); base::GUID group_guid = group.saved_guid(); base::GUID tab_1_guid = tab_1.saved_tab_guid(); @@ -607,7 +607,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Google", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); base::GUID group_guid = group.saved_guid(); base::GUID tab_1_guid = tab_1.saved_tab_guid(); @@ -634,7 +634,7 @@ group.saved_guid()); SavedTabGroupTab tab_3(GURL("https://youtube.com"), u"Youtube", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); base::GUID group_guid = group.saved_guid(); base::GUID tab_1_guid = tab_1.saved_tab_guid(); @@ -651,7 +651,8 @@ // `tab_2` will have its position updated. Once tab ordering is implemented, // only the affected tabs will need to be updated. In that case, the Put() // call for tab_1 can be removed. - saved_tab_group_model_.AddTabToGroup(group_guid, tab_3, 1); + saved_tab_group_model_.AddTabToGroup(group_guid, tab_3, + /*update_tab_positions=*/true); } // Verify that locally removed tabs remove the correct tabs from the processor. @@ -663,7 +664,7 @@ group.saved_guid()); SavedTabGroupTab tab_2(GURL("https://google.com"), u"Goole", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); base::GUID group_guid = group.saved_guid(); base::GUID tab_1_guid = tab_1.saved_tab_guid(); @@ -674,7 +675,8 @@ EXPECT_CALL(processor_, Put(tab_2_guid.AsLowercaseString(), _, _)).Times(0); EXPECT_CALL(processor_, Put(group_guid.AsLowercaseString(), _, _)).Times(0); - saved_tab_group_model_.RemoveTabFromGroup(group_guid, tab_1_guid); + saved_tab_group_model_.RemoveTabFromGroup(group_guid, tab_1_guid, + /*update_tab_positions=*/true); } // Verify that locally updated tabs update the correct tabs in the processor. @@ -688,7 +690,7 @@ group.saved_guid()); SavedTabGroupTab tab_3(GURL("https://youtube.com"), u"Youtube", group.saved_guid()); - group.AddTab(0, tab_1).AddTab(1, tab_2); + group.AddTab(tab_1).AddTab(tab_2); base::GUID group_guid = group.saved_guid(); base::GUID tab_1_guid = tab_1.saved_tab_guid();
diff --git a/components/saved_tab_groups/saved_tab_group_tab.cc b/components/saved_tab_groups/saved_tab_group_tab.cc index f48d5bc..94b0e0f5 100644 --- a/components/saved_tab_groups/saved_tab_group_tab.cc +++ b/components/saved_tab_groups/saved_tab_group_tab.cc
@@ -14,6 +14,7 @@ SavedTabGroup* group, absl::optional<base::GUID> saved_tab_guid, absl::optional<base::Token> local_tab_id, + absl::optional<int> position, absl::optional<base::Time> creation_time_windows_epoch_micros, absl::optional<base::Time> update_time_windows_epoch_micros, absl::optional<gfx::Image> favicon) @@ -22,6 +23,7 @@ : base::GUID::GenerateRandomV4()), saved_group_guid_(group_guid), local_tab_id_(local_tab_id), + position_(position.value_or(kUnsetPosition)), saved_tab_group_(group), url_(url), title_(title), @@ -66,6 +68,7 @@ base::GUID::ParseLowercase(specific.tab().group_guid()); const GURL& url = GURL(specific.tab().url()); const std::u16string title = base::UTF8ToUTF16(specific.tab().title()); + int position = specific.tab().position(); base::GUID guid = base::GUID::ParseLowercase(specific.guid()); base::Time creation_time = base::Time::FromDeltaSinceWindowsEpoch( @@ -74,7 +77,7 @@ base::Microseconds(specific.update_time_windows_epoch_micros())); return SavedTabGroupTab(url, title, group_guid, nullptr, guid, absl::nullopt, - creation_time, update_time); + position, creation_time, update_time); } std::unique_ptr<sync_pb::SavedTabGroupSpecifics> SavedTabGroupTab::ToSpecifics() @@ -95,6 +98,7 @@ pb_tab->set_url(url().spec()); pb_tab->set_group_guid(saved_group_guid().AsLowercaseString()); pb_tab->set_title(base::UTF16ToUTF8(title())); + pb_tab->set_position(position()); return pb_specific; }
diff --git a/components/saved_tab_groups/saved_tab_group_tab.h b/components/saved_tab_groups/saved_tab_group_tab.h index 2ec9c53b..4b8461a 100644 --- a/components/saved_tab_groups/saved_tab_group_tab.h +++ b/components/saved_tab_groups/saved_tab_group_tab.h
@@ -23,12 +23,16 @@ // A SavedTabGroupTab stores the url, title, and favicon of a tab. class SavedTabGroupTab { public: + // Used to denote groups that have not been given a position. + static constexpr int kUnsetPosition = -1; + SavedTabGroupTab(const GURL& url, const std::u16string& title, const base::GUID& group_guid, SavedTabGroup* group = nullptr, absl::optional<base::GUID> saved_tab_guid = absl::nullopt, absl::optional<base::Token> local_tab_id = absl::nullopt, + absl::optional<int> position = absl::nullopt, absl::optional<base::Time> creation_time_windows_epoch_micros = absl::nullopt, absl::optional<base::Time> update_time_windows_epoch_micros = @@ -43,6 +47,7 @@ const absl::optional<base::Token> local_tab_id() const { return local_tab_id_; } + int position() const { return position_; } SavedTabGroup* saved_tab_group() const { return saved_tab_group_; } const GURL& url() const { return url_; } const std::u16string& title() const { return title_; } @@ -80,6 +85,11 @@ SetUpdateTimeWindowsEpochMicros(base::Time::Now()); return *this; } + SavedTabGroupTab& SetPosition(int position) { + position_ = position; + SetUpdateTimeWindowsEpochMicros(base::Time::Now()); + return *this; + } SavedTabGroupTab& SetUpdateTimeWindowsEpochMicros( base::Time update_time_windows_epoch_micros) { update_time_windows_epoch_micros_ = update_time_windows_epoch_micros; @@ -114,6 +124,11 @@ // The ID used to represent the tab in reference to the web_contents locally. absl::optional<base::Token> local_tab_id_; + // The current position of the tab in relation to all other tabs in the group. + // A value of kUnsetPosition means that the group was not assigned a position + // and will be assigned one when it is added into its saved group. + int position_; + // The Group which owns this tab, this can be null if sync hasn't sent the // group over yet. raw_ptr<SavedTabGroup> saved_tab_group_;
diff --git a/components/saved_tab_groups/saved_tab_group_unittest.cc b/components/saved_tab_groups/saved_tab_group_unittest.cc index 29d6d77..ce7d024 100644 --- a/components/saved_tab_groups/saved_tab_group_unittest.cc +++ b/components/saved_tab_groups/saved_tab_group_unittest.cc
@@ -29,18 +29,21 @@ tab_groups::TabGroupColorId::kGrey, {}); } +SavedTabGroupTab CreateDefaultSavedTabGroupTab(const base::GUID& group_guid) { + return SavedTabGroupTab(GURL("www.google.com"), u"Default Title", group_guid); +} + void AddTabToEndOfGroup( SavedTabGroup& group, absl::optional<base::GUID> saved_guid = absl::nullopt, absl::optional<base::Token> local_tab_id = absl::nullopt) { - group.AddTab(group.saved_tabs().size(), - SavedTabGroupTab( - GURL(url::kAboutBlankURL), std::u16string(u"default_title"), - group.saved_guid(), &group, saved_guid, local_tab_id)); + group.AddTab(SavedTabGroupTab( + GURL(url::kAboutBlankURL), std::u16string(u"default_title"), + group.saved_guid(), &group, saved_guid, local_tab_id)); } } // namespace -TEST(SavedTabGroup, GetTabByGUID) { +TEST(SavedTabGroupTest, GetTabByGUID) { base::GUID tab_1_saved_guid = MakeUniqueGUID(); base::GUID tab_2_saved_guid = MakeUniqueGUID(); @@ -57,7 +60,7 @@ EXPECT_EQ(&group.saved_tabs()[1], tab_2); } -TEST(SavedTabGroup, GetTabByToken) { +TEST(SavedTabGroupTest, GetTabByToken) { base::Token tab_1_local_id = MakeUniqueToken(); base::Token tab_2_local_id = MakeUniqueToken(); @@ -73,3 +76,138 @@ SavedTabGroupTab* tab_2 = group.GetTab(tab_2_local_id); EXPECT_EQ(&group.saved_tabs()[1], tab_2); } + +TEST(SavedTabGroupTest, AddTabLocallyDisrespectsPositions) { + // Create a group and 2 tabs + SavedTabGroup group = CreateDefaultEmptySavedTabGroup(); + SavedTabGroupTab tab_1 = CreateDefaultSavedTabGroupTab(group.saved_guid()); + SavedTabGroupTab tab_2 = CreateDefaultSavedTabGroupTab(group.saved_guid()); + + base::GUID tab_1_saved_guid = tab_1.saved_tab_guid(); + base::GUID tab_2_saved_guid = tab_2.saved_tab_guid(); + + // Set the positions on the tabs and expect the group to ignore them. + tab_1.SetPosition(1); + tab_2.SetPosition(0); + + // Add both tabs to the group. + group.AddTab(std::move(tab_1), /*update_tab_positions=*/true); + group.AddTab(std::move(tab_2), /*update_tab_positions=*/true); + ASSERT_EQ(2u, group.saved_tabs().size()); + + // Locally added groups will be added into their preferred positions if + // possible. If not, they will be added as close to the preferred position as + // possible, and have their position updated to reflect this. + SavedTabGroupTab* first_tab = group.GetTab(tab_1_saved_guid); + EXPECT_EQ(&group.saved_tabs()[0], first_tab); + EXPECT_EQ(first_tab->position(), 0); + + // Expect tab_2 to be at the front of the group. + SavedTabGroupTab* second_tab = group.GetTab(tab_2_saved_guid); + EXPECT_EQ(&group.saved_tabs()[1], second_tab); + EXPECT_EQ(second_tab->position(), 1); +} + +TEST(SavedTabGroupTest, RemoveTabLocallyReordersPositions) { + // Create a group and 2 tabs + SavedTabGroup group = CreateDefaultEmptySavedTabGroup(); + SavedTabGroupTab tab_1 = CreateDefaultSavedTabGroupTab(group.saved_guid()); + SavedTabGroupTab tab_2 = CreateDefaultSavedTabGroupTab(group.saved_guid()); + + base::GUID tab_1_saved_guid = tab_1.saved_tab_guid(); + base::GUID tab_2_saved_guid = tab_2.saved_tab_guid(); + + // Add both tabs to the group. + group.AddTab(std::move(tab_1)); + group.AddTab(std::move(tab_2)); + ASSERT_EQ(2u, group.saved_tabs().size()); + + // Verify tab_2 has a position of 1. + { + SavedTabGroupTab* second_tab = group.GetTab(tab_2_saved_guid); + EXPECT_EQ(&group.saved_tabs()[1], second_tab); + EXPECT_EQ(second_tab->position(), 1); + } + + // Remove tab_1 from the group. + group.RemoveTab(tab_1_saved_guid, /*update_tab_positions=*/true); + + // Verify only tab_2 is in the group. + EXPECT_EQ(group.saved_tabs().size(), 1u); + EXPECT_FALSE(group.ContainsTab(tab_1_saved_guid)); + EXPECT_TRUE(group.ContainsTab(tab_2_saved_guid)); + + // Verify tab_2 has a position of 0 now. + { + // Expect tab two to be at the front of the group. + SavedTabGroupTab* second_tab = group.GetTab(tab_2_saved_guid); + EXPECT_EQ(&group.saved_tabs()[0], second_tab); + EXPECT_EQ(second_tab->position(), 0); + } +} + +TEST(SavedTabGroupTest, AddTabFromSyncRespectsPositions) { + // Create a group and 2 tabs + SavedTabGroup group = CreateDefaultEmptySavedTabGroup(); + SavedTabGroupTab tab_1 = CreateDefaultSavedTabGroupTab(group.saved_guid()); + SavedTabGroupTab tab_2 = CreateDefaultSavedTabGroupTab(group.saved_guid()); + + base::GUID tab_1_saved_guid = tab_1.saved_tab_guid(); + base::GUID tab_2_saved_guid = tab_2.saved_tab_guid(); + + // Set the positions on the tabs and expect the group to respect them. + tab_1.SetPosition(1); + tab_2.SetPosition(0); + + group.AddTab(std::move(tab_1), /*update_tab_positions=*/false); + group.AddTab(std::move(tab_2), /*update_tab_positions=*/false); + ASSERT_EQ(2u, group.saved_tabs().size()); + + // Expect tab one to be at the end of the group. + SavedTabGroupTab* first_tab = group.GetTab(tab_1_saved_guid); + EXPECT_EQ(&group.saved_tabs()[1], first_tab); + EXPECT_EQ(first_tab->position(), 1); + + // Expect tab two to be at the front of the group. + SavedTabGroupTab* second_tab = group.GetTab(tab_2_saved_guid); + EXPECT_EQ(&group.saved_tabs()[0], second_tab); + EXPECT_EQ(second_tab->position(), 0); +} + +TEST(SavedTabGroupTest, RemoveTabFromSyncMaintainsPositions) { + // Create a group and 2 tabs + SavedTabGroup group = CreateDefaultEmptySavedTabGroup(); + SavedTabGroupTab tab_1 = CreateDefaultSavedTabGroupTab(group.saved_guid()); + SavedTabGroupTab tab_2 = CreateDefaultSavedTabGroupTab(group.saved_guid()); + + base::GUID tab_1_saved_guid = tab_1.saved_tab_guid(); + base::GUID tab_2_saved_guid = tab_2.saved_tab_guid(); + + // Add both tabs to the group. + group.AddTab(std::move(tab_1)); + group.AddTab(std::move(tab_2)); + ASSERT_EQ(2u, group.saved_tabs().size()); + + // Verify tab_2 has a position of 1. + { + SavedTabGroupTab* second_tab = group.GetTab(tab_2_saved_guid); + EXPECT_EQ(&group.saved_tabs()[1], second_tab); + EXPECT_EQ(second_tab->position(), 1); + } + + // Remove tab_1 from the group. + group.RemoveTab(tab_1_saved_guid, /*update_tab_positions=*/false); + + // Verify only tab_2 is in the group. + EXPECT_EQ(group.saved_tabs().size(), 1u); + EXPECT_FALSE(group.ContainsTab(tab_1_saved_guid)); + EXPECT_TRUE(group.ContainsTab(tab_2_saved_guid)); + + // Verify tab_2 keeps its position of 1. + { + // Expect tab two to be at the front of the group. + SavedTabGroupTab* second_tab = group.GetTab(tab_2_saved_guid); + EXPECT_EQ(&group.saved_tabs()[0], second_tab); + EXPECT_EQ(second_tab->position(), 1); + } +}
diff --git a/components/services/storage/dom_storage/session_storage_metadata.cc b/components/services/storage/dom_storage/session_storage_metadata.cc index ef4939a..fdedcc8f 100644 --- a/components/services/storage/dom_storage/session_storage_metadata.cc +++ b/components/services/storage/dom_storage/session_storage_metadata.cc
@@ -112,9 +112,14 @@ initial_database_version_from_disk_ = kInvalidDatabaseVersion; return false; } + if (initial_database_version_from_disk_ > + kLatestSessionStorageSchemaVersion) { + return false; + } if (initial_database_version_from_disk_ == - kLatestSessionStorageSchemaVersion) + kLatestSessionStorageSchemaVersion) { return true; + } } if (initial_database_version_from_disk_ < kMinSessionStorageSchemaVersion) return false;
diff --git a/components/services/storage/dom_storage/session_storage_metadata_unittest.cc b/components/services/storage/dom_storage/session_storage_metadata_unittest.cc index 5cc653c1..e7c181f 100644 --- a/components/services/storage/dom_storage/session_storage_metadata_unittest.cc +++ b/components/services/storage/dom_storage/session_storage_metadata_unittest.cc
@@ -12,6 +12,7 @@ #include "base/guid.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/task/thread_pool.h" @@ -405,6 +406,16 @@ EXPECT_FALSE(base::Contains(contents, StdStringToUint8Vector("map-4-key1"))); } +TEST_F(SessionStorageMetadataTest, DatabaseVersionTooNew) { + SessionStorageMetadata metadata; + std::vector<AsyncDomStorageDatabase::BatchDatabaseTask> migration_tasks; + auto version_str = base::NumberToString( + SessionStorageMetadata::kLatestSessionStorageSchemaVersion + 1); + EXPECT_FALSE(metadata.ParseDatabaseVersion( + std::vector<uint8_t>(version_str.begin(), version_str.end()), + &migration_tasks)); +} + class SessionStorageMetadataMigrationTest : public testing::Test { public: SessionStorageMetadataMigrationTest()
diff --git a/components/subresource_filter/tools/filter_tool.cc b/components/subresource_filter/tools/filter_tool.cc index e91b605..09f89ad 100644 --- a/components/subresource_filter/tools/filter_tool.cc +++ b/components/subresource_filter/tools/filter_tool.cc
@@ -86,13 +86,12 @@ return filter.FindMatchingUrlRule(request_url, type); } -const std::string& ExtractStringFromDictionary(base::Value* dictionary, - const std::string& key) { - DCHECK(dictionary->is_dict()); - - const base::Value* found = dictionary->FindKey(key); +const std::string& ExtractStringFromDictionary( + const base::Value::Dict& dictionary, + const std::string& key) { + const std::string* found = dictionary.FindString(key); CHECK(found); - return found->GetString(); + return *found; } } // namespace @@ -166,12 +165,13 @@ base::JSONReader::ReadDeprecated(line); CHECK(dictionary); + DCHECK(dictionary->is_dict()); const std::string& origin = - ExtractStringFromDictionary(dictionary.get(), "origin"); + ExtractStringFromDictionary(dictionary->GetDict(), "origin"); const std::string& request_url = - ExtractStringFromDictionary(dictionary.get(), "request_url"); + ExtractStringFromDictionary(dictionary->GetDict(), "request_url"); const std::string& request_type = - ExtractStringFromDictionary(dictionary.get(), "request_type"); + ExtractStringFromDictionary(dictionary->GetDict(), "request_type"); bool blocked; const url_pattern_index::flat::UrlRule* rule =
diff --git a/components/sync/protocol/contact_info_specifics.proto b/components/sync/protocol/contact_info_specifics.proto index c6275ae..50840366 100644 --- a/components/sync/protocol/contact_info_specifics.proto +++ b/components/sync/protocol/contact_info_specifics.proto
@@ -76,17 +76,6 @@ // The value of the label can be freely chosen by the user. optional string profile_label = 5; - // Tracks the application that initially created the profile. The integer - // represents a value in the server-side enum `BillableService`. A value of - // 70073 represents Chrome (enum value BILLABLE_SERVICE_CHROME_PAYMENTS). - optional int32 initial_creator_id = 39; - // Tracks the application that applied the last modification to the - // non-metadata content of the profile. It represents a value in the same - // `BillableService` enum. - // All String- and IntegerToken, and the `profile_label` are considered - // non-metadata. - optional int32 last_modifier_id = 40; - // Contact info name fields. optional StringToken name_honorific = 6; optional StringToken name_first = 7;
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h index 88f024a..e63b4bb 100644 --- a/components/sync/protocol/proto_visitors.h +++ b/components/sync/protocol/proto_visitors.h
@@ -306,8 +306,6 @@ VISIT(date_modified_windows_epoch_micros); VISIT(language_code); VISIT(profile_label); - VISIT(initial_creator_id); - VISIT(last_modifier_id); VISIT(name_honorific); VISIT(name_first); VISIT(name_middle);
diff --git a/components/test/data/web_database/version_109.sql b/components/test/data/web_database/version_109.sql deleted file mode 100644 index e10183a1..0000000 --- a/components/test/data/web_database/version_109.sql +++ /dev/null
@@ -1,36 +0,0 @@ -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; -CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); -INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','109'); -INSERT INTO meta VALUES('last_compatible_version','106'); -INSERT INTO meta VALUES('Builtin Keyword Version','127'); -CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); -CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR,last_visited INTEGER DEFAULT 0, created_from_play_api INTEGER DEFAULT 0, is_active INTEGER DEFAULT 0, starter_pack_id INTEGER DEFAULT 0); -CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value)); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); -CREATE TABLE ibans ( guid VARCHAR PRIMARY KEY, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, value VARCHAR, nickname VARCHAR); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, label VARCHAR, disallow_settings_visible_updates INTEGER NOT NULL DEFAULT 0); -CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0, apartment_number VARCHAR, floor VARCHAR, apartment_number_status INTEGER DEFAULT 0, floor_status INTEGER DEFAULT 0); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); -CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); -CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); -CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR, card_issuer_id VARCHAR); -CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); -CREATE TABLE virtual_card_usage_data (id VARCHAR PRIMARY KEY, instrument_id INTEGER DEFAULT 0, merchant_domain VARCHAR, last_four VARCHAR); -CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); -CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR); -CREATE TABLE server_address_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, has_converted BOOL NOT NULL DEFAULT FALSE); -CREATE TABLE autofill_sync_metadata (model_type INTEGER NOT NULL, storage_key VARCHAR NOT NULL, value BLOB, PRIMARY KEY (model_type, storage_key)); -CREATE TABLE autofill_model_type_state (model_type INTEGER NOT NULL PRIMARY KEY, value BLOB); -CREATE TABLE payments_customer_data (customer_id VARCHAR); -CREATE TABLE payments_upi_vpa (vpa VARCHAR); -CREATE TABLE server_card_cloud_token_data ( id VARCHAR, suffix VARCHAR, exp_month INTEGER DEFAULT 0, exp_year INTEGER DEFAULT 0, card_art_url VARCHAR, instrument_token VARCHAR); -CREATE TABLE offer_data ( offer_id UNSIGNED LONG, offer_reward_amount VARCHAR, expiry UNSIGNED LONG, offer_details_url VARCHAR, merchant_domain VARCHAR, promo_code VARCHAR, value_prop_text VARCHAR, see_details_text VARCHAR, usage_instructions_text VARCHAR); -CREATE TABLE offer_eligible_instrument ( offer_id UNSIGNED LONG,instrument_id UNSIGNED LONG); -CREATE TABLE offer_merchant_domain ( offer_id UNSIGNED LONG,merchant_domain VARCHAR); -CREATE TABLE contact_info( guid VARCHAR PRIMARY KEY, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, date_modified INTEGER NOT NULL DEFAULT 0, language_code VARCHAR, label VARCHAR); -CREATE TABLE contact_info_type_tokens( guid VARCHAR, type INTEGER, value VARCHAR, verification_status INTEGER DEFAULT 0, PRIMARY KEY (guid, type)); -CREATE INDEX autofill_name ON autofill (name); -CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -COMMIT;
diff --git a/components/user_education/common/help_bubble.cc b/components/user_education/common/help_bubble.cc index eacd33c..c5b54b2 100644 --- a/components/user_education/common/help_bubble.cc +++ b/components/user_education/common/help_bubble.cc
@@ -6,9 +6,12 @@ #include "base/auto_reset.h" #include "base/notreached.h" +#include "ui/base/interaction/element_tracker.h" namespace user_education { +DEFINE_CUSTOM_ELEMENT_EVENT_TYPE(kHelpBubbleAnchorBoundsChangedEvent); + HelpBubble::HelpBubble() : on_close_callbacks_(std::make_unique<CallbackList>()) {}
diff --git a/components/user_education/common/help_bubble.h b/components/user_education/common/help_bubble.h index b3b367a..127732a 100644 --- a/components/user_education/common/help_bubble.h +++ b/components/user_education/common/help_bubble.h
@@ -9,11 +9,14 @@ #include "base/compiler_specific.h" #include "base/functional/callback.h" #include "ui/base/interaction/element_identifier.h" +#include "ui/base/interaction/element_tracker.h" #include "ui/base/interaction/framework_specific_implementation.h" #include "ui/gfx/geometry/rect.h" namespace user_education { +DECLARE_CUSTOM_ELEMENT_EVENT_TYPE(kHelpBubbleAnchorBoundsChangedEvent); + // HelpBubble is an interface for the lifecycle of an IPH or tutorial bubble. // it is implemented by a framework's bubble. It is returned as the result of // HelpBubbleFactory's CreateBubble...() method.
diff --git a/components/user_education/views/help_bubble_factory_views.cc b/components/user_education/views/help_bubble_factory_views.cc index 6242b217..de44714 100644 --- a/components/user_education/views/help_bubble_factory_views.cc +++ b/components/user_education/views/help_bubble_factory_views.cc
@@ -10,6 +10,7 @@ #include "base/functional/bind.h" #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "components/user_education/common/help_bubble.h" #include "components/user_education/common/help_bubble_params.h" #include "components/user_education/common/user_education_class_properties.h" #include "components/user_education/views/help_bubble_delegate.h" @@ -34,15 +35,16 @@ DCHECK(help_bubble_view->GetWidget()); scoped_observation_.Observe(help_bubble_view->GetWidget()); - // Set up an event listener so that the bubble can be closed if the anchor - // element disappears. The specific anchor view is not tracked because in a - // few cases (e.g. Mac native menus) the anchor view is not the anchor - // element itself but a placeholder. - anchor_subscription_ = + anchor_hidden_subscription_ = ui::ElementTracker::GetElementTracker()->AddElementHiddenCallback( anchor_element->identifier(), anchor_element->context(), base::BindRepeating(&HelpBubbleViews::OnElementHidden, base::Unretained(this))); + anchor_bounds_changed_subscription_ = + ui::ElementTracker::GetElementTracker()->AddCustomEventCallback( + kHelpBubbleAnchorBoundsChangedEvent, anchor_element->context(), + base::BindRepeating(&HelpBubbleViews::OnElementBoundsChanged, + base::Unretained(this))); } HelpBubbleViews::~HelpBubbleViews() { @@ -147,7 +149,8 @@ if (!help_bubble_view_) return; - anchor_subscription_ = base::CallbackListSubscription(); + anchor_hidden_subscription_ = base::CallbackListSubscription(); + anchor_bounds_changed_subscription_ = base::CallbackListSubscription(); scoped_observation_.Reset(); MaybeResetAnchorView(); help_bubble_view_->GetWidget()->Close(); @@ -155,7 +158,8 @@ } void HelpBubbleViews::OnWidgetDestroying(views::Widget* widget) { - anchor_subscription_ = base::CallbackListSubscription(); + anchor_hidden_subscription_ = base::CallbackListSubscription(); + anchor_bounds_changed_subscription_ = base::CallbackListSubscription(); scoped_observation_.Reset(); MaybeResetAnchorView(); help_bubble_view_ = nullptr; @@ -168,11 +172,19 @@ if (element != anchor_element_) return; - anchor_subscription_ = base::CallbackListSubscription(); + anchor_hidden_subscription_ = base::CallbackListSubscription(); + anchor_bounds_changed_subscription_ = base::CallbackListSubscription(); anchor_element_ = nullptr; Close(); } +void HelpBubbleViews::OnElementBoundsChanged(ui::TrackedElement* element) { + if (help_bubble_view_ && element == anchor_element_) { + help_bubble_view_->set_force_anchor_rect(element->GetScreenBounds()); + OnAnchorBoundsChanged(); + } +} + HelpBubbleFactoryViews::HelpBubbleFactoryViews( const HelpBubbleDelegate* delegate) : delegate_(delegate) { @@ -197,8 +209,7 @@ std::unique_ptr<HelpBubble> HelpBubbleFactoryViews::CreateBubbleImpl( ui::TrackedElement* element, const internal::HelpBubbleAnchorParams& anchor, - HelpBubbleParams params, - absl::optional<gfx::Rect> anchor_rect) { + HelpBubbleParams params) { anchor.view->SetProperty(kHasInProductHelpPromoKey, true); auto result = base::WrapUnique(new HelpBubbleViews( new HelpBubbleView(delegate_, anchor, std::move(params)), element));
diff --git a/components/user_education/views/help_bubble_factory_views.h b/components/user_education/views/help_bubble_factory_views.h index 55f0f7c..c77bfd2 100644 --- a/components/user_education/views/help_bubble_factory_views.h +++ b/components/user_education/views/help_bubble_factory_views.h
@@ -62,6 +62,7 @@ private: friend class HelpBubbleFactoryViews; friend class HelpBubbleFactoryMac; + friend class HelpBubbleViewsTest; explicit HelpBubbleViews(HelpBubbleView* help_bubble_view, ui::TrackedElement* anchor_element); @@ -76,6 +77,7 @@ void OnWidgetDestroying(views::Widget* widget) override; void OnElementHidden(ui::TrackedElement* element); + void OnElementBoundsChanged(ui::TrackedElement* element); raw_ptr<HelpBubbleView> help_bubble_view_; base::ScopedObservation<views::Widget, views::WidgetObserver> @@ -83,7 +85,17 @@ // Track the anchor element to determine if/when it goes away. base::raw_ptr<const ui::TrackedElement, DanglingUntriaged> anchor_element_; - base::CallbackListSubscription anchor_subscription_; + + // Listens so that the bubble can be closed if the anchor element disappears. + // The specific anchor view is not tracked because in a few cases (e.g. Mac + // native menus) the anchor view is not the anchor element itself but a + // placeholder. + base::CallbackListSubscription anchor_hidden_subscription_; + + // Listens for changes to the anchor bounding rect that are independent of the + // anchor view. Necessary for e.g. WebUI elements, which can be scrolled or + // moved within the web page. + base::CallbackListSubscription anchor_bounds_changed_subscription_; base::WeakPtrFactory<HelpBubbleViews> weak_ptr_factory_{this}; }; @@ -106,8 +118,7 @@ std::unique_ptr<HelpBubble> CreateBubbleImpl( ui::TrackedElement* element, const internal::HelpBubbleAnchorParams& anchor, - HelpBubbleParams params, - absl::optional<gfx::Rect> anchor_rect = absl::nullopt); + HelpBubbleParams params); private: base::raw_ptr<const HelpBubbleDelegate> delegate_;
diff --git a/components/user_education/views/help_bubble_view.h b/components/user_education/views/help_bubble_view.h index a5117a4..a9711b7 100644 --- a/components/user_education/views/help_bubble_view.h +++ b/components/user_education/views/help_bubble_view.h
@@ -79,6 +79,10 @@ views::LabelButton* GetDefaultButtonForTesting() const; views::LabelButton* GetNonDefaultButtonForTesting(int index) const; + void set_force_anchor_rect(gfx::Rect force_anchor_rect) { + force_anchor_rect_ = force_anchor_rect; + } + protected: // BubbleDialogDelegateView: bool OnMousePressed(const ui::MouseEvent& event) override;
diff --git a/components/user_education/views/help_bubble_view_unittest.cc b/components/user_education/views/help_bubble_view_unittest.cc index 26191916..d621a729 100644 --- a/components/user_education/views/help_bubble_view_unittest.cc +++ b/components/user_education/views/help_bubble_view_unittest.cc
@@ -13,16 +13,20 @@ #include "base/memory/raw_ptr.h" #include "base/test/mock_callback.h" #include "components/user_education/common/feature_promo_specification.h" +#include "components/user_education/common/help_bubble.h" #include "components/user_education/common/help_bubble_params.h" #include "components/user_education/views/help_bubble_delegate.h" #include "components/user_education/views/help_bubble_factory_views.h" #include "components/user_education/views/help_bubble_views_test_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/base/accelerators/accelerator.h" +#include "ui/base/interaction/element_identifier.h" +#include "ui/base/interaction/element_test_util.h" #include "ui/base/interaction/element_tracker.h" #include "ui/base/interaction/expect_call_in_scope.h" #include "ui/base/interaction/interaction_test_util.h" #include "ui/base/theme_provider.h" +#include "ui/gfx/geometry/vector2d.h" #include "ui/views/interaction/interaction_test_util_views.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/widget.h" @@ -30,6 +34,12 @@ namespace user_education { +namespace { +DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kTestElementId); +const ui::ElementContext kTestElementContext{1}; +constexpr gfx::Rect kWidgetBounds{400, 200, 200, 200}; +} // namespace + // Unit tests for HelpBubbleView. Timeout functionality isn't tested here due to // the vagaries of trying to get simulated timed events to run without a full // execution environment (specifically, Mac tests were extremely flaky without @@ -48,6 +58,7 @@ widget_->Init(CreateParamsForTestWidget()); view_ = widget_->SetContentsView(std::make_unique<views::View>()); widget_->Show(); + widget_->SetBounds(kWidgetBounds); } void TearDown() override { @@ -56,9 +67,17 @@ } protected: - HelpBubbleView* CreateHelpBubbleView(HelpBubbleParams params) { - return new HelpBubbleView(&test_delegate_, - internal::HelpBubbleAnchorParams{view_}, + gfx::Rect GetWidgetClientBounds() const { + return widget_->GetClientAreaBoundsInScreen(); + } + + HelpBubbleView* CreateHelpBubbleView( + HelpBubbleParams params, + absl::optional<gfx::Rect> bounds = absl::nullopt) { + internal::HelpBubbleAnchorParams anchor_params; + anchor_params.view = view_; + anchor_params.rect = bounds; + return new HelpBubbleView(&test_delegate_, anchor_params, std::move(params)); } @@ -145,4 +164,128 @@ EXPECT_EQ(kButton3Text, bubble->GetNonDefaultButtonForTesting(1)->GetText()); } +TEST_F(HelpBubbleViewTest, AnchorToRect) { + HelpBubbleParams params; + params.body_text = u"To X, do Y"; + params.arrow = HelpBubbleArrow::kRightCenter; + + const auto widget_bounds = GetWidgetClientBounds(); + gfx::Rect anchor_bounds = widget_bounds; + anchor_bounds.Inset(50); + + HelpBubbleView* const bubble = + CreateHelpBubbleView(std::move(params), anchor_bounds); + const auto bubble_bounds = bubble->GetWidget()->GetWindowBoundsInScreen(); + + // The right side of the bubble should overlap the widget. + EXPECT_TRUE(widget_bounds.Contains(bubble_bounds.right_center())); + + // The right side of the widget should be outside and aligned with the center + // of the anchor bounds. Allow for rounding error when checking alignment. + EXPECT_LT(bubble_bounds.right(), anchor_bounds.x()); + EXPECT_LE(std::abs(bubble_bounds.CenterPoint().y() - + anchor_bounds.CenterPoint().y()), + 2); +} + +TEST_F(HelpBubbleViewTest, AnchorRectUpdated) { + HelpBubbleParams params; + params.body_text = u"To X, do Y"; + params.arrow = HelpBubbleArrow::kRightCenter; + + const auto widget_bounds = GetWidgetClientBounds(); + gfx::Rect anchor_bounds = widget_bounds; + anchor_bounds.Inset(50); + + HelpBubbleView* const bubble = + CreateHelpBubbleView(std::move(params), anchor_bounds); + const auto bubble_bounds = bubble->GetWidget()->GetWindowBoundsInScreen(); + + constexpr gfx::Vector2d kAnchorOffset{9, 13}; + anchor_bounds.Offset(kAnchorOffset); + bubble->set_force_anchor_rect(anchor_bounds); + bubble->OnAnchorBoundsChanged(); + + gfx::Rect expected = bubble_bounds; + expected.Offset(kAnchorOffset); + EXPECT_EQ(expected, bubble->GetWidget()->GetWindowBoundsInScreen()); +} + +class HelpBubbleViewsTest : public HelpBubbleViewTest { + public: + HelpBubbleViewsTest() = default; + ~HelpBubbleViewsTest() override = default; + + // This simulates logic used by e.g. FloatingWebUIHelpBubbleFactory. + std::unique_ptr<HelpBubbleViews> CreateHelpBubble( + HelpBubbleParams params, + ui::TrackedElement* element) { + HelpBubbleView* const bubble_view = + CreateHelpBubbleView(std::move(params), element->GetScreenBounds()); + return base::WrapUnique(new HelpBubbleViews(bubble_view, element)); + } + + void SetUp() override { + HelpBubbleViewTest::SetUp(); + + HelpBubbleParams params; + params.body_text = u"To X, do Y"; + params.arrow = HelpBubbleArrow::kRightCenter; + + gfx::Rect anchor_bounds = GetWidgetClientBounds(); + anchor_bounds.Inset(50); + + test_element_ = std::make_unique<ui::test::TestElement>( + kTestElementId, kTestElementContext); + test_element_->SetScreenBounds(anchor_bounds); + test_element_->Show(); + + help_bubble_ = CreateHelpBubble(std::move(params), test_element_.get()); + } + + void TearDown() override { + test_element_.reset(); + HelpBubbleViewTest::TearDown(); + } + + protected: + std::unique_ptr<ui::test::TestElement> test_element_; + std::unique_ptr<HelpBubbleViews> help_bubble_; +}; + +// This duplicates the previous test, but with a HelpBubbleViews object. +TEST_F(HelpBubbleViewsTest, AnchorToRect) { + const auto widget_bounds = GetWidgetClientBounds(); + const auto anchor_bounds = test_element_->GetScreenBounds(); + const auto bubble_bounds = help_bubble_->GetBoundsInScreen(); + + // The right side of the bubble should overlap the widget. + EXPECT_TRUE(widget_bounds.Contains(bubble_bounds.right_center())); + + // The right side of the widget should be outside and aligned with the center + // of the anchor bounds. Allow for rounding error when checking alignment. + EXPECT_LT(bubble_bounds.right(), anchor_bounds.x()); + EXPECT_LE(std::abs(bubble_bounds.CenterPoint().y() - + anchor_bounds.CenterPoint().y()), + 2); +} + +// This duplicates the previous test, but with a HelpBubbleViews object. +TEST_F(HelpBubbleViewsTest, AnchorRectUpdated) { + const gfx::Rect old_bounds = help_bubble_->GetBoundsInScreen(); + + // Move the anchor target by a small but noticeable amount. + auto new_bounds = test_element_->GetScreenBounds(); + constexpr gfx::Vector2d kAnchorOffset{9, 13}; + new_bounds.Offset(kAnchorOffset); + test_element_->SetScreenBounds(new_bounds); + ui::ElementTracker::GetFrameworkDelegate()->NotifyCustomEvent( + test_element_.get(), kHelpBubbleAnchorBoundsChangedEvent); + + // Verify that the help bubble has moved by a similar amount. + gfx::Rect expected = old_bounds; + expected.Offset(kAnchorOffset); + EXPECT_EQ(expected, help_bubble_->GetBoundsInScreen()); +} + } // namespace user_education
diff --git a/components/user_education/webui/tracked_element_webui.cc b/components/user_education/webui/tracked_element_webui.cc index 290209e..148d14c 100644 --- a/components/user_education/webui/tracked_element_webui.cc +++ b/components/user_education/webui/tracked_element_webui.cc
@@ -5,6 +5,7 @@ #include "components/user_education/webui/tracked_element_webui.h" #include "base/check.h" +#include "components/user_education/common/help_bubble.h" #include "components/user_education/webui/help_bubble_handler.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" @@ -47,10 +48,17 @@ } void TrackedElementWebUI::SetVisible(bool visible, gfx::RectF bounds) { - last_known_bounds_ = bounds; - if (visible == visible_) + if (visible == visible_) { + if (visible && last_known_bounds_ != bounds) { + // This event signals that the bounds of the element have been updated. + ui::ElementTracker::GetFrameworkDelegate()->NotifyCustomEvent( + this, kHelpBubbleAnchorBoundsChangedEvent); + last_known_bounds_ = bounds; + } return; + } + last_known_bounds_ = bounds; visible_ = visible; auto* const delegate = ui::ElementTracker::GetFrameworkDelegate(); if (visible) {
diff --git a/components/viz/common/resources/shared_bitmap.h b/components/viz/common/resources/shared_bitmap.h index 9eb297e86..b59eb07a 100644 --- a/components/viz/common/resources/shared_bitmap.h +++ b/components/viz/common/resources/shared_bitmap.h
@@ -28,7 +28,7 @@ // An object returned by the SharedBitmapGenerator that exposes the // pixels for a SharedBitmapId. They are exposed via a class so that // this object (or its subclass) can ensure the lifetime of the pixels -// is not cut short. While this object is kept alive, the pixels should +// is not cut short. While this object is kept alive, the pixels must // remain valid. class VIZ_COMMON_EXPORT SharedBitmap { public: @@ -43,7 +43,7 @@ uint8_t* pixels() { return pixels_; } - private: + protected: raw_ptr<uint8_t> pixels_; };
diff --git a/components/viz/service/display/ca_layer_overlay.h b/components/viz/service/display/ca_layer_overlay.h index 713474a..9076cfa0 100644 --- a/components/viz/service/display/ca_layer_overlay.h +++ b/components/viz/service/display/ca_layer_overlay.h
@@ -62,7 +62,8 @@ scoped_refptr<CALayerOverlaySharedState> shared_state; // Texture that corresponds to an IOSurface to set as the content of the - // CALayer. If this is 0 then the CALayer is a solid color. + // CALayer. If this is 0 then the CALayer is a solid color, or it's the root + // render pass if |is_root_render_pass| = true. ResourceId contents_resource_id = kInvalidResourceId; // Mailbox from contents_resource_id. It is used by SkiaRenderer. gpu::Mailbox mailbox; @@ -88,6 +89,8 @@ // If |rpdq| is present, then the renderer must draw the filter effects and // copy the result into an IOSurface. const AggregatedRenderPassDrawQuad* rpdq = nullptr; + // Whether this overlay candidate represents the root render pass. + bool is_root_render_pass = false; }; typedef std::vector<CALayerOverlay> CALayerOverlayList;
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index 395b18c..589dd22 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc
@@ -29,6 +29,7 @@ #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/resources/platform_color.h" +#include "components/viz/common/resources/resource_format_utils.h" #include "components/viz/common/viz_utils.h" #include "components/viz/service/display/bsp_tree.h" #include "components/viz/service/display/bsp_walk_action.h" @@ -191,10 +192,15 @@ base::flat_map<AggregatedRenderPassId, RenderPassRequirements> render_passes_in_frame; for (const auto& pass : render_passes_in_draw_order) { + // The root render pass doesn't need to be updated here because the backing + // is reused and updated in AllocateRenderPassResourceIfNeeded(). + if (pass == root_render_pass) { + continue; + } + // If there's a copy request, we need an explicit renderpass backing so // only try to draw directly if there are no copy requests. - bool is_root = pass == root_render_pass; - if (!is_root && pass->copy_requests.empty()) { + if (pass->copy_requests.empty()) { if (const DrawQuad* quad = CanPassBeDrawnDirectly(pass.get())) { // If the render pass is drawn directly, it will not be drawn from as // a render pass so it's not added to the map. @@ -202,12 +208,7 @@ continue; } } - gfx::Size size = pass->output_rect.size(); - // We should not change the buffer size for the root render pass. - // The requirement is used for non-root render pass only. - if (!is_root) { - size = CalculateTextureSizeForRenderPass(pass.get()); - } + gfx::Size size = CalculateTextureSizeForRenderPass(pass.get()); auto color_space = RenderPassColorSpace(pass.get()); auto format = GetColorSpaceResourceFormat(color_space); @@ -784,20 +785,24 @@ return; } - gfx::Size size = render_pass->output_rect.size(); - // We should not change the buffer size for the root render pass. + RenderPassRequirements requirements; + // The root pass will use values from |reshape_params_| so this doesn't + // matter. if (!is_root) { - size = CalculateTextureSizeForRenderPass(render_pass); - size.Enlarge(enlarge_pass_texture_amount_.width(), - enlarge_pass_texture_amount_.height()); + requirements.size = CalculateTextureSizeForRenderPass(render_pass); + requirements.size.Enlarge(enlarge_pass_texture_amount_.width(), + enlarge_pass_texture_amount_.height()); + requirements.generate_mipmap = render_pass->generate_mipmap; + requirements.color_space = CurrentRenderPassColorSpace(); + requirements.format = GetColorSpaceResourceFormat(requirements.color_space); + } else { + requirements.size = surface_size_for_swap_buffers(); + requirements.generate_mipmap = false; + requirements.color_space = reshape_color_space(); + requirements.format = GetResourceFormat(reshape_buffer_format()); } - auto color_space = CurrentRenderPassColorSpace(); - auto format = GetColorSpaceResourceFormat(color_space); - - AllocateRenderPassResourceIfNeeded( - render_pass->id, - {size, render_pass->generate_mipmap, format, color_space}); + AllocateRenderPassResourceIfNeeded(render_pass->id, requirements); // TODO(crbug.com/582554): This change applies only when Vulkan is enabled and // it will be removed once SkiaRenderer has complete support for Vulkan.
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 7edc61a7..223a556 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -871,19 +871,24 @@ if (!buffer_queue_) { skia_output_surface_->ScheduleOutputSurfaceAsOverlay(surface_plane); } else { -#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN) - // Windows and Mac have different OverlayList types, but those platforms - // aren't supported by buffer_queue_ yet, so this won't be reached. +#if BUILDFLAG(IS_WIN) + // Windows does not use buffer_queue_ so this won't be reached. NOTREACHED(); #else - auto root_pass_backing = - render_pass_backings_.find(current_frame()->root_render_pass->id); - // The root pass backing should always exist. - DCHECK(root_pass_backing != render_pass_backings_.end()); +#if BUILDFLAG(IS_MAC) + CALayerOverlay surface_candidate; + surface_candidate.shared_state = + base::MakeRefCounted<CALayerOverlaySharedState>(); + surface_candidate.shared_state->sorting_context_id = 0; + surface_candidate.shared_state->rounded_corner_bounds = + surface_plane.rounded_corners; + surface_candidate.contents_rect = surface_plane.uv_rect; + surface_candidate.bounds_rect = surface_plane.display_rect; + surface_candidate.opacity = surface_plane.opacity; + surface_candidate.filter = GL_LINEAR; +#else OverlayCandidate surface_candidate; - surface_candidate.mailbox = root_pass_backing->second.mailbox; - surface_candidate.is_root_render_pass = true; surface_candidate.transform = surface_plane.transform; surface_candidate.display_rect = surface_plane.display_rect; surface_candidate.uv_rect = surface_plane.uv_rect; @@ -897,10 +902,19 @@ surface_candidate.damage_rect = gfx::RectF(surface_plane.damage_rect.value_or( gfx::Rect(surface_plane.resource_size))); +#endif // BUILDFLAG(IS_MAC) + + auto root_pass_backing = + render_pass_backings_.find(current_frame()->root_render_pass->id); + // The root pass backing should always exist. + DCHECK(root_pass_backing != render_pass_backings_.end()); + + surface_candidate.mailbox = root_pass_backing->second.mailbox; + surface_candidate.is_root_render_pass = true; current_frame()->overlay_list.insert( current_frame()->overlay_list.begin(), surface_candidate); -#endif // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN) +#endif // BUILDFLAG(IS_WIN) } } else { #if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_MAC) @@ -2717,6 +2731,10 @@ } #elif BUILDFLAG(IS_APPLE) for (CALayerOverlay& ca_layer_overlay : current_frame()->overlay_list) { + if (ca_layer_overlay.is_root_render_pass) { + continue; + } + if (ca_layer_overlay.rpdq) { PrepareRenderPassOverlay(&ca_layer_overlay); locks.emplace_back(ca_layer_overlay.mailbox); @@ -3159,6 +3177,12 @@ render_passes_in_frame) { std::vector<AggregatedRenderPassId> passes_to_delete; for (const auto& pair : render_pass_backings_) { + // The single root render pass backing is updated in + // AllocateRenderPassResourceIfNeeded(), so we should never erase it here. + if (pair.second.is_root) { + continue; + } + auto render_pass_it = render_passes_in_frame.find(pair.first); if (render_pass_it == render_passes_in_frame.end()) { passes_to_delete.push_back(pair.first); @@ -3186,12 +3210,7 @@ for (size_t i = 0; i < passes_to_delete.size(); ++i) { auto it = render_pass_backings_.find(passes_to_delete[i]); auto& backing = it->second; - // Buffers for root render pass backings are managed by |buffer_queue_|, not - // DisplayResourceProvider, so we should not destroy them here. This - // reallocation is done in Reshape before drawing the frame - if (!backing.is_root) { - skia_output_surface_->DestroySharedImage(backing.mailbox); - } + skia_output_surface_->DestroySharedImage(backing.mailbox); render_pass_backings_.erase(it); } @@ -3208,10 +3227,10 @@ auto& root_pass_backing = render_pass_backings_[render_pass_id]; root_pass_backing.is_root = true; root_pass_backing.mailbox = buffer_queue_->GetCurrentBuffer(); - root_pass_backing.generate_mipmap = false; - root_pass_backing.size = surface_size_for_swap_buffers(); - root_pass_backing.format = GetResourceFormat(reshape_buffer_format()); - root_pass_backing.color_space = reshape_color_space(); + root_pass_backing.generate_mipmap = requirements.generate_mipmap; + root_pass_backing.size = requirements.size; + root_pass_backing.format = requirements.format; + root_pass_backing.color_space = requirements.color_space; return; }
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc index d5353f5..767f829 100644 --- a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc +++ b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
@@ -90,7 +90,10 @@ static_cast<uint8_t*>(const_cast<void*>(bitmap_data->GetMemory()))), bitmap_data_(std::move(bitmap_data)) {} - ~ServerSharedBitmap() override = default; + ~ServerSharedBitmap() override { + // Drop unowned reference before destroying `bitmap_data_`. + pixels_ = nullptr; + } private: scoped_refptr<BitmapData> bitmap_data_;
diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc b/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc index c65ae0a7..47e9ee045 100644 --- a/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc +++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
@@ -62,10 +62,12 @@ OverlayData(std::unique_ptr<gpu::OverlayImageRepresentation> representation, std::unique_ptr<gpu::OverlayImageRepresentation::ScopedReadAccess> - scoped_read_access) + scoped_read_access, + bool is_root_render_pass) : representation_(std::move(representation)), scoped_read_access_(std::move(scoped_read_access)), - ref_(1) { + ref_(1), + is_root_render_pass_(is_root_render_pass) { DCHECK(representation_); DCHECK(scoped_read_access_); } @@ -75,7 +77,7 @@ ~OverlayData() { Reset(); } OverlayData& operator=(OverlayData&& other) { - DCHECK(!IsInUseByWindowServer()); + DCHECK(is_root_render_pass_ || !IsInUseByWindowServer()); DCHECK(!ref_); DCHECK(!scoped_read_access_); DCHECK(!representation_); @@ -83,13 +85,20 @@ representation_ = std::move(other.representation_); ref_ = other.ref_; other.ref_ = 0; + is_root_render_pass_ = other.is_root_render_pass_; return *this; } bool IsInUseByWindowServer() const { #if BUILDFLAG(IS_MAC) - if (!scoped_read_access_) + if (!scoped_read_access_) { return false; + } + // The root render pass buffers are managed by SkiaRenderer so we don't care + // if they're in use by the window server. + if (is_root_render_pass_) { + return false; + } return scoped_read_access_->IsInUseByWindowServer(); #else return false; @@ -103,7 +112,7 @@ if (ref_ > 1) { --ref_; } else if (ref_ == 1) { - DCHECK(!IsInUseByWindowServer()); + DCHECK(is_root_render_pass_ || !IsInUseByWindowServer()); Reset(); } } @@ -117,6 +126,8 @@ return scoped_read_access_.get(); } + bool IsRootRenderPass() { return is_root_render_pass_; } + private: void Reset() { scoped_read_access_.reset(); @@ -128,6 +139,7 @@ std::unique_ptr<gpu::OverlayImageRepresentation::ScopedReadAccess> scoped_read_access_; int ref_ = 0; + bool is_root_render_pass_ = false; }; SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue( @@ -321,6 +333,7 @@ SkiaOutputDeviceBufferQueue::OverlayData* SkiaOutputDeviceBufferQueue::GetOrCreateOverlayData(const gpu::Mailbox& mailbox, + bool is_root_render_pass, bool* is_existing) { if (is_existing) *is_existing = false; @@ -354,8 +367,9 @@ } bool result; - std::tie(it, result) = overlays_.emplace(std::move(shared_image), - std::move(shared_image_access)); + std::tie(it, result) = + overlays_.emplace(std::move(shared_image), std::move(shared_image_access), + is_root_render_pass); DCHECK(result); DCHECK(it->unique()); @@ -394,8 +408,8 @@ OutputPresenter::ScopedOverlayAccess* access = nullptr; bool overlay_has_been_submitted; - auto* overlay_data = - GetOrCreateOverlayData(mailbox, &overlay_has_been_submitted); + auto* overlay_data = GetOrCreateOverlayData( + mailbox, overlay.is_root_render_pass, &overlay_has_been_submitted); if (overlay_data) { access = overlay_data->scoped_read_access(); pending_overlay_mailboxes_.emplace_back(mailbox); @@ -589,11 +603,17 @@ // Go through backings of all overlays, and release overlay backings which are // not used. base::EraseIf(overlays_, [&on_overlay_release](auto& overlay) { - if (!overlay.unique()) + if (!overlay.unique()) { return false; - if (overlay.IsInUseByWindowServer()) + } + if (overlay.IsInUseByWindowServer()) { return false; - on_overlay_release(overlay); + } + // The root render pass buffers are managed by SkiaRenderer so we don't need + // to explicitly return them via callback. + if (!overlay.IsRootRenderPass()) { + on_overlay_release(overlay); + } overlay.Unref(); return true; });
diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue.h b/components/viz/service/display_embedder/skia_output_device_buffer_queue.h index a5717d9..f4a766d9 100644 --- a/components/viz/service/display_embedder/skia_output_device_buffer_queue.h +++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
@@ -93,6 +93,7 @@ // Given an overlay mailbox, returns the corresponding OverlayData* from // |overlays_|. Inserts an OverlayData if mailbox is not in |overlays_|. OverlayData* GetOrCreateOverlayData(const gpu::Mailbox& mailbox, + bool is_root_render_pass, bool* is_existing = nullptr); std::unique_ptr<OutputPresenter> presenter_;
diff --git a/components/webapps/browser/install_result_code.cc b/components/webapps/browser/install_result_code.cc index 9fce22a..b644951 100644 --- a/components/webapps/browser/install_result_code.cc +++ b/components/webapps/browser/install_result_code.cc
@@ -81,6 +81,8 @@ return os << "kHaltedBySyncUninstall"; case InstallResultCode::kInstallURLInvalid: return os << "kInstallURLInvalid"; + case InstallResultCode::kIconDownloadingFailed: + return os << "kIconDownloadingFailed"; } }
diff --git a/components/webapps/browser/install_result_code.h b/components/webapps/browser/install_result_code.h index 4c1f38db..5bc549ff 100644 --- a/components/webapps/browser/install_result_code.h +++ b/components/webapps/browser/install_result_code.h
@@ -86,7 +86,11 @@ // Invalid install URL for externally managed apps. kInstallURLInvalid = 29, - kMaxValue = kInstallURLInvalid, + // Downloading failed for all icons in an installation method which requires + // non-generated icons. + kIconDownloadingFailed = 30, + + kMaxValue = kIconDownloadingFailed, }; // Checks if InstallResultCode is not a failure.
diff --git a/components/webdata/common/BUILD.gn b/components/webdata/common/BUILD.gn index 0a75d6a..fd64e91 100644 --- a/components/webdata/common/BUILD.gn +++ b/components/webdata/common/BUILD.gn
@@ -47,7 +47,6 @@ "//components/test/data/web_database/version_106.sql", "//components/test/data/web_database/version_107.sql", "//components/test/data/web_database/version_108.sql", - "//components/test/data/web_database/version_109.sql", "//components/test/data/web_database/version_82.sql", "//components/test/data/web_database/version_83.sql", "//components/test/data/web_database/version_84.sql",
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc index 4f5e8e01..85001526 100644 --- a/components/webdata/common/web_database.cc +++ b/components/webdata/common/web_database.cc
@@ -13,7 +13,7 @@ // corresponding changes must happen in the unit tests, and new migration test // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|. // static -const int WebDatabase::kCurrentVersionNumber = 110; +const int WebDatabase::kCurrentVersionNumber = 109; const int WebDatabase::kDeprecatedVersionNumber = 82;
diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc index 5de397817..5029114 100644 --- a/components/webdata/common/web_database_migration_unittest.cc +++ b/components/webdata/common/web_database_migration_unittest.cc
@@ -141,7 +141,7 @@ base::ScopedTempDir temp_dir_; }; -const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 110; +const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 109; void WebDatabaseMigrationTest::LoadDatabase( const base::FilePath::StringType& file) { @@ -1049,31 +1049,3 @@ EXPECT_TRUE(connection.DoesTableExist("virtual_card_usage_data")); } } - -// Tests that the initial_creator_id and last_modifier_id columns are added to -// the contact_info table. -TEST_F(WebDatabaseMigrationTest, MigrateVersion109ToCurrent) { - ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_109.sql"))); - { - sql::Database connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - EXPECT_EQ(109, VersionFromConnection(&connection)); - EXPECT_FALSE( - connection.DoesColumnExist("contact_info", "initial_creator_id")); - EXPECT_FALSE( - connection.DoesColumnExist("contact_info", "last_modifier_id")); - } - DoMigration(); - { - sql::Database connection; - ASSERT_TRUE(connection.Open(GetDatabasePath())); - ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); - - EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); - EXPECT_TRUE( - connection.DoesColumnExist("contact_info", "initial_creator_id")); - EXPECT_TRUE(connection.DoesColumnExist("contact_info", "last_modifier_id")); - } -}
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc index 05c2a08..b33033b9f 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc
@@ -717,6 +717,9 @@ RunOtherNamedProcessTypeMain(const std::string& process_type, MainFunctionParams main_function_params, ContentMainDelegate* delegate) { +#if BUILDFLAG(IS_MAC) + base::Process::SetCurrentTaskDefaultRole(); +#endif #if BUILDFLAG(IS_WIN) if (delegate->ShouldHandleConsoleControlEvents()) InstallConsoleControlHandler(/*is_browser_process=*/false);
diff --git a/content/app_shim_remote_cocoa/DEPS b/content/app_shim_remote_cocoa/DEPS index 7aedc66..890417b4 100644 --- a/content/app_shim_remote_cocoa/DEPS +++ b/content/app_shim_remote_cocoa/DEPS
@@ -20,7 +20,6 @@ "+content/browser/web_contents/web_contents_view_mac.h", "+content/browser/web_contents/web_drag_dest_mac.h", "+content/common/content_export.h", - "+content/common/cursors/webcursor.h", "+content/common/render_widget_host_ns_view.mojom.h", "+content/common/web_contents_ns_view_bridge.mojom.h", "+content/public/browser/content_browser_client.h",
diff --git a/content/app_shim_remote_cocoa/render_widget_host_ns_view_bridge.mm b/content/app_shim_remote_cocoa/render_widget_host_ns_view_bridge.mm index 3c66f79..299e3e8 100644 --- a/content/app_shim_remote_cocoa/render_widget_host_ns_view_bridge.mm +++ b/content/app_shim_remote_cocoa/render_widget_host_ns_view_bridge.mm
@@ -8,12 +8,12 @@ #include "base/strings/sys_string_conversions.h" #include "components/remote_cocoa/app_shim/ns_view_ids.h" #include "content/app_shim_remote_cocoa/render_widget_host_ns_view_host_helper.h" -#include "content/common/cursors/webcursor.h" #include "content/common/mac/attributed_string_type_converters.h" #import "skia/ext/skia_utils_mac.h" #include "third_party/blink/public/common/input/web_gesture_event.h" #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" #import "ui/base/cocoa/animation_utils.h" +#import "ui/base/cocoa/cursor_utils.h" #include "ui/base/mojom/attributed_string.mojom.h" #include "ui/display/screen.h" #include "ui/events/blink/did_overscroll_params.h" @@ -242,7 +242,7 @@ } void RenderWidgetHostNSViewBridge::DisplayCursor(const ui::Cursor& cursor) { - [cocoa_view_ updateCursor:content::WebCursor(cursor).GetNativeCursor()]; + [cocoa_view_ updateCursor:ui::GetNativeCursor(cursor)]; } void RenderWidgetHostNSViewBridge::SetCursorLocked(bool locked) {
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index fee2788e..7b1a64d 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -259,7 +259,6 @@ "//ui/base:buildflags", "//ui/base:data_exchange", "//ui/base/clipboard", - "//ui/base/cursor", "//ui/base/cursor/mojom:cursor_type", "//ui/base/dragdrop:types", "//ui/base/dragdrop/mojom", @@ -301,6 +300,7 @@ "//third_party/blink/public/mojom:embedded_frame_sink_mojo_bindings", "//third_party/blink/public/mojom:mojom_broadcastchannel_bindings", "//third_party/leveldatabase", + "//ui/base/cursor", "//ui/base/dragdrop/mojom:mojom_headers", ] @@ -717,8 +717,6 @@ "code_cache/simple_lru_cache.h", "compositor/surface_utils.cc", "compositor/surface_utils.h", - "compute_pressure/pressure_service_impl.cc", - "compute_pressure/pressure_service_impl.h", "contacts/contacts_manager_impl.cc", "contacts/contacts_manager_impl.h", "contacts/contacts_provider.h", @@ -1457,7 +1455,6 @@ "preloading/prefetch/proxy_lookup_client_impl.h", "preloading/prefetcher.cc", "preloading/prefetcher.h", - "preloading/preloading.cc", "preloading/preloading.h", "preloading/preloading_attempt_impl.cc", "preloading/preloading_attempt_impl.h",
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc index b8c8c5e..e3920e1 100644 --- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc +++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -266,7 +266,7 @@ VLOG(1) << "Top of WaitForExpectedText() loop"; // Check to see if the @WAIT-FOR text has appeared yet. bool all_wait_for_strings_found = true; - std::string tree_dump = DumpUnfilteredAccessibilityTreeAsString(); + std::string tree_dump = DumpTreeAsString(); for (const auto& str : scenario_.wait_for) { if (tree_dump.find(str) == std::string::npos) { VLOG(1) << "Still waiting on this text to be found: " << str;
diff --git a/content/browser/attribution_reporting/aggregatable_attribution_utils.cc b/content/browser/attribution_reporting/aggregatable_attribution_utils.cc index 3a89db0..8dc3724 100644 --- a/content/browser/attribution_reporting/aggregatable_attribution_utils.cc +++ b/content/browser/attribution_reporting/aggregatable_attribution_utils.cc
@@ -100,10 +100,11 @@ aggregatable_trigger_data.vec().size()); } - DCHECK(!buckets.empty()); - base::UmaHistogramPercentage( - "Conversions.AggregatableReport.DroppedKeysPercentage", - 100 * (buckets.size() - contributions.size()) / buckets.size()); + if (!buckets.empty()) { + base::UmaHistogramPercentage( + "Conversions.AggregatableReport.DroppedKeysPercentage", + 100 * (buckets.size() - contributions.size()) / buckets.size()); + } const int kExclusiveMaxHistogramValue = 101;
diff --git a/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc b/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc index 5ecb9d73..7015dad 100644 --- a/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc +++ b/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc
@@ -448,6 +448,7 @@ AttributionTrigger trigger(std::move(reporting_origin), std::move(data), /*destination_origin=*/context.context_origin(), + std::move(attestation), context.is_within_fenced_frame()); // Handle the trigger immediately if we're not waiting for any sources to be
diff --git a/content/browser/attribution_reporting/attribution_internals_browsertest.cc b/content/browser/attribution_reporting/attribution_internals_browsertest.cc index d7b26bc..bab22380d 100644 --- a/content/browser/attribution_reporting/attribution_internals_browsertest.cc +++ b/content/browser/attribution_reporting/attribution_internals_browsertest.cc
@@ -47,6 +47,7 @@ #include "content/shell/browser/shell.h" #include "net/base/net_errors.h" #include "testing/gmock/include/gmock/gmock.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { @@ -1024,6 +1025,7 @@ /*debug_reporting=*/false, ::aggregation_service::mojom::AggregationCoordinator::kDefault), *SuitableOrigin::Deserialize("https://d.test"), + /*attestation=*/absl::nullopt, /*is_within_fenced_frame=*/false); static constexpr char kScript[] = R"(
diff --git a/content/browser/attribution_reporting/attribution_manager.h b/content/browser/attribution_reporting/attribution_manager.h index 3b86c07a..5e1f004b 100644 --- a/content/browser/attribution_reporting/attribution_manager.h +++ b/content/browser/attribution_reporting/attribution_manager.h
@@ -12,6 +12,7 @@ #include "components/attribution_reporting/os_support.mojom-forward.h" #include "components/attribution_reporting/source_registration_error.mojom-forward.h" #include "content/browser/attribution_reporting/attribution_report.h" +#include "content/public/browser/attribution_data_model.h" #include "content/public/browser/storage_partition.h" namespace attribution_reporting { @@ -34,13 +35,13 @@ // Interface that mediates data flow between the network, storage layer, and // blink. -class AttributionManager { +class AttributionManager : public AttributionDataModel { public: static AttributionManager* FromWebContents(WebContents* web_contents); static attribution_reporting::mojom::OsSupport GetOsSupport(); - virtual ~AttributionManager() = default; + ~AttributionManager() override = default; virtual void AddObserver(AttributionObserver* observer) = 0;
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.cc b/content/browser/attribution_reporting/attribution_manager_impl.cc index 8ab421b..19cd9e0 100644 --- a/content/browser/attribution_reporting/attribution_manager_impl.cc +++ b/content/browser/attribution_reporting/attribution_manager_impl.cc
@@ -6,6 +6,7 @@ #include <cmath> #include <utility> +#include <vector> #include "base/barrier_closure.h" #include "base/check.h" @@ -56,6 +57,7 @@ #include "content/browser/attribution_reporting/storable_source.h" #include "content/browser/attribution_reporting/stored_source.h" #include "content/browser/storage_partition_impl.h" +#include "content/public/browser/attribution_data_model.h" #include "content/public/browser/attribution_reporting.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browsing_data_filter_builder.h" @@ -800,6 +802,20 @@ NotifyReportsChanged(AttributionReport::Type::kAggregatableAttribution); } +// TODO(crbug.com/1407369): Propagate calls to storage +void AttributionManagerImpl::GetAllDataKeys( + base::OnceCallback<void(std::vector<AttributionManager::DataKey>)> + callback) { + std::move(callback).Run({}); +} + +// TODO(crbug.com/1407369): Propagate calls to storage +void AttributionManagerImpl::RemoveAttributionDataByDataKey( + const AttributionManager::DataKey& data_key, + base::OnceClosure callback) { + std::move(callback).Run(); +} + void AttributionManagerImpl::GetReportsToSend() { // We only get the next report time strictly after now, because if we are // sending a report now but haven't finished doing so and it is still present
diff --git a/content/browser/attribution_reporting/attribution_manager_impl.h b/content/browser/attribution_reporting/attribution_manager_impl.h index dbee862..80251e09 100644 --- a/content/browser/attribution_reporting/attribution_manager_impl.h +++ b/content/browser/attribution_reporting/attribution_manager_impl.h
@@ -163,6 +163,12 @@ const attribution_reporting::SuitableOrigin& reporting_origin, attribution_reporting::mojom::SourceRegistrationError) override; + void GetAllDataKeys( + base::OnceCallback<void(std::vector<DataKey>)> callback) override; + + void RemoveAttributionDataByDataKey(const DataKey& data_key, + base::OnceClosure callback) override; + private: friend class AttributionManagerImplTest;
diff --git a/content/browser/attribution_reporting/attribution_report.cc b/content/browser/attribution_reporting/attribution_report.cc index 23d3d72..86a17b0 100644 --- a/content/browser/attribution_reporting/attribution_report.cc +++ b/content/browser/attribution_reporting/attribution_report.cc
@@ -19,6 +19,7 @@ #include "content/browser/attribution_reporting/attribution_source_type.h" #include "content/browser/attribution_reporting/attribution_utils.h" #include "content/browser/attribution_reporting/common_source_info.h" +#include "net/http/http_request_headers.h" #include "third_party/abseil-cpp/absl/types/variant.h" #include "url/gurl.h" #include "url/origin.h" @@ -57,10 +58,12 @@ Id id, base::Time initial_report_time, ::aggregation_service::mojom::AggregationCoordinator - aggregation_coordinator) + aggregation_coordinator, + absl::optional<std::string> attestation_token) : contributions(std::move(contributions)), id(id), initial_report_time(initial_report_time), + attestation_token(std::move(attestation_token)), aggregation_coordinator(aggregation_coordinator) {} AttributionReport::AggregatableAttributionData::AggregatableAttributionData( @@ -261,4 +264,13 @@ return std::min(*a, *b); } +void AttributionReport::PopulateAdditionalHeaders( + net::HttpRequestHeaders& headers) const { + if (const auto* data = absl::get_if<AggregatableAttributionData>(&data_); + data && data->attestation_token.has_value()) { + headers.SetHeader("Sec-Attribution-Reporting-Private-State-Token", + *data->attestation_token); + } +} + } // namespace content
diff --git a/content/browser/attribution_reporting/attribution_report.h b/content/browser/attribution_reporting/attribution_report.h index f80e3eef..a6fdd9f0 100644 --- a/content/browser/attribution_reporting/attribution_report.h +++ b/content/browser/attribution_reporting/attribution_report.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <string> #include <vector> #include "base/containers/enum_set.h" @@ -26,6 +27,10 @@ class GURL; +namespace net { +class HttpRequestHeaders; +} // namespace net + namespace content { // Class that contains all the data needed to serialize and send an attribution @@ -78,7 +83,8 @@ Id id, base::Time initial_report_time, ::aggregation_service::mojom::AggregationCoordinator - aggregation_coordinator); + aggregation_coordinator, + absl::optional<std::string> attestation_token); AggregatableAttributionData(const AggregatableAttributionData&); AggregatableAttributionData& operator=(const AggregatableAttributionData&); AggregatableAttributionData(AggregatableAttributionData&&); @@ -108,6 +114,10 @@ // The initial report time scheduled by the browser. base::Time initial_report_time; + // A token that can be sent alongside the report to complete trigger + // attestation. + absl::optional<std::string> attestation_token; + ::aggregation_service::mojom::AggregationCoordinator aggregation_coordinator; @@ -143,6 +153,9 @@ base::Value::Dict ReportBody() const; + // Populate additional headers that should be sent alongside the report. + void PopulateAdditionalHeaders(net::HttpRequestHeaders&) const; + Id ReportId() const; const AttributionInfo& attribution_info() const { return attribution_info_; }
diff --git a/content/browser/attribution_reporting/attribution_report_network_sender.cc b/content/browser/attribution_reporting/attribution_report_network_sender.cc index 0fb8128..19d9b00 100644 --- a/content/browser/attribution_reporting/attribution_report_network_sender.cc +++ b/content/browser/attribution_reporting/attribution_report_network_sender.cc
@@ -58,8 +58,10 @@ ReportSentCallback sent_callback) { GURL url = report.ReportURL(is_debug_report); std::string body = SerializeAttributionJson(report.ReportBody()); + net::HttpRequestHeaders headers; + report.PopulateAdditionalHeaders(headers); - SendReport(std::move(url), body, + SendReport(std::move(url), body, std::move(headers), base::BindOnce(&AttributionReportNetworkSender::OnReportSent, base::Unretained(this), std::move(report), is_debug_report, std::move(sent_callback))); @@ -71,7 +73,7 @@ GURL url = report.ReportURL(); std::string body = SerializeAttributionJson(report.ReportBody()); SendReport( - std::move(url), body, + std::move(url), body, net::HttpRequestHeaders(), base::BindOnce(&AttributionReportNetworkSender::OnDebugReportSent, base::Unretained(this), base::BindOnce(std::move(callback), std::move(report)))); @@ -79,9 +81,11 @@ void AttributionReportNetworkSender::SendReport(GURL url, const std::string& body, + net::HttpRequestHeaders headers, UrlLoaderCallback callback) { auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = std::move(url); + resource_request->headers = std::move(headers); resource_request->method = net::HttpRequestHeaders::kPostMethod; resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; resource_request->load_flags =
diff --git a/content/browser/attribution_reporting/attribution_report_network_sender.h b/content/browser/attribution_reporting/attribution_report_network_sender.h index 83872794..bab2ac2 100644 --- a/content/browser/attribution_reporting/attribution_report_network_sender.h +++ b/content/browser/attribution_reporting/attribution_report_network_sender.h
@@ -17,6 +17,7 @@ class GURL; namespace net { +class HttpRequestHeaders; class HttpResponseHeaders; } // namespace net @@ -63,6 +64,7 @@ void SendReport(GURL url, const std::string& body, + net::HttpRequestHeaders headers, UrlLoaderCallback callback); // Called when headers are available for a sent report.
diff --git a/content/browser/attribution_reporting/attribution_report_network_sender_unittest.cc b/content/browser/attribution_reporting/attribution_report_network_sender_unittest.cc index 67ff9aee..48e4497 100644 --- a/content/browser/attribution_reporting/attribution_report_network_sender_unittest.cc +++ b/content/browser/attribution_reporting/attribution_report_network_sender_unittest.cc
@@ -655,12 +655,45 @@ const network::ResourceRequest* pending_request; EXPECT_TRUE(test_url_loader_factory_.IsPending(kAggregatableReportUrl, &pending_request)); + EXPECT_FALSE(pending_request->headers.HasHeader( + "Sec-Attribution-Reporting-Private-State-Token")); EXPECT_EQ(kExpectedReportBody, network::GetUploadData(*pending_request)); EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest( kAggregatableReportUrl, "")); } TEST_F(AttributionReportNetworkSenderTest, + ReportAttestationHeaderSetCorrectly) { + const struct { + bool is_debug_report; + const char* url; + } kTestCases[] = { + {true, kDebugAggregatableReportUrl}, + {false, kAggregatableReportUrl}, + }; + + for (const auto& test_case : kTestCases) { + AttributionReport report = + ReportBuilder( + AttributionInfoBuilder(SourceBuilder().BuildStored()).Build()) + .SetAttestationToken("attestation-token") + .BuildAggregatableAttribution(); + + network_sender_->SendReport(report, test_case.is_debug_report, + base::DoNothing()); + + const network::ResourceRequest* pending_request; + EXPECT_TRUE( + test_url_loader_factory_.IsPending(test_case.url, &pending_request)); + + std::string added_header; + pending_request->headers.GetHeader( + "Sec-Attribution-Reporting-Private-State-Token", &added_header); + EXPECT_EQ(added_header, "attestation-token"); + } +} + +TEST_F(AttributionReportNetworkSenderTest, DebugAggregatableReportSent_ReportUrlAndBodySetCorrectly) { static constexpr char kExpectedReportBody[] = R"({"aggregation_service_payloads":"not generated prior to send",)"
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.cc b/content/browser/attribution_reporting/attribution_storage_sql.cc index 094ebbd..8b1267a7 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql.cc
@@ -68,11 +68,11 @@ // Version number of the database. // TODO: remove the active_unattributed_sources_by_site_reporting_origin index // during the next DB migration. -const int AttributionStorageSql::kCurrentVersionNumber = 40; +const int AttributionStorageSql::kCurrentVersionNumber = 41; // Earliest version which can use a |kCurrentVersionNumber| database // without failing. -const int AttributionStorageSql::kCompatibleVersionNumber = 40; +const int AttributionStorageSql::kCompatibleVersionNumber = 41; // Latest version of the database that cannot be upgraded to // |kCurrentVersionNumber| without razing the database. @@ -312,6 +312,22 @@ } } +void BindStringOrNull(sql::Statement& statement, + int col, + const absl::optional<std::string>& value) { + if (value.has_value()) { + statement.BindString(col, value.value()); + } else { + statement.BindNull(col); + } +} +absl::optional<std::string> ColumnStringOrNull(sql::Statement& statement, + int col) { + return statement.GetColumnType(col) == sql::ColumnType::kNull + ? absl::nullopt + : absl::make_optional(statement.ColumnString(col)); +} + absl::optional<uint64_t> ColumnUint64OrNull(sql::Statement& statement, int col) { return statement.GetColumnType(col) == sql::ColumnType::kNull @@ -840,13 +856,6 @@ AggregatableResult::kInternalError); } - if (source_to_attribute->source.common_info() - .aggregation_keys() - .keys() - .empty()) { - aggregatable_status = AggregatableResult::kNotRegistered; - } - const bool top_level_filters_match = AttributionFiltersMatch( source_to_attribute->source.common_info().filter_data(), source_to_attribute->source.common_info().source_type(), @@ -855,10 +864,15 @@ attribution_info.emplace(std::move(source_to_attribute->source), trigger_time, trigger_registration.debug_key); + if (!top_level_filters_match) { + return assemble_report_result( + EventLevelResult::kNoMatchingSourceFilterData, + AggregatableResult::kNoMatchingSourceFilterData); + } + absl::optional<uint64_t> dedup_key; if (EventLevelResult create_event_level_status = MaybeCreateEventLevelReport( - *attribution_info, trigger, top_level_filters_match, - new_event_level_report, dedup_key, + *attribution_info, trigger, new_event_level_report, dedup_key, limits.max_event_level_reports_per_destination); create_event_level_status != EventLevelResult::kSuccess) { event_level_status = create_event_level_status; @@ -867,8 +881,7 @@ if (!aggregatable_status.has_value()) { if (AggregatableResult create_aggregatable_status = MaybeCreateAggregatableAttributionReport( - *attribution_info, trigger, top_level_filters_match, - new_aggregatable_report, + *attribution_info, trigger, new_aggregatable_report, limits.max_aggregatable_reports_per_destination); create_aggregatable_status != AggregatableResult::kSuccess) { aggregatable_status = create_aggregatable_status; @@ -1047,7 +1060,6 @@ EventLevelResult AttributionStorageSql::MaybeCreateEventLevelReport( const AttributionInfo& attribution_info, const AttributionTrigger& trigger, - const bool top_level_filters_match, absl::optional<AttributionReport>& report, absl::optional<uint64_t>& dedup_key, absl::optional<int>& max_event_level_reports_per_destination) { @@ -1058,10 +1070,6 @@ return EventLevelResult::kFalselyAttributedSource; } - if (!top_level_filters_match) { - return EventLevelResult::kNoMatchingSourceFilterData; - } - const CommonSourceInfo& common_info = attribution_info.source.common_info(); if (attribution_info.time > common_info.event_report_window_time()) { @@ -2281,7 +2289,8 @@ "report_time INTEGER NOT NULL," "failed_send_attempts INTEGER NOT NULL," "initial_report_time INTEGER NOT NULL," - "aggregation_coordinator INTEGER NOT NULL)"; + "aggregation_coordinator INTEGER NOT NULL," + "attestation_token TEXT)"; if (!db_->Execute(kAggregatableReportMetadataTableSql)) { return false; } @@ -2654,13 +2663,8 @@ AttributionStorageSql::MaybeCreateAggregatableAttributionReport( const AttributionInfo& attribution_info, const AttributionTrigger& trigger, - bool top_level_filters_match, absl::optional<AttributionReport>& report, absl::optional<int>& max_aggregatable_reports_per_destination) { - if (!top_level_filters_match) { - return AggregatableResult::kNoMatchingSourceFilterData; - } - const attribution_reporting::TriggerRegistration& trigger_registration = trigger.registration(); @@ -2708,13 +2712,24 @@ base::Time report_time = delegate_->GetAggregatableReportTime(attribution_info.time); + absl::optional<std::string> attestation_token; + + if (trigger.attestation().has_value()) { + attestation_token = trigger.attestation()->token(); + } + + base::GUID external_report_id = + trigger.attestation().has_value() + ? trigger.attestation()->aggregatable_report_id() + : delegate_->NewReportID(); report = AttributionReport( - attribution_info, report_time, delegate_->NewReportID(), + attribution_info, report_time, std::move(external_report_id), /*failed_send_attempts=*/0, AttributionReport::AggregatableAttributionData( std::move(contributions), AttributionReport::AggregatableAttributionData::Id(kUnsetReportId), - report_time, trigger_registration.aggregation_coordinator)); + report_time, trigger_registration.aggregation_coordinator, + std::move(attestation_token))); return AggregatableResult::kSuccess; } @@ -2736,8 +2751,9 @@ static constexpr char kInsertMetadataSql[] = "INSERT INTO aggregatable_report_metadata" "(source_id,trigger_time,debug_key,external_report_id,report_time," - "failed_send_attempts,initial_report_time,aggregation_coordinator)" - "VALUES(?,?,?,?,?,0,?,?)"; + "failed_send_attempts,initial_report_time,aggregation_coordinator," + "attestation_token)" + "VALUES(?,?,?,?,?,0,?,?,?)"; sql::Statement insert_metadata_statement( db_->GetCachedStatement(SQL_FROM_HERE, kInsertMetadataSql)); insert_metadata_statement.BindInt64(0, *attribution_info.source.source_id()); @@ -2751,6 +2767,8 @@ insert_metadata_statement.BindInt( 6, SerializeAggregationCoordinator( aggregatable_attribution->aggregation_coordinator)); + BindStringOrNull(insert_metadata_statement, 7, + aggregatable_attribution->attestation_token); if (!insert_metadata_statement.Run()) { return false; } @@ -2847,7 +2865,7 @@ absl::optional<AttributionReport> AttributionStorageSql::ReadAggregatableAttributionReportFromStatement( sql::Statement& statement) { - DCHECK_EQ(statement.ColumnCount(), kSourceColumnCount + 8); + DCHECK_EQ(statement.ColumnCount(), kSourceColumnCount + 9); absl::optional<StoredSourceData> source_data = ReadSourceFromStatement(statement); @@ -2870,6 +2888,9 @@ aggregation_coordinator = DeserializeAggregationCoordinator(statement.ColumnInt(col++)); + absl::optional<std::string> attestation_token = + ColumnStringOrNull(statement, col++); + // Ensure data is valid before continuing. This could happen if there is // database corruption. if (!external_report_id.is_valid() || failed_send_attempts < 0 || @@ -2883,13 +2904,13 @@ return absl::nullopt; } - return AttributionReport(AttributionInfo(std::move(source_data->source), - trigger_time, trigger_debug_key), - report_time, std::move(external_report_id), - failed_send_attempts, - AttributionReport::AggregatableAttributionData( - std::move(contributions), report_id, - initial_report_time, *aggregation_coordinator)); + return AttributionReport( + AttributionInfo(std::move(source_data->source), trigger_time, + trigger_debug_key), + report_time, std::move(external_report_id), failed_send_attempts, + AttributionReport::AggregatableAttributionData( + std::move(contributions), report_id, initial_report_time, + *aggregation_coordinator, std::move(attestation_token))); } absl::optional<AttributionReport> AttributionStorageSql::GetReport(
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.h b/content/browser/attribution_reporting/attribution_storage_sql.h index 8cdcb3e..1c34c536 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql.h +++ b/content/browser/attribution_reporting/attribution_storage_sql.h
@@ -251,7 +251,6 @@ AttributionTrigger::EventLevelResult MaybeCreateEventLevelReport( const AttributionInfo& attribution_info, const AttributionTrigger& trigger, - bool top_level_filters_match, absl::optional<AttributionReport>& report, absl::optional<uint64_t>& dedup_key, absl::optional<int>& max_event_level_reports_per_destination) @@ -349,7 +348,6 @@ MaybeCreateAggregatableAttributionReport( const AttributionInfo& attribution_info, const AttributionTrigger& trigger, - bool top_level_filters_match, absl::optional<AttributionReport>& report, absl::optional<int>& max_aggregatable_reports_per_destination) VALID_CONTEXT_REQUIRED(sequence_checker_);
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc b/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc index 1b5099e..cb94df4 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc
@@ -531,6 +531,25 @@ return transaction.Commit(); } +bool MigrateToVersion41(sql::Database* db, sql::MetaTable* meta_table) { + // Wrap each migration in its own transaction. See comment in + // `MigrateToVersion34`. + sql::Transaction transaction(db); + if (!transaction.Begin()) { + return false; + } + + static constexpr char kAddAttestationHeaderColumnSql[] = + "ALTER TABLE aggregatable_report_metadata " + "ADD COLUMN attestation_token TEXT"; + if (!db->Execute(kAddAttestationHeaderColumnSql)) { + return false; + } + + meta_table->SetVersionNumber(41); + return transaction.Commit(); +} + } // namespace bool UpgradeAttributionStorageSqlSchema(sql::Database* db, @@ -578,6 +597,11 @@ return false; } } + if (meta_table->GetVersionNumber() == 40) { + if (!MigrateToVersion41(db, meta_table)) { + return false; + } + } // Add similar if () blocks for new versions here. if (base::ThreadTicks::IsSupported()) {
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc b/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc index 5e360d6..6569b805 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc
@@ -24,9 +24,17 @@ namespace { -std::string RemoveQuotes(std::string input) { +// Normalize schema strings to compare them reliabily. Notably, applies the +// following transformations: +// - Remove quotes as sometimes migrations cause table names to be string +// literals. +// - Replaces ", " with "," as CREATE TABLE in schema will be represented with +// or without a space depending if it got there by calling CREATE TABLE +// directly or with an ALTER TABLE. +std::string NormalizeSchema(std::string input) { std::string output; base::RemoveChars(input, "\"", &output); + base::ReplaceSubstringsAfterOffset(&output, 0, ", ", ","); return output; } @@ -171,9 +179,8 @@ EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, VersionFromDatabase(&db)); - // Compare without quotes as sometimes migrations cause table names to be - // string literals. - EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); // Verify that data is not preserved across the migration. sql::Statement s( @@ -218,9 +225,8 @@ EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, VersionFromDatabase(&db)); - // Compare without quotes as sometimes migrations cause table names to be - // string literals. - EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); // Verify that data is preserved across the migration. sql::Statement s( @@ -269,9 +275,9 @@ EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, VersionFromDatabase(&db)); - // Compare without quotes as sometimes migrations cause table names to be - // string literals. - EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + // Compare normalized schemas + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); // Verify that data is preserved across the migration. sql::Statement s(db.GetUniqueStatement("SELECT * FROM rate_limits")); @@ -314,9 +320,9 @@ EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, VersionFromDatabase(&db)); - // Compare without quotes as sometimes migrations cause table names to be - // string literals. - EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + // Compare normalized schemas + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); ASSERT_FALSE(db.DoesIndexExist("sources_by_origin")); ASSERT_TRUE(db.DoesIndexExist("active_sources_by_source_origin")); @@ -356,9 +362,9 @@ EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, VersionFromDatabase(&db)); - // Compare without quotes as sometimes migrations cause table names to be - // string literals. - EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + // Compare normalized schemas + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); // Verify that data is preserved across the migration. sql::Statement s(db.GetUniqueStatement("SELECT * FROM dedup_keys")); @@ -405,9 +411,9 @@ EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, VersionFromDatabase(&db)); - // Compare without quotes as sometimes migrations cause table names to be - // string literals. - EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + // Compare normalized schemas + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); // Verify that data is preserved across the migration. sql::Statement s(db.GetUniqueStatement("SELECT * FROM sources")); @@ -455,9 +461,9 @@ EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, VersionFromDatabase(&db)); - // Compare without quotes as sometimes migrations cause table names to be - // string literals. - EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + // Compare normalized schemas + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); // Verify that data is preserved across the migration. sql::Statement s( @@ -516,7 +522,8 @@ // Compare without quotes as sometimes migrations cause table names to be // string literals. - EXPECT_EQ(RemoveQuotes(GetCurrentSchema()), RemoveQuotes(db.GetSchema())); + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); // Verify that data is preserved across the migration. sql::Statement s( @@ -542,4 +549,53 @@ histograms.ExpectTotalCount("Conversions.Storage.MigrationTime", 1); } +TEST_F(AttributionStorageSqlMigrationsTest, MigrateVersion40ToCurrent) { + base::HistogramTester histograms; + LoadDatabase(GetVersionFilePath(40), DbPath()); + + // Verify pre-conditions. + { + sql::Database db; + ASSERT_TRUE(db.Open(DbPath())); + ASSERT_FALSE(db.DoesColumnExist("aggregatable_report_metadata", + "attestation_token")); + + sql::Statement s( + db.GetUniqueStatement("SELECT * FROM aggregatable_report_metadata")); + + ASSERT_TRUE(s.Step()); + ASSERT_EQ(1, s.ColumnInt(0)); // aggregation_id + ASSERT_FALSE(s.Step()); + } + + MigrateDatabase(); + + // Verify schema is current. + { + sql::Database db; + ASSERT_TRUE(db.Open(DbPath())); + + // Check version. + EXPECT_EQ(AttributionStorageSql::kCurrentVersionNumber, + VersionFromDatabase(&db)); + + // Compare normalized schemas + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); + + // Verify that data is preserved across the migration. + sql::Statement s( + db.GetUniqueStatement("SELECT * FROM aggregatable_report_metadata")); + + ASSERT_TRUE(s.Step()); + ASSERT_EQ(1, s.ColumnInt(0)); // aggregation_id + ASSERT_EQ(sql::ColumnType::kNull, s.GetColumnType(9)); // attestation_token + ASSERT_FALSE(s.Step()); + } + + // DB creation histograms should be recorded. + histograms.ExpectTotalCount("Conversions.Storage.CreationTime", 0); + histograms.ExpectTotalCount("Conversions.Storage.MigrationTime", 1); +} + } // namespace content
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc b/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc index ceb3bd95..d6f5605c 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_unittest.cc
@@ -24,6 +24,7 @@ #include "components/aggregation_service/aggregation_service.mojom.h" #include "components/attribution_reporting/filters.h" #include "components/attribution_reporting/suitable_origin.h" +#include "components/attribution_reporting/trigger_attestation.h" #include "content/browser/attribution_reporting/aggregatable_histogram_contribution.h" #include "content/browser/attribution_reporting/attribution_report.h" #include "content/browser/attribution_reporting/attribution_reporting.pb.h" @@ -37,6 +38,7 @@ #include "sql/test/scoped_error_expecter.h" #include "sql/test/test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/storage_key/storage_key.h" namespace content { @@ -62,6 +64,7 @@ base::Time initial_report_time; int aggregation_coordinator = static_cast<int>( ::aggregation_service::mojom::AggregationCoordinator::kDefault); + absl::optional<std::string> attestation_token; }; struct AggregatableContributionRecord { @@ -167,7 +170,7 @@ static constexpr char kStoreMetadataSql[] = "INSERT INTO aggregatable_report_metadata " - "VALUES(?,?,?,?,?,?,?,?,?)"; + "VALUES(?,?,?,?,?,?,?,?,?,?)"; sql::Statement statement(raw_db.GetUniqueStatement(kStoreMetadataSql)); statement.BindInt64(0, record.aggregation_id); statement.BindInt64(1, record.source_id); @@ -182,6 +185,11 @@ statement.BindInt(6, record.failed_send_attempts); statement.BindTime(7, record.initial_report_time); statement.BindInt(8, record.aggregation_coordinator); + if (record.attestation_token.has_value()) { + statement.BindString(9, record.attestation_token.value()); + } else { + statement.BindNull(9); + } ASSERT_TRUE(statement.Run()); } @@ -317,6 +325,42 @@ ASSERT_THAT(storage()->GetAttributionReports(base::Time::Now()), IsEmpty()); } +TEST_F(AttributionStorageSqlTest, StoreAndRetrieveReportWithAttestation) { + OpenDatabase(); + + StorableSource source = TestAggregatableSourceProvider() + .GetBuilder() + .SetExpiry(base::Days(30)) + .Build(); + storage()->StoreSource(source); + + auto trigger_attestation = attribution_reporting::TriggerAttestation::Create( + /*token=*/"attestation-token", /*aggregatable_report_id=*/ + "55865da3-fb0e-4b71-965e-64fc4bf0a323"); + AttributionTrigger trigger = DefaultAggregatableTriggerBuilder() + .SetAttestation(trigger_attestation) + .Build(); + EXPECT_THAT(storage()->MaybeCreateAndStoreReport(trigger), + AllOf(CreateReportEventLevelStatusIs( + AttributionTrigger::EventLevelResult::kSuccess), + CreateReportAggregatableStatusIs( + AttributionTrigger::AggregatableResult::kSuccess))); + + AttributionReport aggregatable_report = + storage()->GetAttributionReports(base::Time::Max()).at(1); + // Should create the report with the id from the trigger attestation. + EXPECT_EQ(aggregatable_report.external_report_id(), + trigger_attestation->aggregatable_report_id()); + + // Should store the attestation token on the report. + const auto* data = + absl::get_if<AttributionReport::AggregatableAttributionData>( + &aggregatable_report.data()); + EXPECT_EQ(data->attestation_token.value(), trigger_attestation->token()); + + CloseDatabase(); +} + // Create a source with three triggers and craft a query that will target all. TEST_F(AttributionStorageSqlTest, ClearDataRangeMultipleReports) { base::HistogramTester histograms;
diff --git a/content/browser/attribution_reporting/attribution_storage_unittest.cc b/content/browser/attribution_reporting/attribution_storage_unittest.cc index 68ba6c20..d92d310 100644 --- a/content/browser/attribution_reporting/attribution_storage_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_unittest.cc
@@ -58,6 +58,7 @@ using ::testing::AllOf; using ::testing::ElementsAre; +using ::testing::Eq; using ::testing::Ge; using ::testing::IsEmpty; using ::testing::IsTrue; @@ -2705,6 +2706,7 @@ /*debug_reporting=*/false, ::aggregation_service::mojom::AggregationCoordinator::kDefault), /*destination_origin=*/origin, + /*attestation=*/absl::nullopt, /*is_within_fenced_frame=*/false))); EXPECT_THAT(storage()->GetAttributionReports(base::Time::Max()), IsEmpty()); @@ -2798,6 +2800,7 @@ /*debug_reporting=*/false, ::aggregation_service::mojom::AggregationCoordinator::kDefault), /*destination_origin=*/origin, + /*attestation=*/absl::nullopt, /*is_within_fenced_frame=*/false))); EXPECT_THAT(storage()->GetAttributionReports(base::Time::Max()), @@ -2847,7 +2850,8 @@ aggregatable_values, /*debug_reporting=*/false, ::aggregation_service::mojom::AggregationCoordinator::kDefault), - /*destination_origin=*/origin, /*is_within_fenced_frame=*/false); + /*destination_origin=*/origin, /*attestation=*/absl::nullopt, + /*is_within_fenced_frame=*/false); AttributionTrigger trigger2( /*reporting_origin=*/origin, @@ -2865,7 +2869,8 @@ aggregatable_values, /*debug_reporting=*/false, ::aggregation_service::mojom::AggregationCoordinator::kDefault), - /*destination_origin=*/origin, /*is_within_fenced_frame=*/false); + /*destination_origin=*/origin, /*attestation=*/absl::nullopt, + /*is_within_fenced_frame=*/false); AttributionTrigger trigger3( /*reporting_origin=*/origin, @@ -2882,6 +2887,7 @@ /*debug_reporting=*/false, ::aggregation_service::mojom::AggregationCoordinator::kDefault), /*destination_origin=*/origin, + /*attestation=*/absl::nullopt, /*is_within_fenced_frame=*/false); EXPECT_THAT(storage()->MaybeCreateAndStoreReport(trigger1), @@ -2921,6 +2927,25 @@ EXPECT_THAT(storage()->GetAttributionReports(base::Time::Now()), IsEmpty()); } +TEST_F(AttributionStorageTest, + AggregatableAttributionNoAggregationKeys_NoContributions) { + storage()->StoreSource(SourceBuilder().Build()); + + AttributionTrigger trigger = + DefaultAggregatableTriggerBuilder(/*histogram_values=*/{5}) + .SetTriggerData(5) + .Build(); + + EXPECT_THAT( + storage()->MaybeCreateAndStoreReport(trigger), + AllOf(CreateReportEventLevelStatusIs( + AttributionTrigger::EventLevelResult::kSuccess), + CreateReportAggregatableStatusIs( + AttributionTrigger::AggregatableResult::kNoHistograms), + NewEventLevelReportIs(Optional(EventLevelDataIs(TriggerDataIs(5)))), + NewAggregatableReportIs(Eq(absl::nullopt)))); +} + TEST_F(AttributionStorageTest, AggregatableAttribution_ReportsScheduled) { auto source_builder = TestAggregatableSourceProvider().GetBuilder(); storage()->StoreSource(source_builder.Build());
diff --git a/content/browser/attribution_reporting/attribution_test_utils.cc b/content/browser/attribution_reporting/attribution_test_utils.cc index 6e6f9e6..012107dee 100644 --- a/content/browser/attribution_reporting/attribution_test_utils.cc +++ b/content/browser/attribution_reporting/attribution_test_utils.cc
@@ -34,6 +34,7 @@ #include "content/browser/attribution_reporting/attribution_data_host_manager.h" #include "content/browser/attribution_reporting/attribution_observer.h" #include "content/browser/attribution_reporting/attribution_source_type.h" +#include "content/browser/attribution_reporting/attribution_trigger.h" #include "content/browser/attribution_reporting/rate_limit_result.h" #include "content/public/browser/attribution_config.h" #include "content/public/browser/navigation_handle.h" @@ -727,6 +728,12 @@ return *this; } +TriggerBuilder& TriggerBuilder::SetAttestation( + absl::optional<attribution_reporting::TriggerAttestation> attestation) { + attestation_ = std::move(attestation); + return *this; +} + AttributionTrigger TriggerBuilder::Build( bool generate_event_trigger_data) const { std::vector<attribution_reporting::EventTriggerData> event_triggers; @@ -756,7 +763,7 @@ *attribution_reporting::AggregatableTriggerDataList::Create( aggregatable_trigger_data_), aggregatable_values_, debug_reporting_, aggregation_coordinator_), - destination_origin_, is_within_fenced_frame_); + destination_origin_, attestation_, is_within_fenced_frame_); } AttributionInfoBuilder::AttributionInfoBuilder(StoredSource source) @@ -837,6 +844,12 @@ return *this; } +ReportBuilder& ReportBuilder::SetAttestationToken( + absl::optional<std::string> attestation_token) { + attestation_token_ = std::move(attestation_token); + return *this; +} + AttributionReport ReportBuilder::Build() const { return AttributionReport( attribution_info_, report_time_, external_report_id_, @@ -851,7 +864,7 @@ /*failed_send_attempts=*/0, AttributionReport::AggregatableAttributionData( contributions_, aggregatable_attribution_report_id_, report_time_, - aggregation_coordinator_)); + aggregation_coordinator_, attestation_token_)); } bool operator==(const AttributionTrigger& a, const AttributionTrigger& b) { @@ -948,7 +961,8 @@ const AttributionReport::AggregatableAttributionData& b) { const auto tie = [](const AttributionReport::AggregatableAttributionData& data) { - return std::make_tuple(data.contributions, data.initial_report_time); + return std::make_tuple(data.contributions, data.initial_report_time, + data.attestation_token); }; return tie(a) == tie(b); } @@ -976,158 +990,122 @@ AttributionTrigger::EventLevelResult status) { switch (status) { case AttributionTrigger::EventLevelResult::kSuccess: - out << "success"; - break; + return out << "success"; case AttributionTrigger::EventLevelResult::kSuccessDroppedLowerPriority: - out << "successDroppedLowerPriority"; - break; + return out << "successDroppedLowerPriority"; case AttributionTrigger::EventLevelResult::kInternalError: - out << "internalError"; - break; + return out << "internalError"; case AttributionTrigger::EventLevelResult:: kNoCapacityForConversionDestination: - out << "insufficientDestinationCapacity"; - break; + return out << "insufficientDestinationCapacity"; case AttributionTrigger::EventLevelResult::kNoMatchingImpressions: - out << "noMatchingSources"; - break; + return out << "noMatchingSources"; case AttributionTrigger::EventLevelResult::kDeduplicated: - out << "deduplicated"; - break; + return out << "deduplicated"; case AttributionTrigger::EventLevelResult::kExcessiveAttributions: - out << "excessiveAttributions"; - break; + return out << "excessiveAttributions"; case AttributionTrigger::EventLevelResult::kPriorityTooLow: - out << "priorityTooLow"; - break; + return out << "priorityTooLow"; case AttributionTrigger::EventLevelResult::kDroppedForNoise: - out << "noised"; - break; + return out << "noised"; case AttributionTrigger::EventLevelResult::kExcessiveReportingOrigins: - out << "excessiveReportingOrigins"; - break; + return out << "excessiveReportingOrigins"; case AttributionTrigger::EventLevelResult::kNoMatchingSourceFilterData: - out << "noMatchingSourceFilterData"; - break; + return out << "noMatchingSourceFilterData"; case AttributionTrigger::EventLevelResult::kProhibitedByBrowserPolicy: - out << "prohibitedByBrowserPolicy"; - break; + return out << "prohibitedByBrowserPolicy"; case AttributionTrigger::EventLevelResult::kNoMatchingConfigurations: - out << "noMatchingConfigurations"; - break; + return out << "noMatchingConfigurations"; case AttributionTrigger::EventLevelResult::kExcessiveReports: - out << "excessiveReports"; - break; + return out << "excessiveReports"; case AttributionTrigger::EventLevelResult::kFalselyAttributedSource: - out << "falselyAttributedSource"; - break; + return out << "falselyAttributedSource"; case AttributionTrigger::EventLevelResult::kReportWindowPassed: - out << "reportWindowPassed"; - break; + return out << "reportWindowPassed"; } - return out; } std::ostream& operator<<(std::ostream& out, AttributionTrigger::AggregatableResult status) { switch (status) { case AttributionTrigger::AggregatableResult::kSuccess: - out << "success"; - break; + return out << "success"; case AttributionTrigger::AggregatableResult::kInternalError: - out << "internalError"; - break; + return out << "internalError"; case AttributionTrigger::AggregatableResult:: kNoCapacityForConversionDestination: - out << "insufficientDestinationCapacity"; - break; + return out << "insufficientDestinationCapacity"; case AttributionTrigger::AggregatableResult::kNoMatchingImpressions: - out << "noMatchingSources"; - break; + return out << "noMatchingSources"; case AttributionTrigger::AggregatableResult::kExcessiveAttributions: - out << "excessiveAttributions"; - break; + return out << "excessiveAttributions"; case AttributionTrigger::AggregatableResult::kExcessiveReportingOrigins: - out << "excessiveReportingOrigins"; - break; + return out << "excessiveReportingOrigins"; case AttributionTrigger::AggregatableResult::kNoHistograms: - out << "noHistograms"; - break; + return out << "noHistograms"; case AttributionTrigger::AggregatableResult::kInsufficientBudget: - out << "insufficientBudget"; - break; + return out << "insufficientBudget"; case AttributionTrigger::AggregatableResult::kNoMatchingSourceFilterData: - out << "noMatchingSourceFilterData"; - break; + return out << "noMatchingSourceFilterData"; case AttributionTrigger::AggregatableResult::kNotRegistered: - out << "notRegistered"; - break; + return out << "notRegistered"; case AttributionTrigger::AggregatableResult::kProhibitedByBrowserPolicy: - out << "prohibitedByBrowserPolicy"; - break; + return out << "prohibitedByBrowserPolicy"; case AttributionTrigger::AggregatableResult::kDeduplicated: - out << "deduplicated"; - break; + return out << "deduplicated"; case AttributionTrigger::AggregatableResult::kReportWindowPassed: - out << "reportWindowPassed"; - break; + return out << "reportWindowPassed"; } - return out; } std::ostream& operator<<(std::ostream& out, RateLimitResult result) { switch (result) { case RateLimitResult::kAllowed: - out << "kAllowed"; - break; + return out << "kAllowed"; case RateLimitResult::kNotAllowed: - out << "kNotAllowed"; - break; + return out << "kNotAllowed"; case RateLimitResult::kError: - out << "kError"; - break; + return out << "kError"; } - return out; } std::ostream& operator<<(std::ostream& out, StoredSource::AttributionLogic attribution_logic) { switch (attribution_logic) { case StoredSource::AttributionLogic::kNever: - out << "kNever"; - break; + return out << "kNever"; case StoredSource::AttributionLogic::kTruthfully: - out << "kTruthfully"; - break; + return out << "kTruthfully"; case StoredSource::AttributionLogic::kFalsely: - out << "kFalsely"; - break; + return out << "kFalsely"; } - return out; } std::ostream& operator<<(std::ostream& out, StoredSource::ActiveState active_state) { switch (active_state) { case StoredSource::ActiveState::kActive: - out << "kActive"; - break; + return out << "kActive"; case StoredSource::ActiveState::kInactive: - out << "kInactive"; - break; + return out << "kInactive"; case StoredSource::ActiveState::kReachedEventLevelAttributionLimit: - out << "kReachedEventLevelAttributionLimit"; - break; + return out << "kReachedEventLevelAttributionLimit"; } - return out; } std::ostream& operator<<(std::ostream& out, const AttributionTrigger& conversion) { - return out << "{registration=" << conversion.registration() - << ",destination_origin=" << conversion.destination_origin() - << ",is_within_fenced_frame=" - << conversion.is_within_fenced_frame(); + out << "{registration=" << conversion.registration() + << ",destination_origin=" << conversion.destination_origin() + << ",is_within_fenced_frame=" << conversion.is_within_fenced_frame(); + + if (conversion.attestation().has_value()) { + out << ",attestation=" << conversion.attestation().value(); + } else { + out << ",attestation=(null)"; + } + + return out << "}"; } std::ostream& operator<<(std::ostream& out, const CommonSourceInfo& source) { @@ -1223,8 +1201,14 @@ separator = ", "; } - return out << "],id=" << *data.id - << ",initial_report_time=" << data.initial_report_time << "}"; + out << "],id=" << *data.id + << ",initial_report_time=" << data.initial_report_time; + if (data.attestation_token.has_value()) { + out << ",attestation_token=" << data.attestation_token.value(); + } else { + out << ",attestation_token=(null)"; + } + return out << "}"; } namespace { @@ -1250,34 +1234,25 @@ AttributionReport::Type report_type) { switch (report_type) { case AttributionReport::Type::kEventLevel: - out << "kEventLevel"; - break; + return out << "kEventLevel"; case AttributionReport::Type::kAggregatableAttribution: - out << "kAggregatableAttribution"; - break; + return out << "kAggregatableAttribution"; } - return out; } std::ostream& operator<<(std::ostream& out, SendResult::Status status) { switch (status) { case SendResult::Status::kSent: - out << "kSent"; - break; + return out << "kSent"; case SendResult::Status::kTransientFailure: - out << "kTransientFailure"; - break; + return out << "kTransientFailure"; case SendResult::Status::kFailure: - out << "kFailure"; - break; + return out << "kFailure"; case SendResult::Status::kDropped: - out << "kDropped"; - break; + return out << "kDropped"; case SendResult::Status::kFailedToAssemble: - out << "kFailedToAssemble"; - break; + return out << "kFailedToAssemble"; } - return out; } std::ostream& operator<<(std::ostream& out, const SendResult& info) { @@ -1417,7 +1392,9 @@ cfg.destination_origin), Property("is_within_fenced_frame", &AttributionTrigger::is_within_fenced_frame, - cfg.is_within_fenced_frame)); + cfg.is_within_fenced_frame), + Property("trigger_attestation", &AttributionTrigger::attestation, + cfg.attestation)); } std::vector<AttributionReport> GetAttributionReportsForTesting(
diff --git a/content/browser/attribution_reporting/attribution_test_utils.h b/content/browser/attribution_reporting/attribution_test_utils.h index 419d4bc..3f0f110 100644 --- a/content/browser/attribution_reporting/attribution_test_utils.h +++ b/content/browser/attribution_reporting/attribution_test_utils.h
@@ -31,6 +31,7 @@ #include "components/attribution_reporting/source_registration_error.mojom-forward.h" #include "components/attribution_reporting/suitable_origin.h" #include "components/attribution_reporting/test_utils.h" +#include "components/attribution_reporting/trigger_attestation.h" #include "components/attribution_reporting/trigger_registration.h" #include "content/browser/attribution_reporting/aggregatable_histogram_contribution.h" #include "content/browser/attribution_reporting/attribution_host.h" @@ -292,6 +293,18 @@ attribution_reporting::mojom::SourceRegistrationError), (override)); + MOCK_METHOD(void, + GetAllDataKeys, + (base::OnceCallback< + void(std::vector<AttributionManager::DataKey>)> callback), + (override)); + + MOCK_METHOD(void, + RemoveAttributionDataByDataKey, + (const AttributionManager::DataKey& data_key, + base::OnceClosure callback), + (override)); + void AddObserver(AttributionObserver* observer) override; void RemoveObserver(AttributionObserver* observer) override; AttributionDataHostManager* GetDataHostManager() override; @@ -537,6 +550,9 @@ TriggerBuilder& SetAggregationCoordinator( ::aggregation_service::mojom::AggregationCoordinator); + TriggerBuilder& SetAttestation( + absl::optional<attribution_reporting::TriggerAttestation> attestation); + AttributionTrigger Build(bool generate_event_trigger_data = true) const; private: @@ -556,6 +572,7 @@ ::aggregation_service::mojom::AggregationCoordinator aggregation_coordinator_ = ::aggregation_service::mojom::AggregationCoordinator::kDefault; + absl::optional<attribution_reporting::TriggerAttestation> attestation_; }; // Helper class to construct an `AttributionInfo` for tests using default data. @@ -604,6 +621,9 @@ ReportBuilder& SetAggregationCoordinator( ::aggregation_service::mojom::AggregationCoordinator); + ReportBuilder& SetAttestationToken( + absl::optional<std::string> attestation_token); + AttributionReport Build() const; AttributionReport BuildAggregatableAttribution() const; @@ -622,6 +642,7 @@ ::aggregation_service::mojom::AggregationCoordinator aggregation_coordinator_ = ::aggregation_service::mojom::AggregationCoordinator::kDefault; + absl::optional<std::string> attestation_token_; }; bool operator==(const AttributionTrigger& a, const AttributionTrigger& b); @@ -986,6 +1007,9 @@ registration = ::testing::_; ::testing::Matcher<const attribution_reporting::SuitableOrigin&> destination_origin = ::testing::_; + ::testing::Matcher< + const absl::optional<attribution_reporting::TriggerAttestation>&> + attestation = ::testing::_; ::testing::Matcher<bool> is_within_fenced_frame = ::testing::_;
diff --git a/content/browser/attribution_reporting/attribution_trigger.cc b/content/browser/attribution_reporting/attribution_trigger.cc index a186d21bb..7fbc37f7 100644 --- a/content/browser/attribution_reporting/attribution_trigger.cc +++ b/content/browser/attribution_reporting/attribution_trigger.cc
@@ -7,6 +7,8 @@ #include <utility> #include "components/attribution_reporting/suitable_origin.h" +#include "components/attribution_reporting/trigger_attestation.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { @@ -14,10 +16,12 @@ attribution_reporting::SuitableOrigin reporting_origin, attribution_reporting::TriggerRegistration registration, attribution_reporting::SuitableOrigin destination_origin, + absl::optional<attribution_reporting::TriggerAttestation> attestation, bool is_within_fenced_frame) : reporting_origin_(std::move(reporting_origin)), registration_(std::move(registration)), destination_origin_(std::move(destination_origin)), + attestation_(std::move(attestation)), is_within_fenced_frame_(is_within_fenced_frame) {} AttributionTrigger::AttributionTrigger(const AttributionTrigger&) = default;
diff --git a/content/browser/attribution_reporting/attribution_trigger.h b/content/browser/attribution_reporting/attribution_trigger.h index 9fafa6f..17f5fa04 100644 --- a/content/browser/attribution_reporting/attribution_trigger.h +++ b/content/browser/attribution_reporting/attribution_trigger.h
@@ -6,8 +6,10 @@ #define CONTENT_BROWSER_ATTRIBUTION_REPORTING_ATTRIBUTION_TRIGGER_H_ #include "components/attribution_reporting/suitable_origin.h" +#include "components/attribution_reporting/trigger_attestation.h" #include "components/attribution_reporting/trigger_registration.h" #include "content/common/content_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace content { @@ -64,10 +66,12 @@ kMaxValue = kReportWindowPassed, }; - AttributionTrigger(attribution_reporting::SuitableOrigin reporting_origin, - attribution_reporting::TriggerRegistration registration, - attribution_reporting::SuitableOrigin destination_origin, - bool is_within_fenced_frame); + AttributionTrigger( + attribution_reporting::SuitableOrigin reporting_origin, + attribution_reporting::TriggerRegistration registration, + attribution_reporting::SuitableOrigin destination_origin, + absl::optional<attribution_reporting::TriggerAttestation> attestation, + bool is_within_fenced_frame); AttributionTrigger(const AttributionTrigger&); AttributionTrigger& operator=(const AttributionTrigger&); @@ -93,6 +97,11 @@ bool is_within_fenced_frame() const { return is_within_fenced_frame_; } + const absl::optional<attribution_reporting::TriggerAttestation>& attestation() + const { + return attestation_; + } + private: attribution_reporting::SuitableOrigin reporting_origin_; @@ -101,6 +110,9 @@ // Origin on which this trigger was registered. attribution_reporting::SuitableOrigin destination_origin_; + // Optional token attesting to the veracity of the trigger. + absl::optional<attribution_reporting::TriggerAttestation> attestation_; + // Whether the trigger is registered within a fenced frame tree. bool is_within_fenced_frame_; };
diff --git a/content/browser/attribution_reporting/sql_queries.h b/content/browser/attribution_reporting/sql_queries.h index 90dd2b8..b4d72ea 100644 --- a/content/browser/attribution_reporting/sql_queries.h +++ b/content/browser/attribution_reporting/sql_queries.h
@@ -187,7 +187,7 @@ ATTRIBUTION_SOURCE_COLUMNS_SQL("I.") \ ",A.aggregation_id,A.trigger_time,A.report_time,A.debug_key," \ "A.external_report_id,A.failed_send_attempts,A.initial_report_time," \ - "A.aggregation_coordinator " \ + "A.aggregation_coordinator,A.attestation_token " \ "FROM aggregatable_report_metadata A " \ "JOIN sources I ON A.source_id=I.source_id "
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h index 993d4f9..0d086bd 100644 --- a/content/browser/bad_message.h +++ b/content/browser/bad_message.h
@@ -319,6 +319,9 @@ MSDH_ON_STREAM_STARTED_DISALLOWED = 292, RFH_WINDOW_CLOSE_ON_NON_OUTERMOST_FRAME = 293, RFPH_WINDOW_CLOSE_ON_NON_OUTERMOST_FRAME = 294, + BIBI_BIND_PRESSURE_MANAGER_FOR_INSECURE_ORIGIN = 295, + BIBI_BIND_PRESSURE_MANAGER_FOR_FENCED_FRAME = 296, + BIBI_BIND_PRESSURE_MANAGER_BLOCKED_BY_PERMISSIONS_POLICY = 297, // Please add new elements here. The naming convention is abbreviated class // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc index aba67ba..fe0f453 100644 --- a/content/browser/browser_context.cc +++ b/content/browser/browser_context.cc
@@ -157,15 +157,6 @@ partition_map->ForEach(std::move(callback)); } -void BrowserContext::DisposeStoragePartition( - StoragePartition* storage_partition) { - StoragePartitionImplMap* partition_map = impl()->storage_partition_map(); - if (!partition_map) - return; - - partition_map->DisposeInMemory(storage_partition); -} - size_t BrowserContext::GetLoadedStoragePartitionCount() { StoragePartitionImplMap* partition_map = impl()->storage_partition_map(); return partition_map ? partition_map->size() : 0;
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc index 11b1bc8..73c56cb 100644 --- a/content/browser/browser_interface_binders.cc +++ b/content/browser/browser_interface_binders.cc
@@ -23,7 +23,6 @@ #include "content/browser/browser_context_impl.h" #include "content/browser/browser_main_loop.h" #include "content/browser/browsing_topics/browsing_topics_document_host.h" -#include "content/browser/compute_pressure/pressure_service_impl.h" #include "content/browser/contacts/contacts_manager_impl.h" #include "content/browser/content_index/content_index_service_impl.h" #include "content/browser/cookie_store/cookie_store_manager.h" @@ -93,11 +92,14 @@ #include "media/mojo/mojom/video_decode_perf_history.mojom.h" #include "media/mojo/mojom/webrtc_video_perf.mojom.h" #include "media/mojo/services/webrtc_video_perf_recorder.h" +#include "mojo/public/cpp/bindings/message.h" #include "services/device/public/mojom/battery_monitor.mojom.h" +#include "services/device/public/mojom/pressure_manager.mojom.h" #include "services/device/public/mojom/sensor_provider.mojom.h" #include "services/device/public/mojom/vibration_manager.mojom.h" #include "services/metrics/public/mojom/ukm_interface.mojom.h" #include "services/metrics/ukm_recorder_interface.h" +#include "services/network/public/cpp/is_potentially_trustworthy.h" #include "services/network/public/mojom/p2p.mojom.h" #include "services/network/public/mojom/restricted_cookie_manager.mojom.h" #include "services/shape_detection/public/mojom/barcodedetection_provider.mojom.h" @@ -116,7 +118,6 @@ #include "third_party/blink/public/mojom/buckets/bucket_manager_host.mojom.h" #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom.h" #include "third_party/blink/public/mojom/choosers/color_chooser.mojom.h" -#include "third_party/blink/public/mojom/compute_pressure/pressure_service.mojom.h" #include "third_party/blink/public/mojom/contacts/contacts_manager.mojom.h" #include "third_party/blink/public/mojom/content_index/content_index.mojom.h" #include "third_party/blink/public/mojom/cookie_store/cookie_store.mojom.h" @@ -148,6 +149,7 @@ #include "third_party/blink/public/mojom/payments/payment_credential.mojom.h" #include "third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom.h" #include "third_party/blink/public/mojom/permissions/permission.mojom.h" +#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h" #include "third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom.h" #include "third_party/blink/public/mojom/preloading/anchor_element_interaction_host.mojom.h" #include "third_party/blink/public/mojom/prerender/prerender.mojom.h" @@ -602,6 +604,39 @@ GetDeviceService().BindBatteryMonitor(std::move(receiver)); } +void BindPressureManager( + RenderFrameHostImpl* host, + mojo::PendingReceiver<device::mojom::PressureManager> receiver) { + if (!network::IsOriginPotentiallyTrustworthy( + host->GetLastCommittedOrigin())) { + bad_message::ReceivedBadMessage( + host->GetProcess(), bad_message::BadMessageReason:: + BIBI_BIND_PRESSURE_MANAGER_FOR_INSECURE_ORIGIN); + return; + } + + if (host->IsNestedWithinFencedFrame()) { + // The renderer is supposed to disallow the use of compute pressure API + // when inside a fenced frame. Anything getting past the renderer checks + // must be marked as a bad request. + bad_message::ReceivedBadMessage( + host->GetProcess(), bad_message::BadMessageReason:: + BIBI_BIND_PRESSURE_MANAGER_FOR_FENCED_FRAME); + return; + } + + if (!host->IsFeatureEnabled( + blink::mojom::PermissionsPolicyFeature::kComputePressure)) { + bad_message::ReceivedBadMessage( + host->GetProcess(), + bad_message::BadMessageReason:: + BIBI_BIND_PRESSURE_MANAGER_BLOCKED_BY_PERMISSIONS_POLICY); + return; + } + + GetDeviceService().BindPressureManager(std::move(receiver)); +} + DevicePostureProviderBinder& GetDevicePostureProviderBinderOverride() { static base::NoDestructor<DevicePostureProviderBinder> binder; return *binder; @@ -673,8 +708,8 @@ } if (base::FeatureList::IsEnabled(blink::features::kComputePressure)) { - map->Add<blink::mojom::PressureService>(base::BindRepeating( - &PressureServiceImpl::Create, base::Unretained(host))); + map->Add<device::mojom::PressureManager>( + base::BindRepeating(&BindPressureManager, base::Unretained(host))); } map->Add<blink::mojom::ContactsManager>(
diff --git a/content/browser/compute_pressure/COMMON_METADATA b/content/browser/compute_pressure/COMMON_METADATA deleted file mode 100644 index 47735de..0000000 --- a/content/browser/compute_pressure/COMMON_METADATA +++ /dev/null
@@ -1,4 +0,0 @@ -monorail { - component: "Blink>PerformanceAPIs>ComputePressure" -} -team_email: "device-dev@chromium.org"
diff --git a/content/browser/compute_pressure/DIR_METADATA b/content/browser/compute_pressure/DIR_METADATA index d2b9158..2bcea0be 100644 --- a/content/browser/compute_pressure/DIR_METADATA +++ b/content/browser/compute_pressure/DIR_METADATA
@@ -1 +1 @@ -mixins: "//content/browser/compute_pressure/COMMON_METADATA" +mixins: "//services/device/compute_pressure/COMMON_METADATA"
diff --git a/content/browser/compute_pressure/compute_pressure_unittest.cc b/content/browser/compute_pressure/compute_pressure_unittest.cc new file mode 100644 index 0000000..cdbaf96d --- /dev/null +++ b/content/browser/compute_pressure/compute_pressure_unittest.cc
@@ -0,0 +1,315 @@ +// Copyright 2021 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <vector> + +#include "base/barrier_closure.h" +#include "base/functional/callback_helpers.h" +#include "base/memory/raw_ref.h" +#include "base/run_loop.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/test_future.h" +#include "base/time/time.h" +#include "content/browser/renderer_host/render_frame_host_impl.h" +#include "content/public/test/navigation_simulator.h" +#include "content/test/test_render_frame_host.h" +#include "content/test/test_render_view_host.h" +#include "content/test/test_web_contents.h" +#include "services/device/public/cpp/test/scoped_pressure_manager_overrider.h" +#include "services/device/public/mojom/pressure_manager.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/permissions_policy/permissions_policy.h" +#include "third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h" +#include "url/gurl.h" + +namespace content { + +using device::mojom::PressureFactor; +using device::mojom::PressureState; +using device::mojom::PressureStatus; +using device::mojom::PressureUpdate; + +namespace { + +constexpr base::TimeDelta kSampleInterval = base::Seconds(1); + +// Synchronous proxy to a device::mojom::PressureManager. +class PressureManagerSync { + public: + explicit PressureManagerSync(device::mojom::PressureManager* manager) + : manager_(*manager) { + DCHECK(manager); + } + ~PressureManagerSync() = default; + + PressureManagerSync(const PressureManagerSync&) = delete; + PressureManagerSync& operator=(const PressureManagerSync&) = delete; + + PressureStatus AddClient( + mojo::PendingRemote<device::mojom::PressureClient> client) { + base::test::TestFuture<PressureStatus> future; + manager_->AddClient(std::move(client), future.GetCallback()); + return future.Get(); + } + + private: + // The reference is immutable, so accessing it is thread-safe. The referenced + // device::mojom::PressureManager implementation is called synchronously, + // so it's acceptable to rely on its own thread-safety checks. + const raw_ref<device::mojom::PressureManager> manager_; +}; + +// Test double for PressureClient that records all updates. +class FakePressureClient : public device::mojom::PressureClient { + public: + FakePressureClient() : receiver_(this) {} + ~FakePressureClient() override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + } + + FakePressureClient(const FakePressureClient&) = delete; + FakePressureClient& operator=(const FakePressureClient&) = delete; + + // device::mojom::PressureClient implementation. + void OnPressureUpdated(device::mojom::PressureUpdatePtr state) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + updates_.push_back(*state); + if (update_callback_) { + std::move(update_callback_).Run(); + update_callback_.Reset(); + } + } + + std::vector<PressureUpdate>& updates() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return updates_; + } + + void SetNextUpdateCallback(base::OnceClosure callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!update_callback_) << " already called before update received"; + + update_callback_ = std::move(callback); + } + + void WaitForUpdate() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + base::RunLoop run_loop; + SetNextUpdateCallback(run_loop.QuitClosure()); + run_loop.Run(); + } + + static void WaitForUpdates( + std::initializer_list<FakePressureClient*> clients) { + base::RunLoop run_loop; + base::RepeatingClosure update_barrier = + base::BarrierClosure(clients.size(), run_loop.QuitClosure()); + for (FakePressureClient* client : clients) { + client->SetNextUpdateCallback(update_barrier); + } + run_loop.Run(); + } + + mojo::PendingRemote<device::mojom::PressureClient> + BindNewPipeAndPassRemote() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return receiver_.BindNewPipeAndPassRemote(); + } + + private: + SEQUENCE_CHECKER(sequence_checker_); + + std::vector<PressureUpdate> updates_ GUARDED_BY_CONTEXT(sequence_checker_); + + // Used to implement WaitForUpdate(). + base::OnceClosure update_callback_ GUARDED_BY_CONTEXT(sequence_checker_); + + mojo::Receiver<device::mojom::PressureClient> receiver_ + GUARDED_BY_CONTEXT(sequence_checker_); +}; + +} // namespace + +class ComputePressureTest : public RenderViewHostImplTestHarness { + public: + ComputePressureTest() { + scoped_feature_list_.InitAndEnableFeature( + blink::features::kComputePressure); + } + + ~ComputePressureTest() override = default; + + ComputePressureTest(const ComputePressureTest&) = delete; + ComputePressureTest& operator=(const ComputePressureTest&) = delete; + + void SetUp() override { + RenderViewHostImplTestHarness::SetUp(); + NavigateAndCommit(kTestUrl); + + SetComputePressureTest(); + } + + void TearDown() override { + pressure_manager_sync_.reset(); + pressure_manager_overrider_.reset(); + task_environment()->RunUntilIdle(); + + RenderViewHostImplTestHarness::TearDown(); + } + + void SetComputePressureTest() { + pressure_manager_overrider_ = + std::make_unique<device::ScopedPressureManagerOverrider>(); + pressure_manager_.reset(); + RenderFrameHostImpl* rfh = + static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()); + mojo::Receiver<blink::mojom::BrowserInterfaceBroker>& bib = + rfh->browser_interface_broker_receiver_for_testing(); + blink::mojom::BrowserInterfaceBroker* broker = bib.internal_state()->impl(); + broker->GetInterface(pressure_manager_.BindNewPipeAndPassReceiver()); + pressure_manager_sync_ = + std::make_unique<PressureManagerSync>(pressure_manager_.get()); + task_environment()->RunUntilIdle(); + } + + protected: + const GURL kTestUrl{"https://example.com/compute_pressure.html"}; + const GURL kInsecureUrl{"http://example.com/compute_pressure.html"}; + + base::test::ScopedFeatureList scoped_feature_list_; + + mojo::Remote<device::mojom::PressureManager> pressure_manager_; + std::unique_ptr<PressureManagerSync> pressure_manager_sync_; + std::unique_ptr<device::ScopedPressureManagerOverrider> + pressure_manager_overrider_; +}; + +TEST_F(ComputePressureTest, AddClient) { + FakePressureClient client; + ASSERT_EQ( + pressure_manager_sync_->AddClient(client.BindNewPipeAndPassRemote()), + PressureStatus::kOk); + + const base::Time time = base::Time::Now(); + PressureUpdate update(PressureState::kNominal, {PressureFactor::kThermal}, + time); + pressure_manager_overrider_->UpdateClients(update); + client.WaitForUpdate(); + ASSERT_EQ(client.updates().size(), 1u); + EXPECT_EQ(client.updates()[0], update); +} + +TEST_F(ComputePressureTest, UpdatePressureFactors) { + FakePressureClient client; + ASSERT_EQ( + pressure_manager_sync_->AddClient(client.BindNewPipeAndPassRemote()), + PressureStatus::kOk); + + const base::Time time = base::Time::Now(); + PressureUpdate update1(PressureState::kNominal, + {PressureFactor::kPowerSupply}, time); + + pressure_manager_overrider_->UpdateClients(update1); + client.WaitForUpdate(); + ASSERT_EQ(client.updates().size(), 1u); + EXPECT_EQ(client.updates()[0], update1); + client.updates().clear(); + + PressureUpdate update2( + PressureState::kCritical, + {PressureFactor::kThermal, PressureFactor::kPowerSupply}, + time + kSampleInterval); + pressure_manager_overrider_->UpdateClients(update2); + client.WaitForUpdate(); + ASSERT_EQ(client.updates().size(), 1u); + EXPECT_EQ(client.updates()[0], update2); + client.updates().clear(); + + PressureUpdate update3(PressureState::kCritical, {PressureFactor::kThermal}, + time + kSampleInterval * 2); + pressure_manager_overrider_->UpdateClients(update3); + client.WaitForUpdate(); + ASSERT_EQ(client.updates().size(), 1u); + EXPECT_EQ(client.updates()[0], update3); + client.updates().clear(); +} + +TEST_F(ComputePressureTest, AddClient_NotSupported) { + pressure_manager_overrider_->set_is_supported(false); + + FakePressureClient client; + EXPECT_EQ( + pressure_manager_sync_->AddClient(client.BindNewPipeAndPassRemote()), + PressureStatus::kNotSupported); +} + +TEST_F(ComputePressureTest, InsecureOrigin) { + NavigateAndCommit(kInsecureUrl); + + SetComputePressureTest(); + EXPECT_EQ(1, process()->bad_msg_count()); +} + +TEST_F(ComputePressureTest, PermissionsPolicyBlock) { + // Make compute pressure blocked by permissions policy and it can only be + // made once on page load, so we refresh the page to simulate that. + RenderFrameHost* rfh = + static_cast<RenderFrameHost*>(contents()->GetPrimaryMainFrame()); + blink::ParsedPermissionsPolicy permissions_policy(1); + permissions_policy[0].feature = + blink::mojom::PermissionsPolicyFeature::kComputePressure; + auto navigation_simulator = NavigationSimulator::CreateRendererInitiated( + rfh->GetLastCommittedURL(), rfh); + navigation_simulator->SetPermissionsPolicyHeader(permissions_policy); + navigation_simulator->Commit(); + + SetComputePressureTest(); + EXPECT_EQ(1, process()->bad_msg_count()); +} + +class ComputePressureFencedFrameTest : public ComputePressureTest { + public: + ComputePressureFencedFrameTest() { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + blink::features::kFencedFrames, {{"implementation_type", "mparch"}}); + } + ~ComputePressureFencedFrameTest() override = default; + + protected: + RenderFrameHost* CreateFencedFrame(RenderFrameHost* parent) { + RenderFrameHost* fenced_frame = + RenderFrameHostTester::For(parent)->AppendFencedFrame(); + return fenced_frame; + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +TEST_F(ComputePressureFencedFrameTest, AccessFromFencedFrame) { + auto* fenced_frame_rfh = CreateFencedFrame(contents()->GetPrimaryMainFrame()); + // Secure origin check will fail if the RenderFrameHost* passed to it has + // not navigated to a secure origin, so we need to create a navigation here. + auto navigation_simulator = NavigationSimulator::CreateRendererInitiated( + GURL("https://fencedframe.com"), fenced_frame_rfh); + navigation_simulator->Commit(); + fenced_frame_rfh = static_cast<RenderFrameHostImpl*>( + navigation_simulator->GetFinalRenderFrameHost()); + + mojo::Remote<device::mojom::PressureManager> fenced_frame_pressure_manager; + mojo::Receiver<blink::mojom::BrowserInterfaceBroker>& bib = + static_cast<RenderFrameHostImpl*>(fenced_frame_rfh) + ->browser_interface_broker_receiver_for_testing(); + blink::mojom::BrowserInterfaceBroker* broker = bib.internal_state()->impl(); + broker->GetInterface( + fenced_frame_pressure_manager.BindNewPipeAndPassReceiver()); + EXPECT_EQ(1, static_cast<TestRenderFrameHost*>(fenced_frame_rfh) + ->GetProcess() + ->bad_msg_count()); +} + +} // namespace content
diff --git a/content/browser/compute_pressure/pressure_service_impl.cc b/content/browser/compute_pressure/pressure_service_impl.cc deleted file mode 100644 index 33ff00d..0000000 --- a/content/browser/compute_pressure/pressure_service_impl.cc +++ /dev/null
@@ -1,161 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/compute_pressure/pressure_service_impl.h" - -#include <utility> - -#include "base/memory/ptr_util.h" -#include "content/public/browser/device_service.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents.h" -#include "mojo/public/cpp/bindings/message.h" -#include "services/network/public/cpp/is_potentially_trustworthy.h" -#include "third_party/blink/public/common/features.h" -#include "third_party/blink/public/mojom/compute_pressure/pressure_service.mojom.h" -#include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h" - -namespace content { - -// static -void PressureServiceImpl::Create( - RenderFrameHost* render_frame_host, - mojo::PendingReceiver<blink::mojom::PressureService> receiver) { - if (!network::IsOriginPotentiallyTrustworthy( - render_frame_host->GetLastCommittedOrigin())) { - mojo::ReportBadMessage("Compute Pressure access from an insecure origin"); - return; - } - - GetOrCreateForCurrentDocument(render_frame_host) - ->BindReceiver(std::move(receiver)); -} - -PressureServiceImpl::PressureServiceImpl(RenderFrameHost* render_frame_host) - : DocumentUserData<PressureServiceImpl>(render_frame_host) { - DCHECK(render_frame_host); -} - -PressureServiceImpl::~PressureServiceImpl() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); -} - -void PressureServiceImpl::BindReceiver( - mojo::PendingReceiver<blink::mojom::PressureService> receiver) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (receiver_.is_bound()) { - mojo::ReportBadMessage("PressureService is already connected"); - return; - } - receiver_.Bind(std::move(receiver)); - // base::Unretained is safe because Mojo guarantees the callback will not - // be called after `observers_` is deallocated, and `observers_` is owned by - // this class. - receiver_.set_disconnect_handler( - base::BindRepeating(&PressureServiceImpl::OnServiceReceiverDisconnected, - base::Unretained(this))); -} - -void PressureServiceImpl::BindObserver( - mojo::PendingRemote<blink::mojom::PressureObserver> observer, - BindObserverCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!render_frame_host().IsActive() || - render_frame_host().IsNestedWithinFencedFrame()) { - std::move(callback).Run(blink::mojom::PressureStatus::kNotSupported); - return; - } - - if (!remote_.is_bound()) { - auto receiver = remote_.BindNewPipeAndPassReceiver(); - // base::Unretained is safe because Mojo guarantees the callback will not - // be called after `remote_` is deallocated, and `remote_` is owned by - // this class. - remote_.set_disconnect_handler( - base::BindRepeating(&PressureServiceImpl::OnManagerRemoteDisconnected, - base::Unretained(this))); - GetDeviceService().BindPressureManager(std::move(receiver)); - } - - ResetObserverState(); - - observer_.Bind(std::move(observer)); - // base::Unretained is safe because Mojo guarantees the callback will not - // be called after `observers_` is deallocated, and `observers_` is owned by - // this class. - observer_.set_disconnect_handler( - base::BindRepeating(&PressureServiceImpl::OnObserverRemoteDisconnected, - base::Unretained(this))); - - client_.reset(); - remote_->AddClient( - client_.BindNewPipeAndPassRemote(), - base::BindOnce(&PressureServiceImpl::DidBindObserver, - base::Unretained(this), std::move(callback))); - - // base::Unretained is safe because Mojo guarantees the callback will not - // be called after `client_` is deallocated, and `client_` is owned by - // this class. - client_.set_disconnect_handler(base::BindOnce( - &PressureServiceImpl::ResetObserverState, base::Unretained(this))); -} - -// TODO(crbug.com/1391848): PressureUpdate can be sent from PressureManagerImpl -// to PressureObserverManager directly, because PressureUpdate is not filtered -// in PressureServiceImpl any more. -void PressureServiceImpl::PressureStateChanged( - device::mojom::PressureUpdatePtr update) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - observer_->OnUpdate(update.Clone()); -} - -void PressureServiceImpl::OnObserverRemoteDisconnected() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - client_.reset(); - ResetObserverState(); -} - -void PressureServiceImpl::OnManagerRemoteDisconnected() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - observer_.reset(); - client_.reset(); - remote_.reset(); -} - -void PressureServiceImpl::OnServiceReceiverDisconnected() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - receiver_.reset(); - observer_.reset(); - client_.reset(); - remote_.reset(); -} - -void PressureServiceImpl::DidBindObserver(BindObserverCallback callback, - bool success) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!success) { - std::move(callback).Run(blink::mojom::PressureStatus::kNotSupported); - ResetObserverState(); - return; - } - - std::move(callback).Run(blink::mojom::PressureStatus::kOk); -} - -void PressureServiceImpl::ResetObserverState() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - observer_.reset(); -} - -DOCUMENT_USER_DATA_KEY_IMPL(PressureServiceImpl); - -} // namespace content
diff --git a/content/browser/compute_pressure/pressure_service_impl.h b/content/browser/compute_pressure/pressure_service_impl.h deleted file mode 100644 index 4e6e497d8..0000000 --- a/content/browser/compute_pressure/pressure_service_impl.h +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_COMPUTE_PRESSURE_PRESSURE_SERVICE_IMPL_H_ -#define CONTENT_BROWSER_COMPUTE_PRESSURE_PRESSURE_SERVICE_IMPL_H_ - -#include "base/functional/callback.h" -#include "base/sequence_checker.h" -#include "base/thread_annotations.h" -#include "base/time/time.h" -#include "content/common/content_export.h" -#include "content/public/browser/document_user_data.h" -#include "mojo/public/cpp/bindings/receiver.h" -#include "mojo/public/cpp/bindings/remote.h" -#include "services/device/public/mojom/pressure_manager.mojom.h" -#include "services/device/public/mojom/pressure_update.mojom.h" -#include "third_party/blink/public/mojom/compute_pressure/pressure_service.mojom.h" - -namespace content { - -class RenderFrameHost; - -// Serves all the Compute Pressure API mojo requests for a frame. -// RenderFrameHostImpl owns an instance of this class. -// -// This class is not thread-safe, so each instance must be used on one sequence. -class CONTENT_EXPORT PressureServiceImpl - : public blink::mojom::PressureService, - public device::mojom::PressureClient, - public DocumentUserData<PressureServiceImpl> { - public: - static void Create( - RenderFrameHost* render_frame_host, - mojo::PendingReceiver<blink::mojom::PressureService> receiver); - - ~PressureServiceImpl() override; - - PressureServiceImpl(const PressureServiceImpl&) = delete; - PressureServiceImpl& operator=(const PressureServiceImpl&) = delete; - - void BindReceiver( - mojo::PendingReceiver<blink::mojom::PressureService> receiver); - - // blink::mojom::PressureService implementation. - void BindObserver( - mojo::PendingRemote<blink::mojom::PressureObserver> observer, - BindObserverCallback callback) override; - - // device::mojom::PressureClient implementation. - void PressureStateChanged(device::mojom::PressureUpdatePtr update) override; - - private: - explicit PressureServiceImpl(RenderFrameHost* render_frame_host); - - void OnObserverRemoteDisconnected(); - - void OnManagerRemoteDisconnected(); - - void OnServiceReceiverDisconnected(); - - void DidBindObserver(BindObserverCallback callback, bool success); - - // Resets the state used to dispatch updates to observer. - void ResetObserverState(); - - SEQUENCE_CHECKER(sequence_checker_); - - // Callback from |receiver_| is passed to |remote_| and the Receiver - // should be destroyed first so that the callback is invalidated before - // being discarded. - mojo::Remote<device::mojom::PressureManager> remote_ - GUARDED_BY_CONTEXT(sequence_checker_); - mojo::Receiver<device::mojom::PressureClient> GUARDED_BY_CONTEXT( - sequence_checker_) client_{this}; - - mojo::Remote<blink::mojom::PressureObserver> observer_ - GUARDED_BY_CONTEXT(sequence_checker_); - mojo::Receiver<blink::mojom::PressureService> GUARDED_BY_CONTEXT( - sequence_checker_) receiver_{this}; - - friend DocumentUserData; - DOCUMENT_USER_DATA_KEY_DECL(); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_COMPUTE_PRESSURE_PRESSURE_SERVICE_IMPL_H_
diff --git a/content/browser/compute_pressure/pressure_service_impl_unittest.cc b/content/browser/compute_pressure/pressure_service_impl_unittest.cc deleted file mode 100644 index 1beb49df..0000000 --- a/content/browser/compute_pressure/pressure_service_impl_unittest.cc +++ /dev/null
@@ -1,346 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/compute_pressure/pressure_service_impl.h" - -#include <vector> - -#include "base/barrier_closure.h" -#include "base/functional/callback_helpers.h" -#include "base/memory/raw_ref.h" -#include "base/run_loop.h" -#include "base/test/bind.h" -#include "base/test/scoped_feature_list.h" -#include "base/test/test_future.h" -#include "base/time/time.h" -#include "content/browser/renderer_host/render_frame_host_impl.h" -#include "content/public/test/navigation_simulator.h" -#include "content/test/test_render_view_host.h" -#include "content/test/test_web_contents.h" -#include "mojo/public/cpp/test_support/fake_message_dispatch_context.h" -#include "mojo/public/cpp/test_support/test_utils.h" -#include "services/device/public/cpp/test/scoped_pressure_manager_overrider.h" -#include "services/device/public/mojom/pressure_manager.mojom.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/public/mojom/compute_pressure/pressure_service.mojom.h" -#include "url/gurl.h" - -namespace content { - -using device::mojom::PressureFactor; -using device::mojom::PressureState; -using device::mojom::PressureUpdate; - -namespace { - -constexpr base::TimeDelta kSampleInterval = base::Seconds(1); - -// Synchronous proxy to a blink::mojom::PressureService. -class PressureServiceImplSync { - public: - explicit PressureServiceImplSync(blink::mojom::PressureService* service) - : service_(*service) { - DCHECK(service); - } - ~PressureServiceImplSync() = default; - - PressureServiceImplSync(const PressureServiceImplSync&) = delete; - PressureServiceImplSync& operator=(const PressureServiceImplSync&) = delete; - - blink::mojom::PressureStatus BindObserver( - mojo::PendingRemote<blink::mojom::PressureObserver> observer) { - base::test::TestFuture<blink::mojom::PressureStatus> future; - service_->BindObserver(std::move(observer), future.GetCallback()); - return future.Get(); - } - - private: - // The reference is immutable, so accessing it is thread-safe. The referenced - // blink::mojom::PressureService implementation is called synchronously, - // so it's acceptable to rely on its own thread-safety checks. - const raw_ref<blink::mojom::PressureService> service_; -}; - -// Test double for PressureObserver that records all updates. -class FakePressureObserver : public blink::mojom::PressureObserver { - public: - FakePressureObserver() : receiver_(this) {} - ~FakePressureObserver() override { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - } - - FakePressureObserver(const FakePressureObserver&) = delete; - FakePressureObserver& operator=(const FakePressureObserver&) = delete; - - // blink::mojom::PressureObserver implementation. - void OnUpdate(device::mojom::PressureUpdatePtr state) override { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - updates_.push_back(*state); - if (update_callback_) { - std::move(update_callback_).Run(); - update_callback_.Reset(); - } - } - - std::vector<PressureUpdate>& updates() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return updates_; - } - - void SetNextUpdateCallback(base::OnceClosure callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!update_callback_) << " already called before update received"; - - update_callback_ = std::move(callback); - } - - void WaitForUpdate() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - base::RunLoop run_loop; - SetNextUpdateCallback(run_loop.QuitClosure()); - run_loop.Run(); - } - - static void WaitForUpdates( - std::initializer_list<FakePressureObserver*> observers) { - base::RunLoop run_loop; - base::RepeatingClosure update_barrier = - base::BarrierClosure(observers.size(), run_loop.QuitClosure()); - for (FakePressureObserver* observer : observers) - observer->SetNextUpdateCallback(update_barrier); - run_loop.Run(); - } - - mojo::PendingRemote<blink::mojom::PressureObserver> - BindNewPipeAndPassRemote() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return receiver_.BindNewPipeAndPassRemote(); - } - - private: - SEQUENCE_CHECKER(sequence_checker_); - - std::vector<PressureUpdate> updates_ GUARDED_BY_CONTEXT(sequence_checker_); - - // Used to implement WaitForUpdate(). - base::OnceClosure update_callback_ GUARDED_BY_CONTEXT(sequence_checker_); - - mojo::Receiver<blink::mojom::PressureObserver> receiver_ - GUARDED_BY_CONTEXT(sequence_checker_); -}; - -} // namespace - -class PressureServiceImplTest : public RenderViewHostImplTestHarness { - public: - PressureServiceImplTest() { - scoped_feature_list_.InitAndEnableFeature( - blink::features::kComputePressure); - } - - ~PressureServiceImplTest() override = default; - - PressureServiceImplTest(const PressureServiceImplTest&) = delete; - PressureServiceImplTest& operator=(const PressureServiceImplTest&) = delete; - - void SetUp() override { - RenderViewHostImplTestHarness::SetUp(); - NavigateAndCommit(kTestUrl); - - SetPressureServiceImpl(); - } - - void TearDown() override { - pressure_service_impl_sync_.reset(); - pressure_manager_overrider_.reset(); - task_environment()->RunUntilIdle(); - - RenderViewHostImplTestHarness::TearDown(); - } - - void SetPressureServiceImpl() { - pressure_manager_overrider_ = - std::make_unique<device::ScopedPressureManagerOverrider>(); - pressure_service_.reset(); - PressureServiceImpl::Create(contents()->GetPrimaryMainFrame(), - pressure_service_.BindNewPipeAndPassReceiver()); - pressure_service_impl_sync_ = - std::make_unique<PressureServiceImplSync>(pressure_service_.get()); - } - - protected: - const GURL kTestUrl{"https://example.com/compute_pressure.html"}; - const GURL kInsecureUrl{"http://example.com/compute_pressure.html"}; - - base::test::ScopedFeatureList scoped_feature_list_; - - mojo::Remote<blink::mojom::PressureService> pressure_service_; - std::unique_ptr<PressureServiceImplSync> pressure_service_impl_sync_; - std::unique_ptr<device::ScopedPressureManagerOverrider> - pressure_manager_overrider_; -}; - -TEST_F(PressureServiceImplTest, BindObserver) { - FakePressureObserver observer; - ASSERT_EQ(pressure_service_impl_sync_->BindObserver( - observer.BindNewPipeAndPassRemote()), - blink::mojom::PressureStatus::kOk); - - const base::Time time = base::Time::Now(); - PressureUpdate update(PressureState::kNominal, {PressureFactor::kThermal}, - time); - pressure_manager_overrider_->UpdateClients(update); - observer.WaitForUpdate(); - ASSERT_EQ(observer.updates().size(), 1u); - EXPECT_EQ(observer.updates()[0], update); -} - -TEST_F(PressureServiceImplTest, UpdatePressureFactors) { - FakePressureObserver observer; - ASSERT_EQ(pressure_service_impl_sync_->BindObserver( - observer.BindNewPipeAndPassRemote()), - blink::mojom::PressureStatus::kOk); - - const base::Time time = base::Time::Now(); - PressureUpdate update1(PressureState::kNominal, - {PressureFactor::kPowerSupply}, time); - - pressure_manager_overrider_->UpdateClients(update1); - observer.WaitForUpdate(); - ASSERT_EQ(observer.updates().size(), 1u); - EXPECT_EQ(observer.updates()[0], update1); - observer.updates().clear(); - - PressureUpdate update2( - PressureState::kCritical, - {PressureFactor::kThermal, PressureFactor::kPowerSupply}, - time + kSampleInterval); - pressure_manager_overrider_->UpdateClients(update2); - observer.WaitForUpdate(); - ASSERT_EQ(observer.updates().size(), 1u); - EXPECT_EQ(observer.updates()[0], update2); - observer.updates().clear(); - - PressureUpdate update3(PressureState::kCritical, {PressureFactor::kThermal}, - time + kSampleInterval * 2); - pressure_manager_overrider_->UpdateClients(update3); - observer.WaitForUpdate(); - ASSERT_EQ(observer.updates().size(), 1u); - EXPECT_EQ(observer.updates()[0], update3); - observer.updates().clear(); -} - -class PressureServiceImplFencedFrameTest : public PressureServiceImplTest { - public: - PressureServiceImplFencedFrameTest() { - scoped_feature_list_.InitAndEnableFeatureWithParameters( - blink::features::kFencedFrames, {{"implementation_type", "mparch"}}); - } - ~PressureServiceImplFencedFrameTest() override = default; - - protected: - RenderFrameHost* CreateFencedFrame(RenderFrameHost* parent) { - RenderFrameHost* fenced_frame = - RenderFrameHostTester::For(parent)->AppendFencedFrame(); - return fenced_frame; - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - -TEST_F(PressureServiceImplFencedFrameTest, BindObserverFromFencedFrame) { - auto* fenced_frame_rfh = CreateFencedFrame(contents()->GetPrimaryMainFrame()); - // PressureServiceImpl::Create() will fail if the RenderFrameHost* passed to - // it has not navigated to a secure origin, so we need to create a navigation - // here. - auto navigation_simulator = NavigationSimulator::CreateRendererInitiated( - GURL("https://fencedframe.com"), fenced_frame_rfh); - navigation_simulator->Commit(); - fenced_frame_rfh = static_cast<RenderFrameHostImpl*>( - navigation_simulator->GetFinalRenderFrameHost()); - - mojo::Remote<blink::mojom::PressureService> fenced_frame_pressure_service; - PressureServiceImpl::Create( - fenced_frame_rfh, - fenced_frame_pressure_service.BindNewPipeAndPassReceiver()); - ASSERT_TRUE(fenced_frame_pressure_service.is_bound()); - - auto fenced_frame_sync_service = std::make_unique<PressureServiceImplSync>( - fenced_frame_pressure_service.get()); - FakePressureObserver observer; - EXPECT_EQ(fenced_frame_sync_service->BindObserver( - observer.BindNewPipeAndPassRemote()), - blink::mojom::PressureStatus::kNotSupported); -} - -TEST_F(PressureServiceImplTest, BindObserver_NotSupported) { - pressure_manager_overrider_->set_is_supported(false); - - FakePressureObserver observer; - EXPECT_EQ(pressure_service_impl_sync_->BindObserver( - observer.BindNewPipeAndPassRemote()), - blink::mojom::PressureStatus::kNotSupported); -} - -TEST_F(PressureServiceImplTest, InsecureOrigin) { - NavigateAndCommit(kInsecureUrl); - - mojo::FakeMessageDispatchContext fake_dispatch_context; - mojo::test::BadMessageObserver bad_message_observer; - SetPressureServiceImpl(); - EXPECT_EQ("Compute Pressure access from an insecure origin", - bad_message_observer.WaitForBadMessage()); -} - -// Allows callers to run a custom callback before running -// FakePressureManager::AddClient(). -class InterceptingFakePressureManager : public device::FakePressureManager { - public: - explicit InterceptingFakePressureManager( - base::OnceClosure interception_callback) - : interception_callback_(std::move(interception_callback)) {} - - void AddClient(mojo::PendingRemote<device::mojom::PressureClient> client, - AddClientCallback callback) override { - std::move(interception_callback_).Run(); - device::FakePressureManager::AddClient(std::move(client), - std::move(callback)); - } - - private: - base::OnceClosure interception_callback_; -}; - -// Test for https://crbug.com/1355662: destroying PressureServiceImplTest -// between calling PressureServiceImpl::BindObserver() and its |remote_| -// invoking the callback it receives does not crash. -TEST_F(PressureServiceImplTest, DestructionOrderWithOngoingCallback) { - auto intercepting_fake_pressure_manager = - std::make_unique<InterceptingFakePressureManager>( - base::BindLambdaForTesting([&]() { - // Delete the current WebContents and consequently trigger - // PressureServiceImpl's destruction between calling - // PressureServiceImpl::BindObserver() and its |remote_| - // invoking the callback it receives. - DeleteContents(); - })); - pressure_manager_overrider_->set_fake_pressure_manager( - std::move(intercepting_fake_pressure_manager)); - - base::RunLoop run_loop; - pressure_service_.set_disconnect_handler(run_loop.QuitClosure()); - FakePressureObserver observer; - pressure_service_->BindObserver( - observer.BindNewPipeAndPassRemote(), - base::BindOnce([](blink::mojom::PressureStatus) { - ADD_FAILURE() << "Reached BindObserver callback unexpectedly"; - })); - run_loop.Run(); -} - -} // namespace content
diff --git a/content/browser/devtools/protocol/browser_handler.cc b/content/browser/devtools/protocol/browser_handler.cc index 81d10de..97171b7f 100644 --- a/content/browser/devtools/protocol/browser_handler.cc +++ b/content/browser/devtools/protocol/browser_handler.cc
@@ -82,6 +82,7 @@ } contexts_with_overridden_downloads_.clear(); SetDownloadEventsEnabled(false); + histograms_snapshots_.clear(); return Response::Success(); } @@ -105,44 +106,6 @@ } namespace { - -// Converts an histogram. -std::unique_ptr<Browser::Histogram> Convert(base::HistogramBase& in_histogram, - bool in_delta) { - std::unique_ptr<const base::HistogramSamples> in_buckets; - if (!in_delta) { - in_buckets = in_histogram.SnapshotSamples(); - } else { - // TODO(crbug/1377433): Remove this call, as SnapshotDelta() should not be - // called outside the metrics collection system. - in_buckets = in_histogram.SnapshotDelta(); - } - DCHECK(in_buckets); - - auto out_buckets = std::make_unique<Array<Browser::Bucket>>(); - - for (const std::unique_ptr<base::SampleCountIterator> bucket_it = - in_buckets->Iterator(); - !bucket_it->Done(); bucket_it->Next()) { - base::HistogramBase::Count count; - base::HistogramBase::Sample low; - int64_t high; - bucket_it->Get(&low, &high, &count); - out_buckets->emplace_back(Browser::Bucket::Create() - .SetLow(low) - .SetHigh(high) - .SetCount(count) - .Build()); - } - - return Browser::Histogram::Create() - .SetName(in_histogram.histogram_name()) - .SetSum(in_buckets->sum()) - .SetCount(in_buckets->TotalCount()) - .SetBuckets(std::move(out_buckets)) - .Build(); -} - // Parses PermissionDescriptors (|descriptor|) into their appropriate // PermissionType |permission_type| by duplicating the logic in the methods // //third_party/blink/renderer/modules/permissions:permissions @@ -315,24 +278,6 @@ } // namespace -Response BrowserHandler::GetHistograms( - const Maybe<std::string> in_query, - const Maybe<bool> in_delta, - std::unique_ptr<Array<Browser::Histogram>>* const out_histograms) { - // Convert histograms. - DCHECK(out_histograms); - *out_histograms = std::make_unique<Array<Browser::Histogram>>(); - for (base::HistogramBase* const h : - base::StatisticsRecorder::Sort(base::StatisticsRecorder::WithName( - base::StatisticsRecorder::GetHistograms(), - in_query.fromMaybe("")))) { - DCHECK(h); - (*out_histograms)->emplace_back(Convert(*h, in_delta.fromMaybe(false))); - } - - return Response::Success(); -} - // static Response BrowserHandler::FindBrowserContext( const Maybe<std::string>& browser_context_id, @@ -544,6 +489,24 @@ return Response::Success(); } +Response BrowserHandler::GetHistograms( + const Maybe<std::string> in_query, + const Maybe<bool> in_delta, + std::unique_ptr<Array<Browser::Histogram>>* const out_histograms) { + DCHECK(out_histograms); + bool get_deltas = in_delta.fromMaybe(false); + *out_histograms = std::make_unique<Array<Browser::Histogram>>(); + for (base::HistogramBase* const h : + base::StatisticsRecorder::Sort(base::StatisticsRecorder::WithName( + base::StatisticsRecorder::GetHistograms(), + in_query.fromMaybe("")))) { + DCHECK(h); + (*out_histograms)->emplace_back(GetHistogramData(*h, get_deltas)); + } + + return Response::Success(); +} + Response BrowserHandler::GetHistogram( const std::string& in_name, const Maybe<bool> in_delta, @@ -554,9 +517,8 @@ if (!in_histogram) return Response::InvalidParams("Cannot find histogram: " + in_name); - // Convert histogram. DCHECK(out_histogram); - *out_histogram = Convert(*in_histogram, in_delta.fromMaybe(false)); + *out_histogram = GetHistogramData(*in_histogram, in_delta.fromMaybe(false)); return Response::Success(); } @@ -650,5 +612,51 @@ download_events_enabled_ = enabled; } +std::unique_ptr<Browser::Histogram> BrowserHandler::GetHistogramData( + const base::HistogramBase& histogram, + bool get_delta) { + std::unique_ptr<base::HistogramSamples> data = histogram.SnapshotSamples(); + std::unique_ptr<base::HistogramSamples> previous_data; + if (get_delta) { + auto it = histograms_snapshots_.find(histogram.histogram_name()); + if (it != histograms_snapshots_.end()) { + previous_data = std::move(it->second); + data->Subtract(*previous_data); + } + } + + auto out_buckets = std::make_unique<Array<Browser::Bucket>>(); + for (const std::unique_ptr<base::SampleCountIterator> it = data->Iterator(); + !it->Done(); it->Next()) { + base::HistogramBase::Count count; + base::HistogramBase::Sample low; + int64_t high; + it->Get(&low, &high, &count); + out_buckets->emplace_back(Browser::Bucket::Create() + .SetLow(low) + .SetHigh(high) + .SetCount(count) + .Build()); + } + + auto result = Browser::Histogram::Create() + .SetName(histogram.histogram_name()) + .SetSum(data->sum()) + .SetCount(data->TotalCount()) + .SetBuckets(std::move(out_buckets)) + .Build(); + + // Keep track of the data we returned for future delta requests. + if (get_delta) { + if (previous_data) { + // If we had subtracted previous data, re-add it to get the full snapshot. + data->Add(*previous_data); + } + histograms_snapshots_[histogram.histogram_name()] = std::move(data); + } + + return result; +} + } // namespace protocol } // namespace content
diff --git a/content/browser/devtools/protocol/browser_handler.h b/content/browser/devtools/protocol/browser_handler.h index b4ac6cd..c8f005a4 100644 --- a/content/browser/devtools/protocol/browser_handler.h +++ b/content/browser/devtools/protocol/browser_handler.h
@@ -5,7 +5,10 @@ #ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_BROWSER_HANDLER_H_ #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_BROWSER_HANDLER_H_ +#include <map> + #include "base/containers/flat_set.h" +#include "base/metrics/histogram.h" #include "components/download/public/common/download_item.h" #include "content/browser/devtools/protocol/browser.h" #include "content/browser/devtools/protocol/devtools_domain_handler.h" @@ -95,12 +98,23 @@ private: void SetDownloadEventsEnabled(bool enabled); + // Retrieves the data for the given histogram, returning it in the converted + // format. If `get_delta` is true, returns the only the new data since the + // last `get_delta` true call for the given histogram, or all data if it's + // the first such call. + std::unique_ptr<Browser::Histogram> GetHistogramData( + const base::HistogramBase& histogram, + bool get_delta); + std::unique_ptr<Browser::Frontend> frontend_; base::flat_set<std::string> contexts_with_overridden_permissions_; base::flat_set<std::string> contexts_with_overridden_downloads_; bool download_events_enabled_; const bool allow_set_download_behavior_; base::flat_set<download::DownloadItem*> pending_downloads_; + // Stores past histogram snapshots for producing histogram deltas. + std::map<std::string, std::unique_ptr<base::HistogramSamples>> + histograms_snapshots_; }; } // namespace protocol
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc index 92e5a9a..bcbd2c04 100644 --- a/content/browser/devtools/protocol/tracing_handler.cc +++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -94,19 +94,19 @@ base::Value ConvertDictKeyStyle(const base::Value& value) { if (value.is_dict()) { - base::Value out(base::Value::Type::DICTIONARY); + base::Value::Dict out; for (auto kv : value.DictItems()) { - out.SetKey(ConvertFromCamelCase(kv.first, '_'), - ConvertDictKeyStyle(kv.second)); + out.Set(ConvertFromCamelCase(kv.first, '_'), + ConvertDictKeyStyle(kv.second)); } - return out; + return base::Value(std::move(out)); } if (value.is_list()) { - base::Value out(base::Value::Type::LIST); + base::Value::List out; for (const auto& v : value.GetList()) out.Append(ConvertDictKeyStyle(v)); - return out; + return base::Value(std::move(out)); } return value.Clone();
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc index 40e64d1..68493c5 100644 --- a/content/browser/dom_storage/dom_storage_context_wrapper.cc +++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -25,6 +25,7 @@ #include "components/services/storage/public/mojom/storage_policy_update.mojom.h" #include "components/services/storage/public/mojom/storage_usage_info.mojom.h" #include "content/browser/dom_storage/session_storage_namespace_impl.h" +#include "content/browser/renderer_host/frame_tree.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/storage_partition_impl.h" #include "content/public/browser/browser_task_traits.h" @@ -296,7 +297,18 @@ if (!host) { return false; } - host_storage_key_did_not_match = host->storage_key() != storage_key; + switch (type) { + case StorageType::kLocalStorage: { + host_storage_key_did_not_match = host->storage_key() != storage_key; + break; + } + case StorageType::kSessionStorage: { + host_storage_key_did_not_match = + host->frame_tree()->GetSessionStorageKey(host->storage_key()) != + storage_key; + break; + } + } } if (!security_policy_handle.CanAccessDataForOrigin(storage_key.origin())) { const std::string type_string =
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc index 6e92cb28..d2e7a1e 100644 --- a/content/browser/download/save_package.cc +++ b/content/browser/download/save_package.cc
@@ -137,8 +137,6 @@ return "text/html"; case SAVE_PAGE_TYPE_AS_MHTML: return "multipart/related"; - case SAVE_PAGE_TYPE_AS_WEB_BUNDLE: - return "application/webbundle"; case SAVE_PAGE_TYPE_UNKNOWN: case SAVE_PAGE_TYPE_MAX: NOTREACHED(); @@ -198,8 +196,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) || (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) || - (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) || - (save_type_ == SAVE_PAGE_TYPE_AS_WEB_BUNDLE)) + (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML)) << save_type_; DCHECK(!saved_main_file_path_.empty() && saved_main_file_path_.value().length() <= kMaxFilePathLength); @@ -343,14 +340,8 @@ } else if (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) { MHTMLGenerationParams mhtml_generation_params(saved_main_file_path_); GetWebContents(page_.get()) - ->GenerateMHTML( - mhtml_generation_params, - base::BindOnce(&SavePackage::OnMHTMLOrWebBundleGenerated, this)); - } else if (save_type_ == SAVE_PAGE_TYPE_AS_WEB_BUNDLE) { - GetWebContents(page_.get()) - ->GenerateWebBundle( - saved_main_file_path_, - base::BindOnce(&SavePackage::OnWebBundleGenerated, this)); + ->GenerateMHTML(mhtml_generation_params, + base::BindOnce(&SavePackage::OnMHTMLGenerated, this)); } else { DCHECK_EQ(SAVE_PAGE_TYPE_AS_ONLY_HTML, save_type_); wait_state_ = NET_FILES; @@ -366,7 +357,7 @@ } } -void SavePackage::OnMHTMLOrWebBundleGenerated(int64_t size) { +void SavePackage::OnMHTMLGenerated(int64_t size) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!download_) return; @@ -387,16 +378,6 @@ } } -void SavePackage::OnWebBundleGenerated( - uint64_t size, - data_decoder::mojom::WebBundlerError error) { - if (error == data_decoder::mojom::WebBundlerError::kOK) - DCHECK_GT(size, 0ULL); - else - DCHECK_EQ(size, 0ULL); - OnMHTMLOrWebBundleGenerated(size); -} - // On POSIX, the length of |base_name| + |file_name_ext| is further // restricted by NAME_MAX. The maximum allowed path looks like: // '/path/to/save_dir' + '/' + NAME_MAX. @@ -805,8 +786,7 @@ file_manager_, list_of_failed_save_item_ids)); if (download_) { - if (save_type_ != SAVE_PAGE_TYPE_AS_MHTML && - save_type_ != SAVE_PAGE_TYPE_AS_WEB_BUNDLE) { + if (save_type_ != SAVE_PAGE_TYPE_AS_MHTML) { CHECK_EQ(download_->GetState(), download::DownloadItem::IN_PROGRESS); download_->DestinationUpdate( all_save_items_count_, CurrentSpeed(), @@ -951,11 +931,10 @@ void SavePackage::DoSavingProcess() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (save_type_ != SAVE_PAGE_TYPE_AS_COMPLETE_HTML) { - // Save as HTML only or MHTML, or Web Bundle. + // Save as HTML only or MHTML. DCHECK_EQ(NET_FILES, wait_state_); DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) || - (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) || - (save_type_ == SAVE_PAGE_TYPE_AS_WEB_BUNDLE)) + (save_type_ == SAVE_PAGE_TYPE_AS_MHTML)) << save_type_; if (waiting_item_queue_.size()) { DCHECK_EQ(all_save_items_count_, waiting_item_queue_.size()); @@ -1471,8 +1450,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK((type == SAVE_PAGE_TYPE_AS_ONLY_HTML) || (type == SAVE_PAGE_TYPE_AS_MHTML) || - (type == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) || - (type == SAVE_PAGE_TYPE_AS_WEB_BUNDLE)) + (type == SAVE_PAGE_TYPE_AS_COMPLETE_HTML)) << type; if (!page_) return;
diff --git a/content/browser/download/save_package.h b/content/browser/download/save_package.h index 0031163d..462c319 100644 --- a/content/browser/download/save_package.h +++ b/content/browser/download/save_package.h
@@ -29,7 +29,6 @@ #include "content/public/browser/save_page_type.h" #include "content/public/common/referrer.h" #include "net/base/net_errors.h" -#include "services/data_decoder/public/mojom/web_bundler.mojom.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "third_party/blink/public/mojom/frame/frame.mojom-forward.h" #include "url/gurl.h" @@ -178,13 +177,8 @@ SavePackageDownloadCreatedCallback download_created_callback, download::DownloadItemImpl* item); - // Callback for WebContents::GenerateMHTML() and - // WebContents::GenerateWebBundle(). - void OnMHTMLOrWebBundleGenerated(int64_t size); - - // Callback for WebContents::GenerateWebBundle(). - void OnWebBundleGenerated(uint64_t size, - data_decoder::mojom::WebBundlerError error); + // Callback for WebContents::GenerateMHTML(). + void OnMHTMLGenerated(int64_t size); // Notes from Init() above applies here as well. void InternalInit();
diff --git a/content/browser/download/save_package_browsertest.cc b/content/browser/download/save_package_browsertest.cc index c14d0ca..445d517 100644 --- a/content/browser/download/save_package_browsertest.cc +++ b/content/browser/download/save_package_browsertest.cc
@@ -7,17 +7,13 @@ #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "base/run_loop.h" -#include "base/strings/utf_string_conversions.h" #include "base/task/sequenced_task_runner.h" -#include "base/test/scoped_feature_list.h" #include "content/browser/download/download_manager_impl.h" #include "content/browser/download/save_package.h" #include "content/browser/web_contents/web_contents_impl.h" -#include "content/browser/web_package/web_bundle_utils.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/content_features.h" #include "content/public/test/browser_test.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" @@ -25,7 +21,6 @@ #include "content/public/test/fenced_frame_test_util.h" #include "content/shell/browser/shell.h" #include "content/shell/browser/shell_download_manager_delegate.h" -#include "net/base/filename_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gmock/include/gmock/gmock.h" @@ -45,12 +40,7 @@ const base::FilePath::StringType& default_extension, bool can_save_as_complete, SavePackagePathPickedCallback callback) override { - base::FilePath suggested_path_copy = suggested_path; - if (save_page_type_ == SAVE_PAGE_TYPE_AS_WEB_BUNDLE) { - suggested_path_copy = - suggested_path_copy.ReplaceExtension(FILE_PATH_LITERAL("wbn")); - } - std::move(callback).Run(suggested_path_copy, save_page_type_, + std::move(callback).Run(suggested_path, save_page_type_, SavePackageDownloadCreatedCallback()); } @@ -282,61 +272,6 @@ download_manager->SetDelegate(old_delegate); } -class SavePackageWebBundleBrowserTest : public SavePackageBrowserTest { - public: - void SetUp() override { - std::vector<base::test::FeatureRef> enable_features; - std::vector<base::test::FeatureRef> disabled_features; - enable_features.push_back(features::kSavePageAsWebBundle); - enable_features.push_back(features::kWebBundles); - feature_list_.InitWithFeatures(enable_features, disabled_features); - - SavePackageBrowserTest::SetUp(); - } - - private: - base::test::ScopedFeatureList feature_list_; -}; - -IN_PROC_BROWSER_TEST_F(SavePackageWebBundleBrowserTest, OnePageSimple) { - ASSERT_TRUE(embedded_test_server()->Start()); - GURL url = embedded_test_server()->GetURL( - "/web_bundle/save_page_as_web_bundle/one_page_simple.html"); - EXPECT_TRUE(NavigateToURL(shell(), url)); - auto* download_manager = static_cast<DownloadManagerImpl*>( - shell()->web_contents()->GetBrowserContext()->GetDownloadManager()); - auto delegate = std::make_unique<TestShellDownloadManagerDelegate>( - SAVE_PAGE_TYPE_AS_WEB_BUNDLE); - delegate->download_dir_ = save_dir_.GetPath(); - auto* old_delegate = download_manager->GetDelegate(); - download_manager->SetDelegate(delegate.get()); - - GURL wbn_file_url; - { - base::RunLoop run_loop; - DownloadCompleteObserver observer(run_loop.QuitClosure()); - download_manager->AddObserver(&observer); - scoped_refptr<SavePackage> save_package( - new SavePackage(web_contents_impl()->GetPrimaryPage())); - save_package->GetSaveInfo(); - run_loop.Run(); - download_manager->RemoveObserver(&observer); - EXPECT_TRUE(save_package->finished()); - EXPECT_EQ("application/webbundle", observer.mime_type()); - wbn_file_url = net::FilePathToFileURL(observer.target_file_path()); - } - - download_manager->SetDelegate(old_delegate); - EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank"))); - - std::u16string expected_title = u"Hello"; - TitleWatcher title_watcher(shell()->web_contents(), expected_title); - EXPECT_TRUE(NavigateToURL( - shell(), wbn_file_url, - web_bundle_utils::GetSynthesizedUrlForWebBundle(wbn_file_url, url))); - EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); -} - class SavePackageFencedFrameBrowserTest : public SavePackageBrowserTest { public: test::FencedFrameTestHelper& fenced_frame_test_helper() {
diff --git a/content/browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc b/content/browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc index 76d0407..bc43f025 100644 --- a/content/browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc +++ b/content/browser/fenced_frame/redacted_fenced_frame_config_mojom_traits_unittest.cc
@@ -465,10 +465,13 @@ // Test `shared_storage_budget_metadata`. { SharedStorageBudgetMetadata test_shared_storage_budget_metadata = { - url::Origin::Create(test_url), 0.5}; + url::Origin::Create(test_url), 0.5, /*top_navigated=*/true, + /*report_event_called=*/false}; auto eq_fn = [](const SharedStorageBudgetMetadata& a, const SharedStorageBudgetMetadata& b) { - return a.origin == b.origin && a.budget_to_charge == b.budget_to_charge; + return a.origin == b.origin && a.budget_to_charge == b.budget_to_charge && + a.top_navigated == b.top_navigated && + a.report_event_called == b.report_event_called; }; TestProperty(&FencedFrameConfig::shared_storage_budget_metadata_, &RedactedFencedFrameConfig::shared_storage_budget_metadata_, @@ -478,7 +481,9 @@ [](const raw_ptr<const SharedStorageBudgetMetadata>& a, const SharedStorageBudgetMetadata& b) { return a->origin == b.origin && - a->budget_to_charge == b.budget_to_charge; + a->budget_to_charge == b.budget_to_charge && + a->top_navigated == b.top_navigated && + a->report_event_called == b.report_event_called; }; TestProperty( &FencedFrameProperties::shared_storage_budget_metadata_,
diff --git a/content/browser/loader/object_navigation_fallback_body_loader.cc b/content/browser/loader/object_navigation_fallback_body_loader.cc index 8ef9710..239f28e 100644 --- a/content/browser/loader/object_navigation_fallback_body_loader.cc +++ b/content/browser/loader/object_navigation_fallback_body_loader.cc
@@ -109,6 +109,38 @@ base::Unretained(this))); } +void ObjectNavigationFallbackBodyLoader::MaybeComplete() { + // Completion requires receiving the completion status from the `URLLoader`, + // as well as the response body being completely drained. + if (!status_ || response_body_drainer_) + return; + + // At this point, `this` is done and the associated NavigationRequest and + // `this` must be cleaned up, no matter what else happens. Running + // `completion_closure_` will delete the NavigationRequest, which will delete + // `this`. + base::ScopedClosureRunner cleanup(std::move(completion_closure_)); + + timing_info_->response_end = status_->completion_time; + timing_info_->encoded_body_size = status_->encoded_body_length; + timing_info_->decoded_body_size = status_->decoded_body_length; + + RenderFrameHostManager* render_manager = + navigation_request_->frame_tree_node()->render_manager(); + if (RenderFrameProxyHost* proxy = render_manager->GetProxyToParent()) { + if (proxy->is_render_frame_proxy_live()) { + proxy->GetAssociatedRemoteFrame() + ->RenderFallbackContentWithResourceTiming(std::move(timing_info_), + server_timing_value_); + } + } else { + render_manager->current_frame_host() + ->GetAssociatedLocalFrame() + ->RenderFallbackContentWithResourceTiming(std::move(timing_info_), + server_timing_value_); + } +} + void ObjectNavigationFallbackBodyLoader::BodyLoadFailed() { // At this point, `this` is done and the associated NavigationRequest and // `this` must be cleaned up, no matter what else happens. Running @@ -160,36 +192,16 @@ void ObjectNavigationFallbackBodyLoader::OnComplete( const network::URLLoaderCompletionStatus& status) { - response_body_drainer_.reset(); - // At this point, `this` is done and the associated NavigationRequest and - // `this` must be cleaned up, no matter what else happens. Running - // `completion_closure_` will delete the NavigationRequest, which will delete - // `this`. - base::ScopedClosureRunner cleanup(std::move(completion_closure_)); - - timing_info_->response_end = status.completion_time; - timing_info_->encoded_body_size = status.encoded_body_length; - timing_info_->decoded_body_size = status.decoded_body_length; - - RenderFrameHostManager* render_manager = - navigation_request_->frame_tree_node()->render_manager(); - if (RenderFrameProxyHost* proxy = render_manager->GetProxyToParent()) { - if (proxy->is_render_frame_proxy_live()) { - proxy->GetAssociatedRemoteFrame() - ->RenderFallbackContentWithResourceTiming(std::move(timing_info_), - server_timing_value_); - } - } else { - render_manager->current_frame_host() - ->GetAssociatedLocalFrame() - ->RenderFallbackContentWithResourceTiming(std::move(timing_info_), - server_timing_value_); - } + status_ = status; + MaybeComplete(); } void ObjectNavigationFallbackBodyLoader::OnDataAvailable(const void* data, size_t num_bytes) {} -void ObjectNavigationFallbackBodyLoader::OnDataComplete() {} +void ObjectNavigationFallbackBodyLoader::OnDataComplete() { + response_body_drainer_.reset(); + MaybeComplete(); +} } // namespace content
diff --git a/content/browser/loader/object_navigation_fallback_body_loader.h b/content/browser/loader/object_navigation_fallback_body_loader.h index 34acb77..248dab9 100644 --- a/content/browser/loader/object_navigation_fallback_body_loader.h +++ b/content/browser/loader/object_navigation_fallback_body_loader.h
@@ -96,6 +96,7 @@ network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, base::OnceClosure completion_closure); + void MaybeComplete(); void BodyLoadFailed(); // URLLoaderClient overrides: @@ -123,6 +124,7 @@ // `response_body_drainer_` will be reset to null when the response body is // completely drained. std::unique_ptr<mojo::DataPipeDrainer> response_body_drainer_; + absl::optional<network::URLLoaderCompletionStatus> status_; blink::mojom::ResourceTimingInfoPtr timing_info_; std::string server_timing_value_; base::OnceClosure completion_closure_;
diff --git a/content/browser/media/system_media_controls_notifier.cc b/content/browser/media/system_media_controls_notifier.cc index 57e2852..63caa4e 100644 --- a/content/browser/media/system_media_controls_notifier.cc +++ b/content/browser/media/system_media_controls_notifier.cc
@@ -123,6 +123,9 @@ // If no artist was provided, then the source URL will be in the artist // property. system_media_controls_->SetArtist(metadata->artist); + + system_media_controls_->SetAlbum(metadata->album); + system_media_controls_->UpdateDisplay(); } else { // 5.3.2 If the metadata of the active media session is an empty metadata,
diff --git a/content/browser/media/system_media_controls_notifier_unittest.cc b/content/browser/media/system_media_controls_notifier_unittest.cc index ef270034..ad82cc30 100644 --- a/content/browser/media/system_media_controls_notifier_unittest.cc +++ b/content/browser/media/system_media_controls_notifier_unittest.cc
@@ -61,18 +61,19 @@ void SimulateStopped() { notifier_->MediaSessionInfoChanged(nullptr); } - void SimulateMetadataChanged(bool empty, - std::u16string title, - std::u16string artist) { - if (!empty) { - media_session::MediaMetadata metadata; - metadata.title = title; - metadata.artist = artist; - notifier_->MediaSessionMetadataChanged( - absl::optional<media_session::MediaMetadata>(metadata)); - } else { - notifier_->MediaSessionMetadataChanged(absl::nullopt); - } + void SimulateMetadataChanged(std::u16string title, + std::u16string artist, + std::u16string album) { + media_session::MediaMetadata metadata; + metadata.title = title; + metadata.artist = artist; + metadata.album = album; + notifier_->MediaSessionMetadataChanged( + absl::optional<media_session::MediaMetadata>(metadata)); + } + + void SimulateEmptyMetadata() { + notifier_->MediaSessionMetadataChanged(absl::nullopt); } void SimulateImageChanged() { @@ -125,21 +126,24 @@ TEST_F(SystemMediaControlsNotifierTest, ProperlyUpdatesMetadata) { std::u16string title = u"title"; std::u16string artist = u"artist"; + std::u16string album = u"album"; EXPECT_CALL(mock_system_media_controls(), SetTitle(title)); EXPECT_CALL(mock_system_media_controls(), SetArtist(artist)); + EXPECT_CALL(mock_system_media_controls(), SetAlbum(album)); EXPECT_CALL(mock_system_media_controls(), ClearMetadata()).Times(0); EXPECT_CALL(mock_system_media_controls(), UpdateDisplay()); - SimulateMetadataChanged(false, title, artist); + SimulateMetadataChanged(title, artist, album); } TEST_F(SystemMediaControlsNotifierTest, ProperlyUpdatesNullMetadata) { EXPECT_CALL(mock_system_media_controls(), SetTitle(_)).Times(0); EXPECT_CALL(mock_system_media_controls(), SetArtist(_)).Times(0); + EXPECT_CALL(mock_system_media_controls(), SetAlbum(_)).Times(0); EXPECT_CALL(mock_system_media_controls(), ClearMetadata()); - SimulateMetadataChanged(true, std::u16string(), std::u16string()); + SimulateEmptyMetadata(); } TEST_F(SystemMediaControlsNotifierTest, ProperlyUpdatesImage) {
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc index b0f5b05..09a49970 100644 --- a/content/browser/preloading/prefetch/prefetch_container.cc +++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -246,7 +246,7 @@ prefetch_document_manager_, url_) : PreloadingDataImpl::GetSameURLMatcher(url_); auto* attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor(ContentPreloadingPredictor::kSpeculationRules), + content_preloading_predictor::kSpeculationRules, PreloadingType::kPrefetch, std::move(matcher)); attempt_ = attempt->GetWeakPtr(); // `PreloadingPrediction` is added in `PreloadingDecider`.
diff --git a/content/browser/preloading/prefetch/prefetch_service_unittest.cc b/content/browser/preloading/prefetch/prefetch_service_unittest.cc index e335e73c..7b79c05 100644 --- a/content/browser/preloading/prefetch/prefetch_service_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
@@ -244,8 +244,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); attempt_entry_builder_ = std::make_unique<test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ContentPreloadingPredictor::kSpeculationRules)); + content_preloading_predictor::kSpeculationRules); scoped_test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>();
diff --git a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc index b3915e1..b8c673a 100644 --- a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc
@@ -197,8 +197,7 @@ test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); attempt_entry_builder_ = std::make_unique<test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ContentPreloadingPredictor::kSpeculationRules)); + content_preloading_predictor::kSpeculationRules); scoped_test_timer_ = std::make_unique<base::ScopedMockElapsedTimersForTest>();
diff --git a/content/browser/preloading/preloading.cc b/content/browser/preloading/preloading.cc deleted file mode 100644 index edce248a..0000000 --- a/content/browser/preloading/preloading.cc +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/preloading/preloading.h" - -namespace content { - -static_assert( - static_cast<int>(ContentPreloadingPredictor::kMaxValue) < - static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentEnd)); - -PreloadingPredictor ToPreloadingPredictor( - ContentPreloadingPredictor predictor) { - return static_cast<PreloadingPredictor>(predictor); -} - -} // namespace content
diff --git a/content/browser/preloading/preloading.h b/content/browser/preloading/preloading.h index fb8b1d1f6..4e6cf933 100644 --- a/content/browser/preloading/preloading.h +++ b/content/browser/preloading/preloading.h
@@ -7,10 +7,6 @@ #include "content/public/browser/preloading.h" -#include "content/common/content_export.h" - -namespace content { - // Defines various //content triggering mechanisms which trigger different // preloading operations mentioned in content/public/browser/preloading.h. @@ -21,31 +17,23 @@ // go/preloading-dashboard-updates to update the mapping reflected in // dashboard, or if you are not a Googler, please file an FYI bug on // https://crbug.new with component Internals>Preload. -enum class ContentPreloadingPredictor { - // Numbering starts from `kPreloadingPredictorContentStart` defined in - // //content/public/preloading.h. Advance numbering by +1 after adding a new - // element. +namespace content::content_preloading_predictor { - // This API allows an origin to list possible navigation URLs that the user - // might navigate to in order to perform preloading operations. - // For more details please see: - // https://wicg.github.io/nav-speculation/prerendering.html#speculation-rules - kSpeculationRules = - static_cast<int>(PreloadingPredictor::kPreloadingPredictorContentStart), +// Advance numbering by +1 when adding a new element. +// +// Please limit content-internal `PreloadingPredictor` between 50 to 99 +// (inclusive) as 0 to 49 are reserved for content-public definitions, and 100 +// and beyond are reserved for embedder definitions. Both the value and the name +// should be unique across all the namespaces. - // TODO(crbug.com/1309934): Add more predictors as we integrate Preloading - // logging. +// This API allows an origin to list possible navigation URLs that the user +// might navigate to in order to perform preloading operations. +// For more details please see: +// https://wicg.github.io/nav-speculation/prerendering.html#speculation-rules +static constexpr PreloadingPredictor kSpeculationRules(50, "SpeculationRules"); - // The max value of the ContentPreloadingPredictor. Update this when new enums - // are added. - kMaxValue = kSpeculationRules, -}; - -// Helper method to convert ContentPreloadingPredictor to -// content::PreloadingPredictor to avoid casting. -PreloadingPredictor CONTENT_EXPORT -ToPreloadingPredictor(ContentPreloadingPredictor predictor); - -} // namespace content +// TODO(crbug.com/1309934): Add more predictors as we integrate Preloading +// logging. +} // namespace content::content_preloading_predictor #endif // CONTENT_BROWSER_PRELOADING_PRELOADING_H_
diff --git a/content/browser/preloading/preloading_attempt_impl.cc b/content/browser/preloading/preloading_attempt_impl.cc index b73daae9..6ae7927 100644 --- a/content/browser/preloading/preloading_attempt_impl.cc +++ b/content/browser/preloading/preloading_attempt_impl.cc
@@ -4,7 +4,9 @@ #include "content/browser/preloading/preloading_attempt_impl.h" +#include "base/metrics/histogram_functions.h" #include "base/state_transitions.h" +#include "base/strings/strcat.h" #include "content/public/browser/preloading.h" #include "services/metrics/public/cpp/metrics_utils.h" #include "services/metrics/public/cpp/ukm_builders.h" @@ -64,6 +66,24 @@ #endif // DCHECK_IS_ON() } +static base::StringPiece PreloadingTypeToString(PreloadingType type) { + switch (type) { + case PreloadingType::kUnspecified: + return "Unspecified"; + case PreloadingType::kPreconnect: + return "Preconnect"; + case PreloadingType::kPrefetch: + return "Prefetch"; + case PreloadingType::kPrerender: + return "Prerender"; + case PreloadingType::kNoStatePrefetch: + return "NoStatePrefetch"; + default: + NOTREACHED(); + return ""; + } +} + } // namespace void PreloadingAttemptImpl::SetEligibility(PreloadingEligibility eligibility) { @@ -150,7 +170,7 @@ PreloadingAttemptImpl::~PreloadingAttemptImpl() = default; -void PreloadingAttemptImpl::RecordPreloadingAttemptUKMs( +void PreloadingAttemptImpl::RecordPreloadingAttemptMetrics( ukm::SourceId navigated_page_source_id) { ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get(); @@ -165,7 +185,7 @@ if (navigated_page_source_id != ukm::kInvalidSourceId) { ukm::builders::Preloading_Attempt builder(navigated_page_source_id); builder.SetPreloadingType(static_cast<int64_t>(preloading_type_)) - .SetPreloadingPredictor(static_cast<int64_t>(predictor_type_)) + .SetPreloadingPredictor(predictor_type_.ukm_value()) .SetEligibility(static_cast<int64_t>(eligibility_)) .SetHoldbackStatus(static_cast<int64_t>(holdback_status_)) .SetTriggeringOutcome(static_cast<int64_t>(triggering_outcome_)) @@ -186,7 +206,7 @@ ukm::builders::Preloading_Attempt_PreviousPrimaryPage builder( triggered_primary_page_source_id_); builder.SetPreloadingType(static_cast<int64_t>(preloading_type_)) - .SetPreloadingPredictor(static_cast<int64_t>(predictor_type_)) + .SetPreloadingPredictor(predictor_type_.ukm_value()) .SetEligibility(static_cast<int64_t>(eligibility_)) .SetHoldbackStatus(static_cast<int64_t>(holdback_status_)) .SetTriggeringOutcome(static_cast<int64_t>(triggering_outcome_)) @@ -202,6 +222,20 @@ } builder.Record(ukm_recorder); } + + RecordPreloadingAttemptUMA(); +} + +void PreloadingAttemptImpl::RecordPreloadingAttemptUMA() { + // Records the triggering outcome enum. This can be used to: + // 1. Track the number of attempts; + // 2. Track the attempts' rates of various terminal status (i.e. success + // rate). + const auto uma_triggering_outcome_histogram = + base::StrCat({"Preloading.", PreloadingTypeToString(preloading_type_), + ".Attempt.", predictor_type_.name(), ".TriggeringOutcome"}); + base::UmaHistogramEnumeration(std::move(uma_triggering_outcome_histogram), + triggering_outcome_); } void PreloadingAttemptImpl::SetIsAccurateTriggering(const GURL& navigated_url) {
diff --git a/content/browser/preloading/preloading_attempt_impl.h b/content/browser/preloading/preloading_attempt_impl.h index af4f0bd..518ac12 100644 --- a/content/browser/preloading/preloading_attempt_impl.h +++ b/content/browser/preloading/preloading_attempt_impl.h
@@ -30,7 +30,7 @@ void SetFailureReason(PreloadingFailureReason reason) override; base::WeakPtr<PreloadingAttempt> GetWeakPtr() override; - // Records both UKMs Preloading_Attempt and + // Records UKMs and UMA for both Preloading_Attempt and // Preloading_Attempt_PreviousPrimaryPage. Metrics for both these are same. // Only difference is that the Preloading_Attempt_PreviousPrimaryPage UKM is // associated with the WebContents primary page that triggered the preloading @@ -38,7 +38,7 @@ // attempt on the primary visible page. Here `navigated_page` represent the // ukm::SourceId of the navigated page. If the navigation doesn't happen this // could be invalid. - void RecordPreloadingAttemptUKMs(ukm::SourceId navigated_page); + void RecordPreloadingAttemptMetrics(ukm::SourceId navigated_page); // Sets `is_accurate_triggering_` to true if `navigated_url` matches the // predicate URL logic. It also records `time_to_next_navigation_`. @@ -50,9 +50,15 @@ ukm::SourceId triggered_primary_page_source_id, PreloadingURLMatchCallback url_match_predicate); + // Called by the `PreloadingDataImpl` that owns this attempt, to check the + // validity of `predictor_type_`. + PreloadingPredictor predictor_type() const { return predictor_type_; } + private: friend class test::PreloadingAttemptAccessor; + void RecordPreloadingAttemptUMA(); + // Reason why the preloading attempt failed, this is similar to specific // preloading logging reason. Zero as a failure reason signifies no reason is // specified. This value is casted from preloading specific enum to int64_t
diff --git a/content/browser/preloading/preloading_attempt_impl_unittest.cc b/content/browser/preloading/preloading_attempt_impl_unittest.cc new file mode 100644 index 0000000..62db3a31 --- /dev/null +++ b/content/browser/preloading/preloading_attempt_impl_unittest.cc
@@ -0,0 +1,92 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/preloading/preloading_attempt_impl.h" + +#include "base/strings/stringprintf.h" +#include "base/test/metrics/histogram_tester.h" +#include "content/browser/preloading/preloading.h" +#include "content/public/browser/preloading.h" +#include "services/metrics/public/cpp/ukm_source_id.h" +#include "testing/gtest/include/gtest/gtest-param-test.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +namespace { +const PreloadingPredictor kPredictors[] = { + preloading_predictor::kUnspecified, + preloading_predictor::kUrlPointerDownOnAnchor, + preloading_predictor::kUrlPointerHoverOnAnchor, + preloading_predictor::kLinkRel, + content_preloading_predictor::kSpeculationRules, +}; + +const PreloadingType kTypes[] = { + PreloadingType::kUnspecified, PreloadingType::kPreconnect, + PreloadingType::kPrefetch, PreloadingType::kPrerender, + PreloadingType::kNoStatePrefetch, +}; + +const char* kUmaTriggerOutcome = "Preloading.%s.Attempt.%s.TriggeringOutcome"; + +static base::StringPiece PreloadingTypeToString(PreloadingType type) { + switch (type) { + case PreloadingType::kUnspecified: + return "Unspecified"; + case PreloadingType::kPreconnect: + return "Preconnect"; + case PreloadingType::kPrefetch: + return "Prefetch"; + case PreloadingType::kPrerender: + return "Prerender"; + case PreloadingType::kNoStatePrefetch: + return "NoStatePrefetch"; + default: + NOTREACHED(); + return ""; + } +} +} // namespace + +using PreloadingAttemptImplRecordUMATest = ::testing::TestWithParam< + ::testing::tuple<PreloadingPredictor, PreloadingType>>; + +TEST_P(PreloadingAttemptImplRecordUMATest, TestHistogramRecordedCorrectly) { + const auto& test_param = GetParam(); + const auto predictor = ::testing::get<0>(test_param); + const auto preloading_type = ::testing::get<1>(test_param); + auto attempt = std::make_unique<PreloadingAttemptImpl>( + predictor, preloading_type, /*triggered_primary_page_source_id=*/0, + /*url_match_predicate=*/ + PreloadingData::GetSameURLMatcher(GURL("http://example.com/"))); + { + base::HistogramTester histogram_tester; + // Use `ukm::kInvalidSourceId` so we skip the UKM recording. + attempt->RecordPreloadingAttemptMetrics(ukm::kInvalidSourceId); + histogram_tester.ExpectUniqueSample( + base::StringPrintf(kUmaTriggerOutcome, + PreloadingTypeToString(preloading_type).data(), + predictor.name().data()), + PreloadingTriggeringOutcome::kUnspecified, 1); + } + { + attempt->SetEligibility(PreloadingEligibility::kEligible); + attempt->SetHoldbackStatus(PreloadingHoldbackStatus::kAllowed); + attempt->SetTriggeringOutcome(PreloadingTriggeringOutcome::kRunning); + base::HistogramTester histogram_tester; + attempt->RecordPreloadingAttemptMetrics(ukm::kInvalidSourceId); + histogram_tester.ExpectUniqueSample( + base::StringPrintf(kUmaTriggerOutcome, + PreloadingTypeToString(preloading_type).data(), + predictor.name().data()), + PreloadingTriggeringOutcome::kRunning, 1); + } +} + +INSTANTIATE_TEST_SUITE_P(PreloadingAttemptImplRecordUMATests, + PreloadingAttemptImplRecordUMATest, + ::testing::Combine(::testing::ValuesIn(kPredictors), + ::testing::ValuesIn(kTypes))); +} // namespace content
diff --git a/content/browser/preloading/preloading_data_impl.cc b/content/browser/preloading/preloading_data_impl.cc index 4705835..42d846d 100644 --- a/content/browser/preloading/preloading_data_impl.cc +++ b/content/browser/preloading/preloading_data_impl.cc
@@ -11,8 +11,45 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" +#if DCHECK_IS_ON() +#include "base/no_destructor.h" +#endif // DCHECK_IS_ON() + namespace content { +namespace { +// Called by `AddPreloadingAttempt` and `AddPreloadingPrediction`. Fails +// the callers if the predictor is redefined. This method can be racy due to the +// static variable. +static void CheckPreloadingPredictorValidity(PreloadingPredictor predictor) { +#if DCHECK_IS_ON() + // Use `std::string` because we can't guarantee base::StringPiece has a static + // lifetime. + static base::NoDestructor<std::vector<std::pair<int64_t, std::string>>> + seen_predictors; + std::pair<int64_t, std::string> new_predictor(predictor.ukm_value(), + predictor.name()); + bool found = false; + for (const auto& seen : *seen_predictors) { + if ((seen.first == new_predictor.first) ^ + (seen.second == new_predictor.second)) { + // We cannot have two `PreloadingPredictor`s that only differ in either + // the ukm int value or the string description - each new + // `PreloadingPredictor` needs to be unique in both. + DCHECK(false) << new_predictor.second << "/" << new_predictor.first + << " vs " << seen.second << "/" << seen.first; + } else if (seen == new_predictor) { + found = true; + break; + } + } + if (!found) { + seen_predictors->push_back(new_predictor); + } +#endif // DCHECK_IS_ON() +} +} // namespace + // static PreloadingURLMatchCallback PreloadingData::GetSameURLMatcher( const GURL& destination_url) { @@ -126,10 +163,10 @@ ukm::SourceId navigated_page_source_id = navigation_handle->GetNextPageUkmSourceId(); - // Log the UKMs also on navigation when the user ends up navigating. Please + // Log the metrics also on navigation when the user ends up navigating. Please // note that we currently log the metrics on the primary page to analyze // preloading impact on user-visible primary pages. - RecordUKMForPreloadingAttempts(navigated_page_source_id); + RecordMetricsForPreloadingAttempts(navigated_page_source_id); RecordUKMForPreloadingPredictions(navigated_page_source_id); // Delete the user data after logging. @@ -160,11 +197,11 @@ } void PreloadingDataImpl::WebContentsDestroyed() { - // Log the UKMs also on WebContentsDestroyed event to avoid losing the data + // Log the metrics also on WebContentsDestroyed event to avoid losing the data // in case the user doesn't end up navigating. When the WebContents is // destroyed before navigation, we pass ukm::kInvalidSourceId and empty URL to // avoid the UKM associated to wrong page. - RecordUKMForPreloadingAttempts(ukm::kInvalidSourceId); + RecordMetricsForPreloadingAttempts(ukm::kInvalidSourceId); RecordUKMForPreloadingPredictions(ukm::kInvalidSourceId); // Delete the user data after logging. @@ -180,10 +217,16 @@ prediction->SetIsAccuratePrediction(navigated_url); } -void PreloadingDataImpl::RecordUKMForPreloadingAttempts( +void PreloadingDataImpl::RecordMetricsForPreloadingAttempts( ukm::SourceId navigated_page_source_id) { - for (auto& attempt : preloading_attempts_) - attempt->RecordPreloadingAttemptUKMs(navigated_page_source_id); + for (auto& attempt : preloading_attempts_) { + // Check the validity at the time of UKMs reporting, as the UKMs are + // reported from the same thread (whichever thread calls + // `PreloadingDataImpl::WebContentsDestroyed` or + // `PreloadingDataImpl::DidFinishNavigation`). + CheckPreloadingPredictorValidity(attempt->predictor_type()); + attempt->RecordPreloadingAttemptMetrics(navigated_page_source_id); + } // Clear all records once we record the UKMs. preloading_attempts_.clear(); @@ -191,8 +234,14 @@ void PreloadingDataImpl::RecordUKMForPreloadingPredictions( ukm::SourceId navigated_page_source_id) { - for (auto& prediction : preloading_predictions_) + for (auto& prediction : preloading_predictions_) { + // Check the validity at the time of UKMs reporting, as the UKMs are + // reported from the same thread (whichever thread calls + // `PreloadingDataImpl::WebContentsDestroyed` or + // `PreloadingDataImpl::DidFinishNavigation`). + CheckPreloadingPredictorValidity(prediction->predictor_type()); prediction->RecordPreloadingPredictionUKMs(navigated_page_source_id); + } // Clear all records once we record the UKMs. preloading_predictions_.clear();
diff --git a/content/browser/preloading/preloading_data_impl.h b/content/browser/preloading/preloading_data_impl.h index fcdba7c6..3b8b0a2 100644 --- a/content/browser/preloading/preloading_data_impl.h +++ b/content/browser/preloading/preloading_data_impl.h
@@ -68,7 +68,8 @@ friend class WebContentsUserData<PreloadingDataImpl>; WEB_CONTENTS_USER_DATA_KEY_DECL(); - void RecordUKMForPreloadingAttempts(ukm::SourceId navigated_page_source_id); + void RecordMetricsForPreloadingAttempts( + ukm::SourceId navigated_page_source_id); void RecordUKMForPreloadingPredictions( ukm::SourceId navigated_page_source_id); void SetIsAccurateTriggeringAndPrediction(const GURL& navigated_url);
diff --git a/content/browser/preloading/preloading_decider.cc b/content/browser/preloading/preloading_decider.cc index 60c8385d..1488428 100644 --- a/content/browser/preloading/preloading_decider.cc +++ b/content/browser/preloading/preloading_decider.cc
@@ -7,6 +7,7 @@ #include "content/browser/preloading/preloading.h" #include "content/browser/preloading/prerenderer_impl.h" #include "content/browser/renderer_host/render_frame_host_impl.h" +#include "content/public/browser/preloading.h" #include "content/public/browser/web_contents.h" namespace content { @@ -51,7 +52,7 @@ blink::features::kSpeculationRulesPointerDownHeuristics)) { if (MaybePrerender(url)) { AddPreloadingPrediction(url, - PreloadingPredictor::kUrlPointerDownOnAnchor); + preloading_predictor::kUrlPointerDownOnAnchor); return; } if (ShouldWaitForPrerenderResult(url)) @@ -59,7 +60,7 @@ if (MaybePrefetch(url)) { AddPreloadingPrediction(url, - PreloadingPredictor::kUrlPointerDownOnAnchor); + preloading_predictor::kUrlPointerDownOnAnchor); return; } // Ideally it is preferred to fallback to preconnect asynchronously if a @@ -81,7 +82,7 @@ // otherwise try to preconnect to it. if (MaybePrerender(url)) { AddPreloadingPrediction(url, - PreloadingPredictor::kUrlPointerDownOnAnchor); + preloading_predictor::kUrlPointerDownOnAnchor); return; } if (ShouldWaitForPrerenderResult(url)) @@ -89,7 +90,7 @@ if (MaybePrefetch(url)) { AddPreloadingPrediction(url, - PreloadingPredictor::kUrlPointerHoverOnAnchor); + preloading_predictor::kUrlPointerHoverOnAnchor); return; } // ditto (async fallback) @@ -132,9 +133,8 @@ processed_candidates_.insert(std::move(key)); // TODO(crbug.com/1341019): Pass the action requested by speculation rules // to PreloadingPrediction. - AddPreloadingPrediction( - candidate->url, - ToPreloadingPredictor(ContentPreloadingPredictor::kSpeculationRules)); + AddPreloadingPrediction(candidate->url, + content_preloading_predictor::kSpeculationRules); return false; };
diff --git a/content/browser/preloading/preloading_decider.h b/content/browser/preloading/preloading_decider.h index 6a61957..3e32908 100644 --- a/content/browser/preloading/preloading_decider.h +++ b/content/browser/preloading/preloading_decider.h
@@ -13,7 +13,7 @@ namespace content { class RenderFrameHost; -enum class PreloadingPredictor; +class PreloadingPredictor; class PreloadingDeciderObserverForTesting { public:
diff --git a/content/browser/preloading/preloading_prediction.cc b/content/browser/preloading/preloading_prediction.cc index 4f4a90f..67fef723 100644 --- a/content/browser/preloading/preloading_prediction.cc +++ b/content/browser/preloading/preloading_prediction.cc
@@ -30,7 +30,7 @@ // Don't log when the source id is invalid. if (navigated_page_source_id != ukm::kInvalidSourceId) { ukm::builders::Preloading_Prediction builder(navigated_page_source_id); - builder.SetPreloadingPredictor(static_cast<int64_t>(predictor_type_)) + builder.SetPreloadingPredictor(predictor_type_.ukm_value()) .SetConfidence(confidence_) .SetAccuratePrediction(is_accurate_prediction_); if (time_to_next_navigation_) { @@ -43,7 +43,7 @@ if (triggered_primary_page_source_id_ != ukm::kInvalidSourceId) { ukm::builders::Preloading_Prediction_PreviousPrimaryPage builder( triggered_primary_page_source_id_); - builder.SetPreloadingPredictor(static_cast<int64_t>(predictor_type_)) + builder.SetPreloadingPredictor(predictor_type_.ukm_value()) .SetConfidence(confidence_) .SetAccuratePrediction(is_accurate_prediction_); if (time_to_next_navigation_) {
diff --git a/content/browser/preloading/preloading_prediction.h b/content/browser/preloading/preloading_prediction.h index ef758a46..d924dab5 100644 --- a/content/browser/preloading/preloading_prediction.h +++ b/content/browser/preloading/preloading_prediction.h
@@ -44,6 +44,10 @@ ukm::SourceId triggered_primary_page_source_id, base::RepeatingCallback<bool(const GURL&)> url_match_predicate); + // Called by the `PreloadingDataImpl` that owns this prediction, to check the + // validity of `predictor_type_`. + PreloadingPredictor predictor_type() const { return predictor_type_; } + private: // Preloading predictor of this preloading prediction. const PreloadingPredictor predictor_type_;
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc index dda00e5..adc14af 100644 --- a/content/browser/preloading/prerender/prerender_browsertest.cc +++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -221,12 +221,10 @@ host_resolver()->AddRule("*", "127.0.0.1"); attempt_ukm_entry_builder_ = std::make_unique<test::PreloadingAttemptUkmEntryBuilder>( - ToPreloadingPredictor( - ContentPreloadingPredictor::kSpeculationRules)); + content_preloading_predictor::kSpeculationRules); prediction_ukm_entry_builder_ = std::make_unique<test::PreloadingPredictionUkmEntryBuilder>( - ToPreloadingPredictor( - ContentPreloadingPredictor::kSpeculationRules)); + content_preloading_predictor::kSpeculationRules); ssl_server_.AddDefaultHandlers(GetTestDataFilePath()); ssl_server_.SetSSLConfig( net::test_server::EmbeddedTestServer::CERT_TEST_NAMES);
diff --git a/content/browser/preloading/prerender/prerender_host_unittest.cc b/content/browser/preloading/prerender/prerender_host_unittest.cc index 0faa6df..eb62514c 100644 --- a/content/browser/preloading/prerender/prerender_host_unittest.cc +++ b/content/browser/preloading/prerender/prerender_host_unittest.cc
@@ -433,7 +433,7 @@ PreloadingURLMatchCallback same_url_matcher = PreloadingData::GetSameURLMatcher(kPrerenderingUrl); PreloadingAttempt* preloading_attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor(ContentPreloadingPredictor::kSpeculationRules), + content_preloading_predictor::kSpeculationRules, PreloadingType::kPrerender, std::move(same_url_matcher)); const int prerender_frame_tree_node_id = registry().CreateAndStartHost(
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc index fa3d881..6fb42281 100644 --- a/content/browser/preloading/prerenderer_impl.cc +++ b/content/browser/preloading/prerenderer_impl.cc
@@ -211,7 +211,7 @@ PreloadingURLMatchCallback same_url_matcher = PreloadingData::GetSameURLMatcher(candidate->url); PreloadingAttempt* preloading_attempt = preloading_data->AddPreloadingAttempt( - ToPreloadingPredictor(ContentPreloadingPredictor::kSpeculationRules), + content_preloading_predictor::kSpeculationRules, PreloadingType::kPrerender, std::move(same_url_matcher)); auto [begin, end] = base::ranges::equal_range(
diff --git a/content/browser/private_aggregation/private_aggregation_host.cc b/content/browser/private_aggregation/private_aggregation_host.cc index 02b89767..50d846ef 100644 --- a/content/browser/private_aggregation/private_aggregation_host.cc +++ b/content/browser/private_aggregation/private_aggregation_host.cc
@@ -118,13 +118,10 @@ contribution_ptr) { return contribution_ptr.is_null(); })); DCHECK(!debug_mode_details.is_null()); - if (contribution_ptrs.size() > kMaxNumberOfContributions) { - // TODO(crbug.com/1323324): Add histograms for monitoring failures here, - // possibly broken out by failure reason. - mojo::ReportBadMessage("Too many contributions"); - RecordSendHistogramReportResultHistogram( - SendHistogramReportResult::kTooManyContributions); - return; + bool too_many_contributions = + contribution_ptrs.size() > kMaxNumberOfContributions; + if (too_many_contributions) { + contribution_ptrs.resize(kMaxNumberOfContributions); } std::vector<mojom::AggregatableReportHistogramContribution> contributions; @@ -194,7 +191,11 @@ on_report_request_received_.Run(std::move(report_request.value()), std::move(budget_key.value())); - RecordSendHistogramReportResultHistogram(SendHistogramReportResult::kSuccess); + + RecordSendHistogramReportResultHistogram( + too_many_contributions ? SendHistogramReportResult:: + kSuccessButTruncatedDueToTooManyContributions + : SendHistogramReportResult::kSuccess); } } // namespace content
diff --git a/content/browser/private_aggregation/private_aggregation_host.h b/content/browser/private_aggregation/private_aggregation_host.h index 4f21985e..363b634 100644 --- a/content/browser/private_aggregation/private_aggregation_host.h +++ b/content/browser/private_aggregation/private_aggregation_host.h
@@ -36,7 +36,7 @@ enum class SendHistogramReportResult { kSuccess = 0, kApiDisabledInSettings = 1, - kTooManyContributions = 2, + kSuccessButTruncatedDueToTooManyContributions = 2, kDebugKeyPresentWithoutDebugMode = 3, kReportRequestCreationFailed = 4, kMaxValue = kReportRequestCreationFailed,
diff --git a/content/browser/private_aggregation/private_aggregation_host_unittest.cc b/content/browser/private_aggregation/private_aggregation_host_unittest.cc index 30c2949..e3a96d9 100644 --- a/content/browser/private_aggregation/private_aggregation_host_unittest.cc +++ b/content/browser/private_aggregation/private_aggregation_host_unittest.cc
@@ -4,6 +4,8 @@ #include "content/browser/private_aggregation/private_aggregation_host.h" +#include <stddef.h> + #include <memory> #include <utility> #include <vector> @@ -395,15 +397,6 @@ /*bucket=*/123, /*value=*/-1)); std::vector<mojom::AggregatableReportHistogramContributionPtr> - too_many_contributions; - for (int i = 0; i < PrivateAggregationHost::kMaxNumberOfContributions + 1; - ++i) { - too_many_contributions.push_back( - mojom::AggregatableReportHistogramContribution::New( - /*bucket=*/123, /*value=*/1)); - } - - std::vector<mojom::AggregatableReportHistogramContributionPtr> valid_contributions; valid_contributions.push_back( mojom::AggregatableReportHistogramContribution::New( @@ -426,19 +419,6 @@ { base::HistogramTester histogram; - remote->SendHistogramReport(std::move(too_many_contributions), - mojom::AggregationServiceMode::kDefault, - mojom::DebugModeDetails::New()); - remote.FlushForTesting(); - histogram.ExpectUniqueSample( - kSendHistogramReportResultHistogram, - PrivateAggregationHost::SendHistogramReportResult:: - kTooManyContributions, - 1); - } - { - base::HistogramTester histogram; - remote->SendHistogramReport( std::move(valid_contributions), mojom::AggregationServiceMode::kDefault, // Debug mode must be enabled for a debug key to be set. @@ -453,6 +433,46 @@ } } +TEST_F(PrivateAggregationHostTest, TooManyContributions_Truncated) { + const url::Origin kExampleOrigin = + url::Origin::Create(GURL("https://example.com")); + const url::Origin kMainFrameOrigin = + url::Origin::Create(GURL("https://main_frame.com")); + + mojo::Remote<mojom::PrivateAggregationHost> remote; + EXPECT_TRUE(host_->BindNewReceiver(kExampleOrigin, kMainFrameOrigin, + PrivateAggregationBudgetKey::Api::kFledge, + remote.BindNewPipeAndPassReceiver())); + std::vector<mojom::AggregatableReportHistogramContributionPtr> + too_many_contributions; + for (int i = 0; i < PrivateAggregationHost::kMaxNumberOfContributions + 1; + ++i) { + too_many_contributions.push_back( + mojom::AggregatableReportHistogramContribution::New( + /*bucket=*/123, /*value=*/1)); + } + + base::HistogramTester histogram; + + absl::optional<AggregatableReportRequest> validated_request; + EXPECT_CALL(mock_callback_, Run).WillOnce(MoveArg<0>(&validated_request)); + + remote->SendHistogramReport(std::move(too_many_contributions), + mojom::AggregationServiceMode::kDefault, + mojom::DebugModeDetails::New()); + remote.FlushForTesting(); + histogram.ExpectUniqueSample( + kSendHistogramReportResultHistogram, + PrivateAggregationHost::SendHistogramReportResult:: + kSuccessButTruncatedDueToTooManyContributions, + 1); + + ASSERT_TRUE(validated_request); + EXPECT_EQ( + validated_request->payload_contents().contributions.size(), + static_cast<size_t>(PrivateAggregationHost::kMaxNumberOfContributions)); +} + TEST_F(PrivateAggregationHostTest, PrivateAggregationAllowed_RequestSucceeds) { base::HistogramTester histogram;
diff --git a/content/browser/private_aggregation/private_aggregation_manager_impl.cc b/content/browser/private_aggregation/private_aggregation_manager_impl.cc index ccf4d421..483151b 100644 --- a/content/browser/private_aggregation/private_aggregation_manager_impl.cc +++ b/content/browser/private_aggregation/private_aggregation_manager_impl.cc
@@ -148,6 +148,8 @@ PrivateAggregationBudgeter::RequestResult request_result) { RecordBudgeterResultHistogram(request_result); + // TODO(alexmt): Consider allowing a subset of contributions to be sent if + // there's insufficient budget for them all. if (request_result != PrivateAggregationBudgeter::RequestResult::kApproved) { return; }
diff --git a/content/browser/renderer_host/cross_process_frame_connector.cc b/content/browser/renderer_host/cross_process_frame_connector.cc index 1300c9c..02520a1 100644 --- a/content/browser/renderer_host/cross_process_frame_connector.cc +++ b/content/browser/renderer_host/cross_process_frame_connector.cc
@@ -24,6 +24,7 @@ #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom.h" #include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" +#include "ui/base/cursor/cursor.h" #include "ui/gfx/geometry/dip_util.h" namespace content { @@ -218,7 +219,7 @@ render_widget_host->UpdateVisualProperties(propagate); } -void CrossProcessFrameConnector::UpdateCursor(const WebCursor& cursor) { +void CrossProcessFrameConnector::UpdateCursor(const ui::Cursor& cursor) { RenderWidgetHostViewBase* root_view = GetRootRenderWidgetHostView(); // UpdateCursor messages are ignored if the root view does not support // cursors.
diff --git a/content/browser/renderer_host/cross_process_frame_connector.h b/content/browser/renderer_host/cross_process_frame_connector.h index e8e7ef9..05ecb60 100644 --- a/content/browser/renderer_host/cross_process_frame_connector.h +++ b/content/browser/renderer_host/cross_process_frame_connector.h
@@ -33,6 +33,10 @@ class RenderFrameMetadata; } +namespace ui { +class Cursor; +} + namespace viz { class SurfaceId; class SurfaceInfo; @@ -43,7 +47,6 @@ class RenderFrameProxyHost; class RenderWidgetHostViewBase; class RenderWidgetHostViewChildFrame; -class WebCursor; // CrossProcessFrameConnector provides the platform view abstraction for // RenderWidgetHostViewChildFrame allowing RWHVChildFrame to remain ignorant @@ -145,7 +148,7 @@ // Request that the platform change the mouse cursor when the mouse is // positioned over this view's content. - void UpdateCursor(const WebCursor& cursor); + void UpdateCursor(const ui::Cursor& cursor); // Given a point in the current view's coordinate space, return the same // point transformed into the coordinate space of the top-level view's
diff --git a/content/browser/renderer_host/cursor_manager.cc b/content/browser/renderer_host/cursor_manager.cc index 97f970f..845c116d 100644 --- a/content/browser/renderer_host/cursor_manager.cc +++ b/content/browser/renderer_host/cursor_manager.cc
@@ -5,6 +5,8 @@ #include "content/browser/renderer_host/cursor_manager.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" +#include "ui/base/cursor/cursor.h" +#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" namespace content { @@ -14,7 +16,7 @@ CursorManager::~CursorManager() {} void CursorManager::UpdateCursor(RenderWidgetHostViewBase* view, - const WebCursor& cursor) { + const ui::Cursor& cursor) { cursor_map_[view] = cursor; if (view == view_under_cursor_) root_view_->DisplayCursor(cursor); @@ -31,7 +33,7 @@ // ignored. root_view_->UpdateTooltip(std::u16string()); view_under_cursor_ = view; - WebCursor cursor(ui::mojom::CursorType::kPointer); + ui::Cursor cursor(ui::mojom::CursorType::kPointer); auto it = cursor_map_.find(view); if (it != cursor_map_.end()) @@ -54,7 +56,7 @@ } bool CursorManager::GetCursorForTesting(RenderWidgetHostViewBase* view, - WebCursor& cursor) { + ui::Cursor& cursor) { if (cursor_map_.find(view) == cursor_map_.end()) return false;
diff --git a/content/browser/renderer_host/cursor_manager.h b/content/browser/renderer_host/cursor_manager.h index 229475d..9e8a32f 100644 --- a/content/browser/renderer_host/cursor_manager.h +++ b/content/browser/renderer_host/cursor_manager.h
@@ -9,7 +9,7 @@ #include "base/memory/raw_ptr.h" #include "content/common/content_export.h" -#include "content/common/cursors/webcursor.h" +#include "ui/base/cursor/cursor.h" namespace content { @@ -28,7 +28,7 @@ // Called for any RenderWidgetHostView that received an UpdateCursor message // from its renderer process. - void UpdateCursor(RenderWidgetHostViewBase*, const WebCursor&); + void UpdateCursor(RenderWidgetHostViewBase*, const ui::Cursor&); // Called when the mouse moves over a different RenderWidgetHostView. void UpdateViewUnderCursor(RenderWidgetHostViewBase*); @@ -46,11 +46,11 @@ // Accessor for browser tests, enabling verification of the cursor_map_. // Returns false if the provided View is not in the map, and outputs // the cursor otherwise. - bool GetCursorForTesting(RenderWidgetHostViewBase*, WebCursor&); + bool GetCursorForTesting(RenderWidgetHostViewBase*, ui::Cursor&); private: // Stores the last received cursor from each RenderWidgetHostView. - std::map<RenderWidgetHostViewBase*, WebCursor> cursor_map_; + std::map<RenderWidgetHostViewBase*, ui::Cursor> cursor_map_; // The view currently underneath the cursor, which corresponds to the cursor // currently displayed.
diff --git a/content/browser/renderer_host/cursor_manager_unittest.cc b/content/browser/renderer_host/cursor_manager_unittest.cc index 879e57e..3f2e7a7 100644 --- a/content/browser/renderer_host/cursor_manager_unittest.cc +++ b/content/browser/renderer_host/cursor_manager_unittest.cc
@@ -10,13 +10,13 @@ #include "content/browser/renderer_host/mock_render_widget_host.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/site_instance_group.h" -#include "content/common/cursors/webcursor.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_browser_context.h" #include "content/test/mock_render_widget_host_delegate.h" #include "content/test/test_render_view_host.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" // CursorManager is only instantiated on Aura and Mac. @@ -34,16 +34,16 @@ cursor_manager_ = std::make_unique<CursorManager>(this); } - void DisplayCursor(const WebCursor& cursor) override { + void DisplayCursor(const ui::Cursor& cursor) override { current_cursor_ = cursor; } CursorManager* GetCursorManager() override { return cursor_manager_.get(); } - const WebCursor& cursor() { return current_cursor_; } + const ui::Cursor& cursor() { return current_cursor_; } private: - WebCursor current_cursor_; + ui::Cursor current_cursor_; std::unique_ptr<CursorManager> cursor_manager_; }; @@ -105,9 +105,9 @@ top_view_->GetCursorManager()->UpdateViewUnderCursor(top_view_); // The view should be using the default cursor. - EXPECT_EQ(top_view_->cursor(), WebCursor()); + EXPECT_EQ(top_view_->cursor(), ui::Cursor()); - WebCursor cursor_hand(ui::mojom::CursorType::kHand); + ui::Cursor cursor_hand(ui::mojom::CursorType::kHand); // Update the view with a non-default cursor. top_view_->GetCursorManager()->UpdateCursor(top_view_, cursor_hand); @@ -123,7 +123,7 @@ std::unique_ptr<MockRenderWidgetHostViewForCursors> child_view( new MockRenderWidgetHostViewForCursors(widget_host.get(), false)); - WebCursor cursor_hand(ui::mojom::CursorType::kHand); + ui::Cursor cursor_hand(ui::mojom::CursorType::kHand); // Set the child frame's cursor to a hand. This should not propagate to the // top-level view without the mouse moving over the child frame. @@ -150,11 +150,9 @@ std::unique_ptr<MockRenderWidgetHostViewForCursors> child_view2( new MockRenderWidgetHostViewForCursors(widget_host2.get(), false)); - WebCursor cursor_hand(ui::mojom::CursorType::kHand); - - WebCursor cursor_cross(ui::mojom::CursorType::kCross); - - WebCursor cursor_pointer(ui::mojom::CursorType::kPointer); + ui::Cursor cursor_hand(ui::mojom::CursorType::kHand); + ui::Cursor cursor_cross(ui::mojom::CursorType::kCross); + ui::Cursor cursor_pointer(ui::mojom::CursorType::kPointer); // Initialize each View to a different cursor. top_view_->GetCursorManager()->UpdateCursor(top_view_, cursor_hand);
diff --git a/content/browser/renderer_host/input/touch_emulator.cc b/content/browser/renderer_host/input/touch_emulator.cc index 3ca86e19..2b45a83 100644 --- a/content/browser/renderer_host/input/touch_emulator.cc +++ b/content/browser/renderer_host/input/touch_emulator.cc
@@ -160,12 +160,13 @@ use_2x ? IDR_DEVTOOLS_PINCH_CURSOR_ICON_2X : IDR_DEVTOOLS_PINCH_CURSOR_ICON); - pointer_cursor_ = WebCursor(ui::mojom::CursorType::kPointer); + pointer_cursor_ = ui::Cursor(ui::mojom::CursorType::kPointer); return true; } -gfx::SizeF TouchEmulator::InitCursorFromResource( - WebCursor* cursor, float scale, int resource_id) { +gfx::SizeF TouchEmulator::InitCursorFromResource(ui::Cursor* cursor, + float scale, + int resource_id) { gfx::Image& cursor_image = content::GetContentClient()->GetNativeImageNamed(resource_id); ui::Cursor cursor_info(ui::mojom::CursorType::kCustom); @@ -174,7 +175,7 @@ cursor_info.set_custom_hotspot( gfx::Point(cursor_image.Width() / 2, cursor_image.Height() / 2)); - *cursor = WebCursor(cursor_info); + *cursor = cursor_info; return gfx::ScaleSize(gfx::SizeF(cursor_image.Size()), 1.f / scale); }
diff --git a/content/browser/renderer_host/input/touch_emulator.h b/content/browser/renderer_host/input/touch_emulator.h index d15c79b9..267238c7 100644 --- a/content/browser/renderer_host/input/touch_emulator.h +++ b/content/browser/renderer_host/input/touch_emulator.h
@@ -13,9 +13,9 @@ #include "base/time/time.h" #include "content/browser/renderer_host/input/touch_emulator_client.h" #include "content/common/content_export.h" -#include "content/common/cursors/webcursor.h" #include "third_party/blink/public/common/input/web_touch_event.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" +#include "ui/base/cursor/cursor.h" #include "ui/events/gesture_detection/filtered_gesture_provider.h" #include "ui/events/gesture_detection/gesture_provider_config_helper.h" #include "ui/gfx/geometry/size_f.h" @@ -105,8 +105,9 @@ bool RequiresDoubleTapGestureEvents() const override; // Returns cursor size in DIP. - gfx::SizeF InitCursorFromResource( - WebCursor* cursor, float scale, int resource_id); + gfx::SizeF InitCursorFromResource(ui::Cursor* cursor, + float scale, + int resource_id); bool InitCursors(float device_scale_factor, bool force); void ResetState(); void UpdateCursor(); @@ -149,9 +150,9 @@ bool use_2x_cursors_; // While emulation is on, default cursor is touch. Pressing shift changes // cursor to the pinch one. - WebCursor pointer_cursor_; - WebCursor touch_cursor_; - WebCursor pinch_cursor_; + ui::Cursor pointer_cursor_; + ui::Cursor touch_cursor_; + ui::Cursor pinch_cursor_; gfx::SizeF cursor_size_; // These are used to drop extra mouse move events coming too quickly, so
diff --git a/content/browser/renderer_host/input/touch_emulator_client.h b/content/browser/renderer_host/input/touch_emulator_client.h index 952695d40..17ef3555 100644 --- a/content/browser/renderer_host/input/touch_emulator_client.h +++ b/content/browser/renderer_host/input/touch_emulator_client.h
@@ -5,11 +5,14 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_EMULATOR_CLIENT_H_ #define CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_EMULATOR_CLIENT_H_ -#include "content/common/cursors/webcursor.h" #include "third_party/blink/public/common/input/web_gesture_event.h" #include "third_party/blink/public/common/input/web_touch_event.h" #include "ui/base/ui_base_types.h" +namespace ui { +class Cursor; +} + namespace content { class RenderWidgetHostViewBase; @@ -23,7 +26,7 @@ const blink::WebGestureEvent& event) = 0; virtual void ForwardEmulatedTouchEvent(const blink::WebTouchEvent& event, RenderWidgetHostViewBase* target) = 0; - virtual void SetCursor(const WebCursor& cursor) = 0; + virtual void SetCursor(const ui::Cursor& cursor) = 0; // |target| is the view associated with the corresponding input event. virtual void ShowContextMenuAtPoint(const gfx::Point& point, const ui::MenuSourceType source_type,
diff --git a/content/browser/renderer_host/input/touch_emulator_unittest.cc b/content/browser/renderer_host/input/touch_emulator_unittest.cc index bc7b976..2d364c9 100644 --- a/content/browser/renderer_host/input/touch_emulator_unittest.cc +++ b/content/browser/renderer_host/input/touch_emulator_unittest.cc
@@ -86,9 +86,7 @@ } } - void SetCursor(const WebCursor& cursor) override { - cursor_ = cursor; - } + void SetCursor(const ui::Cursor& cursor) override { cursor_ = cursor; } void ShowContextMenuAtPoint(const gfx::Point& point, const ui::MenuSourceType source_type, @@ -253,7 +251,7 @@ void DisableSynchronousTouchAck() { ack_touches_synchronously_ = false; } - float GetCursorScaleFactor() { return cursor_.cursor().image_scale_factor(); } + float GetCursorScaleFactor() { return cursor_.image_scale_factor(); } private: base::test::SingleThreadTaskEnvironment task_environment_; @@ -267,7 +265,7 @@ int last_mouse_x_; int last_mouse_y_; std::vector<WebTouchEvent> touch_events_to_ack_; - WebCursor cursor_; + ui::Cursor cursor_; };
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc index 00a9bfa6..06d0c32f 100644 --- a/content/browser/renderer_host/navigation_controller_impl.cc +++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -3807,9 +3807,10 @@ blink::mojom::CommitNavigationParamsPtr commit_params = blink::mojom::CommitNavigationParams::New( absl::nullopt, - // The correct storage key will be computed before committing the - // navigation. - blink::StorageKey(), override_user_agent, params.redirect_chain, + // The correct storage key and session storage key will be computed + // before committing the navigation. + blink::StorageKey(), blink::StorageKey(), override_user_agent, + params.redirect_chain, std::vector<network::mojom::URLResponseHeadPtr>(), std::vector<net::RedirectInfo>(), params.post_content_type, common_params->url, common_params->method,
diff --git a/content/browser/renderer_host/navigation_entry_impl.cc b/content/browser/renderer_host/navigation_entry_impl.cc index a2380bb..343b740 100644 --- a/content/browser/renderer_host/navigation_entry_impl.cc +++ b/content/browser/renderer_host/navigation_entry_impl.cc
@@ -896,10 +896,10 @@ blink::mojom::CommitNavigationParamsPtr commit_params = blink::mojom::CommitNavigationParams::New( absl::nullopt, - // The correct storage key will be computed before committing the - // navigation. - blink::StorageKey(), GetIsOverridingUserAgent(), redirects, - std::vector<network::mojom::URLResponseHeadPtr>(), + // The correct storage key and session storage key will be computed + // before committing the navigation. + blink::StorageKey(), blink::StorageKey(), GetIsOverridingUserAgent(), + redirects, std::vector<network::mojom::URLResponseHeadPtr>(), std::vector<net::RedirectInfo>(), std::string(), original_url, original_method, GetCanLoadLocalResources(), frame_entry.page_state().ToEncodedData(), GetUniqueID(),
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 77f0dc26..d887a5b6 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc
@@ -1253,9 +1253,9 @@ blink::mojom::CommitNavigationParamsPtr commit_params = blink::mojom::CommitNavigationParams::New( absl::nullopt, - // The correct storage key will be computed before committing the - // navigation. - blink::StorageKey(), override_user_agent, + // The correct storage key and session storage key will be computed + // before committing the navigation. + blink::StorageKey(), blink::StorageKey(), override_user_agent, /*redirects=*/std::vector<GURL>(), /*redirect_response=*/ std::vector<network::mojom::URLResponseHeadPtr>(), @@ -1398,9 +1398,10 @@ blink::mojom::CommitNavigationParamsPtr commit_params = blink::mojom::CommitNavigationParams::New( absl::nullopt, - // The correct storage key is computed right after creating the - // NavigationRequest below. - blink::StorageKey(), is_overriding_user_agent, redirects, + // The correct storage key and session storage key are computed right + // after creating the NavigationRequest below. + blink::StorageKey(), blink::StorageKey(), is_overriding_user_agent, + redirects, /*redirect_response=*/ std::vector<network::mojom::URLResponseHeadPtr>(), /*redirect_infos=*/std::vector<net::RedirectInfo>(), @@ -1476,13 +1477,24 @@ navigation_request->ComputeFencedFrameNonce()); url::Origin top_level_origin = render_frame_host->ComputeTopFrameOrigin(origin); - navigation_request->commit_params_->storage_key = - blink::StorageKey::CreateWithOptionalNonce( - origin, net::SchemefulSite(top_level_origin), - base::OptionalToPtr(nonce), - render_frame_host->ComputeSiteForCookies().IsNull() - ? blink::mojom::AncestorChainBit::kCrossSite - : blink::mojom::AncestorChainBit::kSameSite); + // If the `nonce` is set the `top_level_site` must be the same as `origin` and + // the `ancestor_chain_bit` must be kSameSite. + if (nonce) { + navigation_request->commit_params_->storage_key = + blink::StorageKey::CreateWithOptionalNonce( + origin, net::SchemefulSite(origin), base::OptionalToPtr(nonce), + blink::mojom::AncestorChainBit::kSameSite); + } else { + navigation_request->commit_params_->storage_key = + blink::StorageKey::CreateWithOptionalNonce( + origin, net::SchemefulSite(top_level_origin), nullptr, + render_frame_host->ComputeSiteForCookies().IsNull() + ? blink::mojom::AncestorChainBit::kCrossSite + : blink::mojom::AncestorChainBit::kSameSite); + } + navigation_request->commit_params_->session_storage_key = + frame_tree_node->frame_tree().GetSessionStorageKey( + navigation_request->commit_params_->storage_key); navigation_request->web_bundle_navigation_info_ = std::move(web_bundle_navigation_info); if (subresource_web_bundle_navigation_info) { @@ -5222,6 +5234,9 @@ ComputeFencedFrameNonce()); commit_params_->storage_key = render_frame_host_->CalculateStorageKey( GetOriginToCommit().value(), base::OptionalToPtr(nonce)); + commit_params_->session_storage_key = + frame_tree_node()->frame_tree().GetSessionStorageKey( + commit_params_->storage_key); if (IsServedFromBackForwardCache() || IsPrerenderedPageActivation()) { CommitPageActivation();
diff --git a/content/browser/renderer_host/page_impl.cc b/content/browser/renderer_host/page_impl.cc index 1c55759..03180d3 100644 --- a/content/browser/renderer_host/page_impl.cc +++ b/content/browser/renderer_host/page_impl.cc
@@ -18,6 +18,7 @@ #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/public/browser/render_view_host.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/loader/loader_constants.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value.h" @@ -27,7 +28,13 @@ PageImpl::PageImpl(RenderFrameHostImpl& rfh, PageDelegate& delegate) : main_document_(rfh), delegate_(delegate), - text_autosizer_page_info_({0, 0, 1.f}) {} + text_autosizer_page_info_({0, 0, 1.f}) { + if (base::FeatureList::IsEnabled( + blink::features::kSharedStorageReportEventLimit)) { + select_url_report_event_budget_ = static_cast<double>( + blink::features::kSharedStorageReportEventBitBudgetPerPageLoad.Get()); + } +} PageImpl::~PageImpl() { // As SupportsUserData is a base class of PageImpl, Page members will be @@ -321,4 +328,47 @@ return true; } +bool PageImpl::CheckAndMaybeDebitReportEventForSelectURLBudget( + RenderFrameHost& rfh) { + if (!select_url_report_event_budget_.has_value()) { + // `blink::features::kSharedStorageReportEventLimit` is disabled. + return true; + } + + std::vector<const SharedStorageBudgetMetadata*> metadata_vector = + static_cast<RenderFrameHostImpl&>(rfh) + .frame_tree_node() + ->FindSharedStorageBudgetMetadata(); + + // Get the total charge. + double total_to_charge = 0; + for (const auto* metadata : metadata_vector) { + if (metadata->report_event_called) { + // The bits have already been charged for this URN. + continue; + } + + total_to_charge += metadata->budget_to_charge; + } + + if (total_to_charge > select_url_report_event_budget_.value()) { + // There is insufficient budget remaining. + return false; + } + + // Set flag(s) that `reportEvent()` has now been called. + for (const auto* metadata : metadata_vector) { + if (metadata->report_event_called) { + // The bits have already been charged for this URN. + continue; + } + + metadata->report_event_called = true; + } + + // There is sufficient budget, so charge the total now. + select_url_report_event_budget_.value() -= total_to_charge; + return true; +} + } // namespace content
diff --git a/content/browser/renderer_host/page_impl.h b/content/browser/renderer_host/page_impl.h index a0ad97b..dd06963 100644 --- a/content/browser/renderer_host/page_impl.h +++ b/content/browser/renderer_host/page_impl.h
@@ -184,6 +184,17 @@ // true. bool IsSelectURLAllowed(const url::Origin& origin); + // Returns whether a pending call to `fence.reportEvent()` with + // `FencedFrame::ReportingDestination::kSharedStorageSelectUrl` should be + // allowed. If `blink::features::kSharedStorageReportEventLimit` is enabled, + // checks whether sufficient budget remains in + // `select_url_report_event_budget_`, and if so, deducts the bits + // corresponding to the current call (if they haven't previously been deducted + // for this URN) and returns true. If + // `blink::features::kSharedStorageReportEventLimit` is disabled, always + // returns true without deducting any bits. + bool CheckAndMaybeDebitReportEventForSelectURLBudget(RenderFrameHost& rfh); + private: void DidActivateAllRenderViewsForPrerendering(); @@ -255,6 +266,15 @@ // `blink::features::kSharedStorageSelectURLLimit` is enabled. base::flat_map<url::Origin, int> select_url_count_; + // If `blink::features::kSharedStorageReportEventLimit` is enabled, the + // maximum number of bits of entropy per pageload that are allowed to leak via + // calls to `fence.reportEvent()` with + // `FencedFrame::ReportingDestination::kSharedStorageSelectUrl`. Any + // additional such calls will be blocked. + // `absl::nullopt` if `blink::features::kSharedStorageReportEventLimit` is + // disabled. + absl::optional<double> select_url_report_event_budget_; + // This class is owned by the main RenderFrameHostImpl and it's safe to keep a // reference to it. const raw_ref<RenderFrameHostImpl> main_document_;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 85eb813..b9351cc2 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4050,6 +4050,14 @@ blink::StorageKey RenderFrameHostImpl::CalculateStorageKey( const url::Origin& new_rfh_origin, const base::UnguessableToken* nonce) { + // If the nonce is set the `top_level_site` must be the same as + // `new_rfh_origin` and the `ancestor_chain_bit` must be kSameSite. + if (nonce) { + return blink::StorageKey::CreateWithOptionalNonce( + new_rfh_origin, net::SchemefulSite(new_rfh_origin), nonce, + blink::mojom::AncestorChainBit::kSameSite); + } + std::vector<RenderFrameHostImpl*> ancestor_chain; RenderFrameHostImpl* current = this; while (current) { @@ -4093,13 +4101,15 @@ blink::mojom::AncestorChainBit ancestor_chain_bit = blink::mojom::AncestorChainBit::kSameSite; for (auto* ancestor : ancestor_chain) { - if (!site_for_cookies.IsFirstParty(origin(ancestor).GetURL())) + if (!site_for_cookies.IsFirstParty(origin(ancestor).GetURL())) { ancestor_chain_bit = blink::mojom::AncestorChainBit::kCrossSite; + break; + } } return blink::StorageKey::CreateWithOptionalNonce( - new_rfh_origin, net::SchemefulSite(origin(ancestor_chain.back())), nonce, - ancestor_chain_bit); + new_rfh_origin, net::SchemefulSite(origin(ancestor_chain.back())), + nullptr, ancestor_chain_bit); } void RenderFrameHostImpl::SetOriginDependentStateOfNewFrame( @@ -7754,6 +7764,17 @@ return; } + if (destination == + blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl && + !GetOutermostMainFrame() + ->GetPage() + .CheckAndMaybeDebitReportEventForSelectURLBudget(*this)) { + AddMessageToConsole(blink::mojom::ConsoleMessageLevel::kError, + "The call to fence.reportEvent was blocked due to " + "insufficient budget."); + return; + } + // Construct the resource request. auto request = std::make_unique<network::ResourceRequest>();
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 7bf3ba9..a689c6e6 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -86,7 +86,6 @@ #include "content/browser/scheduler/browser_ui_thread_scheduler.h" #include "content/browser/storage_partition_impl.h" #include "content/common/content_constants_internal.h" -#include "content/common/cursors/webcursor.h" #include "content/common/frame.mojom.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -127,6 +126,7 @@ #include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/input/touch_event.mojom.h" #include "ui/base/clipboard/clipboard_constants.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h" #include "ui/base/ime/mojom/text_input_state.mojom.h" #include "ui/base/ui_base_features.h" @@ -2046,7 +2046,7 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) { if (view_) - view_->UpdateCursor(WebCursor(cursor)); + view_->UpdateCursor(cursor); } void RenderWidgetHostImpl::ShowContextMenuAtPoint(
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index b86c01ca..d5b8de3 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -27,6 +27,7 @@ #include "content/browser/renderer_host/render_widget_host_view_child_frame.h" #include "content/public/browser/render_widget_host_iterator.h" #include "third_party/blink/public/common/input/web_input_event.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/layout.h" #include "ui/compositor/compositor.h" #include "ui/gfx/geometry/dip_util.h" @@ -1960,7 +1961,7 @@ ui::LatencyInfo(), transformed_point, true /* emulated */); } -void RenderWidgetHostInputEventRouter::SetCursor(const WebCursor& cursor) { +void RenderWidgetHostInputEventRouter::SetCursor(const ui::Cursor& cursor) { if (!last_mouse_move_root_view_) return;
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h index 08dc71c..c0519d71 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.h +++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -178,7 +178,7 @@ const blink::WebGestureEvent& event) override; void ForwardEmulatedTouchEvent(const blink::WebTouchEvent& event, RenderWidgetHostViewBase* target) override; - void SetCursor(const WebCursor& cursor) override; + void SetCursor(const ui::Cursor& cursor) override; void ShowContextMenuAtPoint(const gfx::Point& point, const ui::MenuSourceType source_type, RenderWidgetHostViewBase* target) override;
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index f7ba794..2a91016 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -64,6 +64,7 @@ #include "third_party/blink/public/mojom/drag/drag.mojom.h" #include "third_party/blink/public/mojom/input/input_handler.mojom-shared.h" #include "third_party/blink/public/mojom/input/touch_event.mojom.h" +#include "ui/base/cursor/cursor.h" #include "ui/display/display_util.h" #include "ui/display/screen.h" #include "ui/events/base_event_utils.h" @@ -2425,7 +2426,7 @@ cursor.set_custom_bitmap(bitmap); host_->SetCursor(cursor); - EXPECT_EQ(WebCursor(cursor), view_->last_cursor()); + EXPECT_EQ(cursor, view_->last_cursor()); } } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 9238b37..2ee3f1b 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -84,6 +84,7 @@ #include "ui/android/view_android_observer.h" #include "ui/android/window_android.h" #include "ui/android/window_android_compositor.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/layout.h" #include "ui/base/ui_base_types.h" #include "ui/display/display_util.h" @@ -1200,8 +1201,8 @@ return window->mouse_wheel_scroll_factor() / view_.GetDipScale(); } -void RenderWidgetHostViewAndroid::UpdateCursor(const WebCursor& webcursor) { - view_.OnCursorChanged(webcursor.cursor()); +void RenderWidgetHostViewAndroid::UpdateCursor(const ui::Cursor& cursor) { + view_.OnCursorChanged(cursor); } void RenderWidgetHostViewAndroid::SetIsLoading(bool is_loading) {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 1c4032c..a116710 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -140,7 +140,7 @@ void EnsureSurfaceSynchronizedForWebTest() override; uint32_t GetCaptureSequenceNumber() const override; int GetMouseWheelMinimumGranularity() const override; - void UpdateCursor(const WebCursor& cursor) override; + void UpdateCursor(const ui::Cursor& cursor) override; void SetIsLoading(bool is_loading) override; void FocusedNodeChanged(bool is_editable_node, const gfx::Rect& node_bounds_in_screen) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index ddec0e1..65daab4 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -75,6 +75,7 @@ #include "ui/aura_extra/window_position_in_root_monitor.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/scoped_clipboard_writer.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" #include "ui/base/hit_test.h" #include "ui/base/ime/input_method.h" @@ -772,12 +773,12 @@ } } -void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor) { +void RenderWidgetHostViewAura::UpdateCursor(const ui::Cursor& cursor) { GetCursorManager()->UpdateCursor(this, cursor); } -void RenderWidgetHostViewAura::DisplayCursor(const WebCursor& cursor) { - current_cursor_ = cursor; +void RenderWidgetHostViewAura::DisplayCursor(const ui::Cursor& cursor) { + current_cursor_ = WebCursor(cursor); const display::Display display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_); current_cursor_.SetDisplayInfo(display);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 8ca7667..c057fffb 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -133,8 +133,8 @@ const gfx::Rect& pos, const gfx::Rect& anchor_rect) override; void Focus() override; - void UpdateCursor(const WebCursor& cursor) override; - void DisplayCursor(const WebCursor& cursor) override; + void UpdateCursor(const ui::Cursor& cursor) override; + void DisplayCursor(const ui::Cursor& cursor) override; CursorManager* GetCursorManager() override; void SetIsLoading(bool is_loading) override; void RenderProcessGone() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index 1a30c72..9a942b2b4 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -672,7 +672,7 @@ NOTIMPLEMENTED_LOG_ONCE(); } -void RenderWidgetHostViewBase::DisplayCursor(const WebCursor& cursor) { +void RenderWidgetHostViewBase::DisplayCursor(const ui::Cursor& cursor) { return; }
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index d46c8e1..1425fc2e 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -58,11 +58,12 @@ namespace ui { class Compositor; -enum class DomCode; +class Cursor; class LatencyInfo; class TouchEvent; +enum class DomCode; struct DidOverscrollParams; -} +} // namespace ui namespace content { @@ -73,7 +74,6 @@ class SyntheticGestureTarget; class TextInputManager; class TouchSelectionControllerClientManager; -class WebCursor; class WebContentsAccessibility; class DelegatedFrameHost; @@ -430,13 +430,12 @@ const gfx::Rect& bounds, const gfx::Rect& anchor_rect) = 0; - // Sets the cursor for this view to the one associated with the specified - // cursor_type. - virtual void UpdateCursor(const WebCursor& cursor) = 0; + // Sets the cursor for this view to the one specified. + virtual void UpdateCursor(const ui::Cursor& cursor) = 0; // Changes the cursor that is displayed on screen. This may or may not match // the current cursor's view which was set by UpdateCursor. - virtual void DisplayCursor(const WebCursor& cursor); + virtual void DisplayCursor(const ui::Cursor& cursor); // Views that manage cursors for window return a CursorManager. Other views // return nullptr.
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 8bfdba6c..0d51ac7 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
@@ -35,6 +35,7 @@ #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom.h" #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom.h" #include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/ime/mojom/text_input_state.mojom.h" #include "ui/display/display_util.h" #include "ui/gfx/geometry/dip_util.h" @@ -361,7 +362,7 @@ NOTREACHED(); } -void RenderWidgetHostViewChildFrame::UpdateCursor(const WebCursor& cursor) { +void RenderWidgetHostViewChildFrame::UpdateCursor(const ui::Cursor& cursor) { if (frame_connector_) frame_connector_->UpdateCursor(cursor); }
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h index 10f9a24..05c3c2d 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.h +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -108,7 +108,7 @@ void InitAsPopup(RenderWidgetHostView* parent_host_view, const gfx::Rect& bounds, const gfx::Rect& anchor_rect) override; - void UpdateCursor(const WebCursor& cursor) override; + void UpdateCursor(const ui::Cursor& cursor) override; void UpdateScreenInfo() override; void SendInitialPropertiesIfNeeded() override; void SetIsLoading(bool is_loading) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index c1f2725..a58b06e3 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -61,7 +61,6 @@ class RenderWidgetHost; class RenderWidgetHostViewMac; class WebContents; -class WebCursor; /////////////////////////////////////////////////////////////////////////////// // RenderWidgetHostViewMac @@ -131,8 +130,8 @@ const gfx::Rect& pos, const gfx::Rect& anchor_rect) override; void Focus() override; - void UpdateCursor(const WebCursor& cursor) override; - void DisplayCursor(const WebCursor& cursor) override; + void UpdateCursor(const ui::Cursor& cursor) override; + void DisplayCursor(const ui::Cursor& cursor) override; CursorManager* GetCursorManager() override; void OnDidNavigateMainFrameToNewPage() override; void SetIsLoading(bool is_loading) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 62799f0..ab7e3a74 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -61,6 +61,7 @@ #include "ui/base/cocoa/remote_accessibility_api.h" #import "ui/base/cocoa/secure_password_input.h" #include "ui/base/cocoa/text_services_context_menu.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/ime/mojom/text_input_state.mojom.h" #include "ui/base/mojom/attributed_string.mojom.h" #include "ui/base/ui_base_features.h" @@ -581,12 +582,12 @@ return mouse_locked_; } -void RenderWidgetHostViewMac::UpdateCursor(const WebCursor& cursor) { +void RenderWidgetHostViewMac::UpdateCursor(const ui::Cursor& cursor) { GetCursorManager()->UpdateCursor(this, cursor); } -void RenderWidgetHostViewMac::DisplayCursor(const WebCursor& cursor) { - ns_view_->DisplayCursor(cursor.cursor()); +void RenderWidgetHostViewMac::DisplayCursor(const ui::Cursor& cursor) { + ns_view_->DisplayCursor(cursor); } CursorManager* RenderWidgetHostViewMac::GetCursorManager() {
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index ff334339..4937126 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -401,6 +401,11 @@ ->browser_context() ->set_client_hints_controller_delegate( &client_hints_controller_delegate_); + + // Set a custom request handler for Sha256ScriptChecksum test. + embedded_test_server()->RegisterRequestHandler(base::BindRepeating( + &ServiceWorkerBrowserTest::HandleRequestForSha256ScriptChecksumTest, + base::Unretained(this))); } void TearDownOnMainThread() override { @@ -458,6 +463,32 @@ } private: + std::unique_ptr<net::test_server::HttpResponse> + HandleRequestForSha256ScriptChecksumTest( + const net::test_server::HttpRequest& request) { + GURL absolute_url = embedded_test_server()->GetURL(request.relative_url); + if (absolute_url.path() != "/service_worker/import_scripts_test.js") { + return nullptr; + } + + auto http_response = + std::make_unique<net::test_server::BasicHttpResponse>(); + http_response->set_code(net::HTTP_OK); + // Add a counter that is different every request to the script so that a + // service worker will detect it as a script update. + http_response->set_content( + "importScripts('empty.js'); var counter = " + + std::to_string(counter_for_sha256_checksum_test_) + ";"); + http_response->set_content_type("text/javascript"); + http_response->AddCustomHeader("Service-Worker-Allowed", "/"); + + counter_for_sha256_checksum_test_++; + + return http_response; + } + + int64_t counter_for_sha256_checksum_test_ = 0; + base::test::ScopedFeatureList feature_list_; scoped_refptr<ServiceWorkerContextWrapper> wrapper_; MockClientHintsControllerDelegate client_hints_controller_delegate_{ @@ -2274,6 +2305,139 @@ blink::ServiceWorkerStatusCode::kErrorNotFound); } +IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, + Sha256ScriptChecksum_ImportScripts) { + StartServerAndNavigateToSetup(); + + using ServiceWorkerScriptChecksumInfo = std::pair<GURL, std::string>; + std::map<std::string, ServiceWorkerScriptChecksumInfo> sw_scripts{ + {"main_script", + {embedded_test_server()->GetURL( + "/service_worker/import_scripts_test.js"), + "1507F551298E329B279C1077FA52926986465DD8E28831722568FBD01442CFD5"}}, + {"imported_script", + {embedded_test_server()->GetURL("/service_worker/empty.js"), + "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"}}}; + + std::map<std::string, ServiceWorkerScriptChecksumInfo> updated_sw_scripts{ + {"main_script", + {embedded_test_server()->GetURL( + "/service_worker/import_scripts_test.js"), + "45BC089A979085D4AFEC61990D1A3B05C88078A530A230157610E261D97F3187"}}, + {"imported_script", + {embedded_test_server()->GetURL("/service_worker/empty.js"), + "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"}}}; + + // Start the ServiceWorker. + WorkerRunningStatusObserver observer1(public_context()); + const GURL create_service_worker_url(embedded_test_server()->GetURL( + "/service_worker/create_service_worker.html")); + EXPECT_TRUE(NavigateToURL(shell(), create_service_worker_url)); + EXPECT_EQ("DONE", EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + "register('" + + sw_scripts["main_script"].first.spec() + "')")); + observer1.WaitUntilRunning(); + scoped_refptr<ServiceWorkerVersion> version = + wrapper()->GetLiveVersion(observer1.version_id()); + EXPECT_EQ(version->script_url(), sw_scripts["main_script"].first); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status()); + + // Validate checksums for each script, and ServiceWorkerVersion's one. + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources; + version->script_cache_map()->GetResources(&resources); + std::set<std::string> expected_checksums; + for (auto& sw_script : sw_scripts) { + expected_checksums.insert(sw_script.second.second); + } + EXPECT_EQ(expected_checksums.size(), resources.size()); + for (auto& resource : resources) { + EXPECT_TRUE(expected_checksums.find(resource->sha256_checksum.value()) != + expected_checksums.end()); + } + EXPECT_EQ("415B8002080749B4C042B3F3896A5574971C2DC2873505455709990B9B87169B", + version->sha256_script_checksum()); + + // Update the ServiceWorker. + ReloadBlockUntilNavigationsComplete(shell(), 1); + EXPECT_EQ("DONE", + EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + "register('" + + updated_sw_scripts["main_script"].first.spec() + "')")); + WorkerRunningStatusObserver observer2(public_context()); + const GURL scope(embedded_test_server()->GetURL("/service_worker")); + wrapper()->SkipWaitingWorker(scope, + blink::StorageKey(url::Origin::Create(scope))); + observer2.WaitUntilRunning(); + + scoped_refptr<ServiceWorkerVersion> updated_version = + wrapper()->GetLiveVersion(observer2.version_id()); + EXPECT_EQ(updated_version->script_url(), + updated_sw_scripts["main_script"].first); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, updated_version->running_status()); + + // Validate updated checksums for each script, and ServiceWorkerVersion's one. + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> updated_resources; + updated_version->script_cache_map()->GetResources(&updated_resources); + std::set<std::string> updated_expected_checksums; + for (auto& sw_script : updated_sw_scripts) { + updated_expected_checksums.insert(sw_script.second.second); + } + EXPECT_EQ(updated_expected_checksums.size(), updated_resources.size()); + for (auto& resource : updated_resources) { + EXPECT_TRUE( + updated_expected_checksums.find(resource->sha256_checksum.value()) != + updated_expected_checksums.end()); + } + + EXPECT_EQ("A7B70A7BF7F36340EFED59B725CF0DBB2B222D59F01448B8F55F372F1C5C2724", + updated_version->sha256_script_checksum()); +} + +IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, + Sha256ScriptChecksum_StaticImport) { + StartServerAndNavigateToSetup(); + + using ServiceWorkerScriptChecksumInfo = std::pair<GURL, std::string>; + std::map<std::string, ServiceWorkerScriptChecksumInfo> sw_scripts{ + {"main_script", + {embedded_test_server()->GetURL( + "/service_worker/static_import_worker.js"), + "9A61565460D4DD31E31625E08DFF783C96E24759BF2AC92F65449F5BB6C7E438"}}, + {"imported_script", + {embedded_test_server()->GetURL("/service_worker/worker.js"), + "8F940B6CD3F48EB992FAF65BA7500113CEEDE502922F1C09ED705FF47D181C67"}}}; + + // Start the ServiceWorker. + WorkerRunningStatusObserver observer1(public_context()); + const GURL create_service_worker_url(embedded_test_server()->GetURL( + "/service_worker/create_service_worker.html")); + EXPECT_TRUE(NavigateToURL(shell(), create_service_worker_url)); + EXPECT_EQ("DONE", + EvalJs(shell()->web_contents()->GetPrimaryMainFrame(), + "register('" + sw_scripts["main_script"].first.spec() + + "', null, 'module')")); + observer1.WaitUntilRunning(); + scoped_refptr<ServiceWorkerVersion> version = + wrapper()->GetLiveVersion(observer1.version_id()); + EXPECT_EQ(version->script_url(), sw_scripts["main_script"].first); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status()); + + // Validate checksums for each script, and ServiceWorkerVersion's one. + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources; + version->script_cache_map()->GetResources(&resources); + std::set<std::string> expected_checksums; + for (auto& sw_script : sw_scripts) { + expected_checksums.insert(sw_script.second.second); + } + EXPECT_EQ(expected_checksums.size(), resources.size()); + for (auto& resource : resources) { + EXPECT_TRUE(expected_checksums.find(resource->sha256_checksum.value()) != + expected_checksums.end()); + } + EXPECT_EQ("8CC1C2D44A6709AA9285BA56D2956C6F9A0D45678E9F6C0AFBCF02C2F224A811", + version->sha256_script_checksum()); +} + class CacheStorageSideDataSizeChecker : public base::RefCounted<CacheStorageSideDataSizeChecker> { public: @@ -4518,19 +4682,35 @@ run_loop.Run(); } +enum class SkipEmptyFetchHandlerEnum { + kDisabled, + kEnabled, + kEnabledAndStartWorker, +}; + class ServiceWorkerSkipEmptyFetchHandlerBrowserTest : public ServiceWorkerBrowserTest, - public testing::WithParamInterface<bool> { + public testing::WithParamInterface<SkipEmptyFetchHandlerEnum> { public: ServiceWorkerSkipEmptyFetchHandlerBrowserTest() { - if (is_feature_enabled()) { - scoped_feature_list_.InitWithFeaturesAndParameters( - {{features::kServiceWorkerSkipIgnorableFetchHandler, - {{"SkipEmptyFetchHandler", "true"}}}}, - {}); - } else { - scoped_feature_list_.InitWithFeaturesAndParameters( - {}, {{features::kServiceWorkerSkipIgnorableFetchHandler}}); + switch (GetParam()) { + case SkipEmptyFetchHandlerEnum::kEnabled: + scoped_feature_list_.InitWithFeaturesAndParameters( + {{features::kServiceWorkerSkipIgnorableFetchHandler, + {{"SkipEmptyFetchHandler", "true"}}}}, + {}); + break; + case SkipEmptyFetchHandlerEnum::kEnabledAndStartWorker: + scoped_feature_list_.InitWithFeaturesAndParameters( + {{features::kServiceWorkerSkipIgnorableFetchHandler, + {{"SkipEmptyFetchHandler", "true"}, + {"StartServiceWorkerForEmptyFetchHandler", "true"}}}}, + {}); + break; + case SkipEmptyFetchHandlerEnum::kDisabled: + scoped_feature_list_.InitWithFeaturesAndParameters( + {}, {{features::kServiceWorkerSkipIgnorableFetchHandler}}); + break; } } ~ServiceWorkerSkipEmptyFetchHandlerBrowserTest() override = default; @@ -4541,8 +4721,6 @@ return web_contents()->GetPrimaryMainFrame(); } - bool is_feature_enabled() { return GetParam(); } - protected: void SetUpOnMainThread() override { ServiceWorkerBrowserTest::SetUpOnMainThread(); @@ -4553,9 +4731,12 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -INSTANTIATE_TEST_SUITE_P(All, - ServiceWorkerSkipEmptyFetchHandlerBrowserTest, - testing::Bool()); +INSTANTIATE_TEST_SUITE_P( + All, + ServiceWorkerSkipEmptyFetchHandlerBrowserTest, + ::testing::Values(SkipEmptyFetchHandlerEnum::kDisabled, + SkipEmptyFetchHandlerEnum::kEnabled, + SkipEmptyFetchHandlerEnum::kEnabledAndStartWorker)); IN_PROC_BROWSER_TEST_P(ServiceWorkerSkipEmptyFetchHandlerBrowserTest, HasNotSkippedMetrics) { @@ -4630,23 +4811,38 @@ EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status()); // Conduct a main resource load. + WorkerRunningStatusObserver observer2(public_context()); EXPECT_TRUE(NavigateToURL(shell(), in_scope_url)); - if (is_feature_enabled()) { - // If the feature is enabled, navigation request doesn't start the service - // worker if the fetch handler is skipped. - EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status()); - tester.ExpectUniqueSample( - "ServiceWorker.FetchHandler.SkipReason", - ServiceWorkerControlleeRequestHandler::FetchHandlerSkipReason:: - kSkippedForEmptyFetchHandler, - 1); - - } else { - EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status()); - tester.ExpectUniqueSample("ServiceWorker.FetchHandler.SkipReason", - ServiceWorkerControlleeRequestHandler:: - FetchHandlerSkipReason::kNotSkipped, - 1); + switch (GetParam()) { + case SkipEmptyFetchHandlerEnum::kEnabled: + // In this case, navigation request doesn't start the service + // worker if the fetch handler is skipped. + EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status()); + tester.ExpectUniqueSample( + "ServiceWorker.FetchHandler.SkipReason", + ServiceWorkerControlleeRequestHandler::FetchHandlerSkipReason:: + kSkippedForEmptyFetchHandler, + 1); + break; + case SkipEmptyFetchHandlerEnum::kEnabledAndStartWorker: + // In this case, the service worker is started while the fetch handler is + // skipped. + observer2.WaitUntilRunning(); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status()); + tester.ExpectUniqueSample( + "ServiceWorker.FetchHandler.SkipReason", + ServiceWorkerControlleeRequestHandler::FetchHandlerSkipReason:: + kSkippedForEmptyFetchHandler, + 1); + break; + case SkipEmptyFetchHandlerEnum::kDisabled: + observer2.WaitUntilRunning(); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status()); + tester.ExpectUniqueSample("ServiceWorker.FetchHandler.SkipReason", + ServiceWorkerControlleeRequestHandler:: + FetchHandlerSkipReason::kNotSkipped, + 1); + break; } tester.ExpectUniqueSample( "ServiceWorker.FetchHandler."
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc index 2933ca661..4f0ee34 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -540,6 +540,21 @@ registration->active_version()->CountFeature( blink::mojom::WebFeature::kServiceWorkerSkippedForEmptyFetchHandler); CompleteWithoutLoader(); + if (!features::kStartServiceWorkerForEmptyFetchHandler.Get()) { + return; + } + // Start service worker if it is not running so that we run the code + // written in the top level. + if (registration->active_version()->running_status() == + EmbeddedWorkerStatus::STARTING || + registration->active_version()->running_status() == + EmbeddedWorkerStatus::RUNNING) { + return; + } + registration->active_version()->StartWorker( + ServiceWorkerMetrics::EventType::SKIP_EMPTY_FETCH_HANDLER, + base::BindOnce(&ServiceWorkerControlleeRequestHandler::DidStartWorker, + weak_factory_.GetWeakPtr())); return; } case ServiceWorkerVersion::FetchHandlerType::kNotSkippable: { @@ -561,9 +576,9 @@ } registration->active_version()->StartWorker( ServiceWorkerMetrics::EventType::BYPASS_MAIN_RESOURCE, - base::BindOnce(&ServiceWorkerControlleeRequestHandler:: - DidStartWorkerForSubresources, - weak_factory_.GetWeakPtr())); + base::BindOnce( + &ServiceWorkerControlleeRequestHandler::DidStartWorker, + weak_factory_.GetWeakPtr())); return; } // Otherwise, record the skip reason as kNotSkipped. @@ -590,11 +605,10 @@ loader_wrapper_->get()->AsWeakPtr()))); } -void ServiceWorkerControlleeRequestHandler::DidStartWorkerForSubresources( +void ServiceWorkerControlleeRequestHandler::DidStartWorker( blink::ServiceWorkerStatusCode status) { TRACE_EVENT_WITH_FLOW1( - "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::DidStartWorkerForSubresources", + "ServiceWorker", "ServiceWorkerControlleeRequestHandler::DidStartWorker", TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "Status", blink::ServiceWorkerStatusToString(status));
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h index 3f852e4..1dbfd67d 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.h +++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -127,11 +127,14 @@ // initial subresources load, if this handler was for a navigation. void MaybeScheduleUpdate(); - // Runs after ServiceWorker has started. Normally ServiceWorker starts before - // dispatching the main resource request, but if the - // ServiceWorkerBypassFetchHandler feature is enabled, we bypass the main - // resource request and then start ServiceWorker for subresources. - void DidStartWorkerForSubresources(blink::ServiceWorkerStatusCode status); + // Runs after ServiceWorker has started. + // Normally ServiceWorker starts before dispatching the main resource request, + // but if the ServiceWorkerBypassFetchHandler feature is enabled, we bypass + // the main resource request and then start ServiceWorker for subresources. + // Also, if we decided to start the service worker for + // the ServiceWorkerSkipEmptyFetchHandler feature and the browser handles + // an empty fetch handler, this runs after the service worker starts. + void DidStartWorker(blink::ServiceWorkerStatusCode status); const base::WeakPtr<ServiceWorkerContextCore> context_; const base::WeakPtr<ServiceWorkerContainerHost> container_host_;
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc index dc0ccdb..ca333493 100644 --- a/content/browser/service_worker/service_worker_metrics.cc +++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -126,6 +126,8 @@ return "_FETCH_FENCED_FRAME"; case ServiceWorkerMetrics::EventType::BYPASS_MAIN_RESOURCE: return "_BYPASS_MAIN_RESOURCE"; + case ServiceWorkerMetrics::EventType::SKIP_EMPTY_FETCH_HANDLER: + return "_SKIP_EMPTY_FETCH_HANDLER"; } return "_UNKNOWN"; } @@ -190,6 +192,8 @@ return "Fetch Fenced Frame"; case ServiceWorkerMetrics::EventType::BYPASS_MAIN_RESOURCE: return "_BYPASS_MAIN_RESOURCE"; + case ServiceWorkerMetrics::EventType::SKIP_EMPTY_FETCH_HANDLER: + return "Skip Empty Fetch Handler"; } NOTREACHED() << "Got unexpected event type: " << static_cast<int>(event_type); return "error"; @@ -402,6 +406,8 @@ // The bypass main resource should not be sent as an event. case EventType::NAVIGATION_HINT: // The navigation hint should not be sent as an event. + case EventType::SKIP_EMPTY_FETCH_HANDLER: + // The skip empty fetch handler should not be sent as an event. case EventType::UNKNOWN: NOTREACHED() << "Invalid event type"; break;
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h index 51c1290..b242685 100644 --- a/content/browser/service_worker/service_worker_metrics.h +++ b/content/browser/service_worker/service_worker_metrics.h
@@ -82,8 +82,9 @@ PUSH_SUBSCRIPTION_CHANGE = 35, FETCH_FENCED_FRAME = 36, BYPASS_MAIN_RESOURCE = 37, + SKIP_EMPTY_FETCH_HANDLER = 38, // Add new events to record here. - kMaxValue = BYPASS_MAIN_RESOURCE, + kMaxValue = SKIP_EMPTY_FETCH_HANDLER, }; // Not used for UMA.
diff --git a/content/browser/service_worker/service_worker_registry.cc b/content/browser/service_worker/service_worker_registry.cc index d6ad9b2f..8e5f5640 100644 --- a/content/browser/service_worker/service_worker_registry.cc +++ b/content/browser/service_worker/service_worker_registry.cc
@@ -913,9 +913,12 @@ registration.get(), data.script, data.script_type, data.version_id, std::move(version_reference), context_->AsWeakPtr()); version->set_fetch_handler_type(data.fetch_handler_type); + // Set resources before changing the status to ACTIVATED/INSTALLED. + // |sha256_script_checksum_| in ServiceWorkerVersion should be set before + // changing the status. + version->SetResources(resources); version->SetStatus(data.is_active ? ServiceWorkerVersion::ACTIVATED : ServiceWorkerVersion::INSTALLED); - version->script_cache_map()->SetResources(resources); if (data.origin_trial_tokens) version->SetValidOriginTrialTokens(*data.origin_trial_tokens);
diff --git a/content/browser/service_worker/service_worker_script_cache_map.cc b/content/browser/service_worker/service_worker_script_cache_map.cc index 6d7a6731..0fffee9 100644 --- a/content/browser/service_worker/service_worker_script_cache_map.cc +++ b/content/browser/service_worker/service_worker_script_cache_map.cc
@@ -78,7 +78,8 @@ } void ServiceWorkerScriptCacheMap::GetResources( - std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>* resources) { + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>* resources) + const { DCHECK(resources->empty()); for (ResourceMap::const_iterator it = resource_map_.begin(); it != resource_map_.end();
diff --git a/content/browser/service_worker/service_worker_script_cache_map.h b/content/browser/service_worker/service_worker_script_cache_map.h index ca0f5cf0..59cee354 100644 --- a/content/browser/service_worker/service_worker_script_cache_map.h +++ b/content/browser/service_worker/service_worker_script_cache_map.h
@@ -48,8 +48,8 @@ const std::string& status_message); // Used to retrieve the results of the initial run of a new version. - void GetResources( - std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>* resources); + void GetResources(std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>* + resources) const; // Used when loading an existing version. void SetResources(
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index acbbd30..687803e6 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -29,6 +29,7 @@ #include "base/time/default_clock.h" #include "base/time/default_tick_clock.h" #include "base/trace_event/trace_event.h" +#include "components/services/storage/public/mojom/service_worker_database.mojom-forward.h" #include "content/browser/bad_message.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h" @@ -49,6 +50,8 @@ #include "content/public/common/content_client.h" #include "content/public/common/content_features.h" #include "content/public/common/result_codes.h" +#include "crypto/secure_hash.h" +#include "crypto/sha2.h" #include "ipc/ipc_message.h" #include "mojo/public/c/system/types.h" #include "net/base/net_errors.h" @@ -206,6 +209,39 @@ } } +// This function merges SHA256 checksum hash strings in +// ServiceWokrerResourceRecord and return a single hash string. +std::string MergeResourceRecordSHA256ScriptChecksum( + const ServiceWorkerScriptCacheMap& script_cache_map) { + const std::unique_ptr<crypto::SecureHash> checksum = + crypto::SecureHash::Create(crypto::SecureHash::SHA256); + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources; + script_cache_map.GetResources(&resources); + // Sort |resources| by |sha256_checksum| value not to make the merged value + // inconsistent based on the script order. + std::sort(resources.begin(), resources.end(), + [](const storage::mojom::ServiceWorkerResourceRecordPtr& record1, + const storage::mojom::ServiceWorkerResourceRecordPtr& record2) { + return record1->sha256_checksum.value() < + record2->sha256_checksum.value(); + }); + + for (auto& resource : resources) { + // This may not be the case because we use the fixed length string, but + // insert a delimiter here to distinguish following cases to avoid hash + // value collisions: ab,cdef vs abcd,ef + const std::string checksum_with_delimiter = + resource->sha256_checksum.value() + "|"; + checksum->Update(checksum_with_delimiter.data(), + checksum_with_delimiter.size()); + } + + uint8_t result[crypto::kSHA256Length]; + checksum->Finish(result, crypto::kSHA256Length); + + return base::HexEncode(result); +} + } // namespace constexpr base::TimeDelta ServiceWorkerVersion::kTimeoutTimerDelay; @@ -1291,6 +1327,16 @@ } } + // Update |sha256_script_checksum_| if it's empty. This can happen when the + // script is updated and the new service worker version is created. This case + // ServiceWorkerVersion::SetResources() isn't called and + // |sha256_script_checksum_| should be empty. Calculate the checksum string + // with the script newly added/updated in |script_cache_map_|. + if (sha256_script_checksum_.empty()) { + sha256_script_checksum_ = + MergeResourceRecordSHA256ScriptChecksum(script_cache_map_); + } + // Fire all start callbacks. scoped_refptr<ServiceWorkerVersion> protect(this); FinishStartWorker(status); @@ -2673,4 +2719,13 @@ remote_reference_.BindNewPipeAndPassReceiver()); } +void ServiceWorkerVersion::SetResources( + const std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>& + resources) { + DCHECK_EQ(status_, NEW); + DCHECK(sha256_script_checksum_.empty()); + script_cache_map_.SetResources(resources); + sha256_script_checksum_ = + MergeResourceRecordSHA256ScriptChecksum(script_cache_map_); +} } // namespace content
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 1619eb5a..ae84635 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -673,6 +673,14 @@ return ancestor_frame_type_; } + // Used when loading an existing version. Sets ServiceWorkerResourceRecord to + // |script_cache_map_|, then updates |sha256_script_checksum_|. + void SetResources( + const std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>& + resources); + + std::string sha256_script_checksum() { return sha256_script_checksum_; } + private: friend class base::RefCounted<ServiceWorkerVersion>; friend class EmbeddedWorkerTestHelper; @@ -1198,6 +1206,15 @@ base::UnguessableToken reporting_source_; + // The checksum hash string, which is calculated from each checksum string in + // |script_cache_map_|'s resources. This will be used to decide if the main + // resource request is bypassed or not in the experiment (crbug.com/1371756). + // This field should be set before starting the service worker when the + // service worker starts with an existing version. But the field will be set + // after the worker has started when there is a change in the script and new + // version is created. + std::string sha256_script_checksum_; + base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_{this}; };
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc index f9b9c3c..3660b89 100644 --- a/content/browser/service_worker/service_worker_version_unittest.cc +++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -1909,5 +1909,26 @@ EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version_->running_status()); } +TEST_F(ServiceWorkerVersionTest, SetResources) { + // Create a new version + scoped_refptr<ServiceWorkerVersion> version = CreateNewServiceWorkerVersion( + helper_->context()->registry(), registration_.get(), + GURL("https://www.example.com/test/service_worker.js"), + blink::mojom::ScriptType::kClassic); + + // The checksum is empty because still no resource records. + EXPECT_EQ("", version->sha256_script_checksum()); + + // Set resource records. + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> records; + records.push_back(WriteToDiskCacheWithIdSync( + helper_->context()->GetStorageControl(), version->script_url(), 10, + {} /* headers */, "I'm a body", "I'm a meta data")); + version->SetResources(records); + + // The checksum has been calculated after the SetResources. + EXPECT_EQ("CBE5CFDF7C2118A9C3D78EF1D684F3AFA089201352886449A06A6511CFEF74A7", + version->sha256_script_checksum()); +} } // namespace service_worker_version_unittest } // namespace content
diff --git a/content/browser/shared_storage/shared_storage_browsertest.cc b/content/browser/shared_storage/shared_storage_browsertest.cc index 862e977..a78c2b53 100644 --- a/content/browser/shared_storage/shared_storage_browsertest.cc +++ b/content/browser/shared_storage/shared_storage_browsertest.cc
@@ -96,12 +96,31 @@ const int kMaxSelectURLCalls = 2; +const int kReportEventBitBudget = 6; + const char kSelectFrom8URLsScript[] = R"( let urls = []; for (let i = 0; i < 8; ++i) { urls.push({url: '/fenced_frames/title' + i.toString() + '.html', reportingMetadata: { - 'click': '/fenced_frames/report' + i.toString() + '.html' + 'click': '/fenced_frames/report' + i.toString() + '.html', + 'mouse interaction': + '/fenced_frames/report' + (i + 1).toString() + '.html' + }}); + } + + sharedStorage.selectURL( + 'test-url-selection-operation', urls, {data: {'mockResult': 1}}); + )"; + +const char kSelectFrom4URLsScript[] = R"( + let urls = []; + for (let i = 0; i < 4; ++i) { + urls.push({url: '/fenced_frames/title' + i.toString() + '.html', + reportingMetadata: { + 'click': '/fenced_frames/report' + i.toString() + '.html', + 'mouse interaction': + '/fenced_frames/report' + (i + 1).toString() + '.html' }}); } @@ -115,6 +134,20 @@ return base::StrCat({base::NumberToString(delta.InMilliseconds()), "ms"}); } +// With `WebContentsConsoleObserver`, we can only wait for the last message in a +// group. +base::RepeatingCallback< + bool(const content::WebContentsConsoleObserver::Message& message)> +MakeFilter(std::vector<std::string> possible_last_messages) { + return base::BindRepeating( + [](std::vector<std::string> possible_last_messages, + const content::WebContentsConsoleObserver::Message& message) { + return base::Contains(possible_last_messages, + base::UTF16ToUTF8(message.message)); + }, + std::move(possible_last_messages)); +} + void WaitForHistogram(const std::string& histogram_name) { // Continue if histogram was already recorded. if (base::StatisticsRecorder::FindHistogram(histogram_name)) @@ -3043,7 +3076,10 @@ EXPECT_THAT(GetSharedStorageReportingMap(GURL(urn_uuid)), UnorderedElementsAre( Pair("click", https_server()->GetURL( - "a.test", "/fenced_frames/report0.html")))); + "a.test", "/fenced_frames/report0.html")), + Pair("mouse interaction", + https_server()->GetURL("a.test", + "/fenced_frames/report1.html")))); EXPECT_EQ( https_server()->GetURL("a.test", "/fenced_frames/title0.html"), @@ -4499,4 +4535,425 @@ ExpectAccessObserved(expected_accesses); } +class SharedStorageReportEventLimitBrowserTest + : public SharedStorageReportEventBrowserTest, + public testing::WithParamInterface<bool> { + public: + SharedStorageReportEventLimitBrowserTest() { + if (GetParam()) { + feature_list_ + .InitWithFeaturesAndParameters(/*enabled_features=*/ + {{blink::features:: + kSharedStorageReportEventLimit, + {{"SharedStorageReportEventBitBudget" + "PerPageLoad", + base::NumberToString( + kReportEventBitBudget)}}}}, + /*disabled_features=*/{}); + } else { + feature_list_.InitWithFeaturesAndParameters( + /*enabled_features=*/{}, + /*disabled_features=*/ + {blink::features::kSharedStorageReportEventLimit}); + } + } + + // Precondition: `addModule('shared_storage/simple_module.js')` and + // `selectURL()` have been called in the main frame. + void RunSuccessfulReportEvents( + FrameTreeNode* fenced_frame_root_node, + net::test_server::ControllableHttpResponse* response1, + net::test_server::ControllableHttpResponse* response2) { + std::string click_event_data = "this is a click"; + EXPECT_TRUE( + ExecJs(fenced_frame_root_node, + JsReplace("window.fence.reportEvent({" + " eventType: 'click'," + " eventData: $1," + " destination: ['shared-storage-select-url']});", + click_event_data))); + + response1->WaitForRequest(); + EXPECT_EQ(response1->http_request()->content, click_event_data); + + std::string mouse_event_data = "this is a mouse interaction"; + EXPECT_TRUE( + ExecJs(fenced_frame_root_node, + JsReplace("window.fence.reportEvent({" + " eventType: 'mouse interaction'," + " eventData: $1," + " destination: ['shared-storage-select-url']});", + mouse_event_data))); + + response2->WaitForRequest(); + EXPECT_EQ(response2->http_request()->content, mouse_event_data); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +INSTANTIATE_TEST_SUITE_P(All, + SharedStorageReportEventLimitBrowserTest, + testing::Bool(), + [](const auto& info) { + if (info.param) { + return "ReportEventLimit"; + } else { + return "NoReportEventLimit"; + } + }); + +IN_PROC_BROWSER_TEST_P(SharedStorageReportEventLimitBrowserTest, + ReportEvent_SameEntropyCalls_LimitReached) { + // Here each call to `selectURL()` will have 8 input URLs, and hence + // 3 = log2(8) bits of entropy. + size_t call_limit = kReportEventBitBudget / 3; + + std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>> + responses; + for (size_t i = 0; i <= call_limit; ++i) { + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report1.html")); + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report2.html")); + } + ASSERT_TRUE(https_server()->Start()); + + GURL main_url = https_server()->GetURL("a.test", kSimplePagePath); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + WebContentsConsoleObserver console_observer(shell()->web_contents()); + console_observer.SetFilter( + MakeFilter({"The call to fence.reportEvent was blocked due to " + "insufficient budget."})); + + EXPECT_TRUE(ExecJs(shell(), R"( + sharedStorage.worklet.addModule('shared_storage/simple_module.js'); + )")); + + // There is one "worklet operation": `addModule()`. + test_worklet_host_manager() + .GetAttachedWorkletHost() + ->WaitForWorkletResponsesCount(1); + + std::vector<GURL> urns; + for (size_t i = 0; i <= call_limit; ++i) { + urns.emplace_back(EvalJs(shell(), kSelectFrom8URLsScript).ExtractString()); + } + + // There are `call_limit + 1` "worklet operations": `selectURL()`. + test_worklet_host_manager() + .GetAttachedWorkletHost() + ->WaitForWorkletResponsesCount(call_limit + 1); + + for (size_t i = 0; i < call_limit; ++i) { + FrameTreeNode* fenced_frame_root_node = CreateFencedFrame(urns[i]); + + RunSuccessfulReportEvents(fenced_frame_root_node, responses[2 * i].get(), + responses[2 * i + 1].get()); + } + + FrameTreeNode* fenced_frame_root_node = CreateFencedFrame(urns[call_limit]); + + if (GetParam()) { + // The limit for `reportEvent()` has now been reached for this page. Make + // one more call, which will be blocked. + std::string click_event_data = "this is a click"; + EXPECT_TRUE( + ExecJs(fenced_frame_root_node, + JsReplace("window.fence.reportEvent({" + " eventType: 'click'," + " eventData: $1," + " destination: ['shared-storage-select-url']});", + click_event_data))); + + EXPECT_TRUE(console_observer.Wait()); + ASSERT_LE(1u, console_observer.messages().size()); + EXPECT_EQ( + "The call to fence.reportEvent was blocked due to insufficient budget.", + base::UTF16ToUTF8(console_observer.messages().back().message)); + } else { + // The `reportEvent()` limit is disabled. The calls will run successfully. + RunSuccessfulReportEvents(fenced_frame_root_node, + responses[2 * call_limit].get(), + responses[2 * call_limit + 1].get()); + } +} + +IN_PROC_BROWSER_TEST_P(SharedStorageReportEventLimitBrowserTest, + ReportEvent_DifferentEntropyCalls_LimitReached) { + // Here the first call to `selectURL()` will have 8 input URLs, and hence + // 3 = log2(8) bits of entropy, and the subsequent calls will each have 4 + // input URLs, and hence 2 = log2(4) bits of entropy. + size_t input4_call_limit = (kReportEventBitBudget - 3) / 2; + + std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>> + responses; + for (size_t i = 0; i < input4_call_limit + 2; ++i) { + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report1.html")); + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report2.html")); + } + ASSERT_TRUE(https_server()->Start()); + + GURL main_url = https_server()->GetURL("a.test", kSimplePagePath); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + WebContentsConsoleObserver console_observer(shell()->web_contents()); + console_observer.SetFilter( + MakeFilter({"The call to fence.reportEvent was blocked due to " + "insufficient budget."})); + + EXPECT_TRUE(ExecJs(shell(), R"( + sharedStorage.worklet.addModule('shared_storage/simple_module.js'); + )")); + + // There is one "worklet operation": `addModule()`. + test_worklet_host_manager() + .GetAttachedWorkletHost() + ->WaitForWorkletResponsesCount(1); + + std::vector<GURL> urns; + urns.emplace_back(EvalJs(shell(), kSelectFrom8URLsScript).ExtractString()); + + for (size_t i = 0; i <= input4_call_limit; ++i) { + urns.emplace_back(EvalJs(shell(), kSelectFrom4URLsScript).ExtractString()); + } + + // There are `input4_call_limit + 2` "worklet operations": `selectURL()`. + test_worklet_host_manager() + .GetAttachedWorkletHost() + ->WaitForWorkletResponsesCount(input4_call_limit + 2); + + // The first pair of `reportEvent()` calls will deduct 3 bits from the budget. + FrameTreeNode* fenced_frame_root_node0 = CreateFencedFrame(urns[0]); + + RunSuccessfulReportEvents(fenced_frame_root_node0, responses[0].get(), + responses[1].get()); + + for (size_t i = 1; i <= input4_call_limit; ++i) { + // Subsequent pairs of calls to `reportEvent()` will deduct 2 bits from the + // budget. + FrameTreeNode* fenced_frame_root_node1 = CreateFencedFrame(urns[i]); + + RunSuccessfulReportEvents(fenced_frame_root_node1, responses[2 * i].get(), + responses[2 * i + 1].get()); + } + + FrameTreeNode* fenced_frame_root_node2 = + CreateFencedFrame(urns[input4_call_limit + 1]); + + size_t current_response_index = 2 * (input4_call_limit + 1); + + if (GetParam()) { + // The limit for `reportEvent()` has now been reached for this page. Make + // one more call, which will be blocked. + std::string click_event_data = "this is a click"; + EXPECT_TRUE( + ExecJs(fenced_frame_root_node2, + JsReplace("window.fence.reportEvent({" + " eventType: 'click'," + " eventData: $1," + " destination: ['shared-storage-select-url']});", + click_event_data))); + + EXPECT_TRUE(console_observer.Wait()); + ASSERT_LE(1u, console_observer.messages().size()); + EXPECT_EQ( + "The call to fence.reportEvent was blocked due to insufficient budget.", + base::UTF16ToUTF8(console_observer.messages().back().message)); + + // Running the first pair of calls again will not cause any errors. + RunSuccessfulReportEvents(fenced_frame_root_node0, + responses[current_response_index].get(), + responses[current_response_index + 1].get()); + } else { + // The `reportEvent()` limit is disabled. The calls will run successfully. + RunSuccessfulReportEvents(fenced_frame_root_node2, + responses[current_response_index].get(), + responses[current_response_index + 1].get()); + } +} + +IN_PROC_BROWSER_TEST_P(SharedStorageReportEventLimitBrowserTest, + ReportEventThenPopup) { + std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>> + responses; + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report1.html")); + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report2.html")); + ASSERT_TRUE(https_server()->Start()); + + GURL main_url = https_server()->GetURL("a.test", kSimplePagePath); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + url::Origin shared_storage_origin = url::Origin::Create(main_url); + + EXPECT_TRUE(ExecJs(shell(), R"( + sharedStorage.worklet.addModule('shared_storage/simple_module.js'); + )")); + + // There is one "worklet operation": `addModule()`. + test_worklet_host_manager() + .GetAttachedWorkletHost() + ->WaitForWorkletResponsesCount(1); + + GURL urn = GURL(EvalJs(shell(), kSelectFrom8URLsScript).ExtractString()); + + // There is one "worklet operation": `selectURL()`. + test_worklet_host_manager() + .GetAttachedWorkletHost() + ->WaitForWorkletResponsesCount(1); + + FrameTreeNode* fenced_frame_root_node = CreateFencedFrame(urn); + + RunSuccessfulReportEvents(fenced_frame_root_node, responses[0].get(), + responses[1].get()); + + // The origin's entropy budget is untouched. + EXPECT_DOUBLE_EQ(GetRemainingBudget(shared_storage_origin), kBudgetAllowed); + EXPECT_DOUBLE_EQ(RemainingBudgetViaJSForFrame(PrimaryFrameTreeNodeRoot()), + kBudgetAllowed); + + OpenPopup(fenced_frame_root_node, + https_server()->GetURL("b.test", kSimplePagePath), /*name=*/""); + + // After the popup, log(8)=3 bits should have been withdrawn from the + // original shared storage origin without any error. + EXPECT_DOUBLE_EQ(GetRemainingBudget(shared_storage_origin), + kBudgetAllowed - 3); +} + +IN_PROC_BROWSER_TEST_P(SharedStorageReportEventLimitBrowserTest, + PopupThenReportEvent) { + std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>> + responses; + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report1.html")); + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report2.html")); + ASSERT_TRUE(https_server()->Start()); + + GURL main_url = https_server()->GetURL("a.test", kSimplePagePath); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + url::Origin shared_storage_origin = url::Origin::Create(main_url); + + EXPECT_TRUE(ExecJs(shell(), R"( + sharedStorage.worklet.addModule('shared_storage/simple_module.js'); + )")); + + // There is one "worklet operation": `addModule()`. + test_worklet_host_manager() + .GetAttachedWorkletHost() + ->WaitForWorkletResponsesCount(1); + + GURL urn = GURL(EvalJs(shell(), kSelectFrom8URLsScript).ExtractString()); + + // There is one "worklet operation": `selectURL()`. + test_worklet_host_manager() + .GetAttachedWorkletHost() + ->WaitForWorkletResponsesCount(1); + + FrameTreeNode* fenced_frame_root_node = CreateFencedFrame(urn); + + EXPECT_DOUBLE_EQ(GetRemainingBudget(shared_storage_origin), kBudgetAllowed); + EXPECT_DOUBLE_EQ(RemainingBudgetViaJSForFrame(PrimaryFrameTreeNodeRoot()), + kBudgetAllowed); + + OpenPopup(fenced_frame_root_node, + https_server()->GetURL("b.test", kSimplePagePath), /*name=*/""); + + // After the popup, log(8)=3 bits should have been withdrawn from the + // original shared storage origin. + EXPECT_DOUBLE_EQ(GetRemainingBudget(shared_storage_origin), + kBudgetAllowed - 3); + + // the calls to `reportEvent()` should still succeed after the popup. + RunSuccessfulReportEvents(fenced_frame_root_node, responses[0].get(), + responses[1].get()); +} + +IN_PROC_BROWSER_TEST_P(SharedStorageReportEventLimitBrowserTest, + ReportEvent_NestedFencedFrames_LimitReached) { + std::vector<std::unique_ptr<net::test_server::ControllableHttpResponse>> + responses; + for (size_t i = 0; i < 2; ++i) { + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report1.html")); + responses.emplace_back( + std::make_unique<net::test_server::ControllableHttpResponse>( + https_server(), "/fenced_frames/report2.html")); + } + ASSERT_TRUE(https_server()->Start()); + + GURL main_url = https_server()->GetURL("a.test", kSimplePagePath); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + WebContentsConsoleObserver console_observer(shell()->web_contents()); + console_observer.SetFilter( + MakeFilter({"The call to fence.reportEvent was blocked due to " + "insufficient budget."})); + + url::Origin shared_storage_origin1 = + url::Origin::Create(https_server()->GetURL("b.test", kSimplePagePath)); + + // This call to `selectURL()` will have 8 input URLs, and hence + // 3 = log2(8) bits of entropy. + GURL urn_uuid1 = SelectFrom8URLsInContext(shared_storage_origin1); + FrameTreeNode* outer_fenced_frame_root_node = CreateFencedFrame(urn_uuid1); + + url::Origin shared_storage_origin2 = + url::Origin::Create(https_server()->GetURL("c.test", kSimplePagePath)); + + // This call to `selectURL()` will have 8 input URLs, and hence + // 3 = log2(8) bits of entropy. + GURL urn_uuid2 = SelectFrom8URLsInContext(shared_storage_origin2, + outer_fenced_frame_root_node); + + FrameTreeNode* inner_fenced_frame_root_node = + CreateFencedFrame(outer_fenced_frame_root_node, urn_uuid2); + + RunSuccessfulReportEvents(inner_fenced_frame_root_node, responses[0].get(), + responses[1].get()); + + // This call to `selectURL()` will have 8 input URLs, and hence + // 3 = log2(8) bits of entropy. + GURL extra_urn = SelectFrom8URLsInContext(shared_storage_origin1); + + FrameTreeNode* extra_fenced_frame_root_node = CreateFencedFrame(extra_urn); + + if (GetParam()) { + // The limit for `reportEvent()` has now been reached for this page. Make + // one more call, which will be blocked. + std::string click_event_data = "this is a click"; + EXPECT_TRUE( + ExecJs(extra_fenced_frame_root_node, + JsReplace("window.fence.reportEvent({" + " eventType: 'click'," + " eventData: $1," + " destination: ['shared-storage-select-url']});", + click_event_data))); + + EXPECT_TRUE(console_observer.Wait()); + ASSERT_LE(1u, console_observer.messages().size()); + EXPECT_EQ( + "The call to fence.reportEvent was blocked due to insufficient budget.", + base::UTF16ToUTF8(console_observer.messages().back().message)); + } else { + // The `reportEvent()` limit is disabled. The calls will run successfully. + RunSuccessfulReportEvents(extra_fenced_frame_root_node, responses[2].get(), + responses[3].get()); + } +} + } // namespace content
diff --git a/content/browser/shared_storage/shared_storage_budget_charger.cc b/content/browser/shared_storage/shared_storage_budget_charger.cc index 995af2b4..eb59630cf 100644 --- a/content/browser/shared_storage/shared_storage_budget_charger.cc +++ b/content/browser/shared_storage/shared_storage_budget_charger.cc
@@ -61,17 +61,22 @@ ->FindSharedStorageBudgetMetadata(); for (const auto* metadata : shared_storage_budget_metadata) { - if (metadata->budget_to_charge == 0) + if (metadata->top_navigated) { continue; - - shared_storage_manager->MakeBudgetWithdrawal( - metadata->origin, metadata->budget_to_charge, base::DoNothing()); + } // We only want to charge the budget the first time a navigation leaves the // fenced frame, across all fenced frames navigated to the same urn. // We can do this even though the pointer is const because - // `budget_to_charge` is a mutable field of `SharedStorageBudgetMetadata`. - metadata->budget_to_charge = 0; + // `top_navigated` is a mutable field of `SharedStorageBudgetMetadata`. + metadata->top_navigated = true; + + if (metadata->budget_to_charge == 0) { + continue; + } + + shared_storage_manager->MakeBudgetWithdrawal( + metadata->origin, metadata->budget_to_charge, base::DoNothing()); } }
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index bca5fbf..48e97144 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -4340,7 +4340,7 @@ // This should only return nullptr on Android. EXPECT_TRUE(root_view->GetCursorManager()); - WebCursor cursor; + ui::Cursor cursor; EXPECT_FALSE( root_view->GetCursorManager()->GetCursorForTesting(root_view, cursor)); EXPECT_FALSE( @@ -4388,7 +4388,7 @@ EXPECT_TRUE( root_view->GetCursorManager()->GetCursorForTesting(child_view, cursor)); // Since this moused over a text box, this should not be the default cursor. - EXPECT_EQ(cursor.cursor().type(), ui::mojom::CursorType::kIBeam); + EXPECT_EQ(cursor.type(), ui::mojom::CursorType::kIBeam); } } // namespace
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index 86339393..a0aa623d 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -1686,6 +1686,11 @@ return attribution_manager_.get(); } +AttributionDataModel* StoragePartitionImpl::GetAttributionDataModel() { + DCHECK(initialized_); + return attribution_manager_.get(); +} + FontAccessManager* StoragePartitionImpl::GetFontAccessManager() { DCHECK(initialized_); return font_access_manager_.get();
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index 33ea9d8..30a8a15 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h
@@ -197,6 +197,9 @@ InterestGroupManager* GetInterestGroupManager() override; BrowsingTopicsSiteDataManager* GetBrowsingTopicsSiteDataManager() override; leveldb_proto::ProtoDatabaseProvider* GetProtoDatabaseProvider() override; + // Use outside content. + AttributionDataModel* GetAttributionDataModel() override; + void SetProtoDatabaseProvider( std::unique_ptr<leveldb_proto::ProtoDatabaseProvider> proto_db_provider) override; @@ -256,6 +259,7 @@ FileSystemAccessManagerImpl* GetFileSystemAccessManager(); BucketManager* GetBucketManager(); QuotaContext* GetQuotaContext(); + // Use inside content. AttributionManager* GetAttributionManager(); void SetFontAccessManagerForTesting( std::unique_ptr<FontAccessManager> font_access_manager);
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc index 1ae8db8..2372188 100644 --- a/content/browser/storage_partition_impl_map.cc +++ b/content/browser/storage_partition_impl_map.cc
@@ -444,17 +444,6 @@ } } -void StoragePartitionImplMap::DisposeInMemory(StoragePartition* partition) { - for (PartitionMap::const_iterator it = partitions_.begin(); - it != partitions_.end(); ++it) { - if (it->second.get() == partition) { - DCHECK(it->first.in_memory()); - partitions_.erase(it); - return; - } - } -} - void StoragePartitionImplMap::PostCreateInitialization( StoragePartitionImpl* partition, bool in_memory) {
diff --git a/content/browser/storage_partition_impl_map.h b/content/browser/storage_partition_impl_map.h index d999fd35..784ccd5 100644 --- a/content/browser/storage_partition_impl_map.h +++ b/content/browser/storage_partition_impl_map.h
@@ -62,9 +62,6 @@ void ForEach(BrowserContext::StoragePartitionCallback callback); - // Disposes the given in-memory storage partition. - void DisposeInMemory(StoragePartition* partition); - size_t size() const { return partitions_.size(); } private:
diff --git a/content/browser/storage_partition_impl_map_unittest.cc b/content/browser/storage_partition_impl_map_unittest.cc index 3d21ae1..78a1126 100644 --- a/content/browser/storage_partition_impl_map_unittest.cc +++ b/content/browser/storage_partition_impl_map_unittest.cc
@@ -87,37 +87,4 @@ } } -TEST(StoragePartitionImplMapTest, Dispose) { - BrowserTaskEnvironment task_environment; - TestBrowserContext browser_context; - StoragePartitionImplMap map(&browser_context); - - // Start with no partitions. - ASSERT_EQ(map.size(), 0u); - - // Create 1 in-memory partition. - const auto kInMemoryConfig = content::StoragePartitionConfig::Create( - &browser_context, "foo", /*partition_name=*/"", /*in_memory=*/true); - auto* partition = map.Get(kInMemoryConfig, /*can_create=*/true); - ASSERT_TRUE(partition); - - // Dispose the in-memory partition. - map.DisposeInMemory(partition); - EXPECT_EQ(map.size(), 0u); - - // No op to dispose the already disposed partition. - map.DisposeInMemory(partition); - EXPECT_EQ(map.size(), 0u); - - // No op to dispose nullptr. - map.DisposeInMemory(nullptr); - EXPECT_EQ(map.size(), 0u); - - // Disposing an on-disk storage partition is not supported. - const auto kOnDiskConfig = content::StoragePartitionConfig::Create( - &browser_context, "foo", /*partition_name=*/"", /*in_memory=*/false); - auto* on_disk_partition = map.Get(kOnDiskConfig, /*can_create=*/true); - EXPECT_DCHECK_DEATH(map.DisposeInMemory(on_disk_partition)); -} - } // namespace content
diff --git a/content/browser/tracing/background_startup_tracing_observer.cc b/content/browser/tracing/background_startup_tracing_observer.cc index c3e35694..e9f7444 100644 --- a/content/browser/tracing/background_startup_tracing_observer.cc +++ b/content/browser/tracing/background_startup_tracing_observer.cc
@@ -15,6 +15,7 @@ namespace { const char kStartupTracingConfig[] = "startup-config"; +const char kStartupTracingRuleId[] = "org.chromium.background_tracing.startup"; class PreferenceManagerImpl : public BackgroundStartupTracingObserver::PreferenceManager { @@ -45,8 +46,7 @@ BackgroundStartupTracingObserver::FindStartupRuleInConfig( const BackgroundTracingConfigImpl& config) { for (const auto& rule : config.rules()) { - if (rule->category_preset() == - BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP) { + if (rule->rule_id() == kStartupTracingRuleId) { return rule.get(); } } @@ -122,12 +122,10 @@ rules_dict.Set("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); rules_dict.Set("trigger_name", kStartupTracingConfig); rules_dict.Set("trigger_delay", 30); - rules_dict.Set("category", "BENCHMARK_STARTUP"); + rules_dict.Set("rule_id", kStartupTracingRuleId); if (config) { - config->AddReactiveRule( - rules_dict, - BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP); + config->AddReactiveRule(rules_dict); } else { base::Value::Dict dict; base::Value::List rules_list;
diff --git a/content/browser/tracing/background_startup_tracing_observer_unittest.cc b/content/browser/tracing/background_startup_tracing_observer_unittest.cc index 4c4621ef..f50eba3 100644 --- a/content/browser/tracing/background_startup_tracing_observer_unittest.cc +++ b/content/browser/tracing/background_startup_tracing_observer_unittest.cc
@@ -31,8 +31,7 @@ BackgroundStartupTracingObserver::FindStartupRuleInConfig(config); if (exists) { ASSERT_TRUE(rule); - EXPECT_EQ(BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP, - rule->category_preset()); + EXPECT_EQ("org.chromium.background_tracing.startup", rule->rule_id()); EXPECT_EQ(30, rule->GetTraceDelay()); } else { EXPECT_FALSE(rule);
diff --git a/content/browser/tracing/background_tracing_config_impl.cc b/content/browser/tracing/background_tracing_config_impl.cc index e32d474..176bbd3d 100644 --- a/content/browser/tracing/background_tracing_config_impl.cc +++ b/content/browser/tracing/background_tracing_config_impl.cc
@@ -138,12 +138,8 @@ } void BackgroundTracingConfigImpl::AddReactiveRule( - const base::Value::Dict& dict, - BackgroundTracingConfigImpl::CategoryPreset category_preset) { - BackgroundTracingRule* rule = AddRule(dict); - if (rule) { - rule->set_category_preset(category_preset); - } + const base::Value::Dict& dict) { + AddRule(dict); } void BackgroundTracingConfigImpl::AddSystemRule(const base::Value::Dict& dict) { @@ -322,7 +318,7 @@ } } - config->AddReactiveRule(config_dict.GetDict(), config->category_preset_); + config->AddReactiveRule(config_dict.GetDict()); } if (config->rules().empty())
diff --git a/content/browser/tracing/background_tracing_config_impl.h b/content/browser/tracing/background_tracing_config_impl.h index 224493d6..7686024 100644 --- a/content/browser/tracing/background_tracing_config_impl.h +++ b/content/browser/tracing/background_tracing_config_impl.h
@@ -51,9 +51,7 @@ } void AddPreemptiveRule(const base::Value::Dict& dict); - void AddReactiveRule( - const base::Value::Dict& dict, - BackgroundTracingConfigImpl::CategoryPreset category_preset); + void AddReactiveRule(const base::Value::Dict& dict); void AddSystemRule(const base::Value::Dict& dict); base::trace_event::TraceConfig GetTraceConfig() const;
diff --git a/content/browser/tracing/background_tracing_config_unittest.cc b/content/browser/tracing/background_tracing_config_unittest.cc index 1dd079bd..dbb942e14 100644 --- a/content/browser/tracing/background_tracing_config_unittest.cc +++ b/content/browser/tracing/background_tracing_config_unittest.cc
@@ -162,33 +162,33 @@ EXPECT_FALSE( ReadFromJSONString("{\"mode\":\"reactive\"," "\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"}]}")); + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"}]}")); EXPECT_FALSE(ReadFromJSONString( "{\"mode\":\"reactive\"," "\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"category\": " "[]}]}")); EXPECT_FALSE(ReadFromJSONString( "{\"mode\":\"reactive\"," "\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"category\": " "\"\"}]}")); EXPECT_FALSE(ReadFromJSONString( "{\"mode\":\"reactive\"," "\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"category\": " "\"benchmark\"}]}")); EXPECT_FALSE(ReadFromJSONString( "{\"mode\":\"reactive\"," "\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"category\": " "\"benchmark\", \"trigger_name\": []}]}")); EXPECT_FALSE(ReadFromJSONString( "{\"mode\":\"reactive\"," "\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"category\": " "\"benchmark\", \"trigger_name\": 0}]}")); } @@ -348,91 +348,15 @@ config = ReadFromJSONString( "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " - "\"category\": \"BENCHMARK_STARTUP\",\"trigger_delay\":30," + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", " + "\"trigger_delay\":30," "\"trigger_name\": \"foo\"}]}"); EXPECT_TRUE(config); EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); EXPECT_EQ(config->rules().size(), 1u); EXPECT_EQ(RuleToString(config->rules()[0]), - "{\"category\":\"BENCHMARK_STARTUP\"," - "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," + "{\"rule\":\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"," "\"trigger_delay\":30,\"trigger_name\":\"foo\"}"); - - config = ReadFromJSONString( - "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " - "\"category\": \"BENCHMARK_STARTUP\", \"trigger_delay\":30, " - "\"trigger_name\": \"foo\"}]}"); - EXPECT_TRUE(config); - EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); - EXPECT_EQ(config->rules().size(), 1u); - EXPECT_EQ(RuleToString(config->rules()[0]), - "{\"category\":\"BENCHMARK_STARTUP\"," - "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," - "\"trigger_delay\":30,\"trigger_name\":\"foo\"}"); - - config = ReadFromJSONString( - "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " - "\"category\": \"BENCHMARK_STARTUP\",\"trigger_delay\":30," - "\"trigger_name\": \"foo\",\"trigger_delay\":30," - "\"trigger_chance\": 0.5}]}"); - EXPECT_TRUE(config); - EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); - EXPECT_EQ(config->rules().size(), 1u); - EXPECT_EQ(RuleToString(config->rules()[0]), - "{\"category\":\"BENCHMARK_STARTUP\"," - "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," - "\"trigger_chance\":0.5,\"trigger_delay\":30," - "\"trigger_name\":\"foo\"}"); - - config = ReadFromJSONString( - "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " - "\"category\": \"BENCHMARK_STARTUP\", \"trigger_name\": " - "\"foo1\"},{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " - "\"category\": \"BENCHMARK_STARTUP\", \"trigger_name\": \"foo2\"}]}"); - EXPECT_TRUE(config); - EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); - EXPECT_EQ(config->rules().size(), 2u); - EXPECT_EQ(RuleToString(config->rules()[0]), - "{\"category\":\"BENCHMARK_STARTUP\"," - "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," - "\"trigger_delay\":30,\"trigger_name\":\"foo1\"}"); - EXPECT_EQ(RuleToString(config->rules()[1]), - "{\"category\":\"BENCHMARK_STARTUP\"," - "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," - "\"trigger_delay\":30,\"trigger_name\":\"foo2\"}"); - - config = ReadFromJSONString( - "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " - "\"TRACE_AT_RANDOM_INTERVALS\"," - "\"category\": \"BENCHMARK_STARTUP\"," - "\"timeout_min\":10, \"timeout_max\":20}]}"); - EXPECT_TRUE(config); - EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); - EXPECT_EQ(config->rules().size(), 1u); - EXPECT_EQ(RuleToString(config->rules()[0]), - "{\"category\":\"BENCHMARK_STARTUP\",\"rule\":\"TRACE_AT_RANDOM_" - "INTERVALS\"," - "\"timeout_max\":20,\"timeout_min\":10}"); - - config = ReadFromJSONString( - "{\"mode\":\"REACTIVE_TRACING_MODE\"," - "\"custom_categories\": \"benchmark,toplevel\"," - "\"configs\": [{\"rule\": " - "\"TRACE_AT_RANDOM_INTERVALS\"," - "\"timeout_max\":20,\"timeout_min\":10}]}"); - EXPECT_TRUE(config); - EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); - EXPECT_EQ(config->rules().size(), 1u); - EXPECT_EQ(ConfigToString(config.get()), - "{\"configs\":[{\"category\":\"CUSTOM\",\"rule\":\"TRACE_AT_RANDOM_" - "INTERVALS\",\"timeout_" - "max\":20,\"timeout_min\":10}],\"custom_categories\":\"benchmark," - "toplevel\",\"mode\":\"REACTIVE_TRACING_MODE\"}"); } TEST_F(BackgroundTracingConfigTest, ValidPreemptiveConfigToString) { @@ -613,16 +537,14 @@ BackgroundTracingConfig::REACTIVE); base::Value::Dict dict; - dict.Set("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL"); + dict.Set("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); dict.Set("trigger_name", "foo"); - config->AddReactiveRule(dict, - BackgroundTracingConfigImpl::BENCHMARK_STARTUP); + config->AddReactiveRule(dict); - EXPECT_EQ( - ConfigToString(config.get()), - "{\"configs\":[{\"category\":\"BENCHMARK_STARTUP\",\"rule\":\"TRACE_" - "ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\",\"trigger_delay\":30," - "\"trigger_name\":\"foo\"}],\"mode\":\"REACTIVE_TRACING_MODE\"}"); + EXPECT_EQ(ConfigToString(config.get()), + "{\"configs\":[{\"rule\":\"" + "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"," + "\"trigger_name\":\"foo\"}],\"mode\":\"REACTIVE_TRACING_MODE\"}"); } { @@ -630,22 +552,19 @@ BackgroundTracingConfig::REACTIVE); base::Value::Dict dict; - dict.Set("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL"); + dict.Set("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); dict.Set("trigger_name", "foo1"); - config->AddReactiveRule(dict, - BackgroundTracingConfigImpl::BENCHMARK_STARTUP); + config->AddReactiveRule(dict); dict.Set("trigger_name", "foo2"); - config->AddReactiveRule(dict, - BackgroundTracingConfigImpl::BENCHMARK_STARTUP); + config->AddReactiveRule(dict); EXPECT_EQ( ConfigToString(config.get()), - "{\"configs\":[{\"category\":\"BENCHMARK_STARTUP\",\"rule\":\"TRACE_" - "ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\",\"trigger_delay\":30," - "\"trigger_name\":\"foo1\"},{\"category\":\"BENCHMARK_STARTUP\"," - "\"rule\":" - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\",\"trigger_delay\":30," + "{\"configs\":[{\"rule\":" + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"," + "\"trigger_name\":\"foo1\"},{" + "\"rule\":\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"," "\"trigger_name\":\"foo2\"}],\"mode\":\"REACTIVE_TRACING_MODE\"}"); } } @@ -657,7 +576,7 @@ config = ReadFromJSONString( "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " - "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " + "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", " "\"category\": \"BENCHMARK_STARTUP\",\"trigger_delay\":30," "\"trigger_name\": \"foo\"}],\"low_ram_buffer_size_kb\":800," "\"medium_ram_buffer_size_kb\":1000,\"mobile_network_buffer_size_kb\":"
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc index c293970..4c75b9d 100644 --- a/content/browser/tracing/background_tracing_manager_browsertest.cc +++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -457,8 +457,9 @@ base::Value::List rules_list; { base::Value::Dict rules_dict; - rules_dict.Set("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL"); + rules_dict.Set("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); rules_dict.Set("trigger_name", "reactive_test"); + rules_dict.Set("trigger_delay", 15); rules_list.Append(std::move(rules_dict)); } dict.Set("configs", std::move(rules_list)); @@ -1062,7 +1063,7 @@ base::Value::List rules_list; { base::Value::Dict rules_dict; - rules_dict.Set("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL"); + rules_dict.Set("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); rules_dict.Set("trigger_name", "reactive_test1"); rules_dict.Set("trigger_chance", 0.0); @@ -1690,10 +1691,9 @@ { base::Value::Dict rules_dict; rules_dict.Set("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); - rules_dict.Set("trigger_name", "startup-config"); + rules_dict.Set("trigger_name", "startup"); rules_dict.Set("stop_tracing_on_repeated_reactive", false); rules_dict.Set("trigger_delay", 600); - rules_dict.Set("category", "BENCHMARK_STARTUP"); rules_list.Append(std::move(rules_dict)); } dict.Set("configs", std::move(rules_list));
diff --git a/content/browser/tracing/background_tracing_rule.cc b/content/browser/tracing/background_tracing_rule.cc index aa07c62..04ebfc5 100644 --- a/content/browser/tracing/background_tracing_rule.cc +++ b/content/browser/tracing/background_tracing_rule.cc
@@ -31,7 +31,6 @@ namespace { const char kConfigRuleKey[] = "rule"; -const char kConfigCategoryKey[] = "category"; const char kConfigRuleTriggerNameKey[] = "trigger_name"; const char kConfigRuleTriggerDelay[] = "trigger_delay"; const char kConfigRuleTriggerChance[] = "trigger_chance"; @@ -44,28 +43,12 @@ const char kConfigRuleHistogramValue2Key[] = "histogram_upper_value"; const char kConfigRuleHistogramRepeatKey[] = "histogram_repeat"; -const char kConfigRuleRandomIntervalTimeoutMin[] = "timeout_min"; -const char kConfigRuleRandomIntervalTimeoutMax[] = "timeout_max"; - const char kConfigRuleTypeMonitorNamed[] = "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"; const char kConfigRuleTypeMonitorHistogram[] = "MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE"; -const char kConfigRuleTypeTraceOnNavigationUntilTriggerOrFull[] = - "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL"; - -const char kConfigRuleTypeTraceAtRandomIntervals[] = - "TRACE_AT_RANDOM_INTERVALS"; - -const char kTraceAtRandomIntervalsEventName[] = - "ReactiveTraceAtRandomIntervals"; - -const int kConfigTypeNavigationTimeout = 30; -const int kReactiveTraceRandomStartTimeMin = 60; -const int kReactiveTraceRandomStartTimeMax = 120; - } // namespace namespace content { @@ -102,12 +85,6 @@ dict.Set(kConfigRuleIdKey, rule_id_); } - if (category_preset_ != BackgroundTracingConfigImpl::CATEGORY_PRESET_UNSET) { - dict.Set( - kConfigCategoryKey, - BackgroundTracingConfigImpl::CategoryPresetToString(category_preset_)); - } - if (is_crash_) { dict.Set(kConfigIsCrashKey, is_crash_); } @@ -362,149 +339,6 @@ histogram_sample_callback_; }; -class TraceForNSOrTriggerOrFullRule : public BackgroundTracingRule { - private: - explicit TraceForNSOrTriggerOrFullRule(const std::string& named_event) - : BackgroundTracingRule(kConfigTypeNavigationTimeout), - named_event_(named_event) {} - - public: - static std::unique_ptr<BackgroundTracingRule> Create( - const base::Value::Dict& dict) { - if (const std::string* trigger_name = - dict.FindString(kConfigRuleTriggerNameKey)) { - return base::WrapUnique<BackgroundTracingRule>( - new TraceForNSOrTriggerOrFullRule(*trigger_name)); - } - return nullptr; - } - - // BackgroundTracingRule implementation - base::Value::Dict ToDict() const override { - base::Value::Dict dict = BackgroundTracingRule::ToDict(); - dict.Set(kConfigRuleKey, - kConfigRuleTypeTraceOnNavigationUntilTriggerOrFull); - dict.Set(kConfigRuleTriggerNameKey, named_event_.c_str()); - return dict; - } - - void GenerateMetadataProto( - BackgroundTracingRule::MetadataProto* out) const override { - DCHECK(out); - BackgroundTracingRule::GenerateMetadataProto(out); - out->set_trigger_type(MetadataProto::MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED); - out->set_named_rule()->set_event_type(MetadataProto::NamedRule::NAVIGATION); - } - - bool ShouldTriggerNamedEvent(const std::string& named_event) const override { - return named_event == named_event_; - } - - protected: - std::string GetDefaultRuleId() const override { - return base::StrCat({"org.chromium.background_tracing.", named_event_}); - } - - private: - std::string named_event_; -}; - -class TraceAtRandomIntervalsRule : public BackgroundTracingRule { - private: - TraceAtRandomIntervalsRule(int timeout_min, int timeout_max) - : timeout_min_(timeout_min), timeout_max_(timeout_max) { - named_event_ = GenerateUniqueName(); - } - - public: - static std::unique_ptr<BackgroundTracingRule> Create( - const base::Value::Dict& dict) { - absl::optional<int> timeout_min = - dict.FindInt(kConfigRuleRandomIntervalTimeoutMin); - if (!timeout_min) - return nullptr; - - absl::optional<int> timeout_max = - dict.FindInt(kConfigRuleRandomIntervalTimeoutMax); - if (!timeout_max) - return nullptr; - - if (*timeout_min > *timeout_max) - return nullptr; - - return std::unique_ptr<BackgroundTracingRule>( - new TraceAtRandomIntervalsRule(*timeout_min, *timeout_max)); - } - ~TraceAtRandomIntervalsRule() override {} - - base::Value::Dict ToDict() const override { - base::Value::Dict dict = BackgroundTracingRule::ToDict(); - dict.Set(kConfigRuleKey, kConfigRuleTypeTraceAtRandomIntervals); - dict.Set(kConfigRuleRandomIntervalTimeoutMin, timeout_min_); - dict.Set(kConfigRuleRandomIntervalTimeoutMax, timeout_max_); - return dict; - } - - void GenerateMetadataProto( - BackgroundTracingRule::MetadataProto* out) const override { - // TODO(ssid): Add config if we enabled this type of trigger. - NOTREACHED(); - } - - void Install() override { - handle_ = BackgroundTracingManagerImpl::GetInstance().RegisterTriggerType( - named_event_.c_str()); - - StartTimer(); - } - - void OnStartedFinalizing(bool success) { - if (!success) - return; - - StartTimer(); - } - - void OnTriggerTimer() { - BackgroundTracingManagerImpl::GetInstance().TriggerNamedEvent( - handle_, - base::BindOnce(&TraceAtRandomIntervalsRule::OnStartedFinalizing, - base::Unretained(this))); - } - - void StartTimer() { - int time_to_wait = base::RandInt(kReactiveTraceRandomStartTimeMin, - kReactiveTraceRandomStartTimeMax); - trigger_timer_.Start( - FROM_HERE, base::Seconds(time_to_wait), - base::BindOnce(&TraceAtRandomIntervalsRule::OnTriggerTimer, - base::Unretained(this))); - } - - int GetTraceDelay() const override { - return base::RandInt(timeout_min_, timeout_max_); - } - - bool ShouldTriggerNamedEvent(const std::string& named_event) const override { - return named_event == named_event_; - } - - std::string GenerateUniqueName() const { - static int ids = 0; - char work_buffer[256]; - base::strings::SafeSNPrintf(work_buffer, sizeof(work_buffer), "%s_%d", - kTraceAtRandomIntervalsEventName, ids++); - return work_buffer; - } - - private: - std::string named_event_; - base::OneShotTimer trigger_timer_; - BackgroundTracingManagerImpl::TriggerHandle handle_; - int timeout_min_; - int timeout_max_; -}; - } // namespace std::unique_ptr<BackgroundTracingRule> @@ -518,12 +352,7 @@ tracing_rule = NamedTriggerRule::Create(dict); } else if (*type == kConfigRuleTypeMonitorHistogram) { tracing_rule = HistogramRule::Create(dict); - } else if (*type == kConfigRuleTypeTraceOnNavigationUntilTriggerOrFull) { - tracing_rule = TraceForNSOrTriggerOrFullRule::Create(dict); - } else if (*type == kConfigRuleTypeTraceAtRandomIntervals) { - tracing_rule = TraceAtRandomIntervalsRule::Create(dict); } - if (tracing_rule) tracing_rule->Setup(dict);
diff --git a/content/browser/tracing/background_tracing_rule.h b/content/browser/tracing/background_tracing_rule.h index 06c589b..6b52aa4 100644 --- a/content/browser/tracing/background_tracing_rule.h +++ b/content/browser/tracing/background_tracing_rule.h
@@ -27,14 +27,6 @@ virtual ~BackgroundTracingRule(); - BackgroundTracingConfigImpl::CategoryPreset category_preset() const { - return category_preset_; - } - void set_category_preset( - BackgroundTracingConfigImpl::CategoryPreset category_preset) { - category_preset_ = category_preset; - } - virtual void Install() {} virtual base::Value::Dict ToDict() const; virtual void GenerateMetadataProto(MetadataProto* out) const; @@ -62,8 +54,6 @@ double trigger_chance_ = 1.0; int trigger_delay_ = -1; std::string rule_id_; - BackgroundTracingConfigImpl::CategoryPreset category_preset_ = - BackgroundTracingConfigImpl::CATEGORY_PRESET_UNSET; bool is_crash_ = false; };
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 86b7baf..18cc96c4 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -304,7 +304,6 @@ if (is_mac) { sources += [ - "cursors/webcursor_mac.mm", "font_list_mac.mm", "mac/attributed_string_type_converters.h", "mac/attributed_string_type_converters.mm",
diff --git a/content/common/cursors/webcursor.cc b/content/common/cursors/webcursor.cc index c4ffd8f..0b95d9a3 100644 --- a/content/common/cursors/webcursor.cc +++ b/content/common/cursors/webcursor.cc
@@ -4,9 +4,6 @@ #include "content/common/cursors/webcursor.h" -#include <algorithm> - -#include "build/build_config.h" #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h" namespace content { @@ -19,8 +16,6 @@ SetCursor(cursor); } -WebCursor::WebCursor(const WebCursor& other) = default; - bool WebCursor::SetCursor(const ui::Cursor& cursor) { // This value is just large enough to accommodate: // - kMaximumCursorSize in Blink's EventHandler @@ -40,7 +35,9 @@ return false; } - CleanupPlatformData(); +#if defined(USE_AURA) + custom_cursor_.reset(); +#endif cursor_ = cursor; // Clamp the hotspot to the custom image's dimensions. @@ -55,16 +52,4 @@ return true; } -bool WebCursor::operator==(const WebCursor& other) const { - return -#if defined(USE_AURA) || BUILDFLAG(IS_OZONE) - rotation_ == other.rotation_ && -#endif - cursor_ == other.cursor_; -} - -bool WebCursor::operator!=(const WebCursor& other) const { - return !(*this == other); -} - } // namespace content
diff --git a/content/common/cursors/webcursor.h b/content/common/cursors/webcursor.h index 337a1a5..4ccd8c31 100644 --- a/content/common/cursors/webcursor.h +++ b/content/common/cursors/webcursor.h
@@ -19,6 +19,9 @@ namespace content { +// NOTE(https://crbug.com/1149906): This class is deprecated and ui::Cursor +// should be used instead. +// // This class encapsulates a cross-platform description of a cursor. Platform // specific methods are provided to translate the cross-platform cursor into a // platform specific cursor. It is also possible to serialize / de-serialize a @@ -27,7 +30,6 @@ public: WebCursor(); explicit WebCursor(const ui::Cursor& info); - explicit WebCursor(const WebCursor& other); ~WebCursor(); const ui::Cursor& cursor() const { return cursor_; } @@ -35,10 +37,6 @@ // Sets the ui::Cursor |cursor|; returns whether it has reasonable values. bool SetCursor(const ui::Cursor& cursor); - // Equality operator; performs bitmap content comparison as needed. - bool operator==(const WebCursor& other) const; - bool operator!=(const WebCursor& other) const; - // Returns a native cursor representing the current WebCursor instance. gfx::NativeCursor GetNativeCursor(); @@ -54,9 +52,6 @@ #endif private: - // Platform specific cleanup. - void CleanupPlatformData(); - float GetCursorScaleFactor(SkBitmap* bitmap); // The basic cursor info.
diff --git a/content/common/cursors/webcursor_android.cc b/content/common/cursors/webcursor_android.cc index c087ff7f..a574b3e 100644 --- a/content/common/cursors/webcursor_android.cc +++ b/content/common/cursors/webcursor_android.cc
@@ -18,6 +18,4 @@ void WebCursor::SetDisplayInfo(const display::Display& display) {} #endif -void WebCursor::CleanupPlatformData() {} - } // namespace content
diff --git a/content/common/cursors/webcursor_aura.cc b/content/common/cursors/webcursor_aura.cc index f40ba645..cd97cf6 100644 --- a/content/common/cursors/webcursor_aura.cc +++ b/content/common/cursors/webcursor_aura.cc
@@ -50,7 +50,7 @@ return; device_scale_factor_ = display.device_scale_factor(); - CleanupPlatformData(); + custom_cursor_.reset(); } // ozone also has extra calculations for scale factor (taking max cursor size @@ -61,8 +61,4 @@ } #endif -void WebCursor::CleanupPlatformData() { - custom_cursor_.reset(); -} - } // namespace content
diff --git a/content/common/cursors/webcursor_mac.mm b/content/common/cursors/webcursor_mac.mm deleted file mode 100644 index 4329bad..0000000 --- a/content/common/cursors/webcursor_mac.mm +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2012 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/common/cursors/webcursor.h" - -#include "ui/base/cocoa/cursor_utils.h" - -namespace content { - -// Match Safari's cursor choices; see platform/mac/CursorMac.mm . -gfx::NativeCursor WebCursor::GetNativeCursor() { - return ui::GetNativeCursor(cursor_); -} - -void WebCursor::CleanupPlatformData() {} - -} // namespace content
diff --git a/content/common/cursors/webcursor_ozone.cc b/content/common/cursors/webcursor_ozone.cc index 404fcc2..7bfd21b 100644 --- a/content/common/cursors/webcursor_ozone.cc +++ b/content/common/cursors/webcursor_ozone.cc
@@ -30,7 +30,7 @@ // the kDefaultMaxSize constants to a single place. crbug.com/603512 if (maximum_cursor_size_.width() == 0 || maximum_cursor_size_.height() == 0) maximum_cursor_size_ = gfx::Size(kDefaultMaxSize, kDefaultMaxSize); - CleanupPlatformData(); + custom_cursor_.reset(); } float WebCursor::GetCursorScaleFactor(SkBitmap* bitmap) {
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc index 961e24b..20c5dcc 100644 --- a/content/gpu/gpu_main.cc +++ b/content/gpu/gpu_main.cc
@@ -405,12 +405,6 @@ namespace { #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) -bool IsAsahiGpu(const gpu::GPUInfo::GPUDevice& device) { - // Asahi's vendor ID is a stub value (0xffffffff), so match the vendor name - // instead. - return device.vendor_string.find("Asahi") != std::string::npos; -} - bool StartSandboxLinux(gpu::GpuWatchdogThread* watchdog_thread, const gpu::GPUInfo* gpu_info, const gpu::GpuPreferences& gpu_prefs) { @@ -436,8 +430,6 @@ angle::IsVirtIO(gpu_info->active_gpu().vendor_id); sandbox_options.use_nvidia_specific_policies = angle::IsNVIDIA(gpu_info->active_gpu().vendor_id); - sandbox_options.use_asahi_specific_policies = - IsAsahiGpu(gpu_info->active_gpu()); for (const auto& gpu : gpu_info->secondary_gpus) { if (angle::IsAMD(gpu.vendor_id)) sandbox_options.use_amd_specific_policies = true; @@ -445,8 +437,6 @@ sandbox_options.use_intel_specific_policies = true; else if (angle::IsNVIDIA(gpu.vendor_id)) sandbox_options.use_nvidia_specific_policies = true; - else if (IsAsahiGpu(gpu)) - sandbox_options.use_asahi_specific_policies = true; } } sandbox_options.accelerated_video_decode_enabled =
diff --git a/content/gpu/gpu_sandbox_hook_linux.cc b/content/gpu/gpu_sandbox_hook_linux.cc index da71601..d93285a5 100644 --- a/content/gpu/gpu_sandbox_hook_linux.cc +++ b/content/gpu/gpu_sandbox_hook_linux.cc
@@ -393,21 +393,12 @@ } } -void AddStandardGpuPermissions( - std::vector<BrokerFilePermission>* permissions, - const sandbox::policy::SandboxSeccompBPF::Options& options) { +void AddStandardGpuPermissions(std::vector<BrokerFilePermission>* permissions) { static const char kDriCardBasePath[] = "/dev/dri/card"; static const char kNvidiaCtlPath[] = "/dev/nvidiactl"; static const char kNvidiaDeviceBasePath[] = "/dev/nvidia"; static const char kNvidiaDeviceModeSetPath[] = "/dev/nvidia-modeset"; static const char kNvidiaParamsPath[] = "/proc/driver/nvidia/params"; - static const char kAsahiDri[] = -#if defined(DRI_DRIVER_DIR) - DRI_DRIVER_DIR "/asahi_dri.so" -#else - "/usr/lib64/dri/asahi_dri.so" -#endif - ; static const char kDevShm[] = "/dev/shm/"; // For shared memory. @@ -439,11 +430,6 @@ permissions->push_back(BrokerFilePermission::ReadOnly(sw_path)); } } - - // For Asahi drivers. - if (options.use_asahi_specific_policies) { - permissions->push_back(BrokerFilePermission::ReadOnly(kAsahiDri)); - } } std::vector<BrokerFilePermission> FilePermissionsForGpu( @@ -474,7 +460,7 @@ AddIntelGpuPermissions(&permissions); } if (options.use_nvidia_specific_policies) { - AddStandardGpuPermissions(&permissions, options); + AddStandardGpuPermissions(&permissions); } if (options.use_virtio_specific_policies) { AddVirtIOGpuPermissions(&permissions); @@ -492,7 +478,7 @@ } } - AddStandardGpuPermissions(&permissions, options); + AddStandardGpuPermissions(&permissions); return permissions; } @@ -514,22 +500,25 @@ // Preload mesa related libraries for devices which use mesa // (ie. not mali or tegra): if (!is_mali && !is_tegra && - (nullptr != dlopen("libglapi.so", dlopen_flag))) { + (nullptr != dlopen("libglapi.so.0", dlopen_flag))) { const char* driver_paths[] = { #if defined(DRI_DRIVER_DIR) DRI_DRIVER_DIR "/msm_dri.so", DRI_DRIVER_DIR "/panfrost_dri.so", DRI_DRIVER_DIR "/mediatek_dri.so", DRI_DRIVER_DIR "/rockchip_dri.so", + DRI_DRIVER_DIR "/asahi_dri.so", #else "/usr/lib64/dri/msm_dri.so", "/usr/lib64/dri/panfrost_dri.so", "/usr/lib64/dri/mediatek_dri.so", "/usr/lib64/dri/rockchip_dri.so", + "/usr/lib64/dri/asahi_dri.so", "/usr/lib/dri/msm_dri.so", "/usr/lib/dri/panfrost_dri.so", "/usr/lib/dri/mediatek_dri.so", "/usr/lib/dri/rockchip_dri.so", + "/usr/lib/dri/asahi_dri.so", #endif nullptr }; @@ -616,19 +605,18 @@ bool LoadLibrariesForGpu( const sandbox::policy::SandboxSeccompBPF::Options& options) { LoadVulkanLibraries(); + if (IsArchitectureArm()) { + LoadArmGpuLibraries(); + } if (IsChromeOS()) { if (UseV4L2Codec()) LoadV4L2Libraries(options); - if (IsArchitectureArm()) { - LoadArmGpuLibraries(); - } if (options.use_amd_specific_policies) { if (!LoadAmdGpuLibraries()) return false; } } else { if (UseChromecastSandboxAllowlist() && IsArchitectureArm()) { - LoadArmGpuLibraries(); if (UseV4L2Codec()) LoadChromecastV4L2Libraries(); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java index 441ccfb..7331902 100644 --- a/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java
@@ -51,7 +51,7 @@ private final WebContentsImpl mWebContents; private final ObserverList<GestureStateListener> mListeners; private final RewindableIterator<GestureStateListener> mIterator; - private final SelectionPopupControllerImpl mSelectionPopupController; + private SelectionPopupControllerImpl mSelectionPopupController; private ViewAndroidDelegate mViewDelegate; private InternalAccessDelegate mScrollDelegate; private final Point mRootScrollOffsetStruct = new Point(); @@ -95,7 +95,6 @@ mWebContents = (WebContentsImpl) webContents; mListeners = new ObserverList<GestureStateListener>(); mIterator = mListeners.rewindableIterator(); - mSelectionPopupController = SelectionPopupControllerImpl.fromWebContents(mWebContents); mViewDelegate = mWebContents.getViewAndroidDelegate(); mViewDelegate.addVerticalScrollDirectionChangeListener(this); WindowEventObserverManager.from(mWebContents).addObserver(this); @@ -338,7 +337,13 @@ } private void destroyPastePopup() { - if (mSelectionPopupController != null) mSelectionPopupController.destroyPastePopup(); + if (mSelectionPopupController == null) { + mSelectionPopupController = + SelectionPopupControllerImpl.fromWebContentsNoCreate(mWebContents); + } + if (mSelectionPopupController != null) { + mSelectionPopupController.destroyPastePopup(); + } } @CalledByNative @@ -456,6 +461,9 @@ private void setGestureScrollInProgress(boolean gestureScrollInProgress) { mIsGestureScrollInProgress = gestureScrollInProgress; + if (mSelectionPopupController == null) { + mSelectionPopupController = SelectionPopupControllerImpl.fromWebContents(mWebContents); + } // Use the active scroll signal for hiding. The animation movement by // fling will naturally hide the ActionMode by invalidating its content // rect.
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index 589ffef..5249d6f 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -32,6 +32,8 @@ "allow_service_worker_result.h", "anchor_element_preconnect_delegate.h", "attribution_config.h", + "attribution_data_model.cc", + "attribution_data_model.h", "attribution_reporting.h", "audio_service.h", "audio_service_info.cc",
diff --git a/content/public/browser/attribution_data_model.cc b/content/public/browser/attribution_data_model.cc new file mode 100644 index 0000000..6d0216b --- /dev/null +++ b/content/public/browser/attribution_data_model.cc
@@ -0,0 +1,49 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/browser/attribution_data_model.h" + +#include <tuple> +#include <utility> + +#include "base/check.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "url/origin.h" + +namespace content { + +AttributionDataModel::DataKey::DataKey( + url::Origin reporting_origin, + absl::optional<url::Origin> source_origin, + absl::optional<url::Origin> destination_origin) + : reporting_origin_(std::move(reporting_origin)), + source_origin_(std::move(source_origin)), + destination_origin_(std::move(destination_origin)) { + DCHECK(!reporting_origin_.opaque()); + + DCHECK(!source_origin_.has_value() || !source_origin_->opaque()); + + DCHECK(!destination_origin_.has_value() || !destination_origin_->opaque()); +} + +AttributionDataModel::DataKey::DataKey(const DataKey&) = default; + +AttributionDataModel::DataKey::DataKey(DataKey&&) = default; + +AttributionDataModel::DataKey& AttributionDataModel::DataKey::operator=( + const DataKey&) = default; + +AttributionDataModel::DataKey& AttributionDataModel::DataKey::operator=( + DataKey&&) = default; + +AttributionDataModel::DataKey::~DataKey() = default; + +bool AttributionDataModel::DataKey::operator<( + const AttributionDataModel::DataKey& other) const { + return std::tie(reporting_origin_, source_origin_, destination_origin_) < + std::tie(other.reporting_origin_, other.source_origin_, + other.destination_origin_); +} + +} // namespace content \ No newline at end of file
diff --git a/content/public/browser/attribution_data_model.h b/content/public/browser/attribution_data_model.h new file mode 100644 index 0000000..dbc2b73 --- /dev/null +++ b/content/public/browser/attribution_data_model.h
@@ -0,0 +1,64 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_BROWSER_ATTRIBUTION_DATA_MODEL_H_ +#define CONTENT_PUBLIC_BROWSER_ATTRIBUTION_DATA_MODEL_H_ + +#include <vector> + +#include "base/functional/callback_forward.h" +#include "content/common/content_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "url/origin.h" + +namespace content { + +class CONTENT_EXPORT AttributionDataModel { + public: + class DataKey { + public: + DataKey(url::Origin reporting_origin, + absl::optional<url::Origin> source_origin, + absl::optional<url::Origin> destination_origin); + + DataKey(const DataKey&); + DataKey(DataKey&&); + + DataKey& operator=(const DataKey&); + DataKey& operator=(DataKey&&); + + ~DataKey(); + + const url::Origin& reporting_origin() const { return reporting_origin_; } + + const absl::optional<url::Origin>& source_origin() const { + return source_origin_; + } + + const absl::optional<url::Origin>& destination_origin() const { + return destination_origin_; + } + + bool operator<(const DataKey&) const; + + private: + url::Origin reporting_origin_; + + absl::optional<url::Origin> source_origin_; + + absl::optional<url::Origin> destination_origin_; + }; + + virtual ~AttributionDataModel() = default; + + virtual void GetAllDataKeys( + base::OnceCallback<void(std::vector<DataKey>)> callback) = 0; + + virtual void RemoveAttributionDataByDataKey(const DataKey& data_key, + base::OnceClosure callback) = 0; +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_BROWSER_ATTRIBUTION_DATA_MODEL_H_ \ No newline at end of file
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h index 3d8fd49..35e1b40 100644 --- a/content/public/browser/browser_context.h +++ b/content/public/browser/browser_context.h
@@ -171,11 +171,6 @@ // StoragePartitions. size_t GetLoadedStoragePartitionCount(); - // Disposes the given StoragePartition. Only in-memory storage partition - // disposal is supported. Caller needs to be careful that no outstanding - // references are left to access the disposed storage partition. - void DisposeStoragePartition(StoragePartition* storage_partition); - // Starts an asynchronous best-effort attempt to delete all on-disk storage // related to |partition_domain| and synchronously invokes |done_callback| // once all deletable on-disk storage is deleted. |on_gc_required| will be
diff --git a/content/public/browser/preloading.h b/content/public/browser/preloading.h index 496cccf..c8acae55 100644 --- a/content/public/browser/preloading.h +++ b/content/public/browser/preloading.h
@@ -5,14 +5,17 @@ #ifndef CONTENT_PUBLIC_BROWSER_PRELOADING_H_ #define CONTENT_PUBLIC_BROWSER_PRELOADING_H_ -#include <stdint.h> +#include <cstdint> + +#include "base/strings/string_piece.h" +#include "content/common/content_export.h" namespace content { -// If you change any of the following enums, please follow the process in -// go/preloading-dashboard-updates to update the mapping reflected in -// dashboard, or if you are not a Googler, please file an FYI bug on -// https://crbug.new with component Internals>Preload. +// If you change any of the following enums or static variables, please follow +// the process in go/preloading-dashboard-updates to update the mapping +// reflected in dashboard, or if you are not a Googler, please file an FYI bug +// on https://crbug.new with component Internals>Preload. // Defines the different types of preloading speedup techniques. Preloading is a // holistic term to define all the speculative operations the browser does for @@ -52,42 +55,64 @@ }; // Defines various triggering mechanisms which triggers different preloading -// operations mentioned in preloading.h. +// operations mentioned in preloading.h. The integer portion is used for UKM +// logging, and the string portion is used to dynamically compose UMA histogram +// names. Embedders are allowed to define more predictors. +class CONTENT_EXPORT PreloadingPredictor { + public: + constexpr PreloadingPredictor(int64_t ukm_value, base::StringPiece name) + : ukm_value_(ukm_value), name_(name) {} + int64_t ukm_value() const { return ukm_value_; } + base::StringPiece name() const { return name_; } + + private: + int64_t ukm_value_; + base::StringPiece name_; +}; // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. -enum class PreloadingPredictor { - // No PreloadingTrigger is present. This may include the small percentage of - // usages of browser triggers, link-rel, OptimizationGuideService e.t.c which - // will be added later as a separate elements. - kUnspecified = 0, +// +// Advance numbering by +1 when adding a new element. +// +// To add additional predictors in content-internals and embedders, wrap the +// new `PreloadingPredictor` in the corresponding namespaces: +// - `content_preloading_predictor` for content-internals; +// - `chrome_preloading_predictor` for Chrome. +// +// See `content/browser/preloading/preloading.h` and +// `chrome/browser/preloading/chrome_preloading.h` for examples. +// +// Please limit content-public `PreloadingPredictor` between 0 to 49 +// (inclusive) as 50 and beyond are reserved for content-internal and embedders. +// Both the value and the name should be unique across all the namespaces. +// +// The embedder `PreloadingPredictor` definitions should start at 100 (see +// `chrome/browser/preloading/chrome_preloading.h` for example). +namespace preloading_predictor { +// No PreloadingTrigger is present. This may include the small percentage of +// usages of browser triggers, link-rel, OptimizationGuideService e.t.c which +// will be added later as a separate elements. +static constexpr PreloadingPredictor kUnspecified(0, "Unspecified"); - // Preloading is triggered by OnPointerDown event heuristics. - kUrlPointerDownOnAnchor = 1, +// Preloading is triggered by OnPointerDown event heuristics. +static constexpr PreloadingPredictor kUrlPointerDownOnAnchor( + 1, + "UrlPointerDownOnAnchor"); - // Preloading is triggered by OnPointerHover event heuristics. - kUrlPointerHoverOnAnchor = 2, +// Preloading is triggered by OnPointerHover event heuristics. +static constexpr PreloadingPredictor kUrlPointerHoverOnAnchor( + 2, + "UrlPointerHoverOnAnchor"); - // Preloading was triggered by embedding a keyword for the rel attribute of - // the <link> HTML element to hint to browsers that the user might need it for - // next navigation. - kLinkRel = 3, +// Preloading was triggered by embedding a keyword for the rel attribute of +// the <link> HTML element to hint to browsers that the user might need it for +// next navigation. +static constexpr PreloadingPredictor kLinkRel(3, "LinkRel"); - // TODO(crbug.com/1309934): Add more predictors as we integrate Preloading - // logging. - - // This constant is used to define the value from which features can add more - // enums beyond this value both inside and outside content. We mask it by 50 - // and 100 to avoid usage of the same numbers for logging. - - // >= 50 values are reserved for content-internal values, such as - // ContentPreloadingPredictor enum. - kPreloadingPredictorContentStart = 50, - - // >= 100 values are reserved for embedder-specific values, such as the - // ChromePreloadingPredictor enum. - kPreloadingPredictorContentEnd = 100, -}; +// TODO(crbug.com/1309934): Add more predictors as we integrate Preloading +// logging. +} // namespace preloading_predictor // Defines if a preloading operation is eligible for a given preloading // trigger. @@ -195,7 +220,9 @@ // triggered. // These values are persisted to logs. Entries should not be renumbered and -// numeric values should never be reused. +// numeric values should never be reused. Please update +// "PreloadingTriggeringOutcome" in `tools/metrics/histograms/enums.xml` when +// new enums are added. enum class PreloadingTriggeringOutcome { // The outcome is kUnspecified for attempts that were not triggered due to // various ineligibility reasons or due to a field trial holdback. @@ -237,6 +264,9 @@ // navigation. This outcome should not be recorded when // `kPrerender2SequentialPrerendering` is disabled. kTriggeredButPending = 9, + + // Required by UMA histogram macro. + kMaxValue = kTriggeredButPending, }; // These values are persisted to logs. Entries should not be renumbered and
diff --git a/content/public/browser/save_page_type.h b/content/public/browser/save_page_type.h index 4b58531..6301d158 100644 --- a/content/public/browser/save_page_type.h +++ b/content/public/browser/save_page_type.h
@@ -16,8 +16,6 @@ SAVE_PAGE_TYPE_AS_COMPLETE_HTML = 1, // User chose to save complete-html page as MHTML. SAVE_PAGE_TYPE_AS_MHTML = 2, - // User chose to save complete-html page as Web Bundle. - SAVE_PAGE_TYPE_AS_WEB_BUNDLE = 3, // Insert new values BEFORE this value. SAVE_PAGE_TYPE_MAX,
diff --git a/content/public/browser/storage_partition.h b/content/public/browser/storage_partition.h index 380e808..5d96c0f4 100644 --- a/content/public/browser/storage_partition.h +++ b/content/public/browser/storage_partition.h
@@ -63,6 +63,7 @@ namespace content { +class AttributionDataModel; class BackgroundSyncContext; class BrowserContext; class BrowsingDataFilterBuilder; @@ -157,6 +158,7 @@ virtual PlatformNotificationContext* GetPlatformNotificationContext() = 0; virtual InterestGroupManager* GetInterestGroupManager() = 0; virtual BrowsingTopicsSiteDataManager* GetBrowsingTopicsSiteDataManager() = 0; + virtual AttributionDataModel* GetAttributionDataModel() = 0; virtual leveldb_proto::ProtoDatabaseProvider* GetProtoDatabaseProvider() = 0; // Must be set before the first call to GetProtoDatabaseProvider(), or a new
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 95b1e0472..288b2fb 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -1005,17 +1005,20 @@ false, }; +// This feature param controls if the service worker is started for an +// empty service worker fetch handler while `kSkipEmptyFetchHandler` is on. +constexpr base::FeatureParam<bool> kStartServiceWorkerForEmptyFetchHandler{ + &kServiceWorkerSkipIgnorableFetchHandler, + "StartServiceWorkerForEmptyFetchHandler", + false, +}; + // Run video capture service in the Browser process as opposed to a dedicated // utility process BASE_FEATURE(kRunVideoCaptureServiceInBrowserProcess, "RunVideoCaptureServiceInBrowserProcess", base::FEATURE_DISABLED_BY_DEFAULT); -// Enables saving pages as Web Bundle. -BASE_FEATURE(kSavePageAsWebBundle, - "SavePageAsWebBundle", - base::FEATURE_DISABLED_BY_DEFAULT); - // Browser-side feature flag for Secure Payment Confirmation (SPC) that also // controls the render side feature state. SPC is not currently available on // Linux or ChromeOS, as it requires platform authenticator support.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 81bbec57..21a67f6 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -198,7 +198,6 @@ kRenderAccessibilityHostDeserializationOffMainThread); CONTENT_EXPORT BASE_DECLARE_FEATURE(kRenderDocument); CONTENT_EXPORT BASE_DECLARE_FEATURE(kRunVideoCaptureServiceInBrowserProcess); -CONTENT_EXPORT BASE_DECLARE_FEATURE(kSavePageAsWebBundle); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSecurePaymentConfirmation); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSecurePaymentConfirmationDebug); CONTENT_EXPORT BASE_DECLARE_FEATURE(kSecurePaymentConfirmationRemoveRpField); @@ -260,6 +259,8 @@ kServiceWorkerBypassFetchHandlerBypassedOrigins; CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerSkipIgnorableFetchHandler); CONTENT_EXPORT extern const base::FeatureParam<bool> kSkipEmptyFetchHandler; +CONTENT_EXPORT extern const base::FeatureParam<bool> + kStartServiceWorkerForEmptyFetchHandler; CONTENT_EXPORT BASE_DECLARE_FEATURE(kUserMediaCaptureOnFocus); CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebLockScreenApi); CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebOTP);
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index dfc7ee1..02d4e1b 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -27,10 +27,6 @@ // This is used in blimp to emulate android fonts on linux. const char kAndroidFontsPath[] = "android-fonts-path"; -// Indicates that the ash web browser is disabled (i.e. lacros the only -// browser). -const char kAshWebBrowserDisabled[] = "ash-web-browser-disabled"; - // Causes the Attribution Report API to run without delays or noise. const char kAttributionReportingDebugMode[] = "attribution-reporting-debug-mode";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 5a65b9f..bd73d0f 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -21,7 +21,6 @@ CONTENT_EXPORT extern const char kAllowLoopbackInPeerConnection[]; CONTENT_EXPORT extern const char kAllowSyncXHRInPageDismissal[]; CONTENT_EXPORT extern const char kAndroidFontsPath[]; -CONTENT_EXPORT extern const char kAshWebBrowserDisabled[]; CONTENT_EXPORT extern const char kAttributionReportingDebugMode[]; CONTENT_EXPORT extern const char kBrowserCrashTest[]; CONTENT_EXPORT extern const char kBrowserStartupDialog[];
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h index 440f3f45..6b359d3 100644 --- a/content/public/test/browser_test_utils.h +++ b/content/public/test/browser_test_utils.h
@@ -12,6 +12,7 @@ #include "base/containers/flat_set.h" #include "base/containers/queue.h" +#include "base/cxx20_to_address.h" #include "base/files/scoped_temp_dir.h" #include "base/functional/callback.h" #include "base/json/json_writer.h" @@ -526,15 +527,11 @@ // declare additional ConvertToRenderFrameHost functions for convenience. class ToRenderFrameHost { public: - template <typename T> + template <typename Ptr> // NOLINTNEXTLINE(google-explicit-constructor) - ToRenderFrameHost(T* frame_convertible_value) - : render_frame_host_(ConvertToRenderFrameHost(frame_convertible_value)) {} - - template <typename T, typename Traits> - // NOLINTNEXTLINE(google-explicit-constructor) - ToRenderFrameHost(const raw_ptr<T, Traits>& frame_convertible_value) - : ToRenderFrameHost(frame_convertible_value.get()) {} + ToRenderFrameHost(Ptr frame_convertible_value) + : render_frame_host_(ConvertToRenderFrameHost( + base::to_address(frame_convertible_value))) {} // Extract the underlying frame. RenderFrameHost* render_frame_host() const { return render_frame_host_; }
diff --git a/content/public/test/preloading_test_util.cc b/content/public/test/preloading_test_util.cc index 19e79d4..8bfe27de 100644 --- a/content/public/test/preloading_test_util.cc +++ b/content/public/test/preloading_test_util.cc
@@ -50,8 +50,7 @@ std::map<std::string, int64_t> metrics = { {Preloading_Attempt::kPreloadingTypeName, static_cast<int64_t>(preloading_type)}, - {Preloading_Attempt::kPreloadingPredictorName, - static_cast<int64_t>(predictor_)}, + {Preloading_Attempt::kPreloadingPredictorName, predictor_.ukm_value()}, {Preloading_Attempt::kEligibilityName, static_cast<int64_t>(eligibility)}, {Preloading_Attempt::kHoldbackStatusName, static_cast<int64_t>(holdback_status)}, @@ -82,7 +81,7 @@ bool accurate_prediction) const { return UkmEntry{source_id, {{Preloading_Prediction::kPreloadingPredictorName, - static_cast<int64_t>(predictor_)}, + predictor_.ukm_value()}, {Preloading_Prediction::kConfidenceName, confidence}, {Preloading_Prediction::kAccuratePredictionName, accurate_prediction ? 1 : 0},
diff --git a/content/public/test/test_storage_partition.cc b/content/public/test/test_storage_partition.cc index 1003aae..56e6f5e 100644 --- a/content/public/test/test_storage_partition.cc +++ b/content/public/test/test_storage_partition.cc
@@ -137,6 +137,10 @@ return nullptr; } +AttributionDataModel* TestStoragePartition::GetAttributionDataModel() { + return nullptr; +} + BrowsingTopicsSiteDataManager* TestStoragePartition::GetBrowsingTopicsSiteDataManager() { return browsing_topics_site_data_manager_;
diff --git a/content/public/test/test_storage_partition.h b/content/public/test/test_storage_partition.h index bf1e936b..aefe702 100644 --- a/content/public/test/test_storage_partition.h +++ b/content/public/test/test_storage_partition.h
@@ -142,6 +142,8 @@ InterestGroupManager* GetInterestGroupManager() override; + AttributionDataModel* GetAttributionDataModel() override; + void set_browsing_topics_site_data_manager( BrowsingTopicsSiteDataManager* manager) { browsing_topics_site_data_manager_ = manager;
diff --git a/content/renderer/media/renderer_webaudiodevice_impl.cc b/content/renderer/media/renderer_webaudiodevice_impl.cc index ea29dc7..1225a5d8 100644 --- a/content/renderer/media/renderer_webaudiodevice_impl.cc +++ b/content/renderer/media/renderer_webaudiodevice_impl.cc
@@ -94,7 +94,7 @@ const blink::LocalFrameToken& frame_token, const std::string& device_id) { return AudioDeviceFactory::GetInstance() - ->GetOutputDeviceInfo(frame_token, {base::UnguessableToken(), device_id}) + ->GetOutputDeviceInfo(frame_token, device_id) .output_params(); }
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 770e66e..d387e21 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -2027,7 +2027,7 @@ ? blink::AudioDeviceFactory::GetInstance() ->GetOutputDeviceInfo( render_frame()->GetWebFrame()->GetLocalFrameToken(), - media::AudioSinkParameters()) + std::string()) .output_params() .sample_rate() : 0; @@ -2039,7 +2039,7 @@ ? blink::AudioDeviceFactory::GetInstance() ->GetOutputDeviceInfo( render_frame()->GetWebFrame()->GetLocalFrameToken(), - media::AudioSinkParameters()) + std::string()) .output_params() .frames_per_buffer() : 0;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 2e90ae7..6be1a34 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -989,6 +989,8 @@ commit_params.origin_to_commit.value(); } navigation_params->storage_key = std::move(commit_params.storage_key); + navigation_params->session_storage_key = + std::move(commit_params.session_storage_key); navigation_params->frame_policy = commit_params.frame_policy; if (common_params.navigation_type == blink::mojom::NavigationType::RESTORE) { @@ -5954,10 +5956,8 @@ std::move( blink::ConvertToOutputDeviceStatusCB(std::move(completion_callback))) .Run(blink::AudioDeviceFactory::GetInstance() - ->GetOutputDeviceInfo( - GetWebFrame()->GetLocalFrameToken(), - media::AudioSinkParameters(base::UnguessableToken(), - sink_id.Utf8())) + ->GetOutputDeviceInfo(GetWebFrame()->GetLocalFrameToken(), + sink_id.Utf8()) .device_status()); }
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 2569208..b8e31584 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -143,7 +143,7 @@ return blink::AudioDeviceFactory::GetInstance() ->GetOutputDeviceInfo(render_frame->GetWebFrame()->GetLocalFrameToken(), - media::AudioSinkParameters()) + std::string()) .output_params(); }
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc index 02e65277..6368325 100644 --- a/content/renderer/renderer_main.cc +++ b/content/renderer/renderer_main.cc
@@ -163,19 +163,11 @@ } #endif // BUILDFLAG(IS_CHROMEOS_ASH) -#if BUILDFLAG(IS_CHROMEOS_ASH) - // Turn on core scheduling for ash renderers only if kLacrosOnly is not - // enabled. If kLacrosOnly is enabled, ash renderers don't run user code. This - // means they don't need core scheduling. Lacros renderers will get core - // scheduling in this case. - if (!command_line.HasSwitch(switches::kAshWebBrowserDisabled)) { - chromeos::system::EnableCoreSchedulingIfAvailable(); - } -#elif BUILDFLAG(IS_CHROMEOS_LACROS) - // Turn on core scheduling for lacros renderers since they run user code in - // most cases. +#if BUILDFLAG(IS_CHROMEOS) + // When we start the renderer on ChromeOS if the system has core scheduling + // available we want to turn it on. chromeos::system::EnableCoreSchedulingIfAvailable(); -#endif +#endif // BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_CHROMEOS_ASH) #if defined(ARCH_CPU_X86_64)
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 5a3da1c..714ba1df 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -2200,7 +2200,7 @@ "../browser/client_hints/client_hints_unittest.cc", "../browser/code_cache/generated_code_cache_unittest.cc", "../browser/code_cache/simple_lru_cache_unittest.cc", - "../browser/compute_pressure/pressure_service_impl_unittest.cc", + "../browser/compute_pressure/compute_pressure_unittest.cc", "../browser/content_index/content_index_database_unittest.cc", "../browser/content_index/content_index_service_impl_unittest.cc", "../browser/cookie_store/cookie_store_manager_unittest.cc", @@ -2356,6 +2356,7 @@ "../browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc", "../browser/preloading/prefetch/proxy_lookup_client_impl_unittest.cc", "../browser/preloading/prefetcher_unittest.cc", + "../browser/preloading/preloading_attempt_impl_unittest.cc", "../browser/preloading/preloading_decider_unittest.cc", "../browser/preloading/prerender/prerender_host_registry_unittest.cc", "../browser/preloading/prerender/prerender_host_unittest.cc",
diff --git a/content/test/attribution_simulator_input_parser.cc b/content/test/attribution_simulator_input_parser.cc index 471a42c..9f73a7d 100644 --- a/content/test/attribution_simulator_input_parser.cc +++ b/content/test/attribution_simulator_input_parser.cc
@@ -295,6 +295,7 @@ .trigger = AttributionTrigger(std::move(*reporting_origin), std::move(*trigger_registration), std::move(*destination_origin), + /*attestation=*/absl::nullopt, /*is_within_fenced_frame=*/false), .time = trigger_time, });
diff --git a/content/test/attribution_simulator_input_parser_unittest.cc b/content/test/attribution_simulator_input_parser_unittest.cc index 20c776d..fd3a5da 100644 --- a/content/test/attribution_simulator_input_parser_unittest.cc +++ b/content/test/attribution_simulator_input_parser_unittest.cc
@@ -364,6 +364,7 @@ kDefault), /*destination_origin=*/ *SuitableOrigin::Deserialize("https://a.d1.test"), + /*attestation=*/absl::nullopt, /*is_within_fenced_frame=*/false), .time = kOffsetTime + base::Milliseconds(1643235576123), }, @@ -387,6 +388,7 @@ kDefault), /*destination_origin=*/ *SuitableOrigin::Deserialize("https://a.d2.test"), + /*attestation=*/absl::nullopt, /*is_within_fenced_frame=*/false), .time = kOffsetTime + base::Milliseconds(1643235575123), }, @@ -418,6 +420,7 @@ kDefault), /*destination_origin=*/ *SuitableOrigin::Deserialize("https://a.d2.test"), + /*attestation=*/absl::nullopt, /*is_within_fenced_frame=*/false), .time = kOffsetTime + base::Milliseconds(1643235574123), })));
diff --git a/content/test/data/accessibility/aria/aria-describedby-updates.html b/content/test/data/accessibility/aria/aria-describedby-updates.html index 45a63f3..5e8b6bb 100644 --- a/content/test/data/accessibility/aria/aria-describedby-updates.html +++ b/content/test/data/accessibility/aria/aria-describedby-updates.html
@@ -3,6 +3,7 @@ @BLINK-ALLOW:description=* @WIN-ALLOW:description=* @MAC-ALLOW:AXDescription +@MAC-ALLOW:AXHelp @BLINK-DENY:descriptionFrom* --> <!DOCTYPE html>
diff --git a/content/test/data/accessibility/aria/aria-owns-with-role-change-expected-auralinux.txt b/content/test/data/accessibility/aria/aria-owns-with-role-change-expected-auralinux.txt new file mode 100644 index 0000000..438faa7b --- /dev/null +++ b/content/test/data/accessibility/aria/aria-owns-with-role-change-expected-auralinux.txt
@@ -0,0 +1,4 @@ +[document web] +++[landmark] name='Stuff' xml-roles:region +++++[static] name='Text' +++++[push button] name='Button' xml-roles:button
diff --git a/content/test/data/accessibility/aria/aria-owns-with-role-change-expected-uia-win.txt b/content/test/data/accessibility/aria/aria-owns-with-role-change-expected-uia-win.txt new file mode 100644 index 0000000..3d68351 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-owns-with-role-change-expected-uia-win.txt
@@ -0,0 +1,4 @@ +Document LocalizedControlType='document' +++Group LocalizedControlType='region' Name='Stuff' +++++Text LocalizedControlType='text' Name='Text' +++++Button LocalizedControlType='button' Name='Button'
diff --git a/content/test/data/accessibility/aria/aria-owns-with-role-change.html b/content/test/data/accessibility/aria/aria-owns-with-role-change.html index 339bacb..cc3739e8 100644 --- a/content/test/data/accessibility/aria/aria-owns-with-role-change.html +++ b/content/test/data/accessibility/aria/aria-owns-with-role-change.html
@@ -1,5 +1,9 @@ <!-- @WAIT-FOR:region +@AURALINUX-ALLOW:xml-roles* +@WIN-ALLOW:xml-roles* +@MAC-ALLOW:AXRoleDescription* +@UIA-WIN-ALLOW:LocalizedControlType* --> <div id="owner" role="doc-glossary" aria-owns="owned" aria-label="Stuff"> Text
diff --git a/content/test/data/accessibility/html/iframe-coordinates.html b/content/test/data/accessibility/html/iframe-coordinates.html index d55f49a..4d9913a 100644 --- a/content/test/data/accessibility/html/iframe-coordinates.html +++ b/content/test/data/accessibility/html/iframe-coordinates.html
@@ -34,14 +34,6 @@ @BLINK-ALLOW:pageLocation=(0, 300) @BLINK-ALLOW:pageLocation=(25, 325) @BLINK-ALLOW:pageLocation=(0, 450) - -These can be removed when bug 532249 is fixed because -then the test framework will just wait until all frames -have finished loading. Until then we need these because -the test doesn't wait for same-process iframes to finish -loading. -@WAIT-FOR:Ordinary Button -@WAIT-FOR:Scrolled Button --> <!DOCTYPE html> <html>
diff --git a/content/test/data/accessibility/html/input-text-value-changed-expected-auralinux.txt b/content/test/data/accessibility/html/input-text-value-changed-expected-auralinux.txt new file mode 100644 index 0000000..4cdc08c5 --- /dev/null +++ b/content/test/data/accessibility/html/input-text-value-changed-expected-auralinux.txt
@@ -0,0 +1,5 @@ +[document web] text-align:left text='%EF%BF%BC' +++[section] text-align:left text='%EF%BF%BC%EF%BF%BC%EF%BF%BC' +++++[entry] selectable-text text-align:left text-input-type:text text='aaYYYYbb' +++++[entry] selectable-text text-align:left text-input-type:text text='aa' +++++[entry] selectable-text text-align:left text-input-type:text text='After'
diff --git a/content/test/data/accessibility/html/input-text-value-changed.html b/content/test/data/accessibility/html/input-text-value-changed.html index 4ba3874..0d6d27f31 100644 --- a/content/test/data/accessibility/html/input-text-value-changed.html +++ b/content/test/data/accessibility/html/input-text-value-changed.html
@@ -2,6 +2,7 @@ @ANDROID-ALLOW:text_change_added_count @ANDROID-ALLOW:text_change_removed_count @BLINK-ALLOW:inputType=* +@AURALINUX-ALLOW:text* @WAIT-FOR:After --> <html>
diff --git a/content/test/data/accessibility/regression/null-object-on-hypertext-offset-computation-expected-auralinux.txt b/content/test/data/accessibility/regression/null-object-on-hypertext-offset-computation-expected-auralinux.txt new file mode 100644 index 0000000..8fbe9d1 --- /dev/null +++ b/content/test/data/accessibility/regression/null-object-on-hypertext-offset-computation-expected-auralinux.txt
@@ -0,0 +1,4 @@ +[document web] text-align:left text='%EF%BF%BC' +++[section] text-align:left text='%EF%BF%BC%EF%BF%BC' +++++[entry] selectable-text text-align:left text='done' +++++[image] text-align:left
diff --git a/content/test/data/accessibility/regression/null-object-on-hypertext-offset-computation.html b/content/test/data/accessibility/regression/null-object-on-hypertext-offset-computation.html index 54f686ef..bab426d0 100644 --- a/content/test/data/accessibility/regression/null-object-on-hypertext-offset-computation.html +++ b/content/test/data/accessibility/regression/null-object-on-hypertext-offset-computation.html
@@ -1,5 +1,6 @@ <!-- @WAIT-FOR:done +@AURALINUX-ALLOW:text* --> <!DOCTYPE html> <style>
diff --git a/content/test/data/attribution_reporting/databases/version_40.sql b/content/test/data/attribution_reporting/databases/version_40.sql index 8673ba72..87f2fee 100644 --- a/content/test/data/attribution_reporting/databases/version_40.sql +++ b/content/test/data/attribution_reporting/databases/version_40.sql
@@ -46,4 +46,6 @@ CREATE INDEX aggregate_report_time_idx ON aggregatable_report_metadata(report_time); +INSERT INTO aggregatable_report_metadata VALUES (1,2,3,4,5,6,7,8,9); + COMMIT;
diff --git a/content/test/data/attribution_reporting/databases/version_41.sql b/content/test/data/attribution_reporting/databases/version_41.sql new file mode 100644 index 0000000..b2b65b5 --- /dev/null +++ b/content/test/data/attribution_reporting/databases/version_41.sql
@@ -0,0 +1,49 @@ +PRAGMA foreign_keys=OFF; + +BEGIN TRANSACTION; + +CREATE TABLE sources(source_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,source_event_id INTEGER NOT NULL,source_origin TEXT NOT NULL,destination_origin TEXT NOT NULL,reporting_origin TEXT NOT NULL,source_time INTEGER NOT NULL,expiry_time INTEGER NOT NULL,event_report_window_time INTEGER NOT NULL,aggregatable_report_window_time INTEGER NOT NULL,num_attributions INTEGER NOT NULL,event_level_active INTEGER NOT NULL,aggregatable_active INTEGER NOT NULL,destination_site TEXT NOT NULL,source_type INTEGER NOT NULL,attribution_logic INTEGER NOT NULL,priority INTEGER NOT NULL,source_site TEXT NOT NULL,debug_key INTEGER,aggregatable_budget_consumed INTEGER NOT NULL,aggregatable_source BLOB NOT NULL,filter_data BLOB NOT NULL); + +CREATE TABLE event_level_reports(report_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,source_id INTEGER NOT NULL,trigger_data INTEGER NOT NULL,trigger_time INTEGER NOT NULL,report_time INTEGER NOT NULL,priority INTEGER NOT NULL,failed_send_attempts INTEGER NOT NULL,external_report_id TEXT NOT NULL,debug_key INTEGER); + +CREATE TABLE rate_limits(id INTEGER PRIMARY KEY NOT NULL,scope INTEGER NOT NULL,source_id INTEGER NOT NULL,source_site TEXT NOT NULL,source_origin TEXT NOT NULL,destination_site TEXT NOT NULL,destination_origin TEXT NOT NULL,reporting_origin TEXT NOT NULL,time INTEGER NOT NULL,expiry_time INTEGER NOT NULL); + +CREATE TABLE dedup_keys(source_id INTEGER NOT NULL,report_type INTEGER NOT NULL,dedup_key INTEGER NOT NULL,PRIMARY KEY(source_id,report_type,dedup_key))WITHOUT ROWID; + +CREATE TABLE aggregatable_report_metadata(aggregation_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,source_id INTEGER NOT NULL,trigger_time INTEGER NOT NULL,debug_key INTEGER,external_report_id TEXT NOT NULL,report_time INTEGER NOT NULL,failed_send_attempts INTEGER NOT NULL,initial_report_time INTEGER NOT NULL,aggregation_coordinator INTEGER NOT NULL,attestation_token TEXT); + +CREATE TABLE aggregatable_contributions(aggregation_id INTEGER NOT NULL,contribution_id INTEGER NOT NULL,key_high_bits INTEGER NOT NULL,key_low_bits INTEGER NOT NULL,value INTEGER NOT NULL,PRIMARY KEY(aggregation_id,contribution_id))WITHOUT ROWID; + +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); + +INSERT INTO meta VALUES('mmap_status','-1'); +INSERT INTO meta VALUES('version','41'); +INSERT INTO meta VALUES('last_compatible_version','41'); + +CREATE INDEX sources_by_active_destination_site_reporting_origin ON sources(event_level_active,aggregatable_active,destination_site,reporting_origin); + +CREATE INDEX sources_by_expiry_time ON sources(expiry_time); + +CREATE INDEX active_sources_by_source_origin ON sources(source_origin)WHERE event_level_active=1 OR aggregatable_active=1; + +CREATE INDEX active_unattributed_sources_by_site_reporting_origin ON sources(source_site,reporting_origin)WHERE event_level_active=1 AND num_attributions=0 AND aggregatable_active=1 AND aggregatable_budget_consumed=0; + +CREATE INDEX event_level_reports_by_report_time ON event_level_reports(report_time); + +CREATE INDEX event_level_reports_by_source_id ON event_level_reports(source_id); + +CREATE INDEX rate_limit_source_site_reporting_origin_idx ON rate_limits(scope,source_site,reporting_origin); + +CREATE INDEX rate_limit_reporting_origin_idx ON rate_limits(scope,destination_site,source_site); + +CREATE INDEX rate_limit_time_idx ON rate_limits(time); + +CREATE INDEX rate_limit_source_id_idx ON rate_limits(source_id); + +CREATE INDEX aggregate_source_id_idx ON aggregatable_report_metadata(source_id); + +CREATE INDEX aggregate_trigger_time_idx ON aggregatable_report_metadata(trigger_time); + +CREATE INDEX aggregate_report_time_idx ON aggregatable_report_metadata(report_time); + +COMMIT;
diff --git a/content/test/data/attribution_reporting/interop/rate_limit_max_attribution_reporting_endpoints.json b/content/test/data/attribution_reporting/interop/rate_limit_max_attribution_reporting_endpoints.json index e8959c5..f7aa32c 100644 --- a/content/test/data/attribution_reporting/interop/rate_limit_max_attribution_reporting_endpoints.json +++ b/content/test/data/attribution_reporting/interop/rate_limit_max_attribution_reporting_endpoints.json
@@ -152,7 +152,7 @@ }] }, { - "timestamp": "1645827574000", + "timestamp": "1645827573000", "registration_request": { "attribution_src_url": "https://another-reporter.test/register-trigger", "destination_origin": "https://destination.test"
diff --git a/content/test/data/attribution_reporting/interop/rate_limit_max_attributions.json b/content/test/data/attribution_reporting/interop/rate_limit_max_attributions.json index 570ee05..38fb4fd 100644 --- a/content/test/data/attribution_reporting/interop/rate_limit_max_attributions.json +++ b/content/test/data/attribution_reporting/interop/rate_limit_max_attributions.json
@@ -202,7 +202,7 @@ // Should result in an event-level report because the first report falls // outside the rate limit window. { - "timestamp": "1645827574000", + "timestamp": "1645827573000", "registration_request": { "attribution_src_url": "https://reporter.test/register-trigger", "destination_origin": "https://destination.test"
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_deduplicated.input.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_deduplicated.input.json new file mode 100644 index 0000000..fbb6562a --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_deduplicated.input.json
@@ -0,0 +1,47 @@ +{ + "cookies": [ + { + "timestamp": "1643235571000", + "url": "https://r.test/", + "Set-Cookie": "ar_debug=1; SameSite=None; Secure; HttpOnly" + } + ], + "sources": [ + { + "timestamp": "1643235571001", + "source_origin": "https://a.s.test", + "reporting_origin": "https://r.test", + "source_type": "navigation", + "Attribution-Reporting-Register-Source": { + "destination": "https://d.test", + "source_event_id": "123" + } + } + ], + "triggers": [ + { + "timestamp": "1643235571002", + "reporting_origin": "https://r.test", + "destination_origin": "https://d.test", + "Attribution-Reporting-Register-Trigger": { + "debug_reporting": true, + "event_trigger_data": [{ + "trigger_data": "2", + "deduplication_key": "9" + }] + } + }, + { + "timestamp": "1643235571003", + "reporting_origin": "https://r.test", + "destination_origin": "https://d.test", + "Attribution-Reporting-Register-Trigger": { + "debug_reporting": true, + "event_trigger_data": [{ + "trigger_data": "4", + "deduplication_key": "9" + }] + } + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_deduplicated.output.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_deduplicated.output.json new file mode 100644 index 0000000..2f5ed5c6 --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_deduplicated.output.json
@@ -0,0 +1,32 @@ +{ + "verbose_debug_reports": [ + { + "report_time": "1643235571003", + "report_url": "https://r.test/.well-known/attribution-reporting/debug/verbose", + "report": [ + { + "type": "trigger-event-deduplicated", + "body": { + "attribution_destination": "https://d.test", + "source_event_id": "123", + "source_site": "https://s.test" + } + } + ] + } + ], + "event_level_reports": [ + { + "intended_report_time": "1643411971001", + "report_url": "https://r.test/.well-known/attribution-reporting/report-event-attribution", + "report": { + "attribution_destination": "https://d.test", + "randomized_trigger_rate": 0.0024, + "scheduled_report_time": "1643411971", + "source_event_id": "123", + "source_type": "navigation", + "trigger_data": "2" + } + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_no_matching_configurations.input.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_no_matching_configurations.input.json new file mode 100644 index 0000000..15dea6d --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_no_matching_configurations.input.json
@@ -0,0 +1,34 @@ +{ + "cookies": [ + { + "timestamp": "1643235571000", + "url": "https://r.test/", + "Set-Cookie": "ar_debug=1; SameSite=None; Secure; HttpOnly" + } + ], + "sources": [ + { + "timestamp": "1643235571001", + "source_origin": "https://a.s.test", + "reporting_origin": "https://r.test", + "source_type": "navigation", + "Attribution-Reporting-Register-Source": { + "destination": "https://d.test", + "source_event_id": "123" + } + } + ], + "triggers": [ + { + "timestamp": "1643235571002", + "reporting_origin": "https://r.test", + "destination_origin": "https://d.test", + "Attribution-Reporting-Register-Trigger": { + "debug_reporting": true, + "event_trigger_data": [{ + "filters": {"source_type": ["event"]} + }] + } + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_no_matching_configurations.output.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_no_matching_configurations.output.json new file mode 100644 index 0000000..f1f7a9d0 --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_no_matching_configurations.output.json
@@ -0,0 +1,18 @@ +{ + "verbose_debug_reports": [ + { + "report_time": "1643235571002", + "report_url": "https://r.test/.well-known/attribution-reporting/debug/verbose", + "report": [ + { + "type": "trigger-event-no-matching-configurations", + "body": { + "attribution_destination": "https://d.test", + "source_event_id": "123", + "source_site": "https://s.test" + } + } + ] + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_report_window_passed.input.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_report_window_passed.input.json new file mode 100644 index 0000000..e2cad89 --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_report_window_passed.input.json
@@ -0,0 +1,33 @@ +{ + "cookies": [ + { + "timestamp": "1643235571000", + "url": "https://r.test/", + "Set-Cookie": "ar_debug=1; SameSite=None; Secure; HttpOnly" + } + ], + "sources": [ + { + "timestamp": "1643235571001", + "source_origin": "https://a.s.test", + "reporting_origin": "https://r.test", + "source_type": "navigation", + "Attribution-Reporting-Register-Source": { + "destination": "https://d.test", + "event_report_window": "86400", + "source_event_id": "123" + } + } + ], + "triggers": [ + { + "timestamp": "1643321971002", + "reporting_origin": "https://r.test", + "destination_origin": "https://d.test", + "Attribution-Reporting-Register-Trigger": { + "debug_reporting": true, + "event_trigger_data": [{}] + } + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_report_window_passed.output.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_report_window_passed.output.json new file mode 100644 index 0000000..03580f18 --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_event_report_window_passed.output.json
@@ -0,0 +1,18 @@ +{ + "verbose_debug_reports": [ + { + "report_time": "1643321971002", + "report_url": "https://r.test/.well-known/attribution-reporting/debug/verbose", + "report": [ + { + "type": "trigger-event-report-window-passed", + "body": { + "attribution_destination": "https://d.test", + "source_event_id": "123", + "source_site": "https://s.test" + } + } + ] + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug.input.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_low_priority.input.json similarity index 100% rename from content/test/data/attribution_reporting/simulator/verbose_debug.input.json rename to content/test/data/attribution_reporting/simulator/verbose_debug_trigger_low_priority.input.json
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug.output.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_low_priority.output.json similarity index 100% rename from content/test/data/attribution_reporting/simulator/verbose_debug.output.json rename to content/test/data/attribution_reporting/simulator/verbose_debug_trigger_low_priority.output.json
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_filter_data.input.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_filter_data.input.json new file mode 100644 index 0000000..a9077f96 --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_filter_data.input.json
@@ -0,0 +1,33 @@ +{ + "cookies": [ + { + "timestamp": "1643235571000", + "url": "https://r.test/", + "Set-Cookie": "ar_debug=1; SameSite=None; Secure; HttpOnly" + } + ], + "sources": [ + { + "timestamp": "1643235571001", + "source_origin": "https://a.s.test", + "reporting_origin": "https://r.test", + "source_type": "navigation", + "Attribution-Reporting-Register-Source": { + "destination": "https://d.test", + "source_event_id": "123" + } + } + ], + "triggers": [ + { + "timestamp": "1643235571002", + "reporting_origin": "https://r.test", + "destination_origin": "https://d.test", + "Attribution-Reporting-Register-Trigger": { + "debug_reporting": true, + "event_trigger_data": [{}], + "filters": {"source_type": ["event"]} + } + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_filter_data.output.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_filter_data.output.json new file mode 100644 index 0000000..2443258 --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_filter_data.output.json
@@ -0,0 +1,18 @@ +{ + "verbose_debug_reports": [ + { + "report_time": "1643235571002", + "report_url": "https://r.test/.well-known/attribution-reporting/debug/verbose", + "report": [ + { + "type": "trigger-no-matching-filter-data", + "body": { + "attribution_destination": "https://d.test", + "source_event_id": "123", + "source_site": "https://s.test" + } + } + ] + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_source.input.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_source.input.json new file mode 100644 index 0000000..be984eb --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_source.input.json
@@ -0,0 +1,20 @@ +{ + "cookies": [ + { + "timestamp": "1643235571000", + "url": "https://r.test/", + "Set-Cookie": "ar_debug=1; SameSite=None; Secure; HttpOnly" + } + ], + "triggers": [ + { + "timestamp": "1643235571001", + "reporting_origin": "https://r.test", + "destination_origin": "https://d.test", + "Attribution-Reporting-Register-Trigger": { + "debug_reporting": true, + "event_trigger_data": [{}] + } + } + ] +}
diff --git a/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_source.output.json b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_source.output.json new file mode 100644 index 0000000..6f6e2d7b --- /dev/null +++ b/content/test/data/attribution_reporting/simulator/verbose_debug_trigger_no_matching_source.output.json
@@ -0,0 +1,16 @@ +{ + "verbose_debug_reports": [ + { + "report_time": "1643235571001", + "report_url": "https://r.test/.well-known/attribution-reporting/debug/verbose", + "report": [ + { + "type": "trigger-no-matching-source", + "body": { + "attribution_destination": "https://d.test" + } + } + ] + } + ] +}
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt index 4c84d29..09cd248 100644 --- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -117,8 +117,6 @@ # Dual-GPU problem with SkiaRenderer. crbug.com/1170840 [ amd-0x6821 mac renderer-skia-gl ] GpuProcess_mac_webgl_terminated_high_performance [ Failure ] -# Fuchsia flakes. - # Started crashing with passthrough field trial. crbug.com/1099576 [ amd-0x6821 mac ] GpuProcess_mac_webgl_backgrounded_high_performance [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index 9cc74ea..b83e26a 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -239,7 +239,6 @@ # WebGPU pixel tests fail on Linux+SkiaRenderer+Vulkan crbug.com/1213657 [ linux renderer-skia-vulkan ] Pixel_WebGPU* [ Skip ] - # WebGPU canvas capture hang on mac ASAN bot (also see crbug.com/1213170) crbug.com/1345767 [ mac asan ] Pixel_WebGPUCanvasOneCopyCapture [ Skip ] crbug.com/1345767 [ mac asan ] Pixel_WebGPUCanvasDisableOneCopyCapture* [ Skip ] @@ -263,13 +262,9 @@ crbug.com/624256 [ android ] Pixel_SolidColorBackground [ Failure ] -# Failing on Nexus 5; haven't investigated why yet. - crbug.com/1213674 [ mac amd-0x6821 passthrough ] Pixel_WebGLGreenTriangle_NonChromiumImage_NoAA_NoAlpha [ Failure ] crbug.com/1213674 [ mac nvidia passthrough ] Pixel_WebGLGreenTriangle_NonChromiumImage_NoAA_NoAlpha [ Failure ] -# Fails on Nexus 5 - old hardware, won't fix. - # Mark all webview tests as RetryOnFailure due to Nexus 5x driver bug. crbug.com/950932 [ android-webview-instrumentation android-nexus-5x ] * [ RetryOnFailure ] @@ -300,22 +295,12 @@ crbug.com/1230619 [ android android-SM-A235M ] Pixel_WebGLFloat [ Failure ] crbug.com/1230619 [ angle-disabled display-server-wayland intel linux no-passthrough ] Pixel_WebGLFloat [ Failure ] -# HDR rendering with PQ color space appears to be broken on Windows RS2. -# TODO(sunnyps): Revert this temporary suppression after ensuring pixel tests -# always run on Windows RS3 or above. - -# Flakes on gpu-fyi-try-chromeos-kevin and fuchsia-x64, produces notably different image. - # Flakes on gpu-fyi-try-chromeos-amd64-generic, times out. crbug.com/1338173 [ chromeos chromeos-board-amd64-generic ] Pixel_PrecisionRoundedCorner [ Failure ] -# Flaky hang. - # Flaky on Fuchsia. crbug.com/1368748 [ fuchsia ] Pixel_OffscreenCanvasWebGLPaintAfterResize [ Failure ] -# Still fails on Nexus 5 after all other Pixel_CanvasLowLatency* pass. - # Fails on Fuchsia emulators crbug.com/1302427 [ fuchsia fuchsia-board-qemu-x64 ] Pixel_CanvasLowLatencyWebGLAlphaFalse [ Failure ] @@ -333,15 +318,9 @@ crbug.com/1268144 [ fuchsia fuchsia-board-sherlock renderer-skia-vulkan ] Pixel_BackgroundImage [ Skip ] crbug.com/1268144 [ fuchsia fuchsia-board-sherlock renderer-skia-vulkan ] Pixel_SolidColorBackground [ Skip ] -# Pixel_Video_Media_Stream_Incompatible_Stride flakes with SkiaRenderer GL - # Flaky failures on Win10 AMD RX 5500 XT crbug.com/1288134 [ win10 amd-0x7340 renderer-skia-gl ] Pixel_DirectComposition_Video_VP9_YUY2 [ Failure ] -# Pixel 4 Flaky Failures - Passthrough, WebView and Validating - -# Pixel 4 Flaky Failures - Passthrough and Validating on Chromium - # Pixel 6 failures. crbug.com/1286915 [ android android-pixel-6 angle-disabled no-passthrough ] Pixel_CanvasLowLatencyWebGLAlphaFalse [ Failure ] crbug.com/1287280 [ android android-pixel-6 no-passthrough android-chromium ] Pixel_CanvasDisplaySRGBAccelerated2D [ Failure ] @@ -357,20 +336,21 @@ # Vulkan Swiftshader WebGPU interop - flipped destination image crbug.com/1307787 [ linux renderer-skia-vulkan ] Pixel_VulkanSwiftShader_WebGPUCopyExternalImage* [ Failure ] -# Vulkan Swiftshader WebGPU interop - missing destination image - -# Vulkan Swiftshader WebGPU interop - missing source and destination images - # Vulkan Swiftshader WebGPU interop - missing source image crbug.com/1307787 [ linux renderer-skia-vulkan ] Pixel_VulkanSwiftShader_WebGPUImportVideoFrameUnacceleratedOffscreenCanvas [ Failure ] crbug.com/1345777 [ android ] Pixel_VideoStreamFromWebGLCanvas [ Skip ] # WebGPU interop fails -- pixel color diff -crbug.com/1395227 [ mac ] Pixel_WebGPUImportVideoFrameUnaccelerated [ Failure ] -crbug.com/1395227 [ mac ] Pixel_WebGPUImportVideoFrameUnacceleratedOffscreenCanvas [ Failure ] +crbug.com/1395227 [ amd-0x679e mac-x86_64 monterey no-asan release ] Pixel_WebGPUImportVideoFrameUnaccelerated [ Failure ] +crbug.com/1395227 [ asan intel mac-x86_64 monterey release ] Pixel_WebGPUImportVideoFrameUnaccelerated [ Failure ] +crbug.com/1395227 [ mac-x86_64 mojave no-asan nvidia-0xfe9 release ] Pixel_WebGPUImportVideoFrameUnaccelerated [ Failure ] +crbug.com/1395227 [ amd-0x679e mac-x86_64 monterey no-asan release ] Pixel_WebGPUImportVideoFrameUnacceleratedOffscreenCanvas [ Failure ] +crbug.com/1395227 [ asan intel mac-x86_64 monterey release ] Pixel_WebGPUImportVideoFrameUnacceleratedOffscreenCanvas [ Failure ] crbug.com/1395227 [ mac ] Pixel_WebGPUImportVideoFrame [ Failure ] -crbug.com/1395227 [ mac ] Pixel_WebGPUImportVideoFrameOffscreenCanvas [ Failure ] +crbug.com/1395227 [ amd-0x679e mac-x86_64 monterey no-asan release ] Pixel_WebGPUImportVideoFrameOffscreenCanvas [ Failure ] +crbug.com/1395227 [ asan intel mac-x86_64 monterey release ] Pixel_WebGPUImportVideoFrameOffscreenCanvas [ Failure ] +crbug.com/1395227 [ mac-x86_64 mojave no-asan nvidia-0xfe9 release ] Pixel_WebGPUImportVideoFrameOffscreenCanvas [ Failure ] crbug.com/1395227 [ amd-0x7340 release-x64 target-cpu-64 win ] Pixel_WebGPUImportVideoFrameUnaccelerated [ Failure ] crbug.com/1395227 [ win ] Pixel_WebGPUImportVideoFrameUnacceleratedOffscreenCanvas [ Failure ] crbug.com/1395227 [ amd-0x7340 release-x64 target-cpu-64 win ] Pixel_WebGPUImportVideoFrame [ Failure ] @@ -396,7 +376,6 @@ # Pixel_MediaRecorderFromVideoElement fails on several FYI bots crbug.com/1382332 [ amd-0x7340 release-x64 target-cpu-64 win10 ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ] crbug.com/1382332 [ amd-0x6821 asan mac-x86_64 monterey release ] Pixel_MediaRecorderFromVideoElement [ Failure ] -crbug.com/1382332 [ amd-0x6821 asan mac-x86_64 monterey release ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ] crbug.com/1382332 [ mac-x86_64 mojave no-asan nvidia-0xfe9 release ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ] crbug.com/1382332 [ chromeos ] Pixel_MediaRecorderFromVideoElement [ Failure ] crbug.com/1382332 [ chromeos ] Pixel_MediaRecorderFromVideoElementWithOoprCanvasDisabled [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt index 7a44bf1..8dbc9fc 100644 --- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -139,6 +139,13 @@ # This test was mainly meant to run as a pixel test, so skipping in this test suite. TraceTest_MediaFoundationClearDirectComposition [ Skip ] +# WebGPU is only supported on Win10, Mac, and Linux+SkiaRenderer+Vulkan. +crbug.com/852089 [ linux ] WebGPUTraceTest_* [ Skip ] +crbug.com/852089 [ chromeos ] WebGPUTraceTest_* [ Skip ] +crbug.com/852089 [ fuchsia ] WebGPUTraceTest_* [ Skip ] +crbug.com/dawn/549 [ chromeos ] WebGPUCachingTraceTest_* [ Skip ] +crbug.com/dawn/549 [ fuchsia ] WebGPUCachingTraceTest_* [ Skip ] + ############################### # Temporary Skip Expectations # ############################### @@ -146,6 +153,17 @@ # point. This is for things like tests that fail in a way that negatively and # significantly impacts other tests, e.g. killing the test device. +crbug.com/1345777 [ android ] WebGLCanvasCaptureTraceTest_VideoStreamFromWebGLCanvas* [ Skip ] + +crbug.com/852089 [ android ] WebGPUTraceTest_* [ Skip ] + +# WebGPU caching is currently only supporting Win10 and Linux (without +# SkiaRenderer GL). (D3D12 and Vulkan). Android WebGPU support is a work in +# progress. +crbug.com/dawn/549 [ android ] WebGPUCachingTraceTest_* [ Skip ] +crbug.com/dawn/549 [ linux renderer-skia-gl ] WebGPUCachingTraceTest_* [ Skip ] +crbug.com/dawn/549 [ mac ] WebGPUCachingTraceTest_* [ Skip ] + ################### # Failures/Flakes # ################### @@ -154,17 +172,10 @@ # VP9 videos fail to trigger zero copy video presentation path. crbug.com/1385486 [ win10 intel-0x9bc5 ] VideoPathTraceTest_DirectComposition_Video_VP9_Fullsize [ Failure ] -# Incorrectly reporting SCALING instead of DIRECT on Windows 10 UHD 630 GPUs. - -# VP scaling tests are also flaky. - # Zero copy also needs scaling to work. crbug.com/1385486 [ win10 intel-0x9bc5 ] VideoPathTraceTest_DirectComposition_Underlay_Fullsize [ Failure ] crbug.com/1385486 [ win10 intel-0x9bc5 ] VideoPathTraceTest_DirectComposition_Video_MP4_Fullsize [ Failure ] -# Using YUY2 instead of NV12 on Windows 10 HD 630 GPUs due to NV12 support -# showing up as SOFTWARE which causes zero copy to fail. - # Hardware overlay promotion fails on Win10 AMD. crbug.com/1246268 [ win10 amd-0x7340 ] OverlayModeTraceTest_DirectComposition_Video_MP4_FourColors_Aspect_4x3 [ Failure ] @@ -172,32 +183,12 @@ crbug.com/1151767 [ win10 amd-0x7340 ] VideoPathTraceTest_DirectComposition_Video_MP4_YUY2 [ Failure ] crbug.com/1151767 [ win10 amd-0x7340 ] VideoPathTraceTest_DirectComposition_Video_VP9_YUY2 [ Failure ] -# Flakes on linux-rel. - # WebGL's accelerated canvas capture is currently only supported on Win, Mac, ChromeOS. -crbug.com/1345777 [ android ] WebGLCanvasCaptureTraceTest_VideoStreamFromWebGLCanvas* [ Skip ] crbug.com/1201009 [ linux ] WebGLCanvasCaptureTraceTest_VideoStreamFromWebGLCanvas_OneCopy [ Failure ] crbug.com/1201009 [ linux ] WebGLCanvasCaptureTraceTest_VideoStreamFromWebGLCanvas_TwoCopy_Accelerated [ Failure ] crbug.com/1201009 [ fuchsia ] WebGLCanvasCaptureTraceTest_VideoStreamFromWebGLCanvas_OneCopy [ Failure ] crbug.com/1201009 [ fuchsia ] WebGLCanvasCaptureTraceTest_VideoStreamFromWebGLCanvas_TwoCopy_Accelerated [ Failure ] -# Timeout on Nexus 5 - -# WebGL's accelerated canvas capture is failing on ChromeOS - -# WebGPU is only supported on Win10, Mac, and Linux+SkiaRenderer+Vulkan. -crbug.com/852089 [ android ] WebGPUTraceTest_* [ Skip ] -crbug.com/852089 [ linux ] WebGPUTraceTest_* [ Skip ] -crbug.com/852089 [ chromeos ] WebGPUTraceTest_* [ Skip ] -crbug.com/852089 [ fuchsia ] WebGPUTraceTest_* [ Skip ] - -# WebGPU caching is currently only supporting Win10 and Linux (without SkiaRenderer GL). (D3D12 and Vulkan) -crbug.com/dawn/549 [ android ] WebGPUCachingTraceTest_* [ Skip ] -crbug.com/dawn/549 [ linux renderer-skia-gl ] WebGPUCachingTraceTest_* [ Skip ] -crbug.com/dawn/549 [ mac ] WebGPUCachingTraceTest_* [ Skip ] -crbug.com/dawn/549 [ chromeos ] WebGPUCachingTraceTest_* [ Skip ] -crbug.com/dawn/549 [ fuchsia ] WebGPUCachingTraceTest_* [ Skip ] - # finder:group-start crbug.com/1382796 failures happen in many tests, so can be classified as stale for one specific test crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] TraceTest_2DCanvasWebGL [ RetryOnFailure ] crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] TraceTest_Canvas2DRedBox [ RetryOnFailure ] @@ -215,7 +206,11 @@ # x64 Release (Intel) yet. crbug.com/1230619 [ android android-pixel-4 ] TraceTest_WebGLFloat [ Failure ] crbug.com/1230619 [ android android-SM-A235M ] TraceTest_WebGLFloat [ Failure ] -crbug.com/1230619 [ linux intel display-server-wayland ] TraceTest_WebGLFloat [ Failure ] + +crbug.com/1409457 [ win amd ] OverlayModeTraceTest_DirectComposition_Video_MP4_BGRA [ Failure ] +crbug.com/1409457 [ win amd ] OverlayModeTraceTest_DirectComposition_Video_MP4_YUY2 [ Failure ] +crbug.com/1409457 [ win amd ] OverlayModeTraceTest_DirectComposition_Video_VP9_BGRA [ Failure ] +crbug.com/1409457 [ win amd ] OverlayModeTraceTest_DirectComposition_Video_VP9_YUY2 [ Failure ] crbug.com/1402261 [ win intel ] OverlayModeTraceTest_DirectComposition_Video_* [ RetryOnFailure ] crbug.com/1402261 [ win amd ] OverlayModeTraceTest_DirectComposition_Video_* [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt index b9f18bb..ac24bbf 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -79,23 +79,18 @@ # point. This is for things like tests that fail in a way that negatively and # significantly impacts other tests, e.g. killing the test device. +# Suspected of causing flakes in other tests. +crbug.com/1311091 WebCodecs_WebRTCPeerConnection_* [ Skip ] + ################### # Failures/Flakes # ################### # Non-"Skip" expectations go here to suppress regular flakes/failures. - -crbug.com/1311091 WebCodecs_WebRTCPeerConnection_* [ Skip ] - - crbug.com/1371749 [ mac-x86_64 ] WebCodecs_EncodeDecode_offscreen_avc1.42001E_prefer-hardware [ Failure ] - -# TexImage2d tests crashes GPU on Sherlock devices. - -# EncodeDecode tests fail to call flush on the decoder. - -# Camera tests fail with NotFoundError on Sherlock devices. +crbug.com/1409453 [ win amd ] WebCodecs_DrawImage_hw_decoder [ Failure ] +crbug.com/1409453 [ win amd ] WebCodecs_TexImage2d_hw_decoder [ Failure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index ea001da4..dd3fd96d 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -176,8 +176,7 @@ crbug.com/735483 conformance/rendering/texture-switch-performance.html [ Skip ] crbug.com/735483 conformance2/rendering/texture-switch-performance.html [ Skip ] -# Crashes with the Quadro P400's drivers. Can probably be removed after the -# switch to GTX 1660s. +# Crashes on NVIDIA, might be fixed by newer drivers. crbug.com/1236820 [ linux nvidia ] conformance2/glsl3/reciprocal-sqrt-of-sum-of-squares-crash.html [ Skip ] # Can occasionally kill machines. Appears to be tied to kernel version, so can @@ -224,7 +223,6 @@ crbug.com/1131224 conformance2/rendering/framebuffer-mismatched-attachment-targets.html [ Failure ] crbug.com/1108086 [ no-passthrough ] conformance2/renderbuffers/framebuffer-object-attachment.html [ Failure ] crbug.com/angleproject/4807 [ win angle-d3d11 passthrough ] conformance2/glsl3/switch-case.html [ Failure ] -crbug.com/1276153 conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] # Failing at least on Pixel 4, both validating and passthrough crbug.com/1336010 [ android angle-disabled no-passthrough ] conformance2/extensions/oes-draw-buffers-indexed.html [ Failure ] # Failing on at least NVIDIA and Intel @@ -262,21 +260,25 @@ crbug.com/angleproject/4417 [ win angle-d3d11 ] conformance2/rendering/framebuffer-render-to-layer-angle-issue.html [ Failure ] crbug.com/angleproject/7109 [ win angle-d3d11 ] conformance2/renderbuffers/invalidate-framebuffer.html [ Failure ] -# Windows only. crbug.com/angleproject/1465 [ win angle-d3d11 ] conformance2/glsl3/tricky-loop-conditions.html [ Failure ] -# Win / Intel +# win10 / angle-d3d11 / passthrough command decoder failures. +crbug.com/1378372 [ win10 angle-d3d11 passthrough ] conformance/glsl/bugs/complex-glsl-does-not-crash.html [ Failure ] +crbug.com/1378372 [ win10 angle-d3d11 passthrough ] conformance/glsl/misc/shader-uniform-packing-restrictions.html [ Failure ] + +## Win / Intel ## # Random deqp/functional/gles3 flakes on this hardware configuration; # possibly real bugs in tests/browser exposed by slower CPUs. crbug.com/1376608 [ win intel ] deqp/functional/gles3/* [ RetryOnFailure ] -# Win / NVIDIA GeForce GTX 1660 / D3D11 flaky failures +## Win / NVIDIA ## + crbug.com/1073613 [ angle-d3d11 win nvidia-0x2184 ] conformance2/textures/misc/tex-3d-mipmap-levels-intel-bug.html [ Failure ] crbug.com/1073613 [ angle-d3d11 win nvidia-0x2184 ] conformance2/textures/misc/tex-mipmap-levels.html [ Failure ] crbug.com/1073613 [ angle-d3d11 win nvidia-0x2184 ] deqp/functional/gles3/shadertexturefunction/texturesize.html [ Failure ] -# Win / AMD +## Win / AMD ## # Recently many tests have become flaky on this configuration, returning # (72, 72, 72) when reading back pixels, rather than the expected values. @@ -300,16 +302,13 @@ crbug.com/1159539 [ win amd-0x7340 angle-d3d11 passthrough ] deqp/functional/gles3/fbodepthbuffer.html [ RetryOnFailure ] crbug.com/1159539 [ win amd-0x7340 angle-d3d11 passthrough ] deqp/functional/gles3/fborender/recreate_color_* [ RetryOnFailure ] -# win10 / angle-d3d11 / passthrough command decoder failures. -crbug.com/1378372 [ win10 angle-d3d11 passthrough ] conformance/glsl/bugs/complex-glsl-does-not-crash.html [ Failure ] -crbug.com/1378372 [ win10 angle-d3d11 passthrough ] conformance/glsl/misc/shader-uniform-packing-restrictions.html [ Failure ] - ###################### # Mac Metal failures # ###################### -# Metal failures # +## Metal Common ## # Common to all GPU types (both AMD and Intel, at least) + crbug.com/angleproject/6430 [ mac passthrough angle-metal ] WebglExtension_EXT_disjoint_timer_query_webgl2 [ Failure ] crbug.com/angleproject/7079 [ angle-metal mac mac-x86_64 passthrough ] deqp/functional/gles3/fboinvalidate/sub.html [ Failure ] crbug.com/angleproject/7079 [ angle-metal mac mac-x86_64 passthrough ] deqp/functional/gles3/fboinvalidate/whole.html [ Failure ] @@ -318,7 +317,8 @@ crbug.com/angleproject/7079 [ angle-metal mac mac-x86_64 passthrough ] deqp/functional/gles3/fbomultisample.8_samples.html [ Failure ] crbug.com/angleproject/7234 [ amd-0x6821 angle-metal mac mac-x86_64 passthrough ] conformance2/textures/misc/integer-cubemap-texture-sampling.html [ Failure ] -# Metal AMD +## Metal AMD ## + crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] conformance2/textures/misc/tex-srgb-mipmap.html [ Failure ] crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/pixelbufferobject.html [ Failure ] crbug.com/angleproject/6430 [ mac passthrough angle-metal amd ] deqp/functional/gles3/shaderpackingfunction.html [ Failure ] @@ -341,7 +341,8 @@ crbug.com/1395813 [ mac passthrough angle-metal amd ] conformance2/renderbuffers/multisampled-stencil-renderbuffer-initialization.html [ Failure ] crbug.com/1395813 [ mac passthrough angle-metal amd ] deqp/functional/gles3/texturespecification/teximage3d_depth.html [ Failure ] -# Metal Intel +## Metal Intel ## + crbug.com/angleproject/6430 [ mac passthrough angle-metal intel ] conformance2/textures/canvas/tex-2d-rgb16f-rgb-float.html [ Failure ] crbug.com/angleproject/6430 [ mac passthrough angle-metal intel ] conformance2/textures/canvas/tex-2d-rgb16f-rgb-half_float.html [ Failure ] crbug.com/angleproject/6430 [ mac passthrough angle-metal intel ] conformance2/textures/canvas/tex-2d-rgb32f-rgb-float.html [ Failure ] @@ -360,8 +361,8 @@ crbug.com/1316389 [ mac passthrough angle-metal intel ] deqp/functional/gles3/transformfeedback/random_interleaved_points.html [ Failure ] crbug.com/1316389 [ mac passthrough angle-metal intel ] deqp/functional/gles3/transformfeedback/random_separate_points.html [ Failure ] -# Metal M1 -# TODO(crbug.com/1276153) uncomment after fix for updated part of test applies +## Metal M1 ## + crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/framebufferblit/rect_03.html [ Failure ] crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/framebufferblit/rect_04.html [ Failure ] crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/shadertexturefunction/texturegrad.html [ Failure ] @@ -392,7 +393,8 @@ crbug.com/630800 [ nvidia mac ] deqp/functional/gles3/fbocompleteness.html [ Failure ] crbug.com/1289803 [ angle-opengl mac-x86_64 monterey oop-c passthrough ] conformance2/extensions/webgl-multi-draw-instanced-base-vertex-base-instance.html [ Failure ] -# Mac Retina NVIDIA +## Mac Retina NVIDIA ## + crbug.com/728271 [ mac nvidia-0xfe9 ] deqp/functional/gles3/shaderindexing/mat_01.html [ Failure ] crbug.com/728271 [ mac nvidia-0xfe9 ] deqp/functional/gles3/shaderindexing/tmp.html [ Failure ] crbug.com/641209 [ mac nvidia-0xfe9 ] deqp/functional/gles3/fbomultisample* [ Failure ] @@ -432,7 +434,8 @@ crbug.com/1338004 [ mac nvidia-0xfe9 passthrough ] deqp/functional/gles3/multisample/fbo_4_samples.html [ RetryOnFailure ] -# Mac AMD Retina +## Mac AMD Retina ## + # AMD Radeon HD 8870M (1002:6821) # TODO(kbr): uncomment the following two exepectations after test # has been made more robust. @@ -449,7 +452,6 @@ crbug.com/1230781 [ mac amd-0x679e ] conformance/canvas/to-data-url-test.html [ Failure ] - crbug.com/642822 [ mac amd ] conformance2/rendering/clipping-wide-points.html [ Failure ] crbug.com/1278935 [ monterey amd renderer-skia-gl angle-opengl ] deqp/functional/gles3/texturespecification/teximage3d_pbo_2d_array_00.html [ Failure ] @@ -459,7 +461,8 @@ crbug.com/1278935 [ monterey amd renderer-skia-gl angle-opengl ] deqp/functional/gles3/texturespecification/texsubimage3d_pbo_3d_00.html [ Failure ] crbug.com/1278935 [ monterey amd renderer-skia-gl angle-opengl ] deqp/functional/gles3/texturespecification/texsubimage3d_pbo_3d_01.html [ Failure ] -# Mac Intel +## Mac Intel ## + crbug.com/679692 [ angle-metal intel mac no-asan ] conformance2/textures/misc/angle-stuck-depth-textures.html [ Failure ] crbug.com/641209 [ angle-metal intel mac no-asan ] deqp/functional/gles3/fbomultisample* [ Failure ] crbug.com/606074 [ angle-opengl intel mac ] deqp/functional/gles3/texturefiltering/2d_combinations_01.html [ Failure ] @@ -472,16 +475,18 @@ crbug.com/658724 [ angle-opengl intel mac ] deqp/functional/gles3/framebufferblit/rect_04.html [ Failure ] crbug.com/1334684 [ monterey intel angle-metal ] deqp/functional/gles3/shaderbuiltinvar.html [ Failure ] -# Mac Passthrough +## Mac Passthrough ## + crbug.com/angleproject/5223 [ angle-opengl apple-apple-m1 mac-arm64 monterey no-asan oop-c passthrough ] conformance2/textures/misc/tex-mipmap-levels.html [ Failure ] -# Mac Passthrough / AMD +## Mac Passthrough / AMD ## + crbug.com/angleproject/5224 [ mac passthrough angle-opengl amd ] conformance2/rendering/instanced-arrays.html [ Failure ] crbug.com/angleproject/5225 [ mac passthrough angle-opengl amd ] conformance2/rendering/vertex-id.html [ Failure ] crbug.com/angleproject/7412 [ mac passthrough angle-opengl amd ] conformance2/rendering/vertex-id-large-count.html [ Failure ] +## Mac Passthrough / Intel ## -# Mac Passthrough / Intel crbug.com/angleproject/5222 [ mac passthrough angle-opengl intel ] conformance2/textures/misc/tex-unpack-params.html [ Failure ] crbug.com/angleproject/7200 [ mac passthrough angle-opengl intel ] deqp/functional/gles3/fboinvalidate/format_02.html [ Failure ] crbug.com/angleproject/5226 [ mac passthrough angle-opengl intel ] deqp/functional/gles3/texturespecification/basic_copyteximage2d.html [ Failure ] @@ -504,12 +509,14 @@ crbug.com/angleproject/5221 [ mac passthrough angle-opengl intel ] deqp/functional/gles3/transformfeedback/random_separate_points.html [ Failure ] crbug.com/angleproject/5221 [ mac passthrough angle-opengl intel ] deqp/functional/gles3/transformfeedback/random_separate_triangles.html [ Failure ] -# Mac Pro +## Mac Pro ## + # AMD Radeon HD 7800 GPU (1002:679e) crbug.com/1276186 [ mac amd-0x679e angle-opengl passthrough ] conformance/rendering/clear-default-framebuffer-with-scissor-test.html [ Failure ] crbug.com/1240443 [ mac amd-0x679e angle-opengl passthrough ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ Failure ] -# Mac / M1 / OpenGL +## Mac / M1 / OpenGL ## + crbug.com/1130112 [ mac apple-apple-m1 passthrough angle-opengl ] deqp/functional/gles3/texturefiltering/cube_combinations_00.html [ Failure ] crbug.com/1130112 [ mac apple-apple-m1 passthrough angle-opengl ] deqp/functional/gles3/texturefiltering/cube_combinations_02.html [ Failure ] crbug.com/1130112 [ mac apple-apple-m1 passthrough angle-opengl ] deqp/functional/gles3/texturefiltering/cube_combinations_04.html [ Failure ] @@ -540,7 +547,8 @@ crbug.com/982292 [ mac nvidia angle-opengl passthrough ] deqp/functional/gles3/framebufferblit/conversion_31.html [ Failure ] crbug.com/982292 [ mac nvidia angle-opengl passthrough ] deqp/functional/gles3/instancedrendering.html [ Failure ] -# Mac ASAN +## Mac ASAN ## + crbug.com/1403824 [ mac asan passthrough ] deqp/functional/gles3/vertexarrays/single_attribute.first.html [ RetryOnFailure ] #################### @@ -548,15 +556,18 @@ #################### -# Mesa issues +## Mesa issues ## + # Driver tag doesn't work on the passthrough command decoder because the detected driver version is ANGLE's version. crbug.com/1081978 [ linux intel angle-opengl passthrough ] conformance2/textures/misc/tex-3d-size-limit.html [ Failure ] -# Linux NVIDIA +## Linux NVIDIA ## + crbug.com/angleproject/5783 [ linux nvidia angle-opengl passthrough ] conformance2/textures/misc/immutable-tex-render-feedback.html [ Failure ] crbug.com/1115314 [ linux nvidia-0x2184 angle-opengl passthrough ] deqp/functional/gles3/fbocompleteness.html [ Failure ] -# Linux AMD RX 5500 XT +## Linux AMD RX 5500 XT ## + crbug.com/1147232 [ linux amd-0x7340 angle-opengl passthrough ] conformance/textures/misc/texture-size-limit.html [ Failure ] crbug.com/1152588 [ linux amd-0x7340 angle-opengl passthrough ] conformance2/rendering/multisampling-fragment-evaluation.html [ Failure ] @@ -576,8 +587,6 @@ # Failure on validating command decoder only; won't fix. crbug.com/angleproject/5038 [ android no-passthrough ] conformance/extensions/ext-color-buffer-half-float.html [ Failure ] -# Qualcomm (Pixel 2) failures - # TODO(kbr): flakiness is seen on this configuration with the # passthrough command decoder across many different WebGL conformance # tests. Limit this blanket suppression to Android P in case this is @@ -585,30 +594,32 @@ crbug.com/1132297 [ android-pie android-pixel-2 passthrough ] * [ RetryOnFailure ] crbug.com/906737 [ android angle-disabled no-passthrough qualcomm ] conformance/extensions/webgl-compressed-texture-astc.html [ Failure ] -crbug.com/906742 [ android-pie android-pixel-2 no-passthrough qualcomm ] conformance2/glsl3/compare-structs-containing-arrays.html [ Failure ] crbug.com/1176485 [ android qualcomm ] conformance2/glsl3/uint-int-shift-bug.html [ Failure ] -crbug.com/1000354 [ android android-pixel-2 passthrough ] conformance2/reading/read-pixels-from-fbo-test.html [ Failure ] crbug.com/1027125 [ android angle-disabled no-passthrough qualcomm ] deqp/functional/gles3/negativetextureapi.html [ Failure ] -crbug.com/1143323 [ android android-pixel-2 passthrough ] conformance/rendering/draw-arrays-out-of-bounds.html [ Failure ] -crbug.com/1276186 [ android android-pixel-2 ] conformance2/glsl3/array-equality.html [ Failure ] -crbug.com/angleproject/7421 [ android android-pixel-2 angle-disabled no-passthrough ] conformance2/renderbuffers/invalidate-framebuffer.html [ Failure ] # Failing test in passthrough mode when experiment DrDc is enabled via fieldtrial_testing_config.json. crbug.com/1276552 [ android passthrough ] conformance/canvas/render-after-resize-test.html [ Failure ] +## Pixel 2 ## + +crbug.com/906742 [ android-pie android-pixel-2 no-passthrough qualcomm ] conformance2/glsl3/compare-structs-containing-arrays.html [ Failure ] +crbug.com/1000354 [ android android-pixel-2 passthrough ] conformance2/reading/read-pixels-from-fbo-test.html [ Failure ] +crbug.com/1143323 [ android android-pixel-2 passthrough ] conformance/rendering/draw-arrays-out-of-bounds.html [ Failure ] +crbug.com/1276186 [ android android-pixel-2 ] conformance2/glsl3/array-equality.html [ Failure ] +crbug.com/angleproject/7421 [ android android-pixel-2 angle-disabled no-passthrough ] conformance2/renderbuffers/invalidate-framebuffer.html [ Failure ] + +## Pixel 4 ## + # Failing test when experiment DrDc is enabled via fieldtrial_testing_config.json. crbug.com/1289303 [ android-pixel-4 android-r ] conformance/textures/misc/texture-video-transparent.html [ Failure ] -# This test is failing on Android Pixel 2 and 3 (Qualcomm) -# Seems to be an OpenGL ES bug. - -# Pixel 4 crbug.com/1175232 [ android android-pixel-4 angle-opengles passthrough ] conformance2/reading/read-pixels-from-fbo-test.html [ Failure ] crbug.com/1239079 [ android-pixel-4 android-r no-passthrough ] conformance2/transform_feedback/too-small-buffers.html [ Failure ] crbug.com/angleproject/3684 [ android angle-opengles ] conformance2/renderbuffers/multisample-with-full-sample-counts.html [ Failure ] crbug.com/angleproject/3685 [ android-pie android-pixel-2 angle-opengles ] conformance2/transform_feedback/simultaneous_binding.html [ Failure ] crbug.com/angleproject/3686 [ android angle-opengles ] deqp/functional/gles3/multisample/fbo_4_samples.html [ Failure ] crbug.com/angleproject/3686 [ android angle-opengles ] deqp/functional/gles3/multisample/fbo_max_samples.html [ Failure ] + # finder:group-start crbug.com/1382796 failures happen in many tests, so can be classified as stale for one specific test crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] conformance/canvas/rapid-resizing.html [ RetryOnFailure ] crbug.com/1382796 [ android android-pixel-4 angle-opengles passthrough ] conformance/context/context-release-with-workers.html [ RetryOnFailure ] @@ -658,8 +669,9 @@ crbug.com/1221362 [ chromeos chromeos-board-amd64-generic ] conformance2/rendering/blitframebuffer-filter-outofbounds.html [ Failure ] crbug.com/1223542 [ chromeos chromeos-board-amd64-generic ] deqp/functional/gles3/framebufferblit/rect_03.html [ Failure ] crbug.com/1223542 [ chromeos chromeos-board-amd64-generic ] deqp/functional/gles3/framebufferblit/rect_04.html [ Failure ] -# TODO(crbug.com/1276153) uncomment after fix for updated part of test applies -# crbug.com/1232102 [ chromeos chromeos-board-amd64-generic no-passthrough ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] + +crbug.com/1232102 [ chromeos chromeos-board-amd64-generic no-passthrough ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] + crbug.com/1232106 [ chromeos chromeos-board-amd64-generic no-passthrough ] conformance/extensions/webgl-compressed-texture-astc.html [ Failure ] crbug.com/1232118 [ angle-opengles chromeos chromeos-board-amd64-generic passthrough ] conformance/uniforms/uniform-samplers-test.html [ Failure ] crbug.com/1238075 [ chromeos chromeos-board-amd64-generic ] conformance/rendering/gl-scissor-test.html [ Failure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 97af7be4..668d86a2 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -273,6 +273,11 @@ # SwiftShader is disabled on Mac M1 crbug.com/1378476 [ mac mac-arm64 angle-swiftshader ] conformance/rendering/gl-drawelements.html [ Skip ] +# Old hardware + use of validating decoder. Can be removed once the validating +# decoder has been unshipped on Mac. +crbug.com/1321312 [ mac nvidia-0xfe9 no-passthrough ] conformance/glsl/bugs/gl-fragcoord-multisampling-bug.html [ Skip ] +crbug.com/1321312 [ mac nvidia-0xfe9 no-passthrough ] conformance/ogles/GL/array/array_001_to_006.html [ Skip ] + ################### # Failures/Flakes # ################### @@ -302,9 +307,6 @@ # Won't investigate failure on validating command decoder. Remove once it's unshipped. crbug.com/angleproject/5499 [ no-passthrough ] conformance/glsl/misc/shaders-with-name-conflicts.html [ Failure ] -# Skipping new tests -crbug.com/1276153 conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] - # Need to implement new error semantics # https://github.com/KhronosGroup/WebGL/pull/2607 crbug.com/849572 [ win angle-d3d11 passthrough ] conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Failure ] @@ -326,11 +328,7 @@ # Win / Intel / Vulkan / Passthrough command decoder # Technically flaky, but flake rate is too high for RetryOnFailure. -# TODO(crbug.com/1276153) uncomment after fix for updated part of test applies -# crbug.com/angleproject/4922 [ win intel angle-vulkan passthrough ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] -# Bug where RelaxedPrecision applied to normalize() produces 0 - -# Flaky timeouts on multiple platforms - at least Linux/Mac/Win +crbug.com/angleproject/4922 [ win intel angle-vulkan passthrough ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] #################### # Fuchsia failures # @@ -343,11 +341,8 @@ [ fuchsia fuchsia-board-astro ] WebglExtension_EXT_float_blend [ Failure ] [ fuchsia fuchsia-board-sherlock ] WebglExtension_EXT_float_blend [ Failure ] -# Flaky tests - # Anti-aliasing disabled on Fuchsia -# TODO(crbug.com/1276153) uncomment after fix for updated part of test applies -# [ fuchsia ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] +[ fuchsia ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] #################### # Win failures # @@ -357,14 +352,16 @@ # Possible HLSL compiler bug. crbug.com/478572 [ win angle-d3d9 passthrough ] deqp/data/gles2/shaders/functions.html [ Failure ] -# Win / AMD RX 5500 XT failures -crbug.com/1152597 [ win amd-0x7340 angle-d3d11 ] conformance/renderbuffers/framebuffer-state-restoration.html [ Failure ] -crbug.com/1152599 [ win amd-0x7340 angle-d3d11 ] conformance/rendering/polygon-offset.html [ Failure ] - # The functions test have been persistently flaky on D3D9 crbug.com/956134 [ win angle-d3d9 ] conformance/extensions/webgl-depth-texture.html [ Failure ] -# D3D9 / AMD RX 5500 XT / Passthrough command decoder +## Win / AMD RX 5500 XT failures ## + +crbug.com/1152597 [ win amd-0x7340 angle-d3d11 ] conformance/renderbuffers/framebuffer-state-restoration.html [ Failure ] +crbug.com/1152599 [ win amd-0x7340 angle-d3d11 ] conformance/rendering/polygon-offset.html [ Failure ] + +## D3D9 / AMD RX 5500 XT / Passthrough command decoder ## + crbug.com/1159126 [ win amd-0x7340 angle-d3d9 passthrough ] conformance/ogles/GL/* [ RetryOnFailure ] crbug.com/1159126 [ win amd-0x7340 angle-d3d9 passthrough ] conformance/more/glsl/arrayOutOfBounds.html [ RetryOnFailure ] crbug.com/1159126 [ win amd-0x7340 angle-d3d9 passthrough ] conformance/uniforms/* [ RetryOnFailure ] @@ -375,11 +372,13 @@ crbug.com/1362937 [ win amd-0x7340 angle-d3d9 passthrough ] deqp/data/gles2/shaders/conditionals.html [ Failure ] crbug.com/1362937 [ win amd-0x7340 angle-d3d9 passthrough ] deqp/data/gles2/shaders/conversions_matrix_combine.html [ Failure ] -# win10 / angle-d3d11 / Passthrough command decoder failures. +## win10 / angle-d3d11 / Passthrough command decoder failures ## + crbug.com/1378372 [ win10 angle-d3d11 passthrough ] conformance/glsl/bugs/complex-glsl-does-not-crash.html [ Failure ] crbug.com/1378372 [ win10 angle-d3d11 passthrough ] conformance/glsl/misc/shader-uniform-packing-restrictions.html [ Failure ] -# Vulkan / Win / NVIDIA / Passthrough command decoder +## Vulkan / Win / NVIDIA / Passthrough command decoder ## + crbug.com/1209189 [ win nvidia angle-vulkan passthrough ] conformance/glsl/constructors/glsl-construct-vec-mat-index.html [ Failure ] crbug.com/1242454 [ win nvidia angle-vulkan passthrough ] conformance/glsl/bugs/pow-with-constant-exponent-should-not-crash.html [ Failure ] crbug.com/1259977 [ win nvidia-0x2184 angle-vulkan passthrough ] conformance/glsl/functions/glsl-function-abs.html [ Failure ] @@ -388,15 +387,14 @@ crbug.com/1291276 [ win nvidia angle-vulkan passthrough ] conformance/ogles/GL/mod/mod_001_to_008.html [ Failure ] -# Fail when ANGLE GLES3 is requested for OOPR and SkiaRenderer. - #################### # Mac failures # #################### crbug.com/844311 [ angle-opengl mac ] conformance/glsl/misc/fragcolor-fragdata-invariant.html [ Failure ] -# Mac AMD failures +## Mac AMD failures ## + crbug.com/642822 [ mac amd ] conformance/rendering/clipping-wide-points.html [ Failure ] crbug.com/1230781 [ mac amd-0x679e ] conformance/canvas/to-data-url-test.html [ Failure ] crbug.com/1240443 [ mac amd-0x679e angle-opengl ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ Failure ] @@ -407,39 +405,38 @@ # been made more robust. # crbug.com/735483 [ mac amd release ] conformance/rendering/texture-switch-performance.html [ Failure ] -# Mac Retina NVidia failures / flakes +## Mac Retina NVidia failures / flakes ## + crbug.com/996344 [ mac nvidia-0xfe9 ] conformance/glsl/bugs/vector-scalar-arithmetic-inside-loop.html [ Failure ] -crbug.com/1321312 [ mac nvidia-0xfe9 no-passthrough ] conformance/glsl/bugs/gl-fragcoord-multisampling-bug.html [ Skip ] -crbug.com/1321312 [ mac nvidia-0xfe9 no-passthrough ] conformance/ogles/GL/array/array_001_to_006.html [ Skip ] crbug.com/784817 [ mac nvidia-0xfe9 ] conformance/glsl/bugs/init-array-with-loop.html [ Failure ] -# Mac / Passthrough command decoder / OpenGL / NVIDIA +## Mac / Passthrough command decoder / OpenGL / NVIDIA ## + crbug.com/982294 [ mac passthrough nvidia angle-opengl ] conformance/renderbuffers/framebuffer-object-attachment.html [ Failure ] crbug.com/982294 [ mac passthrough nvidia angle-opengl ] conformance/textures/misc/tex-input-validation.html [ Failure ] crbug.com/982294 [ mac passthrough nvidia angle-opengl ] conformance/glsl/samplers/glsl-function-texture2dprojlod.html [ RetryOnFailure ] -# Mac / Passthrough command decoder / Metal +## Mac / Passthrough command decoder / Metal ## -# Mac / M1 / OpenGL +## Mac / M1 / OpenGL ## + # No active browser window, but no crash stack. crbug.com/1240443 [ mac apple-apple-m1 passthrough angle-opengl ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ Failure ] -# Mac / M1 / Metal -# Introduced by upstreaming Apple's direct-to-metal backend -# TODO(crbug.com/1276153) uncomment after fix for updated part of test applies -# crbug.com/angleproject/5505 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] - #################### # Linux failures # #################### -# Linux / Vulkan / Passthrough command decoder +## Linux / Vulkan / Passthrough command decoder ## + crbug.com/1021428 [ linux angle-vulkan passthrough intel ] WebglExtension_WEBGL_depth_texture [ Failure ] # finder:disable-unused Not tested in Chromium, but tested by Intel. -# Linux AMD RX 5500 XT +## Linux AMD RX 5500 XT ## + crbug.com/1147232 [ linux amd-0x7340 angle-opengl passthrough ] conformance/textures/misc/texture-size-limit.html [ Failure ] -# Linux NVIDIA / VANGLE - bot NVIDIA driver is too old. +## Linux NVIDIA / VANGLE - bot NVIDIA driver is too old. ## + crbug.com/1271688 [ linux angle-vulkan passthrough nvidia ] conformance/glsl/constructors/glsl-construct-vec-mat-index.html [ Failure ] crbug.com/1271688 [ linux angle-vulkan passthrough nvidia ] conformance/glsl/functions/glsl-function-abs.html [ Failure ] crbug.com/1271688 [ linux angle-vulkan passthrough nvidia ] conformance/glsl/functions/glsl-function-ceil.html [ Failure ] @@ -465,18 +462,15 @@ # Was too difficult to suppress these failures on individual bots. crbug.com/1165751 [ android-nougat ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] -# Also flaky on nexus9 non-webview (bug=834933) but can't specify both. - # These video tests appear to be flaky. -# TODO(crbug.com/1178518): This crbug caused the test to fail consistently. It -# should be probably back to flaky once the bug is fixed. So uncomment below test once the bug is fixed. -# crbug.com/834933 [ android android-chromium ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ] +crbug.com/834933 [ android android-chromium ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ] # These video tests are flakey on many configurations. crbug.com/1347077 [ android-nexus-5x android-nougat angle-opengles passthrough qualcomm renderer-skia-gl target-cpu-64 ] conformance/textures/misc/video-rotation.html [ Failure ] crbug.com/1347077 [ android-s android-sm-a235m angle-disabled no-passthrough qualcomm renderer-skia-gl target-cpu-32 ] conformance/textures/misc/video-rotation.html [ Failure ] -# Nexus 5X +## Nexus 5X ## + # Was timing out randomly on android_optional_gpu_tests_rel, but became so # flaky (2018-09-10) that it had to be upgraded to Fail. crbug.com/609883 [ android android-nexus-5x ] conformance/glsl/bugs/sampler-struct-function-arg.html [ Failure ] @@ -487,16 +481,19 @@ # Flakily returning RGBA(0,0,0,0) for pixels in video related tests crbug.com/1295370 [ android android-nexus-5x passthrough ] conformance/textures/video/* [ Failure ] -# Android NVIDIA Shield TV +## Android NVIDIA Shield TV ## + crbug.com/1294071 [ android-pie android-shield-android-tv ] conformance/glsl/bugs/vector-matrix-constructor-scalarization.html [ Failure ] # Flakily returning RGBA(0,0,0,0) for all pixels crbug.com/1357064 [ android android-shield-android-tv no-passthrough ] conformance/rendering/blending.html [ Failure ] -# Pixel 4 +## Pixel 4 ## + crbug.com/1175223 [ android android-pixel-4 angle-opengles passthrough ] conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Failure ] crbug.com/1175226 [ android android-pixel-4 no-passthrough ] conformance/rendering/blending.html [ Failure ] -# Pixel 6 +## Pixel 6 ## + crbug.com/1286830 [ android android-pixel-6 arm ] WebglExtension_EXT_shader_texture_lod [ Failure ] crbug.com/1286830 [ android android-pixel-6 arm ] WebglExtension_WEBGL_draw_buffers [ Failure ] crbug.com/1286924 [ android android-pixel-6 arm passthrough ] conformance/glsl/bugs/constant-precision-qualifier.html [ Failure ] @@ -510,12 +507,12 @@ crbug.com/1287280 [ android android-pixel-6 no-passthrough ] WebglExtension_OES_texture_half_float_linear [ Failure ] crbug.com/1287280 [ android android-pixel-6 no-passthrough ] WebglExtension_WEBGL_color_buffer_float [ Failure ] crbug.com/1288590 [ android android-pixel-6 ] conformance/misc/shader-precision-format.html [ Failure ] -# This can be re-added once the general Android suppression due to DrDc (crbug.com/1289303) is removed. -# crbug.com/1288595 [ android android-pixel-6 passthrough ] conformance/canvas/render-after-resize-test.html [ Failure ] crbug.com/1288603 [ android android-pixel-6 passthrough angle-opengles ] conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Failure ] crbug.com/1357064 [ android android-pixel-6 no-passthrough ] conformance/rendering/blending.html [ Failure ] -# Misc failures +crbug.com/1288595 [ android android-pixel-6 passthrough ] conformance/canvas/render-after-resize-test.html [ Failure ] + +## Misc failures ## # Failing webgl passthrough test on nexus 5x. crbug.com/1209254 [ android android-nexus-5x android-chromium passthrough ] conformance/textures/misc/texture-npot-video.html [ Failure ] @@ -524,9 +521,10 @@ crbug.com/1276552 [ android-pixel-4 android-r passthrough qualcomm renderer-skia-gl target-cpu-32 ] conformance/canvas/render-after-resize-test.html [ Failure ] # Failing test when experiment DrDc is enabled via fieldtrial_testing_config.json. -crbug.com/1289303 [ android qualcomm renderer-skia-gl target-cpu-32 ] conformance/textures/misc/texture-video-transparent.html [ Failure ] +crbug.com/1289303 [ android angle-disabled no-passthrough qualcomm renderer-skia-gl target-cpu-32 ] conformance/textures/misc/texture-video-transparent.html [ Failure ] -# Samsung failures +## Samsung failures ## + crbug.com/1372155 [ android android-sm-a135m ] conformance/glsl/bugs/constant-precision-qualifier.html [ Failure ] crbug.com/1372155 [ android android-sm-a135m ] conformance/misc/shader-precision-format.html [ Failure ] crbug.com/1372155 [ android android-sm-a135m ] conformance/offscreencanvas/context-lost-restored-worker.html [ Failure ] @@ -544,9 +542,11 @@ # ChromeOS # ############ -# ChromeOS: affecting all devices. +## ChromeOS: affecting all devices. ## + # TODO(crbug.com/1276153) uncomment after fix for updated part of test applies # crbug.com/957807 [ chromeos ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ] + crbug.com/957807 [ angle-opengles chromeos passthrough ] conformance/uniforms/uniform-samplers-test.html [ Failure ] # finder:disable-unused Reported by Intel but not currently testable in Chromium @@ -554,28 +554,28 @@ crbug.com/1237319 [ chromeos angle-opengles passthrough intel ] conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Failure ] # finder:enable-unused -# Arm-based issues. - -# Failing on chromeos-amd64-generic-rel. -crbug.com/1232446 [ chromeos chromeos-board-amd64-generic ] conformance/rendering/gl-scissor-test.html [ Failure ] -crbug.com/1357064 [ chromeos chromeos-board-amd64-generic no-passthrough ] conformance/rendering/blending.html [ Failure ] - # Need to investigate failure on basically all devices with passthrough on CrOS. crbug.com/angleproject/5038 [ chromeos passthrough ] conformance/extensions/ext-color-buffer-half-float.html [ Failure ] # Failures on validating command decoder only; won't fix. crbug.com/angleproject/5038 [ chromeos no-passthrough ] conformance/extensions/ext-color-buffer-half-float.html [ Failure ] +## Arm-based issues. ## + +## VM Issues ## + +# Failing on chromeos-amd64-generic-rel. +crbug.com/1232446 [ chromeos chromeos-board-amd64-generic ] conformance/rendering/gl-scissor-test.html [ Failure ] +crbug.com/1357064 [ chromeos chromeos-board-amd64-generic no-passthrough ] conformance/rendering/blending.html [ Failure ] + ########################### # Lacros/Wayland failures # ########################### -crbug.com/1185344 [ linux display-server-wayland intel angle-disabled ] WebglExtension_EXT_sRGB [ Failure ] crbug.com/1185344 [ angle-opengles linux display-server-wayland intel ] WebglExtension_EXT_shader_texture_lod [ Failure ] crbug.com/angleproject/5038 [ linux intel display-server-wayland ] conformance/extensions/ext-color-buffer-half-float.html [ Failure ] -crbug.com/1357064 [ linux intel display-server-wayland no-passthrough ] conformance/rendering/blending.html [ Failure ] ####################################################################### # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc index e12bf00a..12f2010 100644 --- a/content/test/test_render_view_host.cc +++ b/content/test/test_render_view_host.cc
@@ -150,7 +150,7 @@ return latest_capture_sequence_number_; } -void TestRenderWidgetHostView::UpdateCursor(const WebCursor& cursor) { +void TestRenderWidgetHostView::UpdateCursor(const ui::Cursor& cursor) { last_cursor_ = cursor; }
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h index faef41a..42b07663 100644 --- a/content/test/test_render_view_host.h +++ b/content/test/test_render_view_host.h
@@ -23,6 +23,7 @@ #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_renderer_host.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/ime/dummy_text_input_client.h" #include "ui/base/layout.h" #include "ui/base/page_transition_types.h" @@ -108,7 +109,7 @@ const gfx::Rect& anchor_rect) override {} void Focus() override {} void SetIsLoading(bool is_loading) override {} - void UpdateCursor(const WebCursor& cursor) override; + void UpdateCursor(const ui::Cursor& cursor) override; void RenderProcessGone() override; void ShowWithVisibility(PageVisibilityState page_visibility) override; void Destroy() override; @@ -135,7 +136,7 @@ void OnFrameTokenChanged(uint32_t frame_token, base::TimeTicks activation_time) override; - const WebCursor& last_cursor() const { return last_cursor_; } + const ui::Cursor& last_cursor() const { return last_cursor_; } void SetCompositor(ui::Compositor* compositor) { compositor_ = compositor; } @@ -169,7 +170,7 @@ bool is_occluded_; PageVisibilityState page_visibility_ = PageVisibilityState::kHidden; ui::DummyTextInputClient text_input_client_; - WebCursor last_cursor_; + ui::Cursor last_cursor_; // Latest capture sequence number which is incremented when the caller // requests surfaces be synchronized via
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc index ae45bb0..e3de05f 100644 --- a/content/utility/utility_main.cc +++ b/content/utility/utility_main.cc
@@ -103,6 +103,18 @@ } #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +void SetUtilityThreadName(const std::string utility_sub_type) { + // Typical utility sub-types are audio.mojom.AudioService or + // proxy_resolver.mojom.ProxyResolverFactory. Using the full sub-type as part + // of the thread name is too verbose so we take the text in front of the first + // period and use that as a prefix. This give us thread names like + // audio.CrUtilityMain and proxy_resolver.CrUtilityMain. If there is no period + // then the entire utility_sub_type string will be put in front. + auto first_period = utility_sub_type.find('.'); + base::PlatformThread::SetName( + (utility_sub_type.substr(0, first_period) + ".CrUtilityMain").c_str()); +} + } // namespace // Mainline routine for running as the utility process. @@ -144,11 +156,11 @@ // The main task executor of the utility process. base::SingleThreadTaskExecutor main_thread_task_executor(message_pump_type); - base::PlatformThread::SetName("CrUtilityMain"); + const std::string utility_sub_type = + parameters.command_line->GetSwitchValueASCII(switches::kUtilitySubType); + SetUtilityThreadName(utility_sub_type); if (parameters.command_line->HasSwitch(switches::kUtilityStartupDialog)) { - const std::string utility_sub_type = - parameters.command_line->GetSwitchValueASCII(switches::kUtilitySubType); auto dialog_match = parameters.command_line->GetSwitchValueASCII( switches::kUtilityStartupDialog); if (dialog_match.empty() || dialog_match == utility_sub_type) {
diff --git a/content/web_test/browser/web_test_storage_access_manager.cc b/content/web_test/browser/web_test_storage_access_manager.cc index 2f8b8ce..f41efd53 100644 --- a/content/web_test/browser/web_test_storage_access_manager.cc +++ b/content/web_test/browser/web_test_storage_access_manager.cc
@@ -43,9 +43,9 @@ return; } - content_settings_for_automation_.push_back( - ContentSettingPatternSource(primary_pattern, secondary_pattern, - base::Value(setting), std::string(), false)); + content_settings_for_automation_.emplace_back( + primary_pattern, secondary_pattern, base::Value(setting), std::string(), + false); // TODO(https://crbug.com/1106098) - Storage Access API should support all // storage types in content shell @@ -64,18 +64,17 @@ // Content Shell, then we should update this class to handle those other // types are well. - auto* storage_partition = browser_context_->GetDefaultStoragePartition(); - auto* cookie_manager = storage_partition->GetCookieManagerForBrowserProcess(); - - // Enable third-party cookies blocking if we have not done so yet. This will - // cause the content settings to take effect. - if (!third_party_cookies_blocked_) { - cookie_manager->BlockThirdPartyCookies(true); - third_party_cookies_blocked_ = true; - } + auto* cookie_manager = browser_context_->GetDefaultStoragePartition() + ->GetCookieManagerForBrowserProcess(); // Update the cookie manager's copy of the content settings. cookie_manager->SetContentSettings(content_settings_for_automation_); + + // Enable third-party cookies blocking if needed, otherwise disable. This will + // cause the content settings to take effect. + cookie_manager->BlockThirdPartyCookies(blocked); + browser_context_->GetDefaultStoragePartition() + ->FlushNetworkInterfaceForTesting(); std::move(callback).Run(true); }
diff --git a/content/web_test/browser/web_test_storage_access_manager.h b/content/web_test/browser/web_test_storage_access_manager.h index 84800e3..13e837f 100644 --- a/content/web_test/browser/web_test_storage_access_manager.h +++ b/content/web_test/browser/web_test_storage_access_manager.h
@@ -47,7 +47,6 @@ mojo::ReceiverSet<blink::test::mojom::StorageAccessAutomation> receivers_; ContentSettingsForOneType content_settings_for_automation_; - bool third_party_cookies_blocked_ = false; }; } // namespace content
diff --git a/docs/closure_compilation.md b/docs/closure_compilation.md index 874e7cea..7286126 100644 --- a/docs/closure_compilation.md +++ b/docs/closure_compilation.md
@@ -1,5 +1,9 @@ # Closure Compilation +**Important: Closure Compilation is only supported on ChromeOS Ash. On all +other platforms, Closure Compiler is deprecated; TypeScript should be used +for type checking.** See [bug](https://www.crbug.com/1316438) + ## What is type safety? [Statically-typed languages](https://en.wikipedia.org/wiki/Type_system#Static_type_checking)
diff --git a/docs/security/security-considerations-for-browser-ui.md b/docs/security/security-considerations-for-browser-ui.md index aae9a9b..c944a78 100644 --- a/docs/security/security-considerations-for-browser-ui.md +++ b/docs/security/security-considerations-for-browser-ui.md
@@ -138,6 +138,14 @@ between when the browser UI is shown and the call-to-action activates. For example, if the user must click a button to grant a permission, introduce a delay before the button becomes active once the permission prompt is -shown. Three seconds is typically considered a delay that is long enough to let -the user notice that some security-sensitive browser UI is showing without being -too disruptive to the typical user experience. \ No newline at end of file +shown. Chrome uses short and long delays in various UI: + +- For large security-sensitive browser surfaces like interstitials, three +seconds is typically considered a delay that is long enough to let the user +notice that the UI is showing without being too disruptive to the typical user +experience. + +- For smaller UI surfaces such as dialog boxes, a shorter delay like 500ms can +be more practical. [`InputEventActivationProtector`]( +ui/views/input_event_activation_protector.h) is a helper class that ignores UI +events that happen within 500ms of the sensitive UI being displayed.
diff --git a/docs/updater/dev_manual.md b/docs/updater/dev_manual.md index 01a754e5..c7881a0 100644 --- a/docs/updater/dev_manual.md +++ b/docs/updater/dev_manual.md
@@ -179,3 +179,22 @@ Non-bot systems can set up this environment variable to collect logs for debugging when the tests are run locally. + +## Testing src changes with trybots + +In some cases, you will want to test the changes you make within +[chromium/src](https://chromium.googlesource.com/chromium/src.git) on +specific builders/testers before landing these changes. It is possible +to do this with the use of the trybots available on the +[tryserver.chromium.updater](https://ci.chromium.org/ui/p/chromium/g/tryserver.chromium.updater/builders) + waterfall. The steps are as follows: + +1. Find a trybot to run your tests with. All of the trybots on the +tryserver.chromium.updater waterfall have a corresponding builder and +tester, so find one that runs a workflow to test your changes. +2. Apply your configuration changes to chromium/src and upload a CL +using the typical workflow: `git cl upload` +3. Run `git cl try -B luci.chromium.try -b {TRYBOT_NAME}` with the +name of the trybot you found. +4. Monitor and debug any failures as you normally would for any +builder or tester.
diff --git a/extensions/OWNERS b/extensions/OWNERS index fa5b3b35..29bdb42 100644 --- a/extensions/OWNERS +++ b/extensions/OWNERS
@@ -13,9 +13,11 @@ rdevlin.cronin@chromium.org lazyboy@chromium.org dbertoni@chromium.org -benwells@chromium.org finnur@chromium.org reillyg@chromium.org +# Mechanical or apps-in-extensions changes only: +ortuno@chromium.org + # Translation artifacts: per-file ....xtb=file://tools/translation/TRANSLATION_OWNERS
diff --git a/extensions/browser/OWNERS b/extensions/browser/OWNERS index 7c8f827a..195704a 100644 --- a/extensions/browser/OWNERS +++ b/extensions/browser/OWNERS
@@ -1,5 +1,4 @@ # Please talk to the apps shell team before adding DEPS. -per-file DEPS=benwells@chromium.org per-file DEPS=rdevlin.cronin@chromium.org per-file extension_event_histogram_value.h=set noparent
diff --git a/extensions/browser/api/app_current_window_internal/OWNERS b/extensions/browser/api/app_current_window_internal/OWNERS index aac10b5b..0b69d20 100644 --- a/extensions/browser/api/app_current_window_internal/OWNERS +++ b/extensions/browser/api/app_current_window_internal/OWNERS
@@ -1,2 +1,2 @@ -benwells@chromium.org +isandrk@chromium.org tapted@chromium.org
diff --git a/extensions/browser/api/app_window/OWNERS b/extensions/browser/api/app_window/OWNERS index aac10b5b..0b69d20 100644 --- a/extensions/browser/api/app_window/OWNERS +++ b/extensions/browser/api/app_window/OWNERS
@@ -1,2 +1,2 @@ -benwells@chromium.org +isandrk@chromium.org tapted@chromium.org
diff --git a/extensions/browser/api/file_handlers/OWNERS b/extensions/browser/api/file_handlers/OWNERS index 64f6677..ab35d48 100644 --- a/extensions/browser/api/file_handlers/OWNERS +++ b/extensions/browser/api/file_handlers/OWNERS
@@ -1,2 +1,2 @@ -benwells@chromium.org +file://ui/file_manager/OWNERS sammc@chromium.org
diff --git a/extensions/browser/api/networking_private/networking_private_api.cc b/extensions/browser/api/networking_private/networking_private_api.cc index cc3bd88..d358a281 100644 --- a/extensions/browser/api/networking_private/networking_private_api.cc +++ b/extensions/browser/api/networking_private/networking_private_api.cc
@@ -474,11 +474,12 @@ } void NetworkingPrivateGetEnabledNetworkTypesFunction::Result( - std::unique_ptr<base::Value> enabled_networks_onc_types) { - if (enabled_networks_onc_types->GetList().empty()) + base::Value::List enabled_networks_onc_types) { + if (enabled_networks_onc_types.empty()) { return Respond(Error(networking_private::kErrorNotSupported)); - base::Value enabled_networks_list(base::Value::Type::LIST); - for (const auto& entry : enabled_networks_onc_types->GetList()) { + } + base::Value::List enabled_networks_list; + for (const auto& entry : enabled_networks_onc_types) { const std::string& type = entry.GetString(); if (type == ::onc::network_type::kEthernet) { enabled_networks_list.Append( @@ -493,7 +494,7 @@ LOG(ERROR) << "networkingPrivate: Unexpected type: " << type; } } - return Respond(OneArgument(std::move(enabled_networks_list))); + return Respond(OneArgument(base::Value(std::move(enabled_networks_list)))); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/extensions/browser/api/networking_private/networking_private_api.h b/extensions/browser/api/networking_private/networking_private_api.h index 50e41d2..fdd6902d 100644 --- a/extensions/browser/api/networking_private/networking_private_api.h +++ b/extensions/browser/api/networking_private/networking_private_api.h
@@ -243,7 +243,7 @@ ResponseAction Run() override; private: - void Result(std::unique_ptr<base::Value> enabled_networks_onc_types); + void Result(base::Value::List enabled_networks_onc_types); }; // Implements the chrome.networkingPrivate.getDeviceStates method.
diff --git a/extensions/browser/api/networking_private/networking_private_chromeos.cc b/extensions/browser/api/networking_private/networking_private_chromeos.cc index 95fb27d..40414e72 100644 --- a/extensions/browser/api/networking_private/networking_private_chromeos.cc +++ b/extensions/browser/api/networking_private/networking_private_chromeos.cc
@@ -675,7 +675,7 @@ EnabledNetworkTypesCallback callback) { NetworkStateHandler* state_handler = GetStateHandler(); - base::Value network_list(base::Value::Type::LIST); + base::Value::List network_list; if (state_handler->IsTechnologyEnabled(NetworkTypePattern::Ethernet())) network_list.Append(::onc::network_type::kEthernet); @@ -684,8 +684,7 @@ if (state_handler->IsTechnologyEnabled(NetworkTypePattern::Cellular())) network_list.Append(::onc::network_type::kCellular); - std::move(callback).Run( - base::Value::ToUniquePtrValue(std::move(network_list))); + std::move(callback).Run(std::move(network_list)); } void NetworkingPrivateChromeOS::GetDeviceStateList(
diff --git a/extensions/browser/api/networking_private/networking_private_delegate.h b/extensions/browser/api/networking_private/networking_private_delegate.h index 8581b9502..ba91d6f 100644 --- a/extensions/browser/api/networking_private/networking_private_delegate.h +++ b/extensions/browser/api/networking_private/networking_private_delegate.h
@@ -30,7 +30,7 @@ using StringCallback = base::OnceCallback<void(const std::string&)>; using NetworkListCallback = base::OnceCallback<void(base::Value::List)>; using EnabledNetworkTypesCallback = - base::OnceCallback<void(std::unique_ptr<base::Value>)>; + base::OnceCallback<void(base::Value::List)>; using FailureCallback = base::OnceCallback<void(const std::string&)>; using DeviceStateList = std::vector< std::unique_ptr<api::networking_private::DeviceStateProperties>>;
diff --git a/extensions/browser/api/networking_private/networking_private_lacros.cc b/extensions/browser/api/networking_private/networking_private_lacros.cc index c4a8547..046c1fbe 100644 --- a/extensions/browser/api/networking_private/networking_private_lacros.cc +++ b/extensions/browser/api/networking_private/networking_private_lacros.cc
@@ -177,16 +177,17 @@ // base::Value::List object. using ValueListMojoCallback = base::OnceCallback<void(absl::optional<base::Value::List>)>; +using ValueListDelegateCallback = + base::OnceCallback<void(base::Value::List result)>; ValueListMojoCallback ValueListAdapterCallback( - ValueDelegateCallback result_callback) { + ValueListDelegateCallback result_callback) { return base::BindOnce( - [](ValueDelegateCallback callback, + [](ValueListDelegateCallback callback, absl::optional<base::Value::List> result) { if (!result) { - std::move(callback).Run(std::make_unique<base::Value>()); + std::move(callback).Run(base::Value::List()); } else { - std::move(callback).Run( - std::make_unique<base::Value>(std::move(*result))); + std::move(callback).Run(std::move(*result)); } }, std::move(result_callback)); @@ -488,7 +489,7 @@ EnabledNetworkTypesCallback callback) { auto* networking_private = GetNetworkingPrivateRemote(); if (!networking_private) { - std::move(callback).Run(nullptr); + std::move(callback).Run(base::Value::List()); return; } (*networking_private)
diff --git a/extensions/browser/api/networking_private/networking_private_linux.cc b/extensions/browser/api/networking_private/networking_private_linux.cc index 558a71b..a7bbcc8 100644 --- a/extensions/browser/api/networking_private/networking_private_linux.cc +++ b/extensions/browser/api/networking_private/networking_private_linux.cc
@@ -604,10 +604,9 @@ void NetworkingPrivateLinux::GetEnabledNetworkTypes( EnabledNetworkTypesCallback callback) { - base::Value network_list(base::Value::Type::LIST); + base::Value::List network_list; network_list.Append(::onc::network_type::kWiFi); - std::move(callback).Run( - base::Value::ToUniquePtrValue(std::move(network_list))); + std::move(callback).Run(std::move(network_list)); } void NetworkingPrivateLinux::GetDeviceStateList(
diff --git a/extensions/browser/api/networking_private/networking_private_service_client.cc b/extensions/browser/api/networking_private/networking_private_service_client.cc index 523d52b..62b98072 100644 --- a/extensions/browser/api/networking_private/networking_private_service_client.cc +++ b/extensions/browser/api/networking_private/networking_private_service_client.cc
@@ -330,10 +330,9 @@ void NetworkingPrivateServiceClient::GetEnabledNetworkTypes( EnabledNetworkTypesCallback callback) { - base::Value network_list(base::Value::Type::LIST); + base::Value::List network_list; network_list.Append(::onc::network_type::kWiFi); - std::move(callback).Run( - base::Value::ToUniquePtrValue(std::move(network_list))); + std::move(callback).Run(std::move(network_list)); } void NetworkingPrivateServiceClient::GetDeviceStateList(
diff --git a/extensions/common/api/API_OWNERS b/extensions/common/api/API_OWNERS index abf200e..a42f801 100644 --- a/extensions/common/api/API_OWNERS +++ b/extensions/common/api/API_OWNERS
@@ -18,4 +18,4 @@ tbarzic@chromium.org mukai@chromium.org xiyuan@chromium.org -benwells@chromium.org +ortuno@chromium.org
diff --git a/extensions/components/native_app_window/OWNERS b/extensions/components/native_app_window/OWNERS index aac10b5b..0b69d20 100644 --- a/extensions/components/native_app_window/OWNERS +++ b/extensions/components/native_app_window/OWNERS
@@ -1,2 +1,2 @@ -benwells@chromium.org +isandrk@chromium.org tapted@chromium.org
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index a59a4fd..8b9f5e0 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn
@@ -515,27 +515,8 @@ "command_buffer/service/gl_context_virtual_unittest.cc", "command_buffer/service/gl_surface_mock.cc", "command_buffer/service/gl_surface_mock.h", - "command_buffer/service/gles2_cmd_decoder_unittest.cc", - "command_buffer/service/gles2_cmd_decoder_unittest.h", - "command_buffer/service/gles2_cmd_decoder_unittest_1.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h", - "command_buffer/service/gles2_cmd_decoder_unittest_2.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h", - "command_buffer/service/gles2_cmd_decoder_unittest_3.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h", - "command_buffer/service/gles2_cmd_decoder_unittest_4.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h", - "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc", "command_buffer/service/gles2_cmd_decoder_unittest_base.cc", "command_buffer/service/gles2_cmd_decoder_unittest_base.h", - "command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_context_lost.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_programs.cc", - "command_buffer/service/gles2_cmd_decoder_unittest_textures.cc", "command_buffer/service/gpu_service_test.cc", "command_buffer/service/gpu_service_test.h", "command_buffer/service/gpu_tracer_unittest.cc", @@ -603,6 +584,30 @@ "ipc/service/gpu_watchdog_thread_unittest.cc", ] + if (enable_validating_command_decoder) { + sources += [ + "command_buffer/service/gles2_cmd_decoder_unittest.cc", + "command_buffer/service/gles2_cmd_decoder_unittest.h", + "command_buffer/service/gles2_cmd_decoder_unittest_1.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h", + "command_buffer/service/gles2_cmd_decoder_unittest_2.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h", + "command_buffer/service/gles2_cmd_decoder_unittest_3.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h", + "command_buffer/service/gles2_cmd_decoder_unittest_4.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h", + "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_context_lost.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_programs.cc", + "command_buffer/service/gles2_cmd_decoder_unittest_textures.cc", + ] + } + if (is_chromeos_ash) { # Image decode acceleration with hardware is only supported in Chrome OS. # The intention is to run this test in the linux-chromeos build.
diff --git a/gpu/command_buffer/client/raster_implementation_gles.cc b/gpu/command_buffer/client/raster_implementation_gles.cc index f07b1c4..34779154 100644 --- a/gpu/command_buffer/client/raster_implementation_gles.cc +++ b/gpu/command_buffer/client/raster_implementation_gles.cc
@@ -204,7 +204,41 @@ SkYUVAInfo::PlaneConfig plane_config, SkYUVAInfo::Subsampling subsampling, const gpu::Mailbox yuva_plane_mailboxes[]) { - NOTREACHED(); + skcms_Matrix3x3 primaries = {{{0}}}; + skcms_TransferFunction transfer = {0}; + if (planes_rgb_color_space) { + planes_rgb_color_space->toXYZD50(&primaries); + planes_rgb_color_space->transferFn(&transfer); + } else { + // Specify an invalid transfer function exponent, to ensure that when + // SkColorSpace::MakeRGB is called in the decoder, the result is nullptr. + transfer.g = -99; + } + + constexpr size_t kByteSize = + sizeof(gpu::Mailbox) * (SkYUVAInfo::kMaxPlanes + 1) + + sizeof(skcms_TransferFunction) + sizeof(skcms_Matrix3x3); + // 144 is the count in build_gles2_cmd_buffer.py for GL_MAILBOX_SIZE_CHROMIUM + // x5 + 16 floats. + static_assert(kByteSize == 144); + GLbyte bytes[kByteSize] = {0}; + size_t offset = 0; + for (int i = 0; i < SkYUVAInfo::NumPlanes(plane_config); ++i) { + memcpy(bytes + offset, yuva_plane_mailboxes + i, sizeof(gpu::Mailbox)); + offset += sizeof(gpu::Mailbox); + } + offset = SkYUVAInfo::kMaxPlanes * sizeof(gpu::Mailbox); + memcpy(bytes + offset, &dest_mailbox, sizeof(gpu::Mailbox)); + offset += sizeof(gpu::Mailbox); + memcpy(bytes + offset, &transfer, sizeof(transfer)); + offset += sizeof(transfer); + memcpy(bytes + offset, &primaries, sizeof(primaries)); + offset += sizeof(primaries); + DCHECK_EQ(offset, kByteSize); + + gl_->ConvertYUVAMailboxesToRGBINTERNAL( + planes_yuv_color_space, static_cast<GLenum>(plane_config), + static_cast<GLenum>(subsampling), reinterpret_cast<GLbyte*>(bytes)); } void RasterImplementationGLES::ConvertRGBAToYUVAMailboxes( @@ -213,7 +247,14 @@ SkYUVAInfo::Subsampling subsampling, const gpu::Mailbox yuva_plane_mailboxes[], const gpu::Mailbox& source_mailbox) { - NOTREACHED(); + gpu::Mailbox mailboxes[SkYUVAInfo::kMaxPlanes + 1]; + for (int i = 0; i < SkYUVAInfo::NumPlanes(plane_config); ++i) { + mailboxes[i] = yuva_plane_mailboxes[i]; + } + mailboxes[SkYUVAInfo::kMaxPlanes] = source_mailbox; + gl_->ConvertRGBAToYUVAMailboxesINTERNAL( + planes_yuv_color_space, static_cast<GLenum>(plane_config), + static_cast<GLenum>(subsampling), reinterpret_cast<GLbyte*>(mailboxes)); } void RasterImplementationGLES::BeginRasterCHROMIUM(
diff --git a/gpu/command_buffer/service/copy_shared_image_helper.cc b/gpu/command_buffer/service/copy_shared_image_helper.cc index 70f9f54..576d98c 100644 --- a/gpu/command_buffer/service/copy_shared_image_helper.cc +++ b/gpu/command_buffer/service/copy_shared_image_helper.cc
@@ -9,7 +9,6 @@ #include "base/check.h" #include "base/strings/string_number_conversions.h" -#include "gpu/command_buffer/service/error_state.h" #include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image/shared_image_factory.h" #include "gpu/command_buffer/service/shared_image/shared_image_representation.h" @@ -27,45 +26,48 @@ namespace gpu { +using GLError = CopySharedImageHelper::GLError; + namespace { // Return true if all of `sk_yuv_color_space`, `sk_plane_config`, // `sk_subsampling`, `rgba_image, `num_yuva_images`, and `yuva_images` were // successfully populated. Return false on error. If this returns false, some // of the output arguments may be left populated. -bool ConvertYUVACommon(const char* function_name, - GLenum yuv_color_space_in, - GLenum plane_config_in, - GLenum subsampling_in, - const volatile GLbyte* mailboxes_in, - SharedImageRepresentationFactory* representation_factory, - SharedContextState* shared_context_state, - gles2::ErrorState* error_state, - SkYUVColorSpace& sk_yuv_color_space, - SkYUVAInfo::PlaneConfig& sk_plane_config, - SkYUVAInfo::Subsampling& sk_subsampling, - std::unique_ptr<SkiaImageRepresentation>& rgba_image, - int& num_yuva_planes, - std::array<std::unique_ptr<SkiaImageRepresentation>, - SkYUVAInfo::kMaxPlanes>& yuva_images) { - if (yuv_color_space_in > kLastEnum_SkYUVColorSpace) { - ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_ENUM, function_name, - "yuv_color_space must be a valid SkYUVColorSpace"); - return false; +base::expected<void, GLError> ConvertYUVACommon( + const char* function_name, + GLenum yuv_color_space_in, + GLenum plane_config_in, + GLenum subsampling_in, + const volatile GLbyte* mailboxes_in, + SharedImageRepresentationFactory* representation_factory, + SharedContextState* shared_context_state, + SkYUVColorSpace& sk_yuv_color_space, + SkYUVAInfo::PlaneConfig& sk_plane_config, + SkYUVAInfo::Subsampling& sk_subsampling, + std::unique_ptr<SkiaImageRepresentation>& rgba_image, + int& num_yuva_planes, + std::array<std::unique_ptr<SkiaImageRepresentation>, + SkYUVAInfo::kMaxPlanes>& yuva_images) { + if (yuv_color_space_in < 0 || + yuv_color_space_in > kLastEnum_SkYUVColorSpace) { + return base::unexpected<GLError>( + GLError(GL_INVALID_ENUM, function_name, + "yuv_color_space must be a valid SkYUVColorSpace")); } sk_yuv_color_space = static_cast<SkYUVColorSpace>(yuv_color_space_in); - if (plane_config_in > static_cast<GLenum>(SkYUVAInfo::PlaneConfig::kLast)) { - ERRORSTATE_SET_GL_ERROR( - error_state, GL_INVALID_ENUM, function_name, - "plane_config must be a valid SkYUVAInfo::PlaneConfig"); - return false; + if (plane_config_in < 0 || + plane_config_in > static_cast<GLenum>(SkYUVAInfo::PlaneConfig::kLast)) { + return base::unexpected<GLError>( + GLError(GL_INVALID_ENUM, function_name, + "plane_config must be a valid SkYUVAInfo::PlaneConfig")); } sk_plane_config = static_cast<SkYUVAInfo::PlaneConfig>(plane_config_in); - if (subsampling_in > static_cast<GLenum>(SkYUVAInfo::Subsampling::kLast)) { - ERRORSTATE_SET_GL_ERROR( - error_state, GL_INVALID_ENUM, function_name, - "subsampling must be a valid SkYUVAInfo::Subsampling"); - return false; + if (subsampling_in < 0 || + subsampling_in > static_cast<GLenum>(SkYUVAInfo::Subsampling::kLast)) { + return base::unexpected<GLError>( + GLError(GL_INVALID_ENUM, function_name, + "subsampling must be a valid SkYUVAInfo::Subsampling")); } sk_subsampling = static_cast<SkYUVAInfo::Subsampling>(subsampling_in); @@ -90,24 +92,22 @@ yuva_images[i] = representation_factory->ProduceSkia(yuva_mailboxes[i], shared_context_state); if (!yuva_images[i]) { - ERRORSTATE_SET_GL_ERROR( - error_state, GL_INVALID_OPERATION, function_name, - ("Attempting to operate on unknown mailbox for plane index " + - base::NumberToString(i) + " using plane config " + - base::NumberToString(plane_config_in) + ".") - .c_str()); - return false; + std::string msg = + "Attempting to operate on unknown mailbox for plane index " + + base::NumberToString(i) + " using plane config " + + base::NumberToString(plane_config_in) + "."; + return base::unexpected<GLError>( + GLError(GL_INVALID_OPERATION, function_name, msg)); } } rgba_image = representation_factory->ProduceSkia(rgba_mailbox, shared_context_state); if (!rgba_image) { - ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, - "ConvertYUVAMailboxesToRGB", - "Attempting to operate on unknown dest mailbox."); - return false; + return base::unexpected<GLError>( + GLError(GL_INVALID_OPERATION, "ConvertYUVAMailboxesToRGB", + "Attempting to operate on unknown dest mailbox.")); } - return true; + return base::ok(); } void FlushSurface(SkiaImageRepresentation::ScopedWriteAccess* access) { @@ -171,15 +171,20 @@ CopySharedImageHelper::CopySharedImageHelper( SharedImageRepresentationFactory* representation_factory, - SharedContextState* shared_context_state, - gles2::ErrorState* error_state) + SharedContextState* shared_context_state) : representation_factory_(representation_factory), - shared_context_state_(shared_context_state), - error_state_(error_state) {} + shared_context_state_(shared_context_state) {} CopySharedImageHelper::~CopySharedImageHelper() = default; -bool CopySharedImageHelper::ConvertRGBAToYUVAMailboxes( +CopySharedImageHelper::GLError::GLError(GLenum gl_error, + std::string function_name, + std::string msg) + : gl_error(gl_error), + function_name(std::move(function_name)), + msg(std::move(msg)) {} + +base::expected<void, GLError> CopySharedImageHelper::ConvertRGBAToYUVAMailboxes( GLenum yuv_color_space, GLenum plane_config, GLenum subsampling, @@ -191,13 +196,13 @@ int num_yuva_planes; std::array<std::unique_ptr<SkiaImageRepresentation>, SkYUVAInfo::kMaxPlanes> yuva_images; - if (!ConvertYUVACommon("ConvertYUVAMailboxesToRGB", yuv_color_space, - plane_config, subsampling, mailboxes_in, - representation_factory_, shared_context_state_, - error_state_, dst_color_space, dst_plane_config, - dst_subsampling, rgba_image, num_yuva_planes, - yuva_images)) { - return false; + auto result = ConvertYUVACommon( + "ConvertYUVAMailboxesToRGB", yuv_color_space, plane_config, subsampling, + mailboxes_in, representation_factory_, shared_context_state_, + dst_color_space, dst_plane_config, dst_subsampling, rgba_image, + num_yuva_planes, yuva_images); + if (!result.has_value()) { + return result; } std::vector<GrBackendSemaphore> begin_semaphores; @@ -206,19 +211,17 @@ auto rgba_scoped_access = rgba_image->BeginScopedReadAccess(&begin_semaphores, &end_semaphores); if (!rgba_scoped_access) { - ERRORSTATE_SET_GL_ERROR(error_state_, GL_INVALID_OPERATION, - "glConvertYUVAMailboxesToRGB", - "RGBA shared image is not readable"); DCHECK(begin_semaphores.empty()); - return false; + return base::unexpected<GLError>( + GLError(GL_INVALID_OPERATION, "glConvertYUVAMailboxesToRGB", + "RGBA shared image is not readable")); } auto rgba_sk_image = rgba_scoped_access->CreateSkImage(shared_context_state_->gr_context()); if (!rgba_sk_image) { - ERRORSTATE_SET_GL_ERROR(error_state_, GL_INVALID_OPERATION, - "glReadbackImagePixels", - "Couldn't create SkImage for reading."); - return false; + return base::unexpected<GLError>( + GLError(GL_INVALID_OPERATION, "glReadbackImagePixels", + "Couldn't create SkImage for reading.")); } std::array<std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess>, @@ -229,23 +232,22 @@ &begin_semaphores, &end_semaphores, SharedImageRepresentation::AllowUnclearedAccess::kYes); if (!yuva_scoped_access[i]) { - ERRORSTATE_SET_GL_ERROR( - error_state_, GL_INVALID_OPERATION, "glConvertRGBAToYUVAMailboxes", - ("Couldn't write shared image for mailbox of plane index " + - base::NumberToString(i) + " using plane config " + - base::NumberToString(plane_config) + ".") - .c_str()); - return false; + std::string msg = + "Couldn't write shared image for mailbox of plane index " + + base::NumberToString(i) + " using plane config " + + base::NumberToString(plane_config) + "."; + return base::unexpected<GLError>( + GLError(GL_INVALID_OPERATION, "glConvertRGBAToYUVAMailboxes", msg)); } } SkSurface* yuva_sk_surfaces[SkYUVAInfo::kMaxPlanes]; for (int i = 0; i < num_yuva_planes; ++i) { yuva_sk_surfaces[i] = yuva_scoped_access[i]->surface(); if (!begin_semaphores.empty()) { - bool result = yuva_sk_surfaces[i]->wait( - begin_semaphores.size(), begin_semaphores.data(), - /*deleteSemaphoresAfterWait=*/false); - DCHECK(result); + bool ret = yuva_sk_surfaces[i]->wait(begin_semaphores.size(), + begin_semaphores.data(), + /*deleteSemaphoresAfterWait=*/false); + DCHECK(ret); } } @@ -260,10 +262,10 @@ } } SubmitIfNecessary(std::move(end_semaphores), shared_context_state_); - return true; + return base::ok(); } -bool CopySharedImageHelper::ConvertYUVAMailboxesToRGB( +base::expected<void, GLError> CopySharedImageHelper::ConvertYUVAMailboxesToRGB( GLenum planes_yuv_color_space, GLenum plane_config, GLenum subsampling, @@ -275,13 +277,15 @@ int num_src_planes; std::array<std::unique_ptr<SkiaImageRepresentation>, SkYUVAInfo::kMaxPlanes> yuva_images; - if (!ConvertYUVACommon( - "ConvertYUVAMailboxesToRGB", planes_yuv_color_space, plane_config, - subsampling, bytes_in, representation_factory_, shared_context_state_, - error_state_, src_yuv_color_space, src_plane_config, src_subsampling, - rgba_image, num_src_planes, yuva_images)) { - return false; + auto result = ConvertYUVACommon( + "ConvertYUVAMailboxesToRGB", planes_yuv_color_space, plane_config, + subsampling, bytes_in, representation_factory_, shared_context_state_, + src_yuv_color_space, src_plane_config, src_subsampling, rgba_image, + num_src_planes, yuva_images); + if (!result.has_value()) { + return result; } + sk_sp<SkColorSpace> src_rgb_color_space = ReadSkColorSpace( bytes_in + (SkYUVAInfo::kMaxPlanes + 1) * sizeof(gpu::Mailbox)); @@ -292,11 +296,10 @@ &begin_semaphores, &end_semaphores, SharedImageRepresentation::AllowUnclearedAccess::kYes); if (!dest_scoped_access) { - ERRORSTATE_SET_GL_ERROR(error_state_, GL_INVALID_VALUE, - "glConvertYUVAMailboxesToRGB", - "Destination shared image is not writable"); DCHECK(begin_semaphores.empty()); - return false; + return base::unexpected<GLError>( + GLError(GL_INVALID_VALUE, "glConvertYUVAMailboxesToRGB", + "Destination shared image is not writable")); } bool source_access_valid = true; @@ -308,23 +311,23 @@ &begin_semaphores, &end_semaphores); if (!source_scoped_access[i]) { - ERRORSTATE_SET_GL_ERROR( - error_state_, GL_INVALID_OPERATION, "glConvertYUVAMailboxesToRGB", - ("Couldn't access shared image for mailbox of plane index " + - base::NumberToString(i) + " using plane config " + - base::NumberToString(plane_config) + ".") - .c_str()); source_access_valid = false; + std::string msg = + "Couldn't access shared image for mailbox of plane index " + + base::NumberToString(i) + " using plane config " + + base::NumberToString(plane_config) + "."; + result = base::unexpected<GLError>( + GLError(GL_INVALID_OPERATION, "glConvertYUVAMailboxesToRGB", msg)); break; } } auto* dest_surface = dest_scoped_access->surface(); if (!begin_semaphores.empty()) { - bool result = + bool ret = dest_surface->wait(begin_semaphores.size(), begin_semaphores.data(), /*deleteSemaphoresAfterWait=*/false); - DCHECK(result); + DCHECK(ret); } bool drew_image = false; @@ -352,9 +355,9 @@ shared_context_state_->gr_context(), yuva_backend_textures, src_rgb_color_space); if (!result_image) { - ERRORSTATE_SET_GL_ERROR( - error_state_, GL_INVALID_OPERATION, "glConvertYUVAMailboxesToRGB", - "Couldn't create destination images from provided sources"); + result = base::unexpected<GLError>( + GLError(GL_INVALID_OPERATION, "glConvertYUVAMailboxesToRGB", + "Couldn't create destination images from provided sources")); } else { SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); @@ -371,7 +374,7 @@ rgba_image->SetCleared(); } - return true; + return result; } } // namespace gpu
diff --git a/gpu/command_buffer/service/copy_shared_image_helper.h b/gpu/command_buffer/service/copy_shared_image_helper.h index 3871730..04e1aa0 100644 --- a/gpu/command_buffer/service/copy_shared_image_helper.h +++ b/gpu/command_buffer/service/copy_shared_image_helper.h
@@ -6,8 +6,10 @@ #define GPU_COMMAND_BUFFER_SERVICE_COPY_SHARED_IMAGE_HELPER_H_ #include <stdint.h> +#include <string> #include "base/memory/raw_ptr.h" +#include "base/types/expected.h" #include "gpu/command_buffer/common/gl2_types.h" #include "gpu/gpu_gles2_export.h" @@ -16,33 +18,37 @@ class SharedContextState; class SharedImageRepresentationFactory; -namespace gles2 { -class ErrorState; -} - // A helper class implementing the common functions for raster and gl // passthrough command buffer decoders. class GPU_GLES2_EXPORT CopySharedImageHelper { public: + struct GLError { + GLError(GLenum gl_error, std::string function_name, std::string msg); + + GLenum gl_error = 0; + std::string function_name = ""; + std::string msg = ""; + }; + CopySharedImageHelper( SharedImageRepresentationFactory* representation_factory, - SharedContextState* shared_context_state, - gles2::ErrorState* error_state); + SharedContextState* shared_context_state); ~CopySharedImageHelper(); - bool ConvertRGBAToYUVAMailboxes(GLenum yuv_color_space, - GLenum plane_config, - GLenum subsampling, - const volatile GLbyte* mailboxes_in); - bool ConvertYUVAMailboxesToRGB(GLenum yuv_color_space, - GLenum plane_config, - GLenum subsampling, - const volatile GLbyte* mailboxes_in); + base::expected<void, GLError> ConvertRGBAToYUVAMailboxes( + GLenum yuv_color_space, + GLenum plane_config, + GLenum subsampling, + const volatile GLbyte* mailboxes_in); + base::expected<void, GLError> ConvertYUVAMailboxesToRGB( + GLenum yuv_color_space, + GLenum plane_config, + GLenum subsampling, + const volatile GLbyte* mailboxes_in); private: raw_ptr<SharedImageRepresentationFactory> representation_factory_ = nullptr; raw_ptr<SharedContextState> shared_context_state_ = nullptr; - raw_ptr<gles2::ErrorState> error_state_ = nullptr; }; } // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc index 080bfa1..38832cd 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -26,9 +26,12 @@ #include "gpu/command_buffer/service/program_cache.h" #include "gpu/command_buffer/service/shared_image/shared_image_representation.h" #include "gpu/config/gpu_finch_features.h" +#include "ui/gl/gl_utils.h" #include "ui/gl/gl_version_info.h" #include "ui/gl/gpu_switching_manager.h" +#include "ui/gl/init/gl_factory.h" #include "ui/gl/progress_reporter.h" +#include "ui/gl/scoped_make_current.h" #if BUILDFLAG(IS_WIN) #include "gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h" @@ -2463,6 +2466,55 @@ return error::kNoError; } +GLES2DecoderPassthroughImpl::LazySharedContextState::LazySharedContextState( + GLES2DecoderPassthroughImpl* impl) + : impl_(impl) { + auto gl_surface = gl::init::CreateOffscreenGLSurface( + impl_->context_->GetGLDisplayEGL(), gfx::Size()); + DCHECK(gl_surface); + + gl::GLContextAttribs attribs; + attribs.global_texture_share_group = true; + attribs.global_semaphore_share_group = true; + auto gl_context = gl::init::CreateGLContext(impl_->context_->share_group(), + gl_surface.get(), attribs); + DCHECK(gl_context); + + // Make current context using `gl_context` and `gl_surface` + ui::ScopedMakeCurrent smc(gl_context.get(), gl_surface.get()); + + ContextGroup* group = impl_->GetContextGroup(); + const GpuPreferences& gpu_preferences = group->gpu_preferences(); + const GpuDriverBugWorkarounds& workarounds = + group->feature_info()->workarounds(); + + shared_context_state_ = base::MakeRefCounted<SharedContextState>( + impl_->context_->share_group(), std::move(gl_surface), + std::move(gl_context), + /*use_virtualized_gl_contexts=*/false, base::DoNothing()); + auto feature_info = base::MakeRefCounted<gles2::FeatureInfo>( + workarounds, group->gpu_feature_info()); + if (!shared_context_state_->InitializeGL(gpu_preferences, feature_info)) { + impl_->InsertError(GL_INVALID_OPERATION, + "ContextResult::kFatalFailure: Failed to Initialize GL " + "for SharedContextState"); + return; + } + if (!shared_context_state_->InitializeGrContext(gpu_preferences, workarounds, + /*cache=*/nullptr)) { + impl_->InsertError(GL_INVALID_OPERATION, + "ContextResult::kFatalFailure: Failed to Initialize " + "GrContext for SharedContextState"); + return; + } +} + +GLES2DecoderPassthroughImpl::LazySharedContextState::~LazySharedContextState() { + ui::ScopedMakeCurrent smc(shared_context_state_->context(), + shared_context_state_->surface()); + shared_context_state_.reset(); +} + void GLES2DecoderPassthroughImpl::InsertError(GLenum error, const std::string& message) { errors_.insert(error);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h index a83bbc6..45a1832 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -28,6 +28,7 @@ #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/logger.h" #include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/command_buffer/service/shared_context_state.h" #include "gpu/command_buffer/service/shared_image/shared_image_representation.h" #include "gpu/command_buffer/service/texture_manager.h" #include "ui/gl/gl_bindings.h" @@ -604,6 +605,26 @@ // A table of CommandInfo for all the commands. static const CommandInfo command_info[kNumCommands - kFirstGLES2Command]; + // Creates lazily and holds a SharedContextState on a GLContext that is in the + // same share group as the command decoder's context. This is done so that + // skia operations can be performed on textures from the context and not worry + // about state tracking. + class LazySharedContextState { + public: + explicit LazySharedContextState(GLES2DecoderPassthroughImpl* impl); + ~LazySharedContextState(); + + SharedContextState* shared_context_state() { + return shared_context_state_.get(); + } + + private: + raw_ptr<GLES2DecoderPassthroughImpl> impl_ = nullptr; + scoped_refptr<SharedContextState> shared_context_state_; + }; + + std::unique_ptr<LazySharedContextState> lazy_context_; + // The GLApi to make the gl calls on. raw_ptr<gl::GLApi> api_ = nullptr;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc index 0f64850..dcd0102 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -15,6 +15,7 @@ #include "base/strings/string_number_conversions.h" #include "build/build_config.h" #include "gpu/command_buffer/common/discardable_handle.h" +#include "gpu/command_buffer/service/copy_shared_image_helper.h" #include "gpu/command_buffer/service/decoder_client.h" #include "gpu/command_buffer/service/gpu_fence_manager.h" #include "gpu/command_buffer/service/gpu_tracer.h" @@ -27,6 +28,7 @@ #include "ui/gfx/overlay_priority_hint.h" #include "ui/gl/gl_utils.h" #include "ui/gl/gl_version_info.h" +#include "ui/gl/scoped_make_current.h" namespace gpu { namespace gles2 { @@ -4955,7 +4957,18 @@ GLenum plane_config, GLenum subsampling, const volatile GLbyte* mailboxes_in) { - NOTIMPLEMENTED_LOG_ONCE(); + if (!lazy_context_) { + lazy_context_ = std::make_unique<LazySharedContextState>(this); + } + ui::ScopedMakeCurrent smc(lazy_context_->shared_context_state()->context(), + lazy_context_->shared_context_state()->surface()); + CopySharedImageHelper helper(group_->shared_image_representation_factory(), + lazy_context_->shared_context_state()); + auto result = helper.ConvertRGBAToYUVAMailboxes(yuv_color_space, plane_config, + subsampling, mailboxes_in); + if (!result.has_value()) { + InsertError(result.error().gl_error, result.error().msg); + } return error::kNoError; } @@ -4964,7 +4977,18 @@ GLenum plane_config, GLenum subsampling, const volatile GLbyte* mailboxes_in) { - NOTIMPLEMENTED_LOG_ONCE(); + if (!lazy_context_) { + lazy_context_ = std::make_unique<LazySharedContextState>(this); + } + ui::ScopedMakeCurrent smc(lazy_context_->shared_context_state()->context(), + lazy_context_->shared_context_state()->surface()); + CopySharedImageHelper helper(group_->shared_image_representation_factory(), + lazy_context_->shared_context_state()); + auto result = helper.ConvertYUVAMailboxesToRGB(yuv_color_space, plane_config, + subsampling, mailboxes_in); + if (!result.has_value()) { + InsertError(result.error().gl_error, result.error().msg); + } return error::kNoError; }
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index 8880aad4..00a8279 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -2748,9 +2748,14 @@ GLenum subsampling, const volatile GLbyte* bytes_in) { CopySharedImageHelper helper(&shared_image_representation_factory_, - shared_context_state_.get(), error_state_.get()); - helper.ConvertYUVAMailboxesToRGB(planes_yuv_color_space, plane_config, - subsampling, bytes_in); + shared_context_state_.get()); + auto result = helper.ConvertYUVAMailboxesToRGB( + planes_yuv_color_space, plane_config, subsampling, bytes_in); + if (!result.has_value()) { + LOCAL_SET_GL_ERROR(result.error().gl_error, + result.error().function_name.c_str(), + result.error().msg.c_str()); + } } void RasterDecoderImpl::DoConvertRGBAToYUVAMailboxesINTERNAL( @@ -2759,9 +2764,14 @@ GLenum subsampling, const volatile GLbyte* mailboxes_in) { CopySharedImageHelper helper(&shared_image_representation_factory_, - shared_context_state_.get(), error_state_.get()); - helper.ConvertRGBAToYUVAMailboxes(yuv_color_space, plane_config, subsampling, - mailboxes_in); + shared_context_state_.get()); + auto result = helper.ConvertRGBAToYUVAMailboxes(yuv_color_space, plane_config, + subsampling, mailboxes_in); + if (!result.has_value()) { + LOCAL_SET_GL_ERROR(result.error().gl_error, + result.error().function_name.c_str(), + result.error().msg.c_str()); + } } void RasterDecoderImpl::DoLoseContextCHROMIUM(GLenum current, GLenum other) {
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing.cc index bd05267a3..f1a60c1 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing.cc
@@ -1017,8 +1017,13 @@ if (swap_chain_) { return absl::make_optional<gl::DCLayerOverlayImage>(size(), swap_chain_); } - return absl::make_optional<gl::DCLayerOverlayImage>(size(), d3d11_texture_, - array_slice_); + // Set only if access isn't synchronized using the shared handle state. + Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex; + if (!dxgi_shared_handle_state_) { + d3d11_texture_.As(&keyed_mutex); + } + return absl::make_optional<gl::DCLayerOverlayImage>( + size(), d3d11_texture_, array_slice_, std::move(keyed_mutex)); } } // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_test_setup_helper.cc b/gpu/command_buffer/tests/gl_test_setup_helper.cc index 4b21799..a164c3d 100644 --- a/gpu/command_buffer/tests/gl_test_setup_helper.cc +++ b/gpu/command_buffer/tests/gl_test_setup_helper.cc
@@ -55,6 +55,7 @@ viz::TestGpuServiceHolder::ResetInstance(); gl::init::ShutdownGL(display_, /*due_to_fallback=*/false); task_environment_ = nullptr; + ::gles2::Terminate(); } } // namespace gpu
diff --git a/gpu/ipc/service/gpu_channel_test_common.cc b/gpu/ipc/service/gpu_channel_test_common.cc index 2706b98..b09be34 100644 --- a/gpu/ipc/service/gpu_channel_test_common.cc +++ b/gpu/ipc/service/gpu_channel_test_common.cc
@@ -25,11 +25,19 @@ #include "gpu/ipc/service/gpu_channel_manager_delegate.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_remote.h" +#include "ui/gl/gl_features.h" #include "ui/gl/init/gl_factory.h" #include "ui/gl/test/gl_surface_test_support.h" #include "url/gurl.h" namespace gpu { +namespace { +GpuPreferences CreateGpuPreferences() { + GpuPreferences prefs; + prefs.use_passthrough_cmd_decoder = features::UsePassthroughCommandDecoder(); + return prefs; +} +} // namespace class TestGpuChannelManagerDelegate : public GpuChannelManagerDelegate { public: @@ -77,7 +85,8 @@ base::trace_event::MemoryDumpManager::CreateInstanceForTesting()), sync_point_manager_(new SyncPointManager()), shared_image_manager_(new SharedImageManager(false /* thread_safe */)), - scheduler_(new Scheduler(sync_point_manager_.get(), GpuPreferences())), + scheduler_( + new Scheduler(sync_point_manager_.get(), CreateGpuPreferences())), channel_manager_delegate_( new TestGpuChannelManagerDelegate(scheduler_.get())) { // We need GL bindings to actually initialize command buffers. @@ -92,7 +101,8 @@ std::move(enabled_workarounds); channel_manager_ = std::make_unique<GpuChannelManager>( - GpuPreferences(), channel_manager_delegate_.get(), nullptr, /* watchdog */ + CreateGpuPreferences(), channel_manager_delegate_.get(), + nullptr, /* watchdog */ task_environment_.GetMainThreadTaskRunner(), task_environment_.GetMainThreadTaskRunner(), scheduler_.get(), sync_point_manager_.get(), shared_image_manager_.get(),
diff --git a/gpu/ipc/service/gpu_channel_unittest.cc b/gpu/ipc/service/gpu_channel_unittest.cc index 4a804f9..019cae67 100644 --- a/gpu/ipc/service/gpu_channel_unittest.cc +++ b/gpu/ipc/service/gpu_channel_unittest.cc
@@ -29,6 +29,12 @@ #endif TEST_F(GpuChannelTest, CreateViewCommandBufferAllowed) { + // TODO(crbug/1406585): Currently it's not possible to create onscreen + // GLSurface with Null binding with angle. + if (channel_manager()->use_passthrough_cmd_decoder()) { + GTEST_SKIP(); + } + int32_t kClientId = 1; bool is_gpu_host = true; GpuChannel* channel = CreateChannel(kClientId, is_gpu_host);
diff --git a/infra/config/generated/builders/ci/lacros-arm-generic-rel-skylab/properties.json b/infra/config/generated/builders/ci/lacros-arm-generic-rel-skylab/properties.json new file mode 100644 index 0000000..1fe65499 --- /dev/null +++ b/infra/config/generated/builders/ci/lacros-arm-generic-rel-skylab/properties.json
@@ -0,0 +1,67 @@ +{ + "$build/chromium_tests_builder_config": { + "builder_config": { + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "ci", + "builder": "lacros-arm-generic-rel-skylab", + "project": "chromium" + }, + "builder_spec": { + "build_gs_bucket": "chromium-chromiumos-archive", + "builder_group": "chromium.chromiumos", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb", + "mb_no_luci_auth" + ], + "build_config": "Release", + "config": "chromium", + "target_arch": "arm", + "target_bits": 32, + "target_cros_boards": [ + "jacuzzi:arm-generic" + ], + "target_platform": "chromeos" + }, + "legacy_gclient_config": { + "apply_configs": [ + "chromeos", + "checkout_lacros_sdk" + ], + "config": "chromium" + }, + "skylab_upload_location": { + "gs_bucket": "chromium-ci-skylab" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "ci", + "builder": "lacros-arm-generic-rel-skylab", + "project": "chromium" + } + ] + } + }, + "$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.chromiumos", + "recipe": "chromium" +} \ No newline at end of file
diff --git a/infra/config/generated/builders/ci/mac10.15-wpt-content-shell-fyi-rel/properties.json b/infra/config/generated/builders/ci/mac10.15-wpt-content-shell-fyi-rel/properties.json index a121149..efbcbd19 100644 --- a/infra/config/generated/builders/ci/mac10.15-wpt-content-shell-fyi-rel/properties.json +++ b/infra/config/generated/builders/ci/mac10.15-wpt-content-shell-fyi-rel/properties.json
@@ -34,6 +34,12 @@ "builder": "mac10.15-wpt-content-shell-fyi-rel", "project": "chromium" } + ], + "mirroring_builder_group_and_names": [ + { + "builder": "mac10.15-wpt-content-shell-fyi-rel", + "group": "tryserver.chromium.mac" + } ] } },
diff --git a/infra/config/generated/builders/ci/mac11-wpt-content-shell-fyi-rel/properties.json b/infra/config/generated/builders/ci/mac11-wpt-content-shell-fyi-rel/properties.json new file mode 100644 index 0000000..c3d903b3 --- /dev/null +++ b/infra/config/generated/builders/ci/mac11-wpt-content-shell-fyi-rel/properties.json
@@ -0,0 +1,54 @@ +{ + "$build/chromium_tests_builder_config": { + "builder_config": { + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "ci", + "builder": "mac11-wpt-content-shell-fyi-rel", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.fyi", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "build_config": "Release", + "config": "chromium", + "target_bits": 64, + "target_platform": "mac" + }, + "legacy_gclient_config": { + "config": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "ci", + "builder": "mac11-wpt-content-shell-fyi-rel", + "project": "chromium" + } + ] + } + }, + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" + }, + "$recipe_engine/resultdb/test_presentation": { + "column_keys": [], + "grouping_keys": [ + "status", + "v.test_suite" + ] + }, + "builder_group": "chromium.fyi", + "recipe": "chromium" +} \ No newline at end of file
diff --git a/infra/config/generated/builders/try/ios-simulator-compilator/properties.json b/infra/config/generated/builders/try/ios-simulator-compilator/properties.json index 09d9b22b6..c5102e2c 100644 --- a/infra/config/generated/builders/try/ios-simulator-compilator/properties.json +++ b/infra/config/generated/builders/try/ios-simulator-compilator/properties.json
@@ -53,11 +53,6 @@ "$build/flakiness": { "check_for_flakiness": true }, - "$build/goma": { - "jobs": 150, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org" - }, "$build/reclient": { "instance": "rbe-chromium-untrusted", "jobs": 300,
diff --git a/infra/config/generated/builders/try/ios-simulator-full-configs/properties.json b/infra/config/generated/builders/try/ios-simulator-full-configs/properties.json index 7bdaf0c..0f5e8737 100644 --- a/infra/config/generated/builders/try/ios-simulator-full-configs/properties.json +++ b/infra/config/generated/builders/try/ios-simulator-full-configs/properties.json
@@ -53,10 +53,6 @@ "$build/flakiness": { "check_for_flakiness": true }, - "$build/goma": { - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org" - }, "$build/reclient": { "instance": "rbe-chromium-untrusted", "metrics_project": "chromium-reclient-metrics"
diff --git a/infra/config/generated/builders/try/linux-blink-rel/properties.json b/infra/config/generated/builders/try/linux-blink-rel/properties.json index ceaabef..fb9ec0c1 100644 --- a/infra/config/generated/builders/try/linux-blink-rel/properties.json +++ b/infra/config/generated/builders/try/linux-blink-rel/properties.json
@@ -44,6 +44,7 @@ }, "$build/reclient": { "instance": "rbe-chromium-untrusted", + "jobs": 150, "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/mac-rel-compilator/properties.json b/infra/config/generated/builders/try/mac-rel-compilator/properties.json index ef8613f..f740cb95 100644 --- a/infra/config/generated/builders/try/mac-rel-compilator/properties.json +++ b/infra/config/generated/builders/try/mac-rel-compilator/properties.json
@@ -159,11 +159,6 @@ "$build/flakiness": { "check_for_flakiness": true }, - "$build/goma": { - "jobs": 300, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org" - }, "$build/reclient": { "instance": "rbe-chromium-untrusted", "jobs": 300,
diff --git a/infra/config/generated/builders/try/mac10.13-blink-rel/properties.json b/infra/config/generated/builders/try/mac10.13-blink-rel/properties.json index c91d97e..2b48a62 100644 --- a/infra/config/generated/builders/try/mac10.13-blink-rel/properties.json +++ b/infra/config/generated/builders/try/mac10.13-blink-rel/properties.json
@@ -41,6 +41,11 @@ "rpc_extra_params": "?prod", "server_host": "goma.chromium.org" }, + "$build/reclient": { + "instance": "rbe-chromium-untrusted", + "jobs": 150, + "metrics_project": "chromium-reclient-metrics" + }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [], "grouping_keys": [
diff --git a/infra/config/generated/builders/try/mac10.14-blink-rel/properties.json b/infra/config/generated/builders/try/mac10.14-blink-rel/properties.json index 192b0795..828d66b 100644 --- a/infra/config/generated/builders/try/mac10.14-blink-rel/properties.json +++ b/infra/config/generated/builders/try/mac10.14-blink-rel/properties.json
@@ -41,6 +41,11 @@ "rpc_extra_params": "?prod", "server_host": "goma.chromium.org" }, + "$build/reclient": { + "instance": "rbe-chromium-untrusted", + "jobs": 150, + "metrics_project": "chromium-reclient-metrics" + }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [], "grouping_keys": [
diff --git a/infra/config/generated/builders/try/mac10.15-blink-rel/properties.json b/infra/config/generated/builders/try/mac10.15-blink-rel/properties.json index ca91cbd0..461a6483 100644 --- a/infra/config/generated/builders/try/mac10.15-blink-rel/properties.json +++ b/infra/config/generated/builders/try/mac10.15-blink-rel/properties.json
@@ -37,9 +37,10 @@ "retry_failed_shards": true } }, - "$build/goma": { - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org" + "$build/reclient": { + "instance": "rbe-chromium-untrusted", + "jobs": 150, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git a/infra/config/generated/builders/try/mac10.15-wpt-content-shell-fyi-rel/properties.json b/infra/config/generated/builders/try/mac10.15-wpt-content-shell-fyi-rel/properties.json new file mode 100644 index 0000000..98423fb3 --- /dev/null +++ b/infra/config/generated/builders/try/mac10.15-wpt-content-shell-fyi-rel/properties.json
@@ -0,0 +1,57 @@ +{ + "$build/chromium_tests_builder_config": { + "builder_config": { + "builder_db": { + "entries": [ + { + "builder_id": { + "bucket": "ci", + "builder": "mac10.15-wpt-content-shell-fyi-rel", + "project": "chromium" + }, + "builder_spec": { + "builder_group": "chromium.fyi", + "execution_mode": "COMPILE_AND_TEST", + "legacy_chromium_config": { + "apply_configs": [ + "mb" + ], + "build_config": "Release", + "config": "chromium", + "target_bits": 64, + "target_platform": "mac" + }, + "legacy_gclient_config": { + "config": "chromium" + } + } + } + ] + }, + "builder_ids": [ + { + "bucket": "ci", + "builder": "mac10.15-wpt-content-shell-fyi-rel", + "project": "chromium" + } + ] + } + }, + "$build/goma": { + "rpc_extra_params": "?prod", + "server_host": "goma.chromium.org" + }, + "$build/reclient": { + "instance": "rbe-chromium-untrusted", + "metrics_project": "chromium-reclient-metrics" + }, + "$recipe_engine/resultdb/test_presentation": { + "column_keys": [], + "grouping_keys": [ + "status", + "v.test_suite" + ] + }, + "builder_group": "tryserver.chromium.mac", + "recipe": "chromium_trybot" +} \ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac11.0-blink-rel/properties.json b/infra/config/generated/builders/try/mac11.0-blink-rel/properties.json index 5df0040..efdd0157 100644 --- a/infra/config/generated/builders/try/mac11.0-blink-rel/properties.json +++ b/infra/config/generated/builders/try/mac11.0-blink-rel/properties.json
@@ -41,6 +41,11 @@ "rpc_extra_params": "?prod", "server_host": "goma.chromium.org" }, + "$build/reclient": { + "instance": "rbe-chromium-untrusted", + "jobs": 150, + "metrics_project": "chromium-reclient-metrics" + }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [], "grouping_keys": [
diff --git a/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/properties.json b/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/properties.json index 86b5ed55..1cc655d 100644 --- a/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/properties.json +++ b/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/properties.json
@@ -38,9 +38,10 @@ "retry_failed_shards": true } }, - "$build/goma": { - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org" + "$build/reclient": { + "instance": "rbe-chromium-untrusted", + "jobs": 150, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git a/infra/config/generated/builders/try/mac12.0-blink-rel/properties.json b/infra/config/generated/builders/try/mac12.0-blink-rel/properties.json index 38a507d..6cb6847 100644 --- a/infra/config/generated/builders/try/mac12.0-blink-rel/properties.json +++ b/infra/config/generated/builders/try/mac12.0-blink-rel/properties.json
@@ -37,9 +37,10 @@ "retry_failed_shards": false } }, - "$build/goma": { - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org" + "$build/reclient": { + "instance": "rbe-chromium-untrusted", + "jobs": 150, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git a/infra/config/generated/builders/try/mac12.0.arm64-blink-rel/properties.json b/infra/config/generated/builders/try/mac12.0.arm64-blink-rel/properties.json index 50fecfd..db936b35 100644 --- a/infra/config/generated/builders/try/mac12.0.arm64-blink-rel/properties.json +++ b/infra/config/generated/builders/try/mac12.0.arm64-blink-rel/properties.json
@@ -41,6 +41,11 @@ "rpc_extra_params": "?prod", "server_host": "goma.chromium.org" }, + "$build/reclient": { + "instance": "rbe-chromium-untrusted", + "jobs": 150, + "metrics_project": "chromium-reclient-metrics" + }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [], "grouping_keys": [
diff --git a/infra/config/generated/builders/try/mac_chromium_compile_dbg_ng/properties.json b/infra/config/generated/builders/try/mac_chromium_compile_dbg_ng/properties.json index b8ebdd3..fc8992c 100644 --- a/infra/config/generated/builders/try/mac_chromium_compile_dbg_ng/properties.json +++ b/infra/config/generated/builders/try/mac_chromium_compile_dbg_ng/properties.json
@@ -110,11 +110,6 @@ "is_compile_only": true } }, - "$build/goma": { - "jobs": 150, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org" - }, "$build/reclient": { "instance": "rbe-chromium-untrusted", "metrics_project": "chromium-reclient-metrics"
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index 3701049c..86231858 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -3326,6 +3326,10 @@ includable_only: true } builders { + name: "chromium/try/mac10.15-wpt-content-shell-fyi-rel" + includable_only: true + } + builders { name: "chromium/try/mac11-arm64-rel" includable_only: true }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index e0b16b1..d4e3673 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -36037,6 +36037,94 @@ } } builders { + name: "lacros-arm-generic-rel-skylab" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "free_space:standard" + 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/lacros-arm-generic-rel-skylab/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "chromium.chromiumos",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chromium"' + '}' + execution_timeout_secs: 10800 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium_swarming.expose_merge_script_failures" + value: 100 + } + experiments { + key: "luci.buildbucket.omit_python2" + value: 100 + } + 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/.+)|(ninja://[^/]*blink_wpt_tests/.+)" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "lacros-arm-generic-rel-skylab-fyi" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" @@ -45163,6 +45251,92 @@ } } builders { + name: "mac11-wpt-content-shell-fyi-rel" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builder:mac11-wpt-content-shell-fyi-rel" + dimensions: "cpu:x86-64" + dimensions: "os:Mac" + dimensions: "pool:luci.chromium.ci" + 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/mac11-wpt-content-shell-fyi-rel/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "chromium.fyi",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chromium"' + '}' + priority: 35 + execution_timeout_secs: 36000 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium_swarming.expose_merge_script_failures" + value: 100 + } + experiments { + key: "luci.buildbucket.omit_python2" + value: 100 + } + 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/.+)|(ninja://[^/]*blink_wpt_tests/.+)" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "mac11-x64-updater-tester-dbg" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" @@ -85698,6 +85872,103 @@ } } builders { + name: "mac10.15-wpt-content-shell-fyi-rel" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "cpu:x86-64" + dimensions: "os:Mac" + 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/mac10.15-wpt-content-shell-fyi-rel/properties.json",' + ' "top_level_project": {' + ' "ref": "refs/heads/main",' + ' "repo": {' + ' "host": "chromium.googlesource.com",' + ' "project": "chromium/src"' + ' }' + ' }' + ' },' + ' "builder_group": "tryserver.chromium.mac",' + ' "led_builder_is_bootstrapped": true,' + ' "recipe": "chromium_trybot"' + '}' + execution_timeout_secs: 14400 + expiration_secs: 7200 + grace_period { + seconds: 120 + } + caches { + name: "win_toolchain" + path: "win_toolchain" + } + build_numbers: YES + service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" + task_template_canary_percentage { + value: 5 + } + experiments { + key: "chromium_swarming.expose_merge_script_failures" + value: 100 + } + experiments { + key: "luci.buildbucket.omit_python2" + value: 100 + } + 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/.+)|(ninja://[^/]*blink_wpt_tests/.+)" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "mac11-arm64-rel" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index ef8c73ba..b4402ab 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -737,6 +737,11 @@ short_name: "arm" } builders { + name: "buildbucket/luci.chromium.ci/lacros-arm-generic-rel-skylab" + category: "chromium.chromiumos|lacros|arm" + short_name: "sky" + } + builders { name: "buildbucket/luci.chromium.ci/lacros-arm64-generic-rel" category: "chromium.chromiumos|lacros|arm64" short_name: "arm64" @@ -1443,6 +1448,11 @@ short_name: "arm" } builders { + name: "buildbucket/luci.chromium.ci/lacros-arm-generic-rel-skylab" + category: "chromium.chromiumos|lacros|arm" + short_name: "sky" + } + builders { name: "buildbucket/luci.chromium.ci/lacros-arm64-generic-rel" category: "chromium.chromiumos|lacros|arm64" short_name: "arm64" @@ -6203,6 +6213,11 @@ short_name: "arm" } builders { + name: "buildbucket/luci.chromium.ci/lacros-arm-generic-rel-skylab" + category: "lacros|arm" + short_name: "sky" + } + builders { name: "buildbucket/luci.chromium.ci/lacros-arm64-generic-rel" category: "lacros|arm64" short_name: "arm64" @@ -8880,6 +8895,10 @@ category: "mac" } builders { + name: "buildbucket/luci.chromium.ci/mac11-wpt-content-shell-fyi-rel" + category: "mac" + } + builders { name: "buildbucket/luci.chromium.ci/mac12-wpt-content-shell-fyi-rel" category: "mac" } @@ -17729,6 +17748,9 @@ name: "buildbucket/luci.chromium.try/mac10.15-blink-rel" } builders { + name: "buildbucket/luci.chromium.try/mac10.15-wpt-content-shell-fyi-rel" + } + builders { name: "buildbucket/luci.chromium.try/mac11-arm64-rel" } builders { @@ -18878,6 +18900,9 @@ name: "buildbucket/luci.chromium.try/mac-rel-inverse-fyi" } builders { + name: "buildbucket/luci.chromium.try/mac10.15-wpt-content-shell-fyi-rel" + } + builders { name: "buildbucket/luci.chromium.try/mac11-arm64-rel" } builders {
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg index dcffceea..b27ff0e 100644 --- a/infra/config/generated/luci/luci-scheduler.cfg +++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -4580,6 +4580,15 @@ } } job { + id: "lacros-arm-generic-rel-skylab" + realm: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "ci" + builder: "lacros-arm-generic-rel-skylab" + } +} +job { id: "lacros-arm-generic-rel-skylab-fyi" realm: "ci" buildbucket { @@ -5580,6 +5589,16 @@ } } job { + id: "mac11-wpt-content-shell-fyi-rel" + realm: "ci" + schedule: "with 5h interval" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "ci" + builder: "mac11-wpt-content-shell-fyi-rel" + } +} +job { id: "mac11-x64-updater-tester-dbg" realm: "ci" buildbucket { @@ -6331,6 +6350,7 @@ triggers: "lacros-amd64-generic-rel-skylab-fyi" triggers: "lacros-arm-archive-rel" triggers: "lacros-arm-generic-rel" + triggers: "lacros-arm-generic-rel-skylab" triggers: "lacros-arm-generic-rel-skylab-fyi" triggers: "lacros-arm64-archive-rel" triggers: "lacros-arm64-generic-rel"
diff --git a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star index 9af0c04..a4dc7c8 100644 --- a/infra/config/subprojects/chromium/ci/chromium.chromiumos.star +++ b/infra/config/subprojects/chromium/ci/chromium.chromiumos.star
@@ -587,6 +587,43 @@ ) ci.builder( + name = "lacros-arm-generic-rel-skylab", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + apply_configs = [ + "chromeos", + "checkout_lacros_sdk", + ], + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = ["mb", "mb_no_luci_auth"], + build_config = builder_config.build_config.RELEASE, + target_arch = builder_config.target_arch.ARM, + target_bits = 32, + target_platform = builder_config.target_platform.CHROMEOS, + target_cros_boards = "jacuzzi:arm-generic", + ), + build_gs_bucket = "chromium-chromiumos-archive", + skylab_upload_location = builder_config.skylab_upload_location( + gs_bucket = "chromium-ci-skylab", + ), + ), + os = os.LINUX_DEFAULT, + console_view_entry = consoles.console_view_entry( + category = "lacros|arm", + short_name = "sky", + ), + # TODO(crbug.com/1407339): Enable when stable. + sheriff_rotations = args.ignore_default(None), + tree_closing = False, + main_console_view = "main", + cq_mirrors_console_view = "mirrors", + reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CI, +) + +ci.builder( name = "lacros-arm64-generic-rel-skylab", builder_spec = builder_config.builder_spec( gclient_config = builder_config.gclient_config(
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index f9cc00a..46b3c1f 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1971,6 +1971,30 @@ ) fyi_mac_builder( + name = "mac11-wpt-content-shell-fyi-rel", + builder_spec = builder_config.builder_spec( + gclient_config = builder_config.gclient_config( + config = "chromium", + ), + chromium_config = builder_config.chromium_config( + config = "chromium", + apply_configs = ["mb"], + build_config = builder_config.build_config.RELEASE, + target_bits = 64, + target_platform = builder_config.target_platform.MAC, + ), + ), + triggered_by = [], + builderless = False, + os = os.MAC_ANY, + cores = None, + console_view_entry = consoles.console_view_entry( + category = "mac", + ), + schedule = "with 5h interval", +) + +fyi_mac_builder( name = "mac12-wpt-content-shell-fyi-rel", builder_spec = builder_config.builder_spec( gclient_config = builder_config.gclient_config(
diff --git a/infra/config/subprojects/chromium/try/tryserver.blink.star b/infra/config/subprojects/chromium/try/tryserver.blink.star index 5140f3d..d0f604b 100644 --- a/infra/config/subprojects/chromium/try/tryserver.blink.star +++ b/infra/config/subprojects/chromium/try/tryserver.blink.star
@@ -16,6 +16,8 @@ pool = try_.DEFAULT_POOL, service_account = try_.DEFAULT_SERVICE_ACCOUNT, execution_timeout = try_.DEFAULT_EXECUTION_TIMEOUT, + reclient_instance = reclient.instance.DEFAULT_UNTRUSTED, + reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ, ) consoles.list_view( @@ -57,7 +59,6 @@ os = os.LINUX_DEFAULT, main_list_view = "try", goma_backend = goma.backend.RBE_PROD, - reclient_instance = reclient.instance.DEFAULT_UNTRUSTED, tryjob = try_.job( location_filters = [ "cc/.+", @@ -91,8 +92,6 @@ builderless = True, os = os.WINDOWS_ANY, goma_backend = None, - reclient_instance = reclient.instance.DEFAULT_UNTRUSTED, - reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ, ) try_.builder( @@ -116,8 +115,6 @@ ), builderless = True, os = os.WINDOWS_ANY, - reclient_instance = reclient.instance.DEFAULT_UNTRUSTED, - reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ, ) blink_mac_builder( @@ -178,6 +175,7 @@ try_settings = builder_config.try_settings( retry_failed_shards = True, ), + goma_backend = None, ) blink_mac_builder( @@ -220,6 +218,7 @@ try_settings = builder_config.try_settings( retry_failed_shards = True, ), + goma_backend = None, ) blink_mac_builder( @@ -240,6 +239,7 @@ try_settings = builder_config.try_settings( retry_failed_shards = False, ), + goma_backend = None, ) blink_mac_builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star index 3a0bd38..85334ab4 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
@@ -150,7 +150,14 @@ os = os.MAC_DEFAULT, main_list_view = "try", check_for_flakiness = True, - goma_jobs = goma.jobs.J300, + goma_backend = None, +) + +try_.builder( + name = "mac10.15-wpt-content-shell-fyi-rel", + mirrors = [ + "ci/mac10.15-wpt-content-shell-fyi-rel", + ], ) try_.builder( @@ -268,7 +275,7 @@ ), os = os.MAC_DEFAULT, main_list_view = "try", - goma_jobs = goma.jobs.J150, + goma_backend = None, tryjob = try_.job(), ) @@ -385,6 +392,7 @@ xcode = xcode.x14main, main_list_view = "try", check_for_flakiness = True, + goma_backend = None, ) ios_builder( @@ -421,6 +429,7 @@ ], ), use_clang_coverage = True, + goma_backend = None, ) ios_builder(
diff --git a/ios/chrome/app/first_run_app_state_agent.mm b/ios/chrome/app/first_run_app_state_agent.mm index 3000331..5401d88d 100644 --- a/ios/chrome/app/first_run_app_state_agent.mm +++ b/ios/chrome/app/first_run_app_state_agent.mm
@@ -16,7 +16,6 @@ #import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/first_run/first_run_coordinator.h" #import "ios/chrome/browser/ui/first_run/first_run_screen_provider.h" -#import "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/first_run/orientation_limiting_navigation_controller.h" #import "ios/chrome/browser/ui/main/browser_interface_provider.h" #import "ios/chrome/browser/ui/main/scene_controller.h"
diff --git a/ios/chrome/app/main_application_delegate.mm b/ios/chrome/app/main_application_delegate.mm index 3e00f94..d5bed6b 100644 --- a/ios/chrome/app/main_application_delegate.mm +++ b/ios/chrome/app/main_application_delegate.mm
@@ -12,6 +12,8 @@ #import "base/metrics/user_metrics.h" #import "base/strings/sys_string_conversions.h" #import "components/download/public/background_service/background_download_service.h" +#import "components/feature_engagement/public/event_constants.h" +#import "components/feature_engagement/public/tracker.h" #import "ios/chrome/app/application_delegate/app_state.h" #import "ios/chrome/app/application_delegate/browser_launcher.h" #import "ios/chrome/app/application_delegate/memory_warning_helper.h" @@ -27,6 +29,7 @@ #import "ios/chrome/browser/commerce/push_notification/push_notification_feature.h" #import "ios/chrome/browser/crash_report/crash_keys_helper.h" #import "ios/chrome/browser/download/background_service/background_download_service_factory.h" +#import "ios/chrome/browser/feature_engagement/tracker_factory.h" #import "ios/chrome/browser/push_notification/push_notification_delegate.h" #import "ios/chrome/browser/push_notification/push_notification_util.h" #import "ios/chrome/browser/ui/keyboard/features.h" @@ -347,6 +350,7 @@ if (!appStartupFromExternalIntent) { base::RecordAction(base::UserMetricsAction("IOSOpenByMainIntent")); } else { + [self notifyFETAppStartupFromExternalIntent]; base::RecordAction(base::UserMetricsAction("IOSOpenByViewIntent")); } }); @@ -419,4 +423,21 @@ } } +// Notifies the FET that the app has launched from external intent (i.e. through +// the share sheet), which is an eligibility criterion for the default browser +// blue dot promo. +- (void)notifyFETAppStartupFromExternalIntent { + ChromeBrowserState* browserState = + _mainController.interfaceProvider.mainInterface.browserState; + + // OTR browsers are ignored because they can sometimes cause a nullptr tracker + // to be returned from the tracker factory. + if (!browserState || browserState->IsOffTheRecord()) { + return; + } + + feature_engagement::TrackerFactory::GetForBrowserState(browserState) + ->NotifyEvent(feature_engagement::events::kBlueDotPromoCriterionMet); +} + @end
diff --git a/ios/chrome/browser/application_context/application_context_impl.mm b/ios/chrome/browser/application_context/application_context_impl.mm index ccd82fbe..dde5619 100644 --- a/ios/chrome/browser/application_context/application_context_impl.mm +++ b/ios/chrome/browser/application_context/application_context_impl.mm
@@ -486,7 +486,8 @@ PromosManager* ApplicationContextImpl::GetPromosManager() { DCHECK(thread_checker_.CalledOnValidThread()); if (IsFullscreenPromosManagerEnabled() && !promos_manager_) { - promos_manager_ = std::make_unique<PromosManagerImpl>(GetLocalState()); + promos_manager_ = std::make_unique<PromosManagerImpl>( + GetLocalState(), base::DefaultClock::GetInstance()); } return promos_manager_.get(); }
diff --git a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm index bc45b99..134601c 100644 --- a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm +++ b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
@@ -169,7 +169,7 @@ [ChromeEarlGreyUI openToolsMenu]; [[[EarlGrey selectElementWithMatcher:ReadingListTextBadge()] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 150) + usingSearchAction:grey_scrollInDirection(kGREYDirectionRight, 150) onElementWithMatcher:grey_accessibilityID(kPopupMenuToolsMenuTableViewId)] assertWithMatcher:grey_notNil()]; @@ -182,7 +182,7 @@ selectElementWithMatcher:grey_allOf(grey_accessibilityID( kToolsMenuReadingListId), grey_sufficientlyVisible(), nil)] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 150) + usingSearchAction:grey_scrollInDirection(kGREYDirectionRight, 150) onElementWithMatcher:grey_accessibilityID(kPopupMenuToolsMenuTableViewId)] assertWithMatcher:grey_notNil()];
diff --git a/ios/chrome/browser/find_in_page/BUILD.gn b/ios/chrome/browser/find_in_page/BUILD.gn index 3ed9402..79e6fb2 100644 --- a/ios/chrome/browser/find_in_page/BUILD.gn +++ b/ios/chrome/browser/find_in_page/BUILD.gn
@@ -5,6 +5,8 @@ source_set("find_in_page") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ + "abstract_find_tab_helper.h", + "abstract_find_tab_helper.mm", "constants.h", "constants.mm", "find_in_page_controller.h", @@ -12,6 +14,8 @@ "find_in_page_model.h", "find_in_page_model.mm", "find_in_page_response_delegate.h", + "find_tab_helper.h", + "find_tab_helper.mm", "java_script_find_in_page_controller.h", "java_script_find_in_page_controller.mm", "java_script_find_tab_helper.h",
diff --git a/ios/chrome/browser/find_in_page/abstract_find_tab_helper.h b/ios/chrome/browser/find_in_page/abstract_find_tab_helper.h new file mode 100644 index 0000000..f5afb2a --- /dev/null +++ b/ios/chrome/browser/find_in_page/abstract_find_tab_helper.h
@@ -0,0 +1,74 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_FIND_IN_PAGE_ABSTRACT_FIND_TAB_HELPER_H_ +#define IOS_CHROME_BROWSER_FIND_IN_PAGE_ABSTRACT_FIND_TAB_HELPER_H_ + +@class FindInPageModel; +@protocol FindInPageResponseDelegate; +@class NSString; + +namespace web { +class WebState; +} + +// Interface shared by JavaScriptFindTabHelper and FindTabHelper. +class AbstractFindTabHelper { + public: + enum FindDirection { + FORWARD, + REVERSE, + }; + + AbstractFindTabHelper() = default; + + AbstractFindTabHelper(const AbstractFindTabHelper&) = delete; + AbstractFindTabHelper& operator=(const AbstractFindTabHelper&) = delete; + + virtual ~AbstractFindTabHelper() = default; + + // Sets the FindInPageResponseDelegate delegate to send responses to + // StartFinding(), ContinueFinding(), and StopFinding(). + virtual void SetResponseDelegate( + id<FindInPageResponseDelegate> response_delegate) = 0; + + // Starts an asynchronous Find operation. Highlights matches on the current + // page. Always searches in the FORWARD direction. + virtual void StartFinding(NSString* search_string) = 0; + + // Runs an asynchronous Find operation. Highlights matches on the current + // page. Uses the previously remembered search string and searches in the + // given `direction`. + virtual void ContinueFinding(FindDirection direction) = 0; + + // Stops any running find operations. Removes any highlighting from the + // current page. + virtual void StopFinding() = 0; + + // Returns the FindInPageModel that contains the latest find results. + virtual FindInPageModel* GetFindResult() const = 0; + + // Returns true if the currently loaded page supports Find in Page. + virtual bool CurrentPageSupportsFindInPage() const = 0; + + // Returns true if the Find in Page UI is currently visible. + virtual bool IsFindUIActive() const = 0; + + // Marks the Find in Page UI as visible or not. This method does not directly + // show or hide the UI. It simply acts as a marker for whether or not the UI + // is visible. + virtual void SetFindUIActive(bool active) = 0; + + // Saves the current find text to persistent storage. + virtual void PersistSearchTerm() = 0; + + // Restores the current find text from persistent storage. + virtual void RestoreSearchTerm() = 0; +}; + +// Get the concrete tab helper currently attached to the given `web_state`. +AbstractFindTabHelper* GetConcreteFindTabHelperFromWebState( + web::WebState* web_state); + +#endif // IOS_CHROME_BROWSER_FIND_IN_PAGE_ABSTRACT_FIND_TAB_HELPER_H_
diff --git a/ios/chrome/browser/find_in_page/abstract_find_tab_helper.mm b/ios/chrome/browser/find_in_page/abstract_find_tab_helper.mm new file mode 100644 index 0000000..c3ea931d --- /dev/null +++ b/ios/chrome/browser/find_in_page/abstract_find_tab_helper.mm
@@ -0,0 +1,21 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/find_in_page/abstract_find_tab_helper.h" + +#import "ios/chrome/browser/find_in_page/find_tab_helper.h" +#import "ios/chrome/browser/find_in_page/java_script_find_tab_helper.h" +#import "ios/public/provider/chrome/browser/find_in_page/find_in_page_api.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +AbstractFindTabHelper* GetConcreteFindTabHelperFromWebState( + web::WebState* web_state) { + if (ios::provider::IsNativeFindInPageEnabled()) { + return FindTabHelper::FromWebState(web_state); + } + return JavaScriptFindTabHelper::FromWebState(web_state); +}
diff --git a/ios/chrome/browser/find_in_page/find_tab_helper.h b/ios/chrome/browser/find_in_page/find_tab_helper.h new file mode 100644 index 0000000..52f0856 --- /dev/null +++ b/ios/chrome/browser/find_in_page/find_tab_helper.h
@@ -0,0 +1,70 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_FIND_IN_PAGE_FIND_TAB_HELPER_H_ +#define IOS_CHROME_BROWSER_FIND_IN_PAGE_FIND_TAB_HELPER_H_ + +#import "base/scoped_observation.h" +#import "ios/chrome/browser/find_in_page/abstract_find_tab_helper.h" +#import "ios/web/public/web_state_observer.h" +#import "ios/web/public/web_state_user_data.h" + +@class FindInPageController; + +// Adds support for the Native Find in Page feature. Instantiates a +// FindInPageController when the web state is realized which itself attaches and +// interacts with a web-layer FindInPageManager. +class FindTabHelper final : public AbstractFindTabHelper, + public web::WebStateObserver, + public web::WebStateUserData<FindTabHelper> { + public: + FindTabHelper(const FindTabHelper&) = delete; + FindTabHelper& operator=(const FindTabHelper&) = delete; + + ~FindTabHelper() final; + + // AbstractFindTabHelper implementation + void SetResponseDelegate( + id<FindInPageResponseDelegate> response_delegate) final; + void StartFinding(NSString* search_string) final; + void ContinueFinding(FindDirection direction) final; + void StopFinding() final; + FindInPageModel* GetFindResult() const final; + bool CurrentPageSupportsFindInPage() const final; + bool IsFindUIActive() const final; + void SetFindUIActive(bool active) final; + void PersistSearchTerm() final; + void RestoreSearchTerm() final; + + private: + friend class web::WebStateUserData<FindTabHelper>; + + // Private constructor used by CreateForWebState(). + FindTabHelper(web::WebState* web_state); + + // Create the FindInPageController for `web_state`. Only called if/when + // the WebState is realized. + void CreateFindInPageController(web::WebState* web_state); + + // web::WebStateObserver. + void WebStateRealized(web::WebState* web_state) final; + void WebStateDestroyed(web::WebState* web_state) final; + void DidFinishNavigation(web::WebState* web_state, + web::NavigationContext* navigation_context) final; + + // The ObjC find in page controller (nil if the WebState is not realized). + FindInPageController* controller_ = nil; + + // The delegate to register with JavaScriptFindInPageController when it is + // created. + __weak id<FindInPageResponseDelegate> response_delegate_ = nil; + + // Manage the registration of this instance as a WebStateObserver. + base::ScopedObservation<web::WebState, web::WebStateObserver> observation_{ + this}; + + WEB_STATE_USER_DATA_KEY_DECL(); +}; + +#endif // IOS_CHROME_BROWSER_FIND_IN_PAGE_FIND_TAB_HELPER_H_
diff --git a/ios/chrome/browser/find_in_page/find_tab_helper.mm b/ios/chrome/browser/find_in_page/find_tab_helper.mm new file mode 100644 index 0000000..c6b7870 --- /dev/null +++ b/ios/chrome/browser/find_in_page/find_tab_helper.mm
@@ -0,0 +1,107 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/find_in_page/find_tab_helper.h" +#import "ios/chrome/browser/find_in_page/find_in_page_controller.h" +#import "ios/chrome/browser/find_in_page/find_in_page_model.h" +#import "ios/web/public/navigation/navigation_context.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +FindTabHelper::FindTabHelper(web::WebState* web_state) { + DCHECK(web_state); + observation_.Observe(web_state); + + if (web_state->IsRealized()) { + CreateFindInPageController(web_state); + } +} + +FindTabHelper::~FindTabHelper() {} + +void FindTabHelper::CreateFindInPageController(web::WebState* web_state) { + DCHECK(!controller_); + controller_ = [[FindInPageController alloc] initWithWebState:web_state]; +} + +void FindTabHelper::SetResponseDelegate( + id<FindInPageResponseDelegate> response_delegate) { + if (!controller_) { + response_delegate_ = response_delegate; + } else { + controller_.responseDelegate = response_delegate; + } +} + +void FindTabHelper::StartFinding(NSString* search_string) { + [controller_ findStringInPage:search_string]; +} + +void FindTabHelper::ContinueFinding(FindDirection direction) { + if (direction == FORWARD) { + [controller_ findNextStringInPage]; + + } else if (direction == REVERSE) { + [controller_ findPreviousStringInPage]; + + } else { + NOTREACHED(); + } +} + +void FindTabHelper::StopFinding() { + SetFindUIActive(false); + [controller_ disableFindInPage]; +} + +FindInPageModel* FindTabHelper::GetFindResult() const { + return controller_.findInPageModel; +} + +bool FindTabHelper::CurrentPageSupportsFindInPage() const { + return [controller_ canFindInPage]; +} + +bool FindTabHelper::IsFindUIActive() const { + return controller_.findInPageModel.enabled; +} + +void FindTabHelper::SetFindUIActive(bool active) { + controller_.findInPageModel.enabled = active; +} + +void FindTabHelper::PersistSearchTerm() { + [controller_ saveSearchTerm]; +} + +void FindTabHelper::RestoreSearchTerm() { + [controller_ restoreSearchTerm]; +} + +void FindTabHelper::WebStateRealized(web::WebState* web_state) { + CreateFindInPageController(web_state); +} + +void FindTabHelper::WebStateDestroyed(web::WebState* web_state) { + observation_.Reset(); + + [controller_ detachFromWebState]; + controller_ = nil; +} + +void FindTabHelper::DidFinishNavigation( + web::WebState* web_state, + web::NavigationContext* navigation_context) { + if (navigation_context->IsSameDocument()) { + return; + } + + if (IsFindUIActive()) { + StopFinding(); + } +} + +WEB_STATE_USER_DATA_KEY_IMPL(FindTabHelper)
diff --git a/ios/chrome/browser/find_in_page/java_script_find_tab_helper.h b/ios/chrome/browser/find_in_page/java_script_find_tab_helper.h index 2cef4a8..4670f6e 100644 --- a/ios/chrome/browser/find_in_page/java_script_find_tab_helper.h +++ b/ios/chrome/browser/find_in_page/java_script_find_tab_helper.h
@@ -7,8 +7,8 @@ #include <Foundation/Foundation.h> -#include "base/ios/block_types.h" #include "base/scoped_observation.h" +#import "ios/chrome/browser/find_in_page/abstract_find_tab_helper.h" #include "ios/web/public/web_state_observer.h" #import "ios/web/public/web_state_user_data.h" @@ -17,60 +17,30 @@ @protocol FindInPageResponseDelegate; // Adds support for the "Find in page" feature. -class JavaScriptFindTabHelper - : public web::WebStateObserver, +class JavaScriptFindTabHelper final + : public AbstractFindTabHelper, + public web::WebStateObserver, public web::WebStateUserData<JavaScriptFindTabHelper> { public: JavaScriptFindTabHelper(const JavaScriptFindTabHelper&) = delete; JavaScriptFindTabHelper& operator=(const JavaScriptFindTabHelper&) = delete; - ~JavaScriptFindTabHelper() override; + ~JavaScriptFindTabHelper() final; - enum FindDirection { - FORWARD, - REVERSE, - }; - - // Sets the FindInPageResponseDelegate delegate to send responses to - // StartFinding(), ContinueFinding(), and StopFinding(). - void SetResponseDelegate(id<FindInPageResponseDelegate> response_delegate); - - // Starts an asynchronous Find operation that will call the given completion - // handler with results. Highlights matches on the current page. Always - // searches in the FORWARD direction. - void StartFinding(NSString* search_string); - - // Runs an asynchronous Find operation that will call the given completion - // handler with results. Highlights matches on the current page. Uses the - // previously remembered search string and searches in the given `direction`. - void ContinueFinding(FindDirection direction); - - // Stops any running find operations and runs the given completion block. - // Removes any highlighting from the current page. - void StopFinding(); - - // Returns the FindInPageModel that contains the latest find results. - FindInPageModel* GetFindResult() const; - - // Returns true if the currently loaded page supports Find in Page. - bool CurrentPageSupportsFindInPage() const; - - // Returns true if the Find in Page UI is currently visible. - bool IsFindUIActive() const; - - // Marks the Find in Page UI as visible or not. This method does not directly - // show or hide the UI. It simply acts as a marker for whether or not the UI - // is visible. - void SetFindUIActive(bool active); - - // Saves the current find text to persistent storage. - void PersistSearchTerm(); - - // Restores the current find text from persistent storage. - void RestoreSearchTerm(); + // AbstractFindTabHelper implementation + void SetResponseDelegate( + id<FindInPageResponseDelegate> response_delegate) final; + void StartFinding(NSString* search_string) final; + void ContinueFinding(FindDirection direction) final; + void StopFinding() final; + FindInPageModel* GetFindResult() const final; + bool CurrentPageSupportsFindInPage() const final; + bool IsFindUIActive() const final; + void SetFindUIActive(bool active) final; + void PersistSearchTerm() final; + void RestoreSearchTerm() final; private: - friend class FindTabHelperTest; friend class web::WebStateUserData<JavaScriptFindTabHelper>; // Private constructor used by CreateForWebState(). @@ -81,10 +51,10 @@ void CreateFindInPageController(web::WebState* web_state); // web::WebStateObserver. - void WebStateRealized(web::WebState* web_state) override; - void WebStateDestroyed(web::WebState* web_state) override; + void WebStateRealized(web::WebState* web_state) final; + void WebStateDestroyed(web::WebState* web_state) final; void DidFinishNavigation(web::WebState* web_state, - web::NavigationContext* navigation_context) override; + web::NavigationContext* navigation_context) final; // The ObjC find in page controller (nil if the WebState is not realized). JavaScriptFindInPageController* controller_ = nil;
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 52a43b1..ffa8193 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -555,6 +555,11 @@ flag_descriptions::kShowAutofillTypePredictionsDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(autofill::features::kAutofillShowTypePredictions)}, + {"autofill-account-profiles-union-view", + flag_descriptions::kAutofillAccountProfilesUnionViewName, + flag_descriptions::kAutofillAccountProfilesUnionViewDescription, + flags_ui::kOsIos, + FEATURE_VALUE_TYPE(autofill::features::kAutofillAccountProfilesUnionView)}, {"autofill-ios-delay-between-fields", flag_descriptions::kAutofillIOSDelayBetweenFieldsName, flag_descriptions::kAutofillIOSDelayBetweenFieldsDescription, @@ -1225,6 +1230,9 @@ kEnableAccessibilityIdentifierToOmniboxLeadingImageDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableAccessibilityIdentifierToOmniboxLeadingImage)}, + {"shopping-list", commerce::flag_descriptions::kShoppingListName, + commerce::flag_descriptions::kShoppingListDescription, + flags_ui::kOsIos, FEATURE_VALUE_TYPE(commerce::kShoppingList)}, }; bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index f1ecc90b..ea6b8c9 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -21,6 +21,11 @@ "When enabled, App Store Rating promo will be presented to eligible " "users."; +const char kAutofillAccountProfilesUnionViewName[] = + "Enable compatibility with GAS"; +const char kAutofillAccountProfilesUnionViewDescription[] = + "When enabled, the GAS profiles would start up showing in settings"; + const char kAutofillBrandingIOSName[] = "Autofill Branding on iOS"; const char kAutofillBrandingIOSDescription[] = "Adds the Chrome logo in the form input suggestions bar. Full color by "
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index d7ed429..5bf1ce8 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -22,6 +22,10 @@ extern const char kAppStoreRatingName[]; extern const char kAppStoreRatingDescription[]; +// Title and description for the flag to enable compatibility with GAS profiles. +extern const char kAutofillAccountProfilesUnionViewName[]; +extern const char kAutofillAccountProfilesUnionViewDescription[]; + // Title and description for the flag to enable Chrome branding on form input // suggestions. extern const char kAutofillBrandingIOSName[];
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm index 074ee3d..0df6332 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm +++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm
@@ -364,26 +364,18 @@ AddIssueToForm(&form2, InsecureType::kWeak, base::Minutes(1)); store().AddLogin(form2); RunUntilIdle(); - // TODO(crbug.com/1406540): Verify that the "weak passwords" warning becomes - // the highest priority warning once the weak passwords are going to be - // returned in InsecureCredentialsManager::GetInsecureCredentialEntries() (as - // of now, we don't take them into account and filter them out). Until then, - // the "dismissed warnings" warning stays the highest priority warning. + EXPECT_THAT(manager().GetWarningOfHighestPriority(), - WarningType::kNoInsecurePasswordsWarning); + WarningType::kWeakPasswordsWarning); // Add a reused password. PasswordForm form3 = MakeSavedPassword(kExampleCom, kUsername216); AddIssueToForm(&form3, InsecureType::kReused, base::Minutes(1)); store().AddLogin(form3); RunUntilIdle(); - // TODO(crbug.com/1406540): Verify that the "reused passwords" warning becomes - // the highest priority warning once the reused passwords are going to be - // returned in InsecureCredentialsManager::GetInsecureCredentialEntries() (as - // of now, we don't take them into account and filter them out). Until then, - // the "dismissed warnings" warning stays the highest priority warning. + EXPECT_THAT(manager().GetWarningOfHighestPriority(), - WarningType::kNoInsecurePasswordsWarning); + WarningType::kReusedPasswordsWarning); // Add an unmuted compromised password. PasswordForm form4 = MakeSavedPassword(kExampleCom, kUsername216);
diff --git a/ios/chrome/browser/passwords/password_controller_js_unittest.mm b/ios/chrome/browser/passwords/password_controller_js_unittest.mm index 5fc7347..6968bdd 100644 --- a/ios/chrome/browser/passwords/password_controller_js_unittest.mm +++ b/ios/chrome/browser/passwords/password_controller_js_unittest.mm
@@ -544,7 +544,7 @@ "document.getElementsByTagName('button')[0].dispatchEvent(e);", web_state()); - // Check that there was only 1 call for invokeOnHost. + // Check that there was only 1 call for sendWebKitMessage. EXPECT_NSEQ(@1, web::test::ExecuteJavaScript(@"submittedFormMessageCalls", web_state())); @@ -575,7 +575,7 @@ @"\"value\":\"password1\",\"label\":\"Password:\"}]}", BaseUrl().c_str(), mainFrameID.c_str()]; - // Check that invokeOnHost was called with the correct argument. + // Check that sendWebKitMessage was called with the correct argument. EXPECT_NSEQ(expected_command, web::test::ExecuteJavaScript( @"__gCrWeb.stringify(submittedFormData)", web_state()));
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm index 8c21bd5..2fac5b3 100644 --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -218,6 +218,8 @@ registry->RegisterListPref(prefs::kIosPromosManagerActivePromos); registry->RegisterListPref(prefs::kIosPromosManagerImpressions); registry->RegisterListPref(prefs::kIosPromosManagerSingleDisplayActivePromos); + registry->RegisterDictionaryPref( + prefs::kIosPromosManagerSingleDisplayPendingPromos); registry->RegisterBooleanPref(enterprise_reporting::kCloudReportingEnabled, false);
diff --git a/ios/chrome/browser/prefs/pref_names.cc b/ios/chrome/browser/prefs/pref_names.cc index 73d7606c..7b4b7bf 100644 --- a/ios/chrome/browser/prefs/pref_names.cc +++ b/ios/chrome/browser/prefs/pref_names.cc
@@ -102,6 +102,11 @@ // campaigns. const char kIosPromosManagerActivePromos[] = "ios.promos_manager.active_promos"; +// Dict preference maintaining the dict of single-display, pending promo +// campaigns. Key is the promo name, value is the time to become active. +const char kIosPromosManagerSingleDisplayPendingPromos[] = + "ios.promos_manager.pending_promos"; + // List preference containing the promo impression history. const char kIosPromosManagerImpressions[] = "ios.promos_manager.impressions";
diff --git a/ios/chrome/browser/prefs/pref_names.h b/ios/chrome/browser/prefs/pref_names.h index b7077db..a8a4b66 100644 --- a/ios/chrome/browser/prefs/pref_names.h +++ b/ios/chrome/browser/prefs/pref_names.h
@@ -36,6 +36,7 @@ extern const char kIosPromosManagerActivePromos[]; extern const char kIosPromosManagerImpressions[]; extern const char kIosPromosManagerSingleDisplayActivePromos[]; +extern const char kIosPromosManagerSingleDisplayPendingPromos[]; extern const char kIosSettingsPromoAlreadySeen[]; extern const char kIosSettingsSigninPromoDisplayedCount[]; extern const char kIosNtpFeedTopPromoAlreadySeen[];
diff --git a/ios/chrome/browser/promos_manager/mock_promos_manager.h b/ios/chrome/browser/promos_manager/mock_promos_manager.h index 1452df2..25bfe0e 100644 --- a/ios/chrome/browser/promos_manager/mock_promos_manager.h +++ b/ios/chrome/browser/promos_manager/mock_promos_manager.h
@@ -13,6 +13,7 @@ #import <set> #import "base/containers/small_map.h" +#import "base/time/time.h" #import "ios/chrome/browser/promos_manager/constants.h" #import "ios/chrome/browser/promos_manager/impression_limit.h" #import "testing/gmock/include/gmock/gmock.h" @@ -39,7 +40,7 @@ MOCK_METHOD(absl::optional<promos_manager::Promo>, NextPromoForDisplay, (), - (const, override)); + (override)); MOCK_METHOD(void, RegisterPromoForContinuousDisplay, (promos_manager::Promo promo), @@ -48,6 +49,11 @@ RegisterPromoForSingleDisplay, (promos_manager::Promo promo), (override)); + MOCK_METHOD(void, + RegisterPromoForSingleDisplay, + (promos_manager::Promo promo, + base::TimeDelta becomes_active_after_period), + (override)); MOCK_METHOD(void, DeregisterPromo, (promos_manager::Promo promo), (override)); };
diff --git a/ios/chrome/browser/promos_manager/promos_manager.h b/ios/chrome/browser/promos_manager/promos_manager.h index d1c39fa..f81bcf7 100644 --- a/ios/chrome/browser/promos_manager/promos_manager.h +++ b/ios/chrome/browser/promos_manager/promos_manager.h
@@ -10,6 +10,7 @@ #import <map> #import "base/containers/small_map.h" +#import "base/time/time.h" #import "third_party/abseil-cpp/absl/types/optional.h" @class ImpressionLimit; @@ -40,6 +41,13 @@ // status across app launches. virtual void RegisterPromoForSingleDisplay(promos_manager::Promo promo) = 0; + // Same as `RegisterPromoForSingleDisplay`, except that the promo can only be + // active after `becomes_active_after_period`. Pending status with time are + // persisted. + virtual void RegisterPromoForSingleDisplay( + promos_manager::Promo promo, + base::TimeDelta becomes_active_after_period) = 0; + // Deregisters `promo` (stopping `promo` from being displayed) by removing the // promo entry from the single-display and continuous-display active promos // lists. @@ -65,7 +73,7 @@ virtual void RecordImpression(promos_manager::Promo promo) = 0; // Returns the next promo for display, if any. - virtual absl::optional<promos_manager::Promo> NextPromoForDisplay() const = 0; + virtual absl::optional<promos_manager::Promo> NextPromoForDisplay() = 0; }; #endif // IOS_CHROME_BROWSER_PROMOS_MANAGER_PROMOS_MANAGER_H_
diff --git a/ios/chrome/browser/promos_manager/promos_manager_impl.h b/ios/chrome/browser/promos_manager/promos_manager_impl.h index 2aabe457..d721b1c 100644 --- a/ios/chrome/browser/promos_manager/promos_manager_impl.h +++ b/ios/chrome/browser/promos_manager/promos_manager_impl.h
@@ -13,6 +13,7 @@ #import <vector> #import "base/containers/small_map.h" +#import "base/time/clock.h" #import "base/values.h" #import "components/prefs/pref_service.h" #import "ios/chrome/browser/promos_manager/constants.h" @@ -24,7 +25,13 @@ // promo_manager.h instead. class PromosManagerImpl : public PromosManager { public: - explicit PromosManagerImpl(PrefService* local_state); + // Context for a promo registration, internally used. + struct PromoContext { + // The promo has had pending status. + bool was_pending; + }; + + PromosManagerImpl(PrefService* local_state, base::Clock* clock); ~PromosManagerImpl() override; // `promo`-specific impression limits, if defined. May return an empty @@ -51,7 +58,7 @@ // recently seen, as `sorted_impressions` is sorted by day (most recent -> // least recent). std::vector<promos_manager::Promo> LeastRecentlyShown( - const std::set<promos_manager::Promo>& active_promos, + const std::map<promos_manager::Promo, PromoContext>& active_promos, const std::vector<promos_manager::Impression>& sorted_impressions) const; // Impression limits that count against all promos. @@ -68,7 +75,10 @@ // Loops over the stored active promos list (base::Value::List) and returns // a corresponding std::set<promos_manager::Promo>. std::set<promos_manager::Promo> ActivePromos( - const base::Value::List& stored_active_promos); + const base::Value::List& stored_active_promos) const; + + // Initializes the `single_display_pending_promos_`, constructs it from Pref. + void InitializePendingPromos(); // Returns true if any impression limit from `impression_limits` is triggered, // and false otherwise. @@ -126,20 +136,30 @@ std::map<promos_manager::Promo, NSArray<ImpressionLimit*>*>> promo_impression_limits) override; void RecordImpression(promos_manager::Promo promo) override; - absl::optional<promos_manager::Promo> NextPromoForDisplay() const override; + absl::optional<promos_manager::Promo> NextPromoForDisplay() override; void RegisterPromoForContinuousDisplay(promos_manager::Promo promo) override; void RegisterPromoForSingleDisplay(promos_manager::Promo promo) override; + void RegisterPromoForSingleDisplay( + promos_manager::Promo promo, + base::TimeDelta becomes_active_after_period) override; void DeregisterPromo(promos_manager::Promo promo) override; // Weak pointer to the local state prefs store. const raw_ptr<PrefService> local_state_; + // The time provider. + const raw_ptr<base::Clock> clock_; + // The set of currently active, continuous-display promos. std::set<promos_manager::Promo> active_promos_; // The set of currently active, single-display promos. std::set<promos_manager::Promo> single_display_active_promos_; + // The map from registered single-display pending promos to the time that they + // can become active. + std::map<promos_manager::Promo, base::Time> single_display_pending_promos_; + // The impression history sorted by `day` (most recent -> least recent). std::vector<promos_manager::Impression> impression_history_;
diff --git a/ios/chrome/browser/promos_manager/promos_manager_impl.mm b/ios/chrome/browser/promos_manager/promos_manager_impl.mm index e5ff902..d5921233 100644 --- a/ios/chrome/browser/promos_manager/promos_manager_impl.mm +++ b/ios/chrome/browser/promos_manager/promos_manager_impl.mm
@@ -6,6 +6,7 @@ #import <Foundation/Foundation.h> +#import <algorithm> #import <iterator> #import <map> #import <numeric> @@ -13,6 +14,7 @@ #import <vector> #import "base/containers/contains.h" +#import "base/json/values_util.h" #import "base/metrics/histogram_functions.h" #import "base/time/time.h" #import "base/values.h" @@ -61,9 +63,11 @@ #pragma mark - Constructor/Destructor -PromosManagerImpl::PromosManagerImpl(PrefService* local_state) - : local_state_(local_state) { +PromosManagerImpl::PromosManagerImpl(PrefService* local_state, + base::Clock* clock) + : local_state_(local_state), clock_(clock) { DCHECK(local_state_); + DCHECK(clock_); } PromosManagerImpl::~PromosManagerImpl() = default; @@ -80,6 +84,9 @@ ActivePromos(local_state_->GetList(prefs::kIosPromosManagerActivePromos)); single_display_active_promos_ = ActivePromos( local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)); + + InitializePendingPromos(); + impression_history_ = ImpressionHistory( local_state_->GetList(prefs::kIosPromosManagerImpressions)); } @@ -102,9 +109,12 @@ impression_history_ = ImpressionHistory( local_state_->GetList(prefs::kIosPromosManagerImpressions)); - // Auto-deregister `promo` if it's a single-display promo. - if (single_display_active_promos_.find(promo) != - single_display_active_promos_.end()) { + // Auto-deregister `promo`. + // Edge case: Possible to remove two instances of promo in + // `single_display_active_promos_` and `single_display_pending_promos_` that + // match the same type. + if (base::Contains(single_display_active_promos_, promo) || + base::Contains(single_display_pending_promos_, promo)) { DeregisterPromo(promo); } } @@ -127,6 +137,24 @@ local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)); } +void PromosManagerImpl::RegisterPromoForSingleDisplay( + promos_manager::Promo promo, + base::TimeDelta becomes_active_after_period) { + DCHECK(local_state_); + + // update the pending promos saved in pref. + ScopedDictPrefUpdate pending_promos_update( + local_state_, prefs::kIosPromosManagerSingleDisplayPendingPromos); + std::string promo_name = promos_manager::NameForPromo(promo); + base::Time becomes_active_time = clock_->Now() + becomes_active_after_period; + pending_promos_update->Set(promo_name, + base::TimeToValue(becomes_active_time)); + + // keep the in-memory pending promos up-to-date to avoid reading from pref + // frequently. + single_display_pending_promos_[promo] = becomes_active_time; +} + void PromosManagerImpl::DeregisterPromo(promos_manager::Promo promo) { DCHECK(local_state_); @@ -134,9 +162,12 @@ local_state_, prefs::kIosPromosManagerActivePromos); ScopedListPrefUpdate single_display_promos_update( local_state_, prefs::kIosPromosManagerSingleDisplayActivePromos); + ScopedDictPrefUpdate pending_promos_update( + local_state_, prefs::kIosPromosManagerSingleDisplayPendingPromos); base::Value::List& active_promos = active_promos_update.Get(); base::Value::List& single_display_promos = single_display_promos_update.Get(); + base::Value::Dict& pending_promos = pending_promos_update.Get(); std::string promo_name = promos_manager::NameForPromo(promo); @@ -144,11 +175,13 @@ // promos lists. active_promos.EraseValue(base::Value(promo_name)); single_display_promos.EraseValue(base::Value(promo_name)); + pending_promos.Remove(promo_name); active_promos_ = ActivePromos(local_state_->GetList(prefs::kIosPromosManagerActivePromos)); single_display_active_promos_ = ActivePromos( local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos)); + single_display_pending_promos_.erase(promo); } void PromosManagerImpl::InitializePromoImpressionLimits( @@ -157,19 +190,41 @@ promo_impression_limits_ = std::move(promo_impression_limits); } -absl::optional<promos_manager::Promo> PromosManagerImpl::NextPromoForDisplay() - const { - // Construct a superset including active (1) single-display and - // (2) continuous-display promo campaigns. - std::set<promos_manager::Promo> all_active_promos(active_promos_); +// TODO: write unit test. +absl::optional<promos_manager::Promo> PromosManagerImpl::NextPromoForDisplay() { + // Construct a map with the promo from (1) single-display and + // (2) continuous-display promo campaigns. (3) single-display pending promos + // that has become active, as keys. The value is the context that will be used + // for ranking purpose. + std::map<promos_manager::Promo, PromoContext> active_promos_with_context; + for (const auto& promo : active_promos_) { + active_promos_with_context[promo] = PromoContext{ + .was_pending = false, + }; + } // Non-destructively insert the single-display promos into // `all_active_promos`. - all_active_promos.insert(single_display_active_promos_.begin(), - single_display_active_promos_.end()); + for (const auto& promo : single_display_active_promos_) { + active_promos_with_context[promo] = PromoContext{ + .was_pending = false, + }; + } + + // Insert the pending promos that have become active. + // Possibly overrides the same promo from `single_display_active_promos_`, as + // the pending promo has higher priority in current use cases. + const base::Time now = clock_->Now(); + for (const auto& [promo, time] : single_display_pending_promos_) { + if (time < now) { + active_promos_with_context[promo] = PromoContext{ + .was_pending = true, + }; + } + } std::vector<promos_manager::Promo> least_recently_shown_promos = - LeastRecentlyShown(all_active_promos, impression_history_); + LeastRecentlyShown(active_promos_with_context, impression_history_); if (least_recently_shown_promos.empty()) return absl::nullopt; @@ -181,8 +236,6 @@ return absl::nullopt; } -#pragma mark - Private - std::vector<promos_manager::Impression> PromosManagerImpl::ImpressionHistory( const base::Value::List& stored_impression_history) { std::vector<promos_manager::Impression> impression_history; @@ -214,7 +267,7 @@ } std::set<promos_manager::Promo> PromosManagerImpl::ActivePromos( - const base::Value::List& stored_active_promos) { + const base::Value::List& stored_active_promos) const { std::set<promos_manager::Promo> active_promos; for (size_t i = 0; i < stored_active_promos.size(); ++i) { @@ -231,6 +284,31 @@ return active_promos; } +// Should only be called in the `init` to avoid excessive reading from pref. +void PromosManagerImpl::InitializePendingPromos() { + DCHECK(local_state_); + + single_display_pending_promos_.clear(); + + const base::Value::Dict& stored_pending_promos = + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos); + + for (const auto [name, value] : stored_pending_promos) { + absl::optional<promos_manager::Promo> promo = + promos_manager::PromoForName(name); + // Skip malformed promo data. + if (!promo.has_value()) { + continue; + } + absl::optional<base::Time> becomes_active_time = ValueToTime(value); + // Skip malformed time data. + if (!becomes_active_time.has_value()) { + continue; + } + single_display_pending_promos_[promo.value()] = becomes_active_time.value(); + } +} + NSArray<ImpressionLimit*>* PromosManagerImpl::PromoImpressionLimits( promos_manager::Promo promo) const { auto it = promo_impression_limits_.find(promo); @@ -415,7 +493,7 @@ } std::vector<promos_manager::Promo> PromosManagerImpl::LeastRecentlyShown( - const std::set<promos_manager::Promo>& active_promos, + const std::map<promos_manager::Promo, PromoContext>& active_promos, const std::vector<promos_manager::Impression>& sorted_impressions) const { std::vector<promos_manager::Promo> active_promos_sorted_by_least_recently_shown; @@ -454,10 +532,9 @@ // // Never-before-seen promos are considered less recently seen than previously // seen promos. - for (promos_manager::Promo unseen_promo : active_promos) { - if (!base::Contains(active_promos_sorted_by_least_recently_shown, - unseen_promo)) { - active_promos_sorted_by_least_recently_shown.push_back(unseen_promo); + for (const auto& [name, _] : active_promos) { + if (!base::Contains(active_promos_sorted_by_least_recently_shown, name)) { + active_promos_sorted_by_least_recently_shown.push_back(name); } }
diff --git a/ios/chrome/browser/promos_manager/promos_manager_impl_unittest.mm b/ios/chrome/browser/promos_manager/promos_manager_impl_unittest.mm index 1f3ec78b..11bff9b7 100644 --- a/ios/chrome/browser/promos_manager/promos_manager_impl_unittest.mm +++ b/ios/chrome/browser/promos_manager/promos_manager_impl_unittest.mm
@@ -6,7 +6,9 @@ #import <set> #import <vector> +#import "base/json/values_util.h" #import "base/test/scoped_feature_list.h" +#import "base/test/simple_test_clock.h" #import "base/values.h" #import "components/prefs/pref_registry_simple.h" #import "components/prefs/testing_pref_service.h" @@ -24,6 +26,8 @@ #error "This file requires ARC support." #endif +using PromoContext = PromosManagerImpl::PromoContext; + namespace { // The number of days since the Unix epoch; one day, in this context, runs @@ -32,6 +36,10 @@ return (base::Time::Now() - base::Time::UnixEpoch()).InDays(); } +const base::TimeDelta kTimeDelta1Day = base::Days(1); +const PromoContext kPromoContextForActive = PromoContext{ + .was_pending = false, +}; } // namespace class PromosManagerImplTest : public PlatformTest { @@ -55,12 +63,15 @@ // Create pref registry for tests. void CreatePrefs(); + base::SimpleTestClock test_clock_; + std::unique_ptr<TestingPrefServiceSimple> local_state_; std::unique_ptr<PromosManagerImpl> promos_manager_; base::test::ScopedFeatureList scoped_feature_list_; }; PromosManagerImplTest::PromosManagerImplTest() { + test_clock_.SetNow(base::Time::Now()); scoped_feature_list_.InitWithFeatures({kFullscreenPromosManager}, {}); } PromosManagerImplTest::~PromosManagerImplTest() {} @@ -91,7 +102,8 @@ void PromosManagerImplTest::CreatePromosManager() { CreatePrefs(); - promos_manager_ = std::make_unique<PromosManagerImpl>(local_state_.get()); + promos_manager_ = + std::make_unique<PromosManagerImpl>(local_state_.get(), &test_clock_); promos_manager_->Init(); } @@ -105,6 +117,8 @@ prefs::kIosPromosManagerActivePromos); local_state_->registry()->RegisterListPref( prefs::kIosPromosManagerSingleDisplayActivePromos); + local_state_->registry()->RegisterDictionaryPref( + prefs::kIosPromosManagerSingleDisplayPendingPromos); } // Tests the initializer correctly creates a PromosManagerImpl* with the @@ -342,11 +356,12 @@ // Tests PromosManager::LeastRecentlyShown() correctly returns a list of active // promos sorted by least recently shown. TEST_F(PromosManagerImplTest, ReturnsLeastRecentlyShown) { - const std::set<promos_manager::Promo> active_promos = { - promos_manager::Promo::Test, - promos_manager::Promo::CredentialProviderExtension, - promos_manager::Promo::AppStoreRating, - promos_manager::Promo::DefaultBrowser, + const std::map<promos_manager::Promo, PromoContext> active_promos = { + {promos_manager::Promo::Test, kPromoContextForActive}, + {promos_manager::Promo::CredentialProviderExtension, + kPromoContextForActive}, + {promos_manager::Promo::AppStoreRating, kPromoContextForActive}, + {promos_manager::Promo::DefaultBrowser, kPromoContextForActive}, }; int today = TodaysDay(); @@ -376,9 +391,9 @@ // active / promos sorted by least recently shown (with some impressions / // belonging to inactive promo campaigns). TEST_F(PromosManagerImplTest, ReturnsLeastRecentlyShownWithSomeInactivePromos) { - const std::set<promos_manager::Promo> active_promos = { - promos_manager::Promo::Test, - promos_manager::Promo::AppStoreRating, + const std::map<promos_manager::Promo, PromoContext> active_promos = { + {promos_manager::Promo::Test, kPromoContextForActive}, + {promos_manager::Promo::AppStoreRating, kPromoContextForActive}, }; int today = TodaysDay(); @@ -405,11 +420,12 @@ // Tests PromosManager::LeastRecentlyShown() gracefully returns a list of // active / promos when multiple promos are tied for least recently shown. TEST_F(PromosManagerImplTest, ReturnsLeastRecentlyShownBreakingTies) { - const std::set<promos_manager::Promo> active_promos = { - promos_manager::Promo::Test, - promos_manager::Promo::CredentialProviderExtension, - promos_manager::Promo::AppStoreRating, - promos_manager::Promo::DefaultBrowser, + const std::map<promos_manager::Promo, PromoContext> active_promos = { + {promos_manager::Promo::Test, kPromoContextForActive}, + {promos_manager::Promo::CredentialProviderExtension, + kPromoContextForActive}, + {promos_manager::Promo::AppStoreRating, kPromoContextForActive}, + {promos_manager::Promo::DefaultBrowser, kPromoContextForActive}, }; int today = TodaysDay(); @@ -437,8 +453,8 @@ // in a list when the impression history contains only one active promo // campaign. TEST_F(PromosManagerImplTest, ReturnsLeastRecentlyShownWithOnlyOnePromoActive) { - const std::set<promos_manager::Promo> active_promos = { - promos_manager::Promo::Test, + const std::map<promos_manager::Promo, PromoContext> active_promos = { + {promos_manager::Promo::Test, kPromoContextForActive}, }; int today = TodaysDay(); @@ -465,8 +481,7 @@ // when there are no active promo campaigns. TEST_F(PromosManagerImplTest, ReturnsEmptyListWhenLeastRecentlyShownHasNoActivePromoCampaigns) { - const std::set<promos_manager::Promo> active_promos; - + const std::map<promos_manager::Promo, PromoContext> active_promos; int today = TodaysDay(); const std::vector<promos_manager::Impression> impressions = { @@ -489,7 +504,7 @@ // when no impression history and no active promos exist. TEST_F(PromosManagerImplTest, ReturnsEmptyListWhenLeastRecentlyShownHasNoImpressionHistory) { - const std::set<promos_manager::Promo> active_promos; + const std::map<promos_manager::Promo, PromoContext> active_promos; const std::vector<promos_manager::Impression> impressions; const std::vector<promos_manager::Promo> expected; @@ -501,11 +516,10 @@ // promos. TEST_F(PromosManagerImplTest, SortsUnshownPromosBeforeShownPromosForLeastRecentlyShown) { - const std::set<promos_manager::Promo> active_promos = { - promos_manager::Promo::Test, - promos_manager::Promo::CredentialProviderExtension, - promos_manager::Promo::AppStoreRating, - promos_manager::Promo::DefaultBrowser, + const std::map<promos_manager::Promo, PromoContext> active_promos = { + {promos_manager::Promo::Test, kPromoContextForActive}, + {promos_manager::Promo::AppStoreRating, kPromoContextForActive}, + {promos_manager::Promo::DefaultBrowser, kPromoContextForActive}, }; int today = TodaysDay(); @@ -517,7 +531,6 @@ }; const std::vector<promos_manager::Promo> expected = { - promos_manager::Promo::CredentialProviderExtension, promos_manager::Promo::AppStoreRating, promos_manager::Promo::DefaultBrowser, promos_manager::Promo::Test, @@ -663,6 +676,59 @@ EXPECT_EQ(expected, promos_manager_->ActivePromos(promos)); } +// Tests `InitializePendingPromos` initializes with pending promos. +TEST_F(PromosManagerImplTest, InitializePendingPromos) { + CreatePromosManager(); + + // write to Pref + base::Value::Dict promos; + promos.Set("promos_manager::Promo::DefaultBrowser", + base::TimeToValue(test_clock_.Now())); + promos.Set("promos_manager::Promo::AppStoreRating", + base::TimeToValue(test_clock_.Now())); + local_state_->SetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos, + std::move(promos)); + + std::map<promos_manager::Promo, base::Time> expected; + expected[promos_manager::Promo::DefaultBrowser] = test_clock_.Now(); + expected[promos_manager::Promo::AppStoreRating] = test_clock_.Now(); + + promos_manager_->InitializePendingPromos(); + + EXPECT_EQ(expected, promos_manager_->single_display_pending_promos_); +} + +// Tests `InitializePendingPromos` initializes empty Pref. +TEST_F(PromosManagerImplTest, InitializePendingPromosEmpty) { + CreatePromosManager(); + promos_manager_->InitializePendingPromos(); + std::map<promos_manager::Promo, base::Time> expected; + EXPECT_EQ(expected, promos_manager_->single_display_pending_promos_); +} + +// Tests `InitializePendingPromos` initializes with malformed data with +// malformed entries pruned. +TEST_F(PromosManagerImplTest, InitializePendingPromosMalformedData) { + CreatePromosManager(); + + // write to Pref + base::Value::Dict promos; + promos.Set("promos_manager::Promo::DefaultBrowser", + base::TimeToValue(test_clock_.Now())); + promos.Set("promos_manager::Promo::Foo", + base::TimeToValue(test_clock_.Now())); + promos.Set("promos_manager::Promo::AppStoreRating", base::Value(1)); + local_state_->SetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos, + std::move(promos)); + + std::map<promos_manager::Promo, base::Time> expected; + expected[promos_manager::Promo::DefaultBrowser] = test_clock_.Now(); + + promos_manager_->InitializePendingPromos(); + + EXPECT_EQ(expected, promos_manager_->single_display_pending_promos_); +} + // Tests PromosManager::RegisterPromoForContinuousDisplay() correctly registers // a promo for continuous display by writing the promo's name to the pref // `kIosPromosManagerActivePromos`. @@ -838,6 +904,58 @@ promos_manager::NameForPromo(promos_manager::Promo::DefaultBrowser)); } +// Tests `RegisterPromoForSingleDisplay` with `becomes_active_after_period` +// registers a promo for single display by writing the promo's name and the +// calculated time to the pref `kIosPromosManagerSingleDisplayPendingPromos`. +TEST_F(PromosManagerImplTest, + RegistersPromoForSingleDisplayWithBecomesActivePeriod) { + CreatePromosManager(); + EXPECT_TRUE( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .empty()); + + // Initial state: 1 active promo, 0 pending promo. + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::AppStoreRating); + EXPECT_EQ( + local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos) + .size(), + (size_t)1); + EXPECT_EQ( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .size(), + (size_t)0); + + // Register new promo with becomes_active_period. + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::CredentialProviderExtension, kTimeDelta1Day); + + // End state: 1 active promo, 1 pending promo. + EXPECT_EQ( + local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos) + .size(), + (size_t)1); + EXPECT_EQ( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .size(), + (size_t)1); + + // Active promo in Pref doesn't change. + EXPECT_EQ( + local_state_->GetList( + prefs::kIosPromosManagerSingleDisplayActivePromos)[0], + promos_manager::NameForPromo(promos_manager::Promo::AppStoreRating)); + + // Pending promo in Pref is updated with the correct time. + absl::optional<base::Time> actual_becomes_active_time = ValueToTime( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .Find(promos_manager::NameForPromo( + promos_manager::Promo::CredentialProviderExtension))); + EXPECT_TRUE(actual_becomes_active_time.has_value()); + EXPECT_EQ(actual_becomes_active_time.value(), + test_clock_.Now() + kTimeDelta1Day); +} + // Tests PromosManager::RegisterPromoForSingleDisplay() correctly registers // a promo for single display by writing the promo's name to the pref // `kIosPromosManagerSingleDisplayActivePromos` and immediately updates @@ -863,6 +981,31 @@ EXPECT_EQ(promos_manager_->single_display_active_promos_.size(), (size_t)3); } +// Tests `RegisterPromoForSingleDisplay` with `becomes_active_after_period` +// registers a promo for single display by writing the promo's name and the +// calculated time to the pref `kIosPromosManagerSingleDisplayActivePromos` +// and updates single_display_pending_promos_. +TEST_F( + PromosManagerImplTest, + RegistersPromoForSingleDisplayWithBecomesActivePeriodAndUpdateVariables) { + CreatePromosManager(); + EXPECT_TRUE( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .empty()); + + // Register + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::CredentialProviderExtension, kTimeDelta1Day); + + // End state: 0 active promo, 1 pending promo + EXPECT_EQ(promos_manager_->single_display_active_promos_.size(), (size_t)0); + EXPECT_EQ(promos_manager_->single_display_pending_promos_.size(), (size_t)1); + base::Time actual_becomes_active_time = + promos_manager_->single_display_pending_promos_ + [promos_manager::Promo::CredentialProviderExtension]; + EXPECT_EQ(actual_becomes_active_time, (test_clock_.Now() + kTimeDelta1Day)); +} + // Tests PromosManager::RegisterPromoForSingleDisplay() correctly registers // a promo for single display—for the very first time—by writing the promo's // name to the pref `kIosPromosManagerSingleDisplayActivePromos`. @@ -955,6 +1098,39 @@ promos_manager::Promo::CredentialProviderExtension)); } +// Tests `RegisterPromoForSingleDisplay` with `becomes_active_after_period` +// correctly registers an already-registered promo for single display by +// overriding the existing entry in the pref +// `kIosPromosManagerSingleDisplayPendingPromos`. +TEST_F(PromosManagerImplTest, + RegistersAlreadyRegisteredPromoForSingleDisplayWithBecomesActiveTime) { + CreatePromosManager(); + EXPECT_TRUE( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .empty()); + + // Initial pending promos state. + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::CredentialProviderExtension, kTimeDelta1Day); + + // Register the same promo. + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::CredentialProviderExtension, kTimeDelta1Day * 2); + + // End state: only the second registered promo is in the pref. + EXPECT_EQ( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .size(), + (size_t)1); + absl::optional<base::Time> actual_becomes_active_time = ValueToTime( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .Find(promos_manager::NameForPromo( + promos_manager::Promo::CredentialProviderExtension))); + EXPECT_TRUE(actual_becomes_active_time.has_value()); + EXPECT_EQ(actual_becomes_active_time.value(), + test_clock_.Now() + kTimeDelta1Day * 2); +} + // Tests PromosManager::InitializePromoImpressionLimits() correctly registers // promo-specific impression limits. TEST_F(PromosManagerImplTest, RegistersPromoSpecificImpressionLimits) { @@ -1034,8 +1210,9 @@ EXPECT_EQ(promos_manager_->impression_history_.size(), (size_t)2); } -// Tests PromosManager::DeregisterPromo() correctly deregisters a currently -// active promo campaign. +// Tests PromosManager::DeregisterPromo() deregisters a promo, all the entries +// with the same promo type in the Pref/in-memory variables will be removed, +// regardless of the context of being single/continuous or active/pending. TEST_F(PromosManagerImplTest, DeregistersActivePromo) { CreatePromosManager(); @@ -1045,36 +1222,44 @@ local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos) .size(), (size_t)0); - - promos_manager_->RegisterPromoForContinuousDisplay( - promos_manager::Promo::CredentialProviderExtension); - - EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(), - (size_t)1); EXPECT_EQ( - local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos) + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) .size(), (size_t)0); - promos_manager_->RegisterPromoForSingleDisplay( + promos_manager_->RegisterPromoForContinuousDisplay( promos_manager::Promo::CredentialProviderExtension); - EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(), (size_t)1); + + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::CredentialProviderExtension); EXPECT_EQ( local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos) .size(), (size_t)1); + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::CredentialProviderExtension, kTimeDelta1Day); + EXPECT_EQ( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .size(), + (size_t)1); + promos_manager_->DeregisterPromo( promos_manager::Promo::CredentialProviderExtension); + // all entries with the same type are removed. EXPECT_EQ(local_state_->GetList(prefs::kIosPromosManagerActivePromos).size(), (size_t)0); EXPECT_EQ( local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos) .size(), (size_t)0); + EXPECT_EQ( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .size(), + (size_t)0); } // Tests PromosManager::DeregisterPromo() correctly deregisters a currently @@ -1090,28 +1275,41 @@ local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos) .size(), (size_t)0); + EXPECT_EQ( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .size(), + (size_t)0); promos_manager_->RegisterPromoForContinuousDisplay( promos_manager::Promo::CredentialProviderExtension); EXPECT_EQ(promos_manager_->active_promos_.size(), (size_t)1); EXPECT_EQ(promos_manager_->single_display_active_promos_.size(), (size_t)0); + EXPECT_EQ(promos_manager_->single_display_pending_promos_.size(), (size_t)0); promos_manager_->RegisterPromoForSingleDisplay( promos_manager::Promo::CredentialProviderExtension); EXPECT_EQ(promos_manager_->active_promos_.size(), (size_t)1); EXPECT_EQ(promos_manager_->single_display_active_promos_.size(), (size_t)1); + EXPECT_EQ(promos_manager_->single_display_pending_promos_.size(), (size_t)0); + + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::CredentialProviderExtension, kTimeDelta1Day); + EXPECT_EQ(promos_manager_->active_promos_.size(), (size_t)1); + EXPECT_EQ(promos_manager_->single_display_pending_promos_.size(), (size_t)1); + EXPECT_EQ(promos_manager_->single_display_active_promos_.size(), (size_t)1); promos_manager_->DeregisterPromo( promos_manager::Promo::CredentialProviderExtension); EXPECT_EQ(promos_manager_->active_promos_.size(), (size_t)0); EXPECT_EQ(promos_manager_->single_display_active_promos_.size(), (size_t)0); + EXPECT_EQ(promos_manager_->single_display_pending_promos_.size(), (size_t)0); } -// Tests PromosManager::DeregisterPromo() gracefully handles deregistration if -// the promo doesn't exist in a given active promos list. +// Tests PromosManager::DeregisterPromo() handles the situation where the promo +// doesn't exist in a given active promos list by removing from all lists. TEST_F(PromosManagerImplTest, DeregistersNonExistentPromo) { CreatePromosManager(); @@ -1169,3 +1367,30 @@ local_state_->GetList(prefs::kIosPromosManagerSingleDisplayActivePromos) .empty()); } + +// Tests a given single-display pending promo is automatically deregistered +// after its impression is recorded. +TEST_F(PromosManagerImplTest, + DeregistersSingleDisplayPendingPromoAfterRecordedImpression) { + CreatePromosManager(); + + EXPECT_TRUE( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .empty()); + + // Initial active promos state. + promos_manager_->RegisterPromoForSingleDisplay( + promos_manager::Promo::CredentialProviderExtension, kTimeDelta1Day); + + EXPECT_EQ( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .size(), + (size_t)1); + + promos_manager_->RecordImpression( + promos_manager::Promo::CredentialProviderExtension); + + EXPECT_TRUE( + local_state_->GetDict(prefs::kIosPromosManagerSingleDisplayPendingPromos) + .empty()); +}
diff --git a/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_coordinator.mm index 776c0541..c0461e4d 100644 --- a/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_coordinator.mm +++ b/ios/chrome/browser/ui/authentication/signin/forced_signin/forced_signin_coordinator.mm
@@ -110,7 +110,7 @@ - (InterruptibleChromeCoordinator*)createChildCoordinatorWithScreenType: (ScreenType)type { switch (type) { - case kLegacySignIn: + case kLegacySignIn_DEPRECATED: return [[LegacySigninScreenCoordinator alloc] initWithBaseNavigationController:self.navigationController browser:self.browser @@ -121,9 +121,9 @@ browser:self.browser showFREConsent:NO delegate:self]; - case kSignInAndSync: + case kSignInAndSync_DEPRECATED: case kTangibleSync: - case kWelcomeAndConsent: + case kWelcomeAndConsent_DEPRECATED: case kDefaultBrowserPromo: case kStepsCompleted: NOTREACHED() << "Type of screen not supported." << static_cast<int>(type);
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_screen_provider.mm b/ios/chrome/browser/ui/authentication/signin/signin_screen_provider.mm index 1a08155..552b6e8 100644 --- a/ios/chrome/browser/ui/authentication/signin/signin_screen_provider.mm +++ b/ios/chrome/browser/ui/authentication/signin/signin_screen_provider.mm
@@ -4,7 +4,6 @@ #import "ios/chrome/browser/ui/authentication/signin/signin_screen_provider.h" -#import "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/screen/screen_provider+protected.h" #import "ios/chrome/browser/ui/screen/screen_type.h" @@ -16,14 +15,7 @@ - (instancetype)init { NSMutableArray* screens = [NSMutableArray array]; - switch (fre_field_trial::GetNewMobileIdentityConsistencyFRE()) { - case NewMobileIdentityConsistencyFRE::kTangibleSyncA: - [screens addObject:@(kSignIn)]; - break; - case NewMobileIdentityConsistencyFRE::kOld: - [screens addObject:@(kLegacySignIn)]; - break; - } + [screens addObject:@(kSignIn)]; [screens addObject:@(kStepsCompleted)]; return [super initWithScreens:screens]; }
diff --git a/ios/chrome/browser/ui/authentication/tangible_sync/tangible_sync_view_controller.mm b/ios/chrome/browser/ui/authentication/tangible_sync/tangible_sync_view_controller.mm index 42c1536..4c38777 100644 --- a/ios/chrome/browser/ui/authentication/tangible_sync/tangible_sync_view_controller.mm +++ b/ios/chrome/browser/ui/authentication/tangible_sync/tangible_sync_view_controller.mm
@@ -9,7 +9,6 @@ #import "components/signin/public/base/signin_metrics.h" #import "ios/chrome/browser/ui/authentication/signin/signin_constants.h" #import "ios/chrome/browser/ui/elements/instruction_view.h" -#import "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/icons/symbols.h" #import "ios/chrome/common/ui/util/constraints_ui_util.h" #import "ios/chrome/grit/ios_strings.h" @@ -80,16 +79,9 @@ self.avatarAccessibilityLabel = self.primaryIdentityAvatarAccessibilityLabel; int titleStringID = 0; int subtitleStringID = 0; - switch (fre_field_trial::GetNewMobileIdentityConsistencyFRE()) { - case NewMobileIdentityConsistencyFRE::kTangibleSyncA: - titleStringID = IDS_IOS_TANGIBLE_SYNC_TITLE_TURN_ON_SYNC; - subtitleStringID = IDS_IOS_TANGIBLE_SYNC_SUBTITLE_BACK_UP; - _activateSyncButtonID = IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON; - break; - case NewMobileIdentityConsistencyFRE::kOld: - NOTREACHED(); - break; - } + titleStringID = IDS_IOS_TANGIBLE_SYNC_TITLE_TURN_ON_SYNC; + subtitleStringID = IDS_IOS_TANGIBLE_SYNC_SUBTITLE_BACK_UP; + _activateSyncButtonID = IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON; DCHECK_NE(0, titleStringID); DCHECK_NE(0, subtitleStringID); [self.delegate addConsentStringID:titleStringID];
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn index 2c7ab429..679223ca1 100644 --- a/ios/chrome/browser/ui/bookmarks/BUILD.gn +++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -5,15 +5,15 @@ source_set("bookmarks") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "bookmark_interaction_controller.h", - "bookmark_interaction_controller.mm", - "bookmark_interaction_controller_delegate.h", "bookmark_navigation_controller.h", "bookmark_navigation_controller.mm", "bookmark_navigation_controller_delegate.h", "bookmark_navigation_controller_delegate.mm", "bookmark_promo_controller.h", "bookmark_promo_controller.mm", + "bookmarks_coordinator.h", + "bookmarks_coordinator.mm", + "bookmarks_coordinator_delegate.h", "bookmarks_home_consumer.h", "bookmarks_home_mediator.h", "bookmarks_home_mediator.mm", @@ -65,6 +65,7 @@ "//ios/chrome/browser/ui/bookmarks/folder_chooser", "//ios/chrome/browser/ui/bookmarks/folder_editor", "//ios/chrome/browser/ui/commands", + "//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/default_promo:utils", "//ios/chrome/browser/ui/elements", "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h deleted file mode 100644 index 1211973..0000000 --- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2013 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_INTERACTION_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_INTERACTION_CONTROLLER_H_ - -#import <UIKit/UIKit.h> - -#import "ios/chrome/browser/ui/commands/bookmarks_commands.h" - -class Browser; -@protocol BookmarkInteractionControllerDelegate; - -namespace bookmarks { -class BookmarkNode; -} - -class GURL; - -namespace web { -class WebState; -} - -// The BookmarkInteractionController abstracts the management of the various -// UIViewControllers used to create, remove and edit a bookmark. -@interface BookmarkInteractionController : NSObject <BookmarksCommands> - -// This object's delegate. -@property(nonatomic, weak) id<BookmarkInteractionControllerDelegate> delegate; - -// The parent controller on top of which the UI needs to be presented. -@property(nonatomic, weak) UIViewController* parentController; - -- (instancetype)initWithBrowser:(Browser*)browser NS_DESIGNATED_INITIALIZER; -- (instancetype)init NS_UNAVAILABLE; - -// Called before the instance is deallocated. -- (void)shutdown; - -// Adds a bookmark for `URL` with the given `title`. -- (void)bookmarkURL:(const GURL&)URL title:(NSString*)title; - -// Presents the bookmark UI to edit an existing bookmark with `URL`. -- (void)presentBookmarkEditorForURL:(const GURL&)URL; - -// Presents the bookmarks browser modally. -- (void)presentBookmarks; - -// Presents the bookmark or folder editor for the given `node`. -- (void)presentEditorForNode:(const bookmarks::BookmarkNode*)node; - -// Removes any bookmark modal controller from view if visible. -// override this method. -- (void)dismissBookmarkModalControllerAnimated:(BOOL)animated; - -// Removes any snackbar related to bookmarks that could have been presented. -- (void)dismissSnackbar; - -@end - -#endif // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_INTERACTION_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller_delegate.h b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller_delegate.h deleted file mode 100644 index eeaf7945..0000000 --- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller_delegate.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_INTERACTION_CONTROLLER_DELEGATE_H_ -#define IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_INTERACTION_CONTROLLER_DELEGATE_H_ - -@class BookmarkInteractionController; - -// BookmarkInteractionControllerDelegate provides methods for the controller to -// notify its delegate when certain events occur. -@protocol BookmarkInteractionControllerDelegate - -// Called when the controller is going to commit the title or URL change. -- (void)bookmarkInteractionControllerWillCommitTitleOrUrlChange: - (BookmarkInteractionController*)controller; - -// Called when the controller is stopped and the receiver can safely free any -// references to `controller`. -- (void)bookmarkInteractionControllerDidStop: - (BookmarkInteractionController*)controller; - -@end - -#endif // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_INTERACTION_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h new file mode 100644 index 0000000..8855394 --- /dev/null +++ b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h
@@ -0,0 +1,62 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARKS_COORDINATOR_H_ +#define IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARKS_COORDINATOR_H_ + +#import <UIKit/UIKit.h> + +#import "ios/chrome/browser/ui/commands/bookmarks_commands.h" +#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" + +class Browser; +@protocol BookmarksCoordinatorDelegate; + +namespace bookmarks { +class BookmarkNode; +} + +class GURL; + +// The BookmarksCoordinator abstracts the management of the various +// pieces of UI used to create, remove and edit a bookmark. +@interface BookmarksCoordinator : ChromeCoordinator <BookmarksCommands> + +// This object's delegate. +@property(nonatomic, weak) id<BookmarksCoordinatorDelegate> delegate; + +// The base view controller for this coordinator +@property(nonatomic, weak, readwrite) UIViewController* baseViewController; + +// Initializes this Coordinator with its `browser` and a nil base view +// controller. +- (instancetype)initWithBrowser:(Browser*)browser NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browser:(Browser*)browser NS_UNAVAILABLE; + +// Called before the instance is deallocated. +- (void)shutdown; + +// Adds a bookmark for `URL` with the given `title`. +- (void)bookmarkURL:(const GURL&)URL title:(NSString*)title; + +// Presents the bookmark UI to edit an existing bookmark with `URL`. +- (void)presentBookmarkEditorForURL:(const GURL&)URL; + +// Presents the bookmarks browser modally. +- (void)presentBookmarks; + +// Presents the bookmark or folder editor for the given `node`. +- (void)presentEditorForNode:(const bookmarks::BookmarkNode*)node; + +// Removes any bookmark modal controller from view if visible. +// override this method. +- (void)dismissBookmarkModalControllerAnimated:(BOOL)animated; + +// Removes any snackbar related to bookmarks that could have been presented. +- (void)dismissSnackbar; + +@end + +#endif // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARKS_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm similarity index 95% rename from ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm rename to ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm index 88577b0..1daff83 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
@@ -1,8 +1,8 @@ -// Copyright 2013 The Chromium Authors +// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" +#import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h" #import <stdint.h> @@ -22,12 +22,12 @@ #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/metrics/new_tab_page_uma.h" #import "ios/chrome/browser/tabs/tab_title_util.h" -#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller_delegate.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_path_cache.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" +#import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator_delegate.h" #import "ios/chrome/browser/ui/bookmarks/bookmarks_home_view_controller.h" #import "ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_view_controller.h" #import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_view_controller.h" @@ -68,7 +68,7 @@ } // namespace -@interface BookmarkInteractionController () < +@interface BookmarksCoordinator () < BookmarksEditorViewControllerDelegate, BookmarksFolderEditorViewControllerDelegate, BookmarksFolderChooserViewControllerDelegate, @@ -148,9 +148,10 @@ @end -@implementation BookmarkInteractionController +@implementation BookmarksCoordinator @synthesize applicationCommandsHandler = _applicationCommandsHandler; @synthesize snackbarCommandsHandler = _snackbarCommandsHandler; +@synthesize baseViewController = _baseViewController; @synthesize bookmarkBrowser = _bookmarkBrowser; @synthesize bookmarkEditor = _bookmarkEditor; @synthesize bookmarkModel = _bookmarkModel; @@ -163,7 +164,7 @@ @synthesize mediator = _mediator; - (instancetype)initWithBrowser:(Browser*)browser { - self = [super init]; + self = [super initWithBaseViewController:nil browser:browser]; if (self) { _browser = browser; // Bookmarks are always opened with the main browser state, even in @@ -223,7 +224,7 @@ return; } - __weak BookmarkInteractionController* weakSelf = self; + __weak BookmarksCoordinator* weakSelf = self; // Copy of `URL` to be captured in block. GURL bookmarkedURL(URL); void (^editAction)() = ^{ @@ -381,9 +382,9 @@ newTab:newTab]; }; - if (_parentController.presentedViewController) { - [_parentController dismissViewControllerAnimated:animated - completion:completion]; + if (self.baseViewController.presentedViewController) { + [self.baseViewController dismissViewControllerAnimated:animated + completion:completion]; } else { completion(); } @@ -481,7 +482,7 @@ - (void)bookmarkEditorWillCommitTitleOrUrlChange: (BookmarksEditorViewController*)controller { - [self.delegate bookmarkInteractionControllerWillCommitTitleOrUrlChange:self]; + [self.delegate bookmarksCoordinatorWillCommitTitleOrURLChange:self]; } #pragma mark - BookmarksFolderEditorViewControllerDelegate @@ -504,7 +505,7 @@ - (void)bookmarkFolderEditorWillCommitTitleChange: (BookmarksFolderEditorViewController*)controller { - [self.delegate bookmarkInteractionControllerWillCommitTitleOrUrlChange:self]; + [self.delegate bookmarksCoordinatorWillCommitTitleOrURLChange:self]; } #pragma mark - BookmarksFolderChooserViewControllerDelegate @@ -615,10 +616,10 @@ return; } - __weak BookmarkInteractionController* weakSelf = self; + __weak BookmarksCoordinator* weakSelf = self; [self presentFolderPickerWithCompletion:^( const bookmarks::BookmarkNode* folder) { - BookmarkInteractionController* strongSelf = weakSelf; + BookmarksCoordinator* strongSelf = weakSelf; if (folder && strongSelf) { [strongSelf.snackbarCommandsHandler showSnackbarMessage:[strongSelf.mediator addBookmarks:command.URLs @@ -655,9 +656,9 @@ [navController setModalPresentationStyle:UIModalPresentationFormSheet]; - [_parentController presentViewController:navController - animated:YES - completion:nil]; + [self.baseViewController presentViewController:navController + animated:YES + completion:nil]; } - (void)openURLInCurrentTab:(const GURL&)url {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator_delegate.h b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator_delegate.h new file mode 100644 index 0000000..dba486b --- /dev/null +++ b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator_delegate.h
@@ -0,0 +1,24 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARKS_COORDINATOR_DELEGATE_H_ +#define IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARKS_COORDINATOR_DELEGATE_H_ + +@class BookmarksCoordinator; + +// BookmarksCoordinatorDelegate provides methods for the coordinator to +// notify its delegate when certain events occur. +@protocol BookmarksCoordinatorDelegate + +// Called when the coordinator is going to commit the title or URL change. +- (void)bookmarksCoordinatorWillCommitTitleOrURLChange: + (BookmarksCoordinator*)coordinator; + +// Called when the coordinator is stopped and the receiver can safely free any +// references to `coordinator`. +- (void)bookmarksCoordinatorDidStop:(BookmarksCoordinator*)coordinator; + +@end + +#endif // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARKS_COORDINATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_home_view_controller.mm index a7555b7..c3ce85d5 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmarks_home_view_controller.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmarks_home_view_controller.mm
@@ -34,12 +34,12 @@ #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h" #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_configurator.h" #import "ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h" -#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" -#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller_delegate.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_path_cache.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h" +#import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h" +#import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator_delegate.h" #import "ios/chrome/browser/ui/bookmarks/bookmarks_home_consumer.h" #import "ios/chrome/browser/ui/bookmarks/bookmarks_home_mediator.h" #import "ios/chrome/browser/ui/bookmarks/bookmarks_home_shared_state.h" @@ -124,10 +124,10 @@ } // namespace @interface BookmarksHomeViewController () < + BookmarksCoordinatorDelegate, BookmarksFolderChooserViewControllerDelegate, BookmarksHomeConsumer, BookmarksHomeSharedStateObserver, - BookmarkInteractionControllerDelegate, BookmarkModelBridgeObserver, BookmarkTableCellTitleEditDelegate, TableViewURLDragDataSource, @@ -207,8 +207,7 @@ // The action sheet coordinator, if one is currently being shown. @property(nonatomic, strong) AlertCoordinator* actionSheetCoordinator; -@property(nonatomic, strong) - BookmarkInteractionController* bookmarkInteractionController; +@property(nonatomic, strong) BookmarksCoordinator* bookmarksCoordinator; @property(nonatomic, assign) WebStateList* webStateList; @@ -250,8 +249,8 @@ } - (void)shutdown { - [_bookmarkInteractionController shutdown]; - _bookmarkInteractionController = nil; + [_bookmarksCoordinator shutdown]; + _bookmarksCoordinator = nil; [self.mediator disconnect]; _sharedState.tableView.dataSource = nil; @@ -662,14 +661,14 @@ // Opens the editor on the given node. - (void)editNode:(const BookmarkNode*)node { - if (!self.bookmarkInteractionController) { - self.bookmarkInteractionController = - [[BookmarkInteractionController alloc] initWithBrowser:self.browser]; - self.bookmarkInteractionController.parentController = self; - self.bookmarkInteractionController.delegate = self; + if (!self.bookmarksCoordinator) { + self.bookmarksCoordinator = + [[BookmarksCoordinator alloc] initWithBrowser:self.browser]; + self.bookmarksCoordinator.baseViewController = self; + self.bookmarksCoordinator.delegate = self; } - [self.bookmarkInteractionController presentEditorForNode:node]; + [self.bookmarksCoordinator presentEditorForNode:node]; } - (void)openAllURLs:(std::vector<GURL>)urls @@ -917,17 +916,16 @@ self.folderSelector = nil; } -#pragma mark - BookmarkInteractionControllerDelegate +#pragma mark - BookmarksCoordinatorDelegate -- (void)bookmarkInteractionControllerWillCommitTitleOrUrlChange: - (BookmarkInteractionController*)controller { +- (void)bookmarksCoordinatorWillCommitTitleOrURLChange: + (BookmarksCoordinator*)coordinator { [self setTableViewEditing:NO]; } -- (void)bookmarkInteractionControllerDidStop: - (BookmarkInteractionController*)controller { +- (void)bookmarksCoordinatorDidStop:(BookmarksCoordinator*)coordinator { // TODO(crbug.com/805182): Use this method to tear down - // `self.bookmarkInteractionController`. + // `self.bookmarksCoordinator`. } #pragma mark - BookmarkModelBridgeObserver
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm index 65b184c..4a54fe6 100644 --- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm +++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -55,7 +55,7 @@ #import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.h" #import "ios/chrome/browser/ui/badges/badge_popup_menu_coordinator.h" -#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" +#import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h" #import "ios/chrome/browser/ui/browser_container/browser_container_coordinator.h" #import "ios/chrome/browser/ui/browser_container/browser_container_view_controller.h" #import "ios/chrome/browser/ui/browser_view/browser_coordinator+private.h" @@ -435,7 +435,7 @@ FullscreenController* _fullscreenController; // The coordinator that shows the Send Tab To Self UI. SendTabToSelfCoordinator* _sendTabToSelfCoordinator; - BookmarkInteractionController* _bookmarkInteractionController; + BookmarksCoordinator* _bookmarksCoordinator; id<TextZoomCommands> _textZoomHandler; id<HelpCommands> _helpHandler; id<PopupMenuCommands> _popupMenuCommandsHandler; @@ -724,8 +724,8 @@ _sideSwipeController.secondaryToolbarSnapshotProvider = _secondaryToolbarCoordinator; - _bookmarkInteractionController = - [[BookmarkInteractionController alloc] initWithBrowser:self.browser]; + _bookmarksCoordinator = + [[BookmarksCoordinator alloc] initWithBrowser:self.browser]; self.browserContainerCoordinator = [[BrowserContainerCoordinator alloc] initWithBaseViewController:nil @@ -799,8 +799,7 @@ _viewControllerDependencies.legacyTabStripCoordinator = _legacyTabStripCoordinator; _viewControllerDependencies.sideSwipeController = _sideSwipeController; - _viewControllerDependencies.bookmarkInteractionController = - _bookmarkInteractionController; + _viewControllerDependencies.bookmarksCoordinator = _bookmarksCoordinator; _viewControllerDependencies.fullscreenController = _fullscreenController; _viewControllerDependencies.textZoomHandler = _textZoomHandler; _viewControllerDependencies.helpHandler = _helpHandler; @@ -811,7 +810,7 @@ } - (void)updateViewControllerDependencies { - _bookmarkInteractionController.parentController = self.viewController; + _bookmarksCoordinator.baseViewController = self.viewController; _bubblePresenter.delegate = self.viewController; _bubblePresenter.rootViewController = self.viewController; @@ -854,10 +853,10 @@ _viewControllerDependencies.sideSwipeController = nil; _viewControllerDependencies.textZoomHandler = nil; _viewControllerDependencies.helpHandler = nil; - _viewControllerDependencies.bookmarkInteractionController = nil; + _viewControllerDependencies.bookmarksCoordinator = nil; - [_bookmarkInteractionController shutdown]; - _bookmarkInteractionController = nil; + [_bookmarksCoordinator shutdown]; + _bookmarksCoordinator = nil; _textZoomHandler = nil; _helpHandler = nil; @@ -1281,7 +1280,7 @@ } - (void)showBookmarksManager { - [_bookmarkInteractionController presentBookmarks]; + [_bookmarksCoordinator presentBookmarks]; } - (void)showFollowWhileBrowsingIPH { @@ -1531,16 +1530,17 @@ - (void)closeFindInPage { web::WebState* currentWebState = self.browser->GetWebStateList()->GetActiveWebState(); + if (!currentWebState) { + return; + } - if (currentWebState) { - JavaScriptFindTabHelper* helper = - JavaScriptFindTabHelper::FromWebState(currentWebState); - if (helper->IsFindUIActive()) { - helper->StopFinding(); - } else { - [self.findBarCoordinator stop]; - self.findBarCoordinator = nil; - } + auto* helper = GetConcreteFindTabHelperFromWebState(currentWebState); + DCHECK(helper); + if (helper->IsFindUIActive()) { + helper->StopFinding(); + } else { + [self.findBarCoordinator stop]; + self.findBarCoordinator = nil; } }
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.h b/ios/chrome/browser/ui/browser_view/browser_view_controller.h index 711a0b1..f98341fd 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.h +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
@@ -24,7 +24,7 @@ #import "ios/chrome/browser/web/web_state_container_view_provider.h" class Browser; -@class BookmarkInteractionController; +@class BookmarksCoordinator; @class BrowserContainerViewController; @class BubblePresenter; @class CommandDispatcher; @@ -64,7 +64,7 @@ TabStripCoordinator* tabStripCoordinator; TabStripLegacyCoordinator* legacyTabStripCoordinator; SideSwipeController* sideSwipeController; - BookmarkInteractionController* bookmarkInteractionController; + BookmarksCoordinator* bookmarksCoordinator; FullscreenController* fullscreenController; id<TextZoomCommands> textZoomHandler; id<HelpCommands> helpHandler;
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm index 349a054..cf4940f 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -46,7 +46,7 @@ #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" #import "ios/chrome/browser/tabs/tab_title_util.h" #import "ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h" -#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" +#import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h" #import "ios/chrome/browser/ui/browser_container/browser_container_view_controller.h" #import "ios/chrome/browser/ui/bubble/bubble_presenter.h" #import "ios/chrome/browser/ui/bubble/bubble_presenter_delegate.h" @@ -290,9 +290,9 @@ // The time at which `_lastTapPoint` was most recently set. CFTimeInterval _lastTapTime; - // The controller that shows the bookmarking UI after the user taps the star + // The coordinator that shows the bookmarking UI after the user taps the star // button. - BookmarkInteractionController* _bookmarkInteractionController; + BookmarksCoordinator* _bookmarksCoordinator; // Toolbar state that broadcasts changes to min and max heights. ToolbarUIState* _toolbarUIState; @@ -478,7 +478,7 @@ _prerenderService = dependencies.prerenderService; _sideSwipeController = dependencies.sideSwipeController; [_sideSwipeController setSwipeDelegate:self]; - _bookmarkInteractionController = dependencies.bookmarkInteractionController; + _bookmarksCoordinator = dependencies.bookmarksCoordinator; self.bubblePresenter = dependencies.bubblePresenter; self.toolbarAccessoryPresenter = dependencies.toolbarAccessoryPresenter; self.ntpCoordinator = dependencies.ntpCoordinator; @@ -905,8 +905,8 @@ // TODO(crbug.com/1329111): Federate ClearPresentedState. - (void)clearPresentedStateWithCompletion:(ProceduralBlock)completion dismissOmnibox:(BOOL)dismissOmnibox { - [_bookmarkInteractionController dismissBookmarkModalControllerAnimated:NO]; - [_bookmarkInteractionController dismissSnackbar]; + [_bookmarksCoordinator dismissBookmarkModalControllerAnimated:NO]; + [_bookmarksCoordinator dismissSnackbar]; if (dismissOmnibox) { [self.omniboxHandler cancelOmniboxEdit]; } @@ -1019,7 +1019,7 @@ _fullscreenDisabler = nullptr; [[NSNotificationCenter defaultCenter] removeObserver:self]; - _bookmarkInteractionController = nil; + _bookmarksCoordinator = nil; } #pragma mark - NSObject @@ -1197,7 +1197,7 @@ activeWebState->SetKeepRenderProcessAlive(false); } - [_bookmarkInteractionController dismissSnackbar]; + [_bookmarksCoordinator dismissSnackbar]; [super viewWillDisappear:animated]; } @@ -2626,7 +2626,7 @@ - (void)tabWillLoadURL:(GURL)URL transitionType:(ui::PageTransition)transitionType { - [_bookmarkInteractionController dismissBookmarkModalControllerAnimated:YES]; + [_bookmarksCoordinator dismissBookmarkModalControllerAnimated:YES]; WebStateList* webStateList = self.browser->GetWebStateList(); web::WebState* current_web_state = webStateList->GetActiveWebState();
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm index eda6c51..80922291 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
@@ -28,7 +28,7 @@ #import "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/signin/fake_authentication_service_delegate.h" #import "ios/chrome/browser/tabs/tab_helper_util.h" -#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" +#import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h" #import "ios/chrome/browser/ui/browser_container/browser_container_view_controller.h" #import "ios/chrome/browser/ui/browser_view/key_commands_provider.h" #import "ios/chrome/browser/ui/bubble/bubble_presenter.h" @@ -240,8 +240,8 @@ side_swipe_controller_ = [[SideSwipeController alloc] initWithBrowser:browser_.get()]; - bookmark_interaction_controller_ = - [[BookmarkInteractionController alloc] initWithBrowser:browser_.get()]; + bookmarks_coordinator_ = + [[BookmarksCoordinator alloc] initWithBrowser:browser_.get()]; fullscreen_controller_ = FullscreenController::FromBrowser(browser_.get()); @@ -254,8 +254,7 @@ dependencies.tabStripCoordinator = tab_strip_coordinator_; dependencies.legacyTabStripCoordinator = legacy_tab_strip_coordinator_; dependencies.sideSwipeController = side_swipe_controller_; - dependencies.bookmarkInteractionController = - bookmark_interaction_controller_; + dependencies.bookmarksCoordinator = bookmarks_coordinator_; dependencies.fullscreenController = fullscreen_controller_; bvc_ = [[BrowserViewController alloc] initWithBrowser:browser_.get() @@ -333,7 +332,7 @@ TabStripCoordinator* tab_strip_coordinator_; TabStripLegacyCoordinator* legacy_tab_strip_coordinator_; SideSwipeController* side_swipe_controller_; - BookmarkInteractionController* bookmark_interaction_controller_; + BookmarksCoordinator* bookmarks_coordinator_; FullscreenController* fullscreen_controller_; };
diff --git a/ios/chrome/browser/ui/browser_view/key_commands_provider.mm b/ios/chrome/browser/ui/browser_view/key_commands_provider.mm index e1b0429f..f0588ea 100644 --- a/ios/chrome/browser/ui/browser_view/key_commands_provider.mm +++ b/ios/chrome/browser/ui/browser_view/key_commands_provider.mm
@@ -13,7 +13,7 @@ #import "components/strings/grit/components_strings.h" #import "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" -#import "ios/chrome/browser/find_in_page/java_script_find_tab_helper.h" +#import "ios/chrome/browser/find_in_page/abstract_find_tab_helper.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" #import "ios/chrome/browser/tabs/tab_title_util.h" @@ -552,8 +552,7 @@ return NO; } - JavaScriptFindTabHelper* helper = - JavaScriptFindTabHelper::FromWebState(currentWebState); + auto* helper = GetConcreteFindTabHelperFromWebState(currentWebState); return (helper && helper->CurrentPageSupportsFindInPage()); } @@ -564,8 +563,7 @@ return NO; } - JavaScriptFindTabHelper* helper = - JavaScriptFindTabHelper::FromWebState(currentWebState); + auto* helper = GetConcreteFindTabHelperFromWebState(currentWebState); return (helper && helper->IsFindUIActive()); }
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn index 0a057b663..373d3b7b 100644 --- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -370,6 +370,7 @@ "//ios/chrome/browser/ui/settings:constants", "//ios/chrome/browser/ui/start_surface:feature_flags", "//ios/chrome/browser/ui/toolbar/public:constants", + "//ios/chrome/browser/ui/whats_new:feature_flags", "//ios/chrome/test:eg_test_support+eg2", "//ios/chrome/test/earl_grey:eg_test_support+eg2", "//ios/testing/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm index 4b9034e..ff7c69e 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -171,7 +171,6 @@ // Check to see if the collection are still scrolled to the top -- // it's possible (and difficult) to unfocus the omnibox and initiate a // -shiftTilesDownForOmniboxDefocus before the animation here completes. - [self.dispatcher fakeboxFocused]; if (IsSplitToolbarMode(self)) { [self.dispatcher onFakeboxAnimationComplete]; }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm index 8caf1a3..f7f993d 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -336,6 +336,7 @@ [self.dispatcher showHistory]; break; case NTPCollectionShortcutTypeWhatsNew: + SetWhatsNewUsed(); base::RecordAction(base::UserMetricsAction("MobileNTPShowWhatsNew")); [self.dispatcher showWhatsNew]; break; @@ -618,7 +619,7 @@ } - (BOOL)shouldShowWhatsNewActionItem { - if (!IsWhatsNewEnabled()) { + if (!IsWhatsNewEnabled() || WasWhatsNewUsed()) { return NO; }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm index 39e2dad..aed6263 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator_unittest.mm
@@ -36,6 +36,7 @@ #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/browser/web_state_list/web_state_opener.h" #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" +#import "ios/chrome/test/testing_application_context.h" #import "ios/web/public/test/fakes/fake_navigation_manager.h" #import "ios/web/public/test/fakes/fake_web_state.h" #import "ios/web/public/test/web_task_environment.h" @@ -77,6 +78,7 @@ dispatcher_ = OCMProtocolMock(@protocol(ContentSuggestionsMediatorDispatcher)); consumer_ = OCMProtocolMock(@protocol(ContentSuggestionsConsumer)); + TestingApplicationContext::GetGlobal()->SetLocalState(local_state_.Get()); favicon::LargeIconService* largeIconService = IOSChromeLargeIconServiceFactory::GetForBrowserState( @@ -288,6 +290,7 @@ histogram_tester_->ExpectUniqueSample( "IOS.ContentSuggestions.ActionOnNTP", IOSContentSuggestionsActionType::kShortcuts, 0); + // Action. ContentSuggestionsMostVisitedActionItem* whatsNew = WhatsNewActionItem(); [mediator_ openMostVisitedItem:whatsNew atIndex:1];
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm index 6ec0268c..796bcffa 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -29,6 +29,7 @@ #import "ios/chrome/browser/ui/start_surface/start_surface_features.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h" #import "ios/chrome/browser/ui/ui_feature_flags.h" +#import "ios/chrome/browser/ui/whats_new/feature_flags.h" #import "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/earl_grey/chrome_actions.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" @@ -177,6 +178,11 @@ // Tests that the collections shortcut are displayed and working. - (void)testCollectionShortcuts { + AppLaunchConfiguration config = self.appConfigurationForTestCase; + config.relaunch_policy = ForceRelaunchByCleanShutdown; + config.features_disabled.push_back(kWhatsNewIOS); + [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; + // Check the Bookmarks. [[EarlGrey selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
diff --git a/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn b/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn index 52ca4034..c7239a5 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn +++ b/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn
@@ -9,9 +9,15 @@ "credential_provider_promo_coordinator.mm", "credential_provider_promo_display_handler.h", "credential_provider_promo_display_handler.mm", + "credential_provider_promo_mediator.h", + "credential_provider_promo_mediator.mm", ] deps = [ + ":credential_provider_promo_ui", "//base", + "//components/prefs", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/credential_provider_promo:features", "//ios/chrome/browser/main:public", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", @@ -27,7 +33,12 @@ "credential_provider_promo_view_controller.h", "credential_provider_promo_view_controller.mm", ] - deps = [ "//base" ] + deps = [ + "//base", + "//components/password_manager/core/browser", + "//ios/chrome/browser/ui/commands", + "//ios/chrome/common/ui/confirmation_alert", + ] frameworks = [ "Foundation.framework", "UIKit.framework",
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.mm b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.mm index abc6c69..fb3e6d6 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.mm +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.mm
@@ -4,9 +4,12 @@ #import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.h" +#import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/commands/credential_provider_promo_commands.h" +#import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_mediator.h" +#import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -14,6 +17,13 @@ @interface CredentialProviderPromoCoordinator () +// Main mediator for this coordinator. +@property(nonatomic, strong) CredentialProviderPromoMediator* mediator; + +// Main view controller for this coordinator. +@property(nonatomic, strong) + CredentialProviderPromoViewController* viewController; + @end @implementation CredentialProviderPromoCoordinator @@ -22,18 +32,30 @@ [self.browser->GetCommandDispatcher() startDispatchingToTarget:self forProtocol:@protocol(CredentialProviderPromoCommands)]; + self.viewController = [[CredentialProviderPromoViewController alloc] init]; + self.mediator = [[CredentialProviderPromoMediator alloc] + initWithConsumer:self.viewController + prefService:self.browser->GetBrowserState()->GetPrefs()]; } - (void)stop { [super stop]; [self.browser->GetCommandDispatcher() stopDispatchingForProtocol:@protocol(CredentialProviderPromoCommands)]; + self.mediator = nil; + self.viewController = nil; } #pragma mark - CredentialProviderPromoCommands - (void)showCredentialProviderPromoWithTrigger: (CredentialProviderPromoTrigger)trigger { + if ([self.mediator canShowCredentialProviderPromo]) { + [self.mediator configureConsumerWithTrigger:trigger]; + [self.baseViewController presentViewController:self.viewController + animated:YES + completion:nil]; + } } @end
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_mediator.h b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_mediator.h new file mode 100644 index 0000000..3fa3896 --- /dev/null +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_mediator.h
@@ -0,0 +1,36 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_CREDENTIAL_PROVIDER_PROMO_CREDENTIAL_PROVIDER_PROMO_MEDIATOR_H_ +#define IOS_CHROME_BROWSER_UI_CREDENTIAL_PROVIDER_PROMO_CREDENTIAL_PROVIDER_PROMO_MEDIATOR_H_ + +#import <Foundation/Foundation.h> + +#import "components/prefs/pref_service.h" +#import "ios/chrome/browser/ui/commands/credential_provider_promo_commands.h" +#import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_consumer.h" + +// Manages the state and interactions of the CredentialProviderPromoConsumer. +@interface CredentialProviderPromoMediator : NSObject + +// Designated initializer. Initializes the mediator with the consumer and +// PrefService. +- (instancetype)initWithConsumer:(id<CredentialProviderPromoConsumer>)consumer + prefService:(PrefService*)prefService + NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithCoder NS_UNAVAILABLE; + +// Returns YES if the user conditions are met to present the Credential +// Provider Promo. +- (BOOL)canShowCredentialProviderPromo; + +// Configures the consumer. +- (void)configureConsumerWithTrigger:(CredentialProviderPromoTrigger)trigger; + +@end + +#endif // IOS_CHROME_BROWSER_UI_CREDENTIAL_PROVIDER_PROMO_CREDENTIAL_PROVIDER_PROMO_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_mediator.mm b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_mediator.mm new file mode 100644 index 0000000..4abaf55 --- /dev/null +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_mediator.mm
@@ -0,0 +1,48 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_mediator.h" + +#import "components/password_manager/core/browser/password_manager_util.h" +#import "components/prefs/pref_service.h" +#import "ios/chrome/browser/credential_provider_promo/features.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface CredentialProviderPromoMediator () + +// The main consumer for this mediator. +@property(nonatomic, weak) id<CredentialProviderPromoConsumer> consumer; + +// The PrefService used by this mediator. +@property(nonatomic, assign) PrefService* prefService; + +@end + +@implementation CredentialProviderPromoMediator + +- (instancetype)initWithConsumer:(id<CredentialProviderPromoConsumer>)consumer + prefService:(PrefService*)prefService { + self = [super init]; + if (self) { + _consumer = consumer; + _prefService = prefService; + } + return self; +} + +- (BOOL)canShowCredentialProviderPromo { + // TODO(crbug.com/1392116): check for user action and impression counts + return IsCredentialProviderExtensionPromoEnabled() && + !password_manager_util::IsCredentialProviderEnabledOnStartup( + self.prefService); +} + +- (void)configureConsumerWithTrigger:(CredentialProviderPromoTrigger)trigger { + // TODO(crbug.com/1392116): configure view controller +} + +@end
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.h b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.h index f93d5bd..9ccac23 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.h +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.h
@@ -9,9 +9,16 @@ #import <UIKit/UIKit.h> +#import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_view_controller.h" + // Container view controller for the Credential Provider Extension promo. Can be // configured to display the half-sheet or full-screen promo. -@interface CredentialProviderPromoViewController : UIViewController +@interface CredentialProviderPromoViewController + : UIViewController <CredentialProviderPromoConsumer> + +// Child view controller used to display the alert screen for the half-screen +// and full-screen promos. +@property(nonatomic, strong) ConfirmationAlertViewController* alertScreen; @end
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.mm b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.mm index d8c9336..b3cc60b 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.mm +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_view_controller.mm
@@ -21,4 +21,26 @@ NOTREACHED(); } +#pragma mark - CredentialProviderPromoConsumer + +- (void)setTitleString:(NSString*)titleString + subtitleString:(NSString*)subtitleString + primaryActionString:(NSString*)primaryActionString + secondaryActionString:(NSString*)secondaryActionString + tertiaryActionString:(NSString*)tertiaryActionString + image:(UIImage*)image { + _alertScreen.titleString = titleString; + _alertScreen.subtitleString = subtitleString; + _alertScreen.primaryActionString = primaryActionString; + _alertScreen.secondaryActionString = secondaryActionString; + _alertScreen.tertiaryActionString = tertiaryActionString; + _alertScreen.image = image; +} + +- (void)setAnimation:(std::unique_ptr<base::Value>)animationAsset { + // TODO(crbug.com/1392116): configure animation view for full-screen + // promo. + NOTREACHED(); +} + @end
diff --git a/ios/chrome/browser/ui/default_promo/BUILD.gn b/ios/chrome/browser/ui/default_promo/BUILD.gn index 272561f..4a28895 100644 --- a/ios/chrome/browser/ui/default_promo/BUILD.gn +++ b/ios/chrome/browser/ui/default_promo/BUILD.gn
@@ -42,7 +42,10 @@ deps = [ ":utils", "//base", + "//components/feature_engagement/public", "//ios/chrome/app/strings", + "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/feature_engagement", "//ios/chrome/browser/main:public", "//ios/chrome/browser/overlays", "//ios/chrome/browser/ui/commands",
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_promo_coordinator.mm b/ios/chrome/browser/ui/default_promo/default_browser_promo_coordinator.mm index 71f90faf..10b01b8d 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_promo_coordinator.mm +++ b/ios/chrome/browser/ui/default_promo/default_browser_promo_coordinator.mm
@@ -8,6 +8,11 @@ #import "base/metrics/histogram_functions.h" #import "base/metrics/user_metrics.h" #import "base/metrics/user_metrics_action.h" +#import "components/feature_engagement/public/event_constants.h" +#import "components/feature_engagement/public/tracker.h" +#import "ios/chrome/browser/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/feature_engagement/tracker_factory.h" +#import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/ui/default_promo/default_browser_promo_view_controller.h" #import "ios/chrome/browser/ui/default_promo/default_browser_string_util.h" #import "ios/chrome/browser/ui/default_promo/default_browser_utils.h" @@ -110,6 +115,7 @@ base::RecordAction(base::UserMetricsAction( "IOS.DefaultBrowserFullscreenPromo.RemindMeTapped")); LogRemindMeLaterPromoActionInteraction(); + [self NotifyFETRemindMeLater]; } else { [self logDefaultBrowserFullscreenRemindMeSecondPromoHistogramForAction: IOSDefaultBrowserFullscreenPromoAction::kCancel]; @@ -170,4 +176,19 @@ "IOS.DefaultBrowserFullscreenPromoRemindMeSecondPromo", action); } +#pragma mark - Private + +// Notifies the FET that the user has clicked "remind me later" on the default +// browser promo, which is an eligibility criterion for the default browser blue +// dot promo. +- (void)NotifyFETRemindMeLater { + ChromeBrowserState* browserState = self.browser->GetBrowserState(); + if (!browserState || browserState->IsOffTheRecord()) { + return; + } + + feature_engagement::TrackerFactory::GetForBrowserState(browserState) + ->NotifyEvent(feature_engagement::events::kBlueDotPromoCriterionMet); +} + @end
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_utils.h b/ios/chrome/browser/ui/default_promo/default_browser_utils.h index 0c3db28..d692b9f 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_utils.h +++ b/ios/chrome/browser/ui/default_promo/default_browser_utils.h
@@ -93,6 +93,16 @@ // Logs that the user has interacted with the first run promo. void LogUserInteractionWithFirstRunPromo(BOOL openedSettings); +// Returns YES if the user has opened the app through first-party intent 2 +// times in the last 7 days, with more than 6 hours between each time. Also +// records that a new launch has happened if the last one was more than one +// session ago. +bool HasRecentFirstPartyIntentLaunchesAndRecordsCurrentLaunch(); + +// Returns YES if the user has pasted a valid URL into the omnibox twice in +// the last 7 days and records the current paste. +bool HasRecentValidURLPastesAndRecordsCurrentPaste(); + // Returns true if the last URL open is within the time threshold that would // indicate Chrome is likely still the default browser. Returns false otherwise. bool IsChromeLikelyDefaultBrowser();
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_utils.mm b/ios/chrome/browser/ui/default_promo/default_browser_utils.mm index f1ef6aee..bd81567 100644 --- a/ios/chrome/browser/ui/default_promo/default_browser_utils.mm +++ b/ios/chrome/browser/ui/default_promo/default_browser_utils.mm
@@ -92,6 +92,15 @@ NSString* const kOpenSettingsActionInteraction = @"openSettingsActionInteraction"; +// Key in storage containing the timestamp of the last time the user opened the +// app via first-party intent. +NSString* const kTimestampAppLastOpenedViaFirstPartyIntent = + @"TimestampAppLastOpenedViaFirstPartyIntent"; + +// Key in storage containing the timestamp of the last time the user pasted a +// valid URL into the omnibox. +NSString* const kTimestampLastValidURLPasted = @"TimestampLastValidURLPasted"; + const char kDefaultBrowserFullscreenPromoExperimentChangeStringsGroupParam[] = "show_switch_description"; @@ -115,6 +124,17 @@ // Short cool down between promos. constexpr base::TimeDelta kPromosShortCoolDown = base::Days(3); +// Maximum time range between first-party app launches to notify the FET. +constexpr base::TimeDelta kMaximumTimeBetweenFirstPartyAppLaunches = + base::Days(7); + +// Minimum time range between first-party app launches to notify the FET. +constexpr base::TimeDelta kMinimumTimeBetweenFirstPartyAppLaunches = + base::Hours(6); + +// Maximum time range between valid user URL pastes to notify the FET. +constexpr base::TimeDelta kMaximumTimeBetweenValidURLPastes = base::Days(7); + // List of DefaultPromoType considered by MostRecentInterestDefaultPromoType. const DefaultPromoType kDefaultPromoTypes[] = { DefaultPromoTypeStaySafe, @@ -420,6 +440,37 @@ }); } +bool HasRecentFirstPartyIntentLaunchesAndRecordsCurrentLaunch() { + if (HasRecordedEventForKeyLessThanDelay( + kTimestampAppLastOpenedViaFirstPartyIntent, + kMaximumTimeBetweenFirstPartyAppLaunches)) { + if (HasRecordedEventForKeyMoreThanDelay( + kTimestampAppLastOpenedViaFirstPartyIntent, + kMinimumTimeBetweenFirstPartyAppLaunches)) { + SetObjectIntoStorageForKey(kTimestampAppLastOpenedViaFirstPartyIntent, + [NSDate date]); + return YES; + } + + return NO; + } + + SetObjectIntoStorageForKey(kTimestampAppLastOpenedViaFirstPartyIntent, + [NSDate date]); + return NO; +} + +bool HasRecentValidURLPastesAndRecordsCurrentPaste() { + if (HasRecordedEventForKeyLessThanDelay(kTimestampLastValidURLPasted, + kMaximumTimeBetweenValidURLPastes)) { + SetObjectIntoStorageForKey(kTimestampLastValidURLPasted, [NSDate date]); + return YES; + } + + SetObjectIntoStorageForKey(kTimestampLastValidURLPasted, [NSDate date]); + return NO; +} + bool IsChromeLikelyDefaultBrowser7Days() { return HasRecordedEventForKeyLessThanDelay(kLastHTTPURLOpenTime, base::Days(7));
diff --git a/ios/chrome/browser/ui/find_bar/find_bar_coordinator.mm b/ios/chrome/browser/ui/find_bar/find_bar_coordinator.mm index c195562..d318632 100644 --- a/ios/chrome/browser/ui/find_bar/find_bar_coordinator.mm +++ b/ios/chrome/browser/ui/find_bar/find_bar_coordinator.mm
@@ -5,7 +5,7 @@ #import "ios/chrome/browser/ui/find_bar/find_bar_coordinator.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" -#import "ios/chrome/browser/find_in_page/java_script_find_tab_helper.h" +#import "ios/chrome/browser/find_in_page/abstract_find_tab_helper.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h" @@ -48,8 +48,7 @@ self.mediator.consumer = self.findBarController; DCHECK(self.currentWebState); - JavaScriptFindTabHelper* helper = - JavaScriptFindTabHelper::FromWebState(self.currentWebState); + auto* helper = GetConcreteFindTabHelperFromWebState(self.currentWebState); helper->SetResponseDelegate(self.mediator); // If the FindUI is already active, just reshow it. if (helper->IsFindUIActive()) { @@ -70,8 +69,7 @@ // the UI will be brought back later. BOOL animated; if (self.currentWebState) { - JavaScriptFindTabHelper* helper = - JavaScriptFindTabHelper::FromWebState(self.currentWebState); + auto* helper = GetConcreteFindTabHelperFromWebState(self.currentWebState); animated = helper && !helper->IsFindUIActive(); } else { animated = true; @@ -96,8 +94,7 @@ if (!self.currentWebState) { return; } - JavaScriptFindTabHelper* helper = - JavaScriptFindTabHelper::FromWebState(self.currentWebState); + auto* helper = GetConcreteFindTabHelperFromWebState(self.currentWebState); DCHECK(helper && helper->IsFindUIActive()); if (!self.browser->GetBrowserState()->IsOffTheRecord()) { helper->RestoreSearchTerm(); @@ -109,8 +106,7 @@ } - (void)defocusFindBar { - JavaScriptFindTabHelper* helper = - JavaScriptFindTabHelper::FromWebState(self.currentWebState); + auto* helper = GetConcreteFindTabHelperFromWebState(self.currentWebState); if (helper && helper->IsFindUIActive()) { [self.findBarController updateView:helper->GetFindResult() initialUpdate:NO
diff --git a/ios/chrome/browser/ui/first_run/BUILD.gn b/ios/chrome/browser/ui/first_run/BUILD.gn index eae64d4..bc18347 100644 --- a/ios/chrome/browser/ui/first_run/BUILD.gn +++ b/ios/chrome/browser/ui/first_run/BUILD.gn
@@ -5,8 +5,6 @@ source_set("field_trial") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "fre_field_trial.cc", - "fre_field_trial.h", "ios_first_run_field_trials.cc", "ios_first_run_field_trials.h", "trending_queries_field_trial.cc", @@ -223,7 +221,6 @@ testonly = true sources = [ "enterprise_loading_screen_egtest.mm", - "first_run_egtest.mm", "first_run_two_steps_egtest.mm", ] deps = [
diff --git a/ios/chrome/browser/ui/first_run/first_run_coordinator.mm b/ios/chrome/browser/ui/first_run/first_run_coordinator.mm index 69d3b292..87f3de5 100644 --- a/ios/chrome/browser/ui/first_run/first_run_coordinator.mm +++ b/ios/chrome/browser/ui/first_run/first_run_coordinator.mm
@@ -129,7 +129,7 @@ // Creates a screen coordinator according to `type`. - (ChromeCoordinator*)createChildCoordinatorWithScreenType:(ScreenType)type { switch (type) { - case kWelcomeAndConsent: + case kWelcomeAndConsent_DEPRECATED: return [[WelcomeScreenCoordinator alloc] initWithBaseNavigationController:self.navigationController browser:self.browser @@ -145,12 +145,12 @@ initWithBaseNavigationController:self.navigationController browser:self.browser delegate:self]; - case kSignInAndSync: + case kSignInAndSync_DEPRECATED: return [[SigninSyncCoordinator alloc] initWithBaseNavigationController:self.navigationController browser:self.browser delegate:self]; - case kLegacySignIn: + case kLegacySignIn_DEPRECATED: return [[LegacySigninScreenCoordinator alloc] initWithBaseNavigationController:self.navigationController browser:self.browser
diff --git a/ios/chrome/browser/ui/first_run/first_run_egtest.mm b/ios/chrome/browser/ui/first_run/first_run_egtest.mm deleted file mode 100644 index 9d2b0b8..0000000 --- a/ios/chrome/browser/ui/first_run/first_run_egtest.mm +++ /dev/null
@@ -1,1017 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "base/strings/string_util.h" -#import "base/strings/sys_string_conversions.h" -#import "components/policy/core/common/policy_loader_ios_constants.h" -#import "components/policy/policy_constants.h" -#import "components/signin/internal/identity_manager/account_capabilities_constants.h" -#import "components/signin/ios/browser/features.h" -#import "ios/chrome/browser/policy/policy_app_interface.h" -#import "ios/chrome/browser/policy/policy_earl_grey_utils.h" -#import "ios/chrome/browser/signin/capabilities_types.h" -#import "ios/chrome/browser/signin/fake_system_identity.h" -#import "ios/chrome/browser/signin/test_constants.h" -#import "ios/chrome/browser/ui/authentication/authentication_constants.h" -#import "ios/chrome/browser/ui/authentication/signin_earl_grey.h" -#import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui_test_util.h" -#import "ios/chrome/browser/ui/authentication/signin_matchers.h" -#import "ios/chrome/browser/ui/authentication/views/views_constants.h" -#import "ios/chrome/browser/ui/first_run/first_run_app_interface.h" -#import "ios/chrome/browser/ui/first_run/first_run_constants.h" -#import "ios/chrome/browser/ui/settings/google_services/manage_sync_settings_constants.h" -#import "ios/chrome/browser/ui/ui_feature_flags.h" -#import "ios/chrome/common/string_util.h" -#import "ios/chrome/common/ui/promo_style/constants.h" -#import "ios/chrome/grit/ios_chromium_strings.h" -#import "ios/chrome/grit/ios_strings.h" -#import "ios/chrome/test/earl_grey/chrome_actions.h" -#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" -#import "ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h" -#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" -#import "ios/chrome/test/earl_grey/chrome_matchers.h" -#import "ios/chrome/test/earl_grey/chrome_test_case.h" -#import "ios/chrome/test/earl_grey/test_switches.h" -#import "ios/testing/earl_grey/app_launch_manager.h" -#import "ios/testing/earl_grey/earl_grey_test.h" -#import "ui/base/l10n/l10n_util.h" - -#import "ios/third_party/earl_grey2/src/CommonLib/Matcher/GREYLayoutConstraint.h" // nogncheck - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -using chrome_test_util::IdentityCellMatcherForEmail; -using chrome_test_util::AdvancedSyncSettingsDoneButtonMatcher; - -namespace { - -NSString* const kBeginBoldTag = @"BEGIN_BOLD[ \t]*"; -NSString* const kEndBoldTag = @"[ \t]*END_BOLD"; - -// Returns a matcher for the welcome screen accept button. -id<GREYMatcher> GetAcceptButton() { - return grey_allOf(grey_text(l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_WELCOME_SCREEN_ACCEPT_BUTTON)), - grey_sufficientlyVisible(), nil); -} - -// Returns a matcher for the button to open the Sync settings. -id<GREYMatcher> GetSyncSettings() { - id<GREYMatcher> disclaimer = - grey_accessibilityID(kPromoStyleDisclaimerViewAccessibilityIdentifier); - return grey_allOf(grey_accessibilityLabel(@"settings"), - grey_ancestor(disclaimer), nil); -} - -// Returns a matcher for the button to add account. -id<GREYMatcher> GetAddAccountButton() { - return grey_allOf(grey_text(l10n_util::GetNSString( - IDS_IOS_ACCOUNT_UNIFIED_CONSENT_ADD_ACCOUNT)), - grey_sufficientlyVisible(), nil); -} - -// Returns a matcher for the button to sign-in and sync (OLD string). -id<GREYMatcher> GetYesImInButton() { - return grey_allOf(grey_text(l10n_util::GetNSString( - IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON)), - grey_sufficientlyVisible(), nil); -} - -// Returns a matcher for the button to skip sign-in and sync (OLD string). -id<GREYMatcher> GetNoThanksButton() { - return grey_allOf( - grey_text(l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_SECONDARY_ACTION)), - grey_sufficientlyVisible(), nil); -} - -// Dismiss default browser promo. -void DismissDefaultBrowserPromo() { - id<GREYMatcher> buttonMatcher = grey_allOf( - grey_ancestor(grey_accessibilityID( - first_run::kFirstRunDefaultBrowserScreenAccessibilityIdentifier)), - GetNoThanksButton(), nil); - [[EarlGrey selectElementWithMatcher:buttonMatcher] performAction:grey_tap()]; -} - -// Returns a constraint where the element is below the reference. -GREYLayoutConstraint* BelowConstraint() { - return [GREYLayoutConstraint - layoutConstraintWithAttribute:kGREYLayoutAttributeTop - relatedBy:kGREYLayoutRelationGreaterThanOrEqual - toReferenceAttribute:kGREYLayoutAttributeBottom - multiplier:1.0 - constant:0.0]; -} - -} // namespace - -// Test first run stages -@interface FirstRunTestCase : ChromeTestCase - -@end - -@implementation FirstRunTestCase - -- (void)setUp { - [[self class] testForStartup]; - - [super setUp]; - [FirstRunAppInterface setUMACollectionEnabled:NO]; - [FirstRunAppInterface resetUMACollectionEnabledByDefault]; -} - -- (void)tearDown { - [PolicyAppInterface clearPolicies]; - [FirstRunAppInterface setUMACollectionEnabled:NO]; - [FirstRunAppInterface resetUMACollectionEnabledByDefault]; - [super tearDown]; -} - -- (AppLaunchConfiguration)appConfigurationForTestCase { - AppLaunchConfiguration config; - config.features_disabled.push_back(signin::kNewMobileIdentityConsistencyFRE); - // Show the First Run UI at startup. - config.additional_args.push_back("-FirstRunForceEnabled"); - config.additional_args.push_back("true"); - - // Relaunch app at each test to rewind the startup state. - config.relaunch_policy = ForceRelaunchByKilling; - - return config; -} - -#pragma mark - Helpers - -// Checks that the welcome screen is displayed. -- (void)verifyWelcomeScreenIsDisplayed { - [[EarlGrey selectElementWithMatcher: - grey_accessibilityID( - first_run::kFirstRunWelcomeScreenAccessibilityIdentifier)] - assertWithMatcher:grey_notNil()]; -} - -// Checks that the sign-in & sync screen is displayed. -- (void)verifySignInSyncScreenIsDisplayed { - [[EarlGrey - selectElementWithMatcher:grey_accessibilityID( - kSigninSyncScreenAccessibilityIdentifier)] - assertWithMatcher:grey_notNil()]; -} - -// Checks that the forced sign-in screen is displayed. -- (void)verifyForcedSigninScreenIsDisplayed { - [[EarlGrey - selectElementWithMatcher: - grey_accessibilityID( - first_run::kFirstRunLegacySignInScreenAccessibilityIdentifier)] - assertWithMatcher:grey_notNil()]; -} - -// Checks that the default browser screen is displayed. -- (void)verifyDefaultBrowserScreenIsDisplayed { - [[EarlGrey - selectElementWithMatcher: - grey_accessibilityID( - first_run::kFirstRunDefaultBrowserScreenAccessibilityIdentifier)] - assertWithMatcher:grey_notNil()]; -} - -// Scrolls down to `elementMatcher` in the scrollable content of the first run -// screen. -- (void)scrollToElementAndAssertVisibility:(id<GREYMatcher>)elementMatcher { - id<GREYMatcher> scrollView = - grey_accessibilityID(kPromoStyleScrollViewAccessibilityIdentifier); - - [[[EarlGrey - selectElementWithMatcher:grey_allOf(elementMatcher, - grey_sufficientlyVisible(), nil)] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 50) - onElementWithMatcher:scrollView] assertWithMatcher:grey_notNil()]; -} - -- (void)toggleSwitchWithIdentifier:(NSString*)identifier - toValue:(BOOL)toggleOn { - [[EarlGrey selectElementWithMatcher:chrome_test_util::TableViewSwitchCell( - identifier, - /*is_toggled_on=*/!toggleOn, - /*enabled=*/YES)] - performAction:chrome_test_util::TurnTableViewSwitchOn(toggleOn)]; -} - -- (void)verifySwitchWithIdentifier:(NSString*)identifier - toValue:(BOOL)toggleOn { - [[EarlGrey selectElementWithMatcher:chrome_test_util::TableViewSwitchCell( - identifier, - /*is_toggled_on=*/toggleOn, - /*enabled=*/YES)] - assertWithMatcher:grey_notNil()]; -} - -#pragma mark - Welcome Screen Tests - -// Checks that the Welcome screen is displayed correctly. -- (void)testWelcomeScreenUI { - [self verifyWelcomeScreenIsDisplayed]; - - // Validate the Title text. - NSString* expectedTitleText = - [ChromeEarlGrey isIPadIdiom] - ? l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TITLE_IPAD) - : l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TITLE_IPHONE); - id<GREYMatcher> title = grey_text(expectedTitleText); - [self scrollToElementAndAssertVisibility:title]; - - // Validate the Subtitle text. - id<GREYMatcher> subtitle = grey_text( - l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_SUBTITLE)); - [self scrollToElementAndAssertVisibility:subtitle]; - - // Validate the Accept box. - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; -} - -// Checks that the Welcome screen is displayed correctly when enterprise is -// enabled. -- (void)testWelcomeScreenUIForEnterprise { - AppLaunchConfiguration config = self.appConfigurationForTestCase; - - // Configure the policy to force sign-in. - std::string policy_data = "<dict>" - " <key>BrowserSignin</key>" - " <integer>2</integer>" - "</dict>"; - base::RemoveChars(policy_data, base::kWhitespaceASCII, &policy_data); - - config.additional_args.push_back( - "-" + base::SysNSStringToUTF8(kPolicyLoaderIOSConfigurationKey)); - config.additional_args.push_back(policy_data); - - // Relaunch the app to take the configuration into account. - [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; - - [self verifyWelcomeScreenIsDisplayed]; - - // Validate the Title text. - id<GREYMatcher> title = grey_text(l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_WELCOME_SCREEN_TITLE_ENTERPRISE)); - [self scrollToElementAndAssertVisibility:title]; - - // Validate the Subtitle text. - id<GREYMatcher> subtitle = grey_text(l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_WELCOME_SCREEN_SUBTITLE_ENTERPRISE)); - [self scrollToElementAndAssertVisibility:subtitle]; - - // Validate the Managed text. - id<GREYMatcher> managed = grey_text( - l10n_util::GetNSString(IDS_IOS_FIRST_RUN_WELCOME_SCREEN_MANAGED)); - [self scrollToElementAndAssertVisibility:managed]; - - // Validate the Accept box. - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; -} - -#pragma mark - Sign-in & Sync Tests - -// Checks that the sign-in & sync screen is displayed correctly with no account -// (using OLD strings set). -- (void)testSignInSyncScreenUIOldStringNoAccount { - [self verifyWelcomeScreenIsDisplayed]; - - // Go to the sign-in & sync screen. - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - - // Validate the Title text. - id<GREYMatcher> title = - grey_text(l10n_util::GetNSString(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_TITLE)); - [self scrollToElementAndAssertVisibility:title]; - - // Validate the Subtitle text. - id<GREYMatcher> subtitle = grey_text( - l10n_util::GetNSString(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_TITLE)); - [self scrollToElementAndAssertVisibility:subtitle]; - - // Validate the Primary button text. - [self scrollToElementAndAssertVisibility:GetAddAccountButton()]; - - // Validate the Secondary button text. - [self scrollToElementAndAssertVisibility:GetNoThanksButton()]; - - // Validate that the sync button is not interactible. - [[EarlGrey selectElementWithMatcher:grey_allOf(GetSyncSettings(), - grey_interactable(), nil)] - assertWithMatcher:grey_nil()]; -} - -// Checks that the sign-in & sync screen is displayed correctly with an account -// (using OLD strings set). -- (void)testSignInSyncScreenUIOldString { - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - [self verifyWelcomeScreenIsDisplayed]; - - // Go to the sign-in & sync screen. - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - - // Validate the Title text. - id<GREYMatcher> title = - grey_text(l10n_util::GetNSString(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_TITLE)); - [self scrollToElementAndAssertVisibility:title]; - - // Validate the Subtitle text. - id<GREYMatcher> subtitle = grey_text( - l10n_util::GetNSString(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_TITLE)); - [self scrollToElementAndAssertVisibility:subtitle]; - - // Validate the Primary button text. - [self scrollToElementAndAssertVisibility:GetYesImInButton()]; - - // Validate the Secondary button text. - [self scrollToElementAndAssertVisibility:GetNoThanksButton()]; - - // Validate that the sync button is interactible. - [[EarlGrey selectElementWithMatcher:grey_allOf(GetSyncSettings(), - grey_interactable(), nil)] - assertWithMatcher:grey_sufficientlyVisible()]; -} - -// Tests that the forced sign-in screen is shown when the policy is enabled. -// If the user says no during the FRE, then they should be re-prompted at the -// end of the FRE. -- (void)testSignInScreenUIWhenForcedByPolicy { - AppLaunchConfiguration configToSetPolicy = self.appConfigurationForTestCase; - - // Configure the policy to force sign-in. - std::string policy_data = "<dict>" - " <key>BrowserSignin</key>" - " <integer>2</integer>" - "</dict>"; - base::RemoveChars(policy_data, base::kWhitespaceASCII, &policy_data); - - configToSetPolicy.additional_args.push_back( - "-" + base::SysNSStringToUTF8(kPolicyLoaderIOSConfigurationKey)); - configToSetPolicy.additional_args.push_back(policy_data); - - // Relaunch the app to take the configuration into account. - [[AppLaunchManager sharedManager] - ensureAppLaunchedWithConfiguration:configToSetPolicy]; - - // Add account for the identity switcher to be shown. - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - // Go to the sign-in & sync screen from the welcome screen. - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - // Sanity check that the sign-in & sync screen is being displayed. - [self verifySignInSyncScreenIsDisplayed]; - - // Do not sign-in or sync. - [self scrollToElementAndAssertVisibility:GetNoThanksButton()]; - [[EarlGrey selectElementWithMatcher:GetNoThanksButton()] - performAction:grey_tap()]; - DismissDefaultBrowserPromo(); - - // Add account for the identity switcher to be shown. - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - [self verifyForcedSigninScreenIsDisplayed]; - - // Restart the app to reset the policies and to make sure that the forced - // sign-in UI isn't retriggered when tearing down. - AppLaunchConfiguration configToCleanPolicy; - configToCleanPolicy.relaunch_policy = ForceRelaunchByCleanShutdown; - [[AppLaunchManager sharedManager] - ensureAppLaunchedWithConfiguration:configToCleanPolicy]; -} - -// Checks that the default browser screen is displayed correctly. -- (void)testDefaultBrowserScreenUI { - // Go to the default browser screen. - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - [[EarlGrey selectElementWithMatcher:GetNoThanksButton()] - performAction:grey_tap()]; - - [self verifyDefaultBrowserScreenIsDisplayed]; - - // Validate the Title text. - id<GREYMatcher> title = grey_text( - l10n_util::GetNSString(IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_TITLE)); - [self scrollToElementAndAssertVisibility:title]; - - // Validate the Subtitle text. - id<GREYMatcher> subtitle = grey_text(l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_SUBTITLE)); - [self scrollToElementAndAssertVisibility:subtitle]; - - // Remove bold tags in instructions. - StringWithTag firstInstructionParsed = ParseStringWithTag( - l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_FIRST_STEP), - kBeginBoldTag, kEndBoldTag); - StringWithTag secondInstructionParsed = ParseStringWithTag( - l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_SECOND_STEP), - kBeginBoldTag, kEndBoldTag); - StringWithTag thirdInstructionParsed = ParseStringWithTag( - l10n_util::GetNSString( - IDS_IOS_FIRST_RUN_DEFAULT_BROWSER_SCREEN_THIRD_STEP), - kBeginBoldTag, kEndBoldTag); - - // Verify instruction order. - id<GREYMatcher> firstInstruction = grey_text(firstInstructionParsed.string); - id<GREYMatcher> secondInstruction = grey_text(secondInstructionParsed.string); - id<GREYMatcher> thirdInstruction = grey_text(thirdInstructionParsed.string); - - // Scroll to ensure that the third instruction is visible. - id<GREYMatcher> scrollViewMatcher = - grey_accessibilityID(kPromoStyleScrollViewAccessibilityIdentifier); - [[EarlGrey selectElementWithMatcher:thirdInstruction] - usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 50) - onElementWithMatcher:scrollViewMatcher]; - - [[EarlGrey selectElementWithMatcher:secondInstruction] - assertWithMatcher:grey_layout(@[ BelowConstraint() ], firstInstruction)]; - [[EarlGrey selectElementWithMatcher:thirdInstruction] - assertWithMatcher:grey_layout(@[ BelowConstraint() ], secondInstruction)]; -} - -// Navigates to the Terms of Service and back. -- (void)testTermsAndConditions { - // Tap on “Terms of Service” on the first screen - [self verifyWelcomeScreenIsDisplayed]; - - // Scroll to and open the ToS screen. - id<GREYMatcher> termsOfServiceLink = - grey_accessibilityLabel(@"Terms of Service"); - [self scrollToElementAndAssertVisibility:termsOfServiceLink]; - [[EarlGrey selectElementWithMatcher:termsOfServiceLink] - performAction:grey_tap()]; - - [[EarlGrey selectElementWithMatcher:grey_text(l10n_util::GetNSString( - IDS_IOS_FIRSTRUN_TERMS_TITLE))] - assertWithMatcher:grey_sufficientlyVisible()]; - - // Tap on “Done” on the ToS screen - [[EarlGrey - selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()] - performAction:grey_tap()]; - - // Ensure we went back to the First Run screen. - [self verifyWelcomeScreenIsDisplayed]; - - // Scroll to and tap the accept ToS button. - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; -} - -// Tests that the FRE is shown when incognito is forced by policy. -- (void)testFirstRunWithIncognitoForced { - AppLaunchConfiguration config = self.appConfigurationForTestCase; - - std::string policy_data = "<dict>" - " <key>IncognitoModeAvailability</key>" - " <integer>2</integer>" - "</dict>"; - base::RemoveChars(policy_data, base::kWhitespaceASCII, &policy_data); - - config.additional_args.push_back( - "-" + base::SysNSStringToUTF8(kPolicyLoaderIOSConfigurationKey)); - config.additional_args.push_back(policy_data); - - [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; - - // Verify that the FRE UI is shown while the browser is in incognito mode. - [self verifyWelcomeScreenIsDisplayed]; -} - -// Tests that the FRE sign in screen is not displayed when sign in is disabled -// by policy. -- (void)testSignInDisabled { - AppLaunchConfiguration config = self.appConfigurationForTestCase; - - // Configure the policy to disable SignIn. - std::string policy_data = "<dict>" - " <key>BrowserSignin</key>" - " <integer>0</integer>" - "</dict>"; - base::RemoveChars(policy_data, base::kWhitespaceASCII, &policy_data); - - config.additional_args.push_back("-EnableSamplePolicies"); - config.additional_args.push_back( - "-" + base::SysNSStringToUTF8(kPolicyLoaderIOSConfigurationKey)); - config.additional_args.push_back(policy_data); - - // Relaunch the app to take the configuration into account. - [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; - - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - [self verifyDefaultBrowserScreenIsDisplayed]; -} - -// Checks that when opening the app no accounts are here and the primary button -// allows to create a new account and that it is updated if a new account is -// added. -- (void)testAddAccount { - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [[EarlGrey selectElementWithMatcher:GetAddAccountButton()] - performAction:grey_tap()]; - - // Check for the fake SSO screen. - [ChromeEarlGrey - waitForMatcher:grey_accessibilityID(kFakeAuthActivityViewIdentifier)]; - // Close the SSO view controller. - id<GREYMatcher> matcher = - grey_allOf(chrome_test_util::ButtonWithAccessibilityLabel(@"Cancel"), - grey_sufficientlyVisible(), nil); - [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()]; - // Make sure the SSO view controller is fully removed before ending the test. - // The tear down needs to remove other view controllers, and it cannot be done - // during the animation of the SSO view controler. - [ChromeEarlGreyUI waitForAppToIdle]; - - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - // Check that the title of the primary button updates for `fakeIdentity`. - [[EarlGrey selectElementWithMatcher:GetYesImInButton()] - performAction:grey_tap()]; - - [[EarlGrey selectElementWithMatcher:GetAddAccountButton()] - assertWithMatcher:grey_nil()]; -} - -// Checks that it is possible to add an account even if there is already account -// and that it is possible to switch accounts when multiple accounts are -// present. -- (void)testSignInSelectAccount { - FakeSystemIdentity* fakeIdentity1 = [FakeSystemIdentity fakeIdentity1]; - FakeSystemIdentity* fakeIdentity2 = [FakeSystemIdentity fakeIdentity2]; - [SigninEarlGrey addFakeIdentity:fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity2]; - - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - id<GREYMatcher> identityButton = - grey_accessibilityID(kIdentityButtonControlIdentifier); - [self scrollToElementAndAssertVisibility:identityButton]; - [[EarlGrey selectElementWithMatcher:identityButton] performAction:grey_tap()]; - - // Check that `fakeIdentity2` is displayed. - [self scrollToElementAndAssertVisibility:IdentityCellMatcherForEmail( - fakeIdentity2.userEmail)]; - // Check that 'Add Account' is displayed. - [self scrollToElementAndAssertVisibility: - grey_accessibilityLabel(l10n_util::GetNSString( - IDS_IOS_ACCOUNT_IDENTITY_CHOOSER_ADD_ACCOUNT))]; - - // Select `fakeIdentity2`. - [[EarlGrey selectElementWithMatcher:IdentityCellMatcherForEmail( - fakeIdentity2.userEmail)] - performAction:grey_tap()]; - - // Check that the title of the primary button updates for `fakeIdentity2`. - [self scrollToElementAndAssertVisibility:GetYesImInButton()]; -} - -// Checks that the user is signed in and that sync is turned on after the user -// chooses to turn on sync. -- (void)testSignInAndTurnOnSync { - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetYesImInButton()]; - [[EarlGrey selectElementWithMatcher:GetYesImInButton()] - performAction:grey_tap()]; - - // Verify that the user is signed in. - [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; - - // Verify that the sync cell is visible and "On" is displayed. - DismissDefaultBrowserPromo(); - [ChromeEarlGreyUI openSettingsMenu]; - [SigninEarlGrey verifySyncUIEnabled:YES]; - - // Close opened settings for proper tear down. - [[self class] removeAnyOpenMenusAndInfoBars]; -} - -// Checks that a supervised user is signed in and that sync is turned on after -// the user chooses to turn on sync. -- (void)testSignInAndTurnOnSyncForSupervisedUser { - // Add a fake supervised identity to the device. - FakeSystemIdentity* fakeSupervisedIdentity = - [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeSupervisedIdentity]; - - ios::CapabilitiesDict* capabilities = @{ - @(kIsSubjectToParentalControlsCapabilityName) : - @(static_cast<int>(SystemIdentityCapabilityResult::kTrue)) - }; - [SigninEarlGrey setCapabilities:capabilities - forIdentity:fakeSupervisedIdentity]; - - // Go to the sign-in & sync screen from the welcome screen. - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - // Sanity check that the sign-in & sync screen is being displayed. - [self verifySignInSyncScreenIsDisplayed]; - - [self scrollToElementAndAssertVisibility:GetYesImInButton()]; - [[EarlGrey selectElementWithMatcher:GetYesImInButton()] - performAction:grey_tap()]; - - // Verify that the user is signed in. - [SigninEarlGrey verifySignedInWithFakeIdentity:fakeSupervisedIdentity]; - - // Verify that the sync cell is visible and "On" is displayed. - DismissDefaultBrowserPromo(); - [ChromeEarlGreyUI openSettingsMenu]; - [SigninEarlGrey verifySyncUIEnabled:YES]; - - // Close opened settings for proper tear down. - [[self class] removeAnyOpenMenusAndInfoBars]; -} - -// Checks that pressing "No thanks" on sign-in & sync screen doesn't sign in the -// user and doesn't sync. -- (void)testNoSignInNoSync { - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetNoThanksButton()]; - [[EarlGrey selectElementWithMatcher:GetNoThanksButton()] - performAction:grey_tap()]; - - // Verify that the user is not signed in. - [SigninEarlGrey verifySignedOut]; - DismissDefaultBrowserPromo(); - [ChromeEarlGreyUI openSettingsMenu]; - - // Because the user is not signed in, the sync cell is not be visible. - [SigninEarlGrey verifySyncUIIsHidden]; - - // Close opened settings for proper tear down. - [[self class] removeAnyOpenMenusAndInfoBars]; -} - -// The browser should only be signed in temporarily while the advanced settings -// prompt is opened and then signed out when the user selects "No thanks". -// Sync is also turned off. -- (void)testAdvancedSettingsSignoutSyncOff { - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - [[EarlGrey selectElementWithMatcher:GetSyncSettings()] - performAction:grey_tap()]; - - // Check that Sync hasn't started yet, allowing the user to change some - // settings. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't have finished its original setup yet"); - - [self scrollToElementAndAssertVisibility: - AdvancedSyncSettingsDoneButtonMatcher()]; - [[EarlGrey selectElementWithMatcher:AdvancedSyncSettingsDoneButtonMatcher()] - performAction:grey_tap()]; - - // Check sync did not start yet. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't start when discarding advanced settings."); - - [self scrollToElementAndAssertVisibility:GetNoThanksButton()]; - [[EarlGrey selectElementWithMatcher:GetNoThanksButton()] - performAction:grey_tap()]; - - // Verify that the browser isn't signed in by validating that there isn't a - // sync cell visible in settings. - DismissDefaultBrowserPromo(); - [ChromeEarlGreyUI openSettingsMenu]; - [SigninEarlGrey verifySyncUIIsHidden]; - - // Close opened settings for proper tear down. - [[self class] removeAnyOpenMenusAndInfoBars]; -} - -// If browser is already signed in and the user opens the advanced settings then -// selects "No thanks", the user should stay signed in, but sync should be -// turned off. -- (void)testAdvancedSettingsSignedInSyncOff { - // Sign-in browser. - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity enableSync:NO]; - - // Reload with forced first run enabled. - AppLaunchConfiguration config = self.appConfigurationForTestCase; - config.relaunch_policy = ForceRelaunchByCleanShutdown; - - // Add the switch to make sure that fakeIdentity1 is known at startup to avoid - // automatic sign out. - config.additional_args.push_back(std::string("-") + - test_switches::kSignInAtStartup); - config.additional_args.push_back( - std::string("-") + test_switches::kAddFakeIdentitiesAtStartup + "=" + - [FakeSystemIdentity encodeIdentitiesToBase64:@[ fakeIdentity ]]); - - [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; - - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - [[EarlGrey selectElementWithMatcher:GetSyncSettings()] - performAction:grey_tap()]; - - // Check that Sync hasn't started yet, allowing the user to change some - // settings. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't have finished its original setup yet"); - - [self scrollToElementAndAssertVisibility: - AdvancedSyncSettingsDoneButtonMatcher()]; - [[EarlGrey selectElementWithMatcher:AdvancedSyncSettingsDoneButtonMatcher()] - performAction:grey_tap()]; - - // Check sync did not start yet. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't start when discarding advanced settings."); - - [self scrollToElementAndAssertVisibility:GetNoThanksButton()]; - [[EarlGrey selectElementWithMatcher:GetNoThanksButton()] - performAction:grey_tap()]; - - // Verify that the user is signed in. - [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; - - // Verify that the sync cell is visible and "Off" is displayed. - DismissDefaultBrowserPromo(); - [ChromeEarlGreyUI openSettingsMenu]; - [SigninEarlGrey verifySyncUIEnabled:NO]; - - // Close opened settings for proper tear down. - [[self class] removeAnyOpenMenusAndInfoBars]; -} - -// Checks that sync is turned on after the user chose to turn on sync in the -// advanced sync settings screen and that the correct sync options are selected. -- (void)testCustomSyncOn { - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - [[EarlGrey selectElementWithMatcher:GetSyncSettings()] - performAction:grey_tap()]; - - // Check that Sync hasn't started yet, allowing the user to change some - // settings. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't have finished its original setup yet"); - - // Toggle OFF Sync Everything and History. - [self toggleSwitchWithIdentifier:kSyncEverythingItemAccessibilityIdentifier - toValue:NO]; - [self toggleSwitchWithIdentifier:kSyncOmniboxHistoryIdentifier toValue:NO]; - - [self scrollToElementAndAssertVisibility: - AdvancedSyncSettingsDoneButtonMatcher()]; - [[EarlGrey selectElementWithMatcher:AdvancedSyncSettingsDoneButtonMatcher()] - performAction:grey_tap()]; - - // Check sync did not start yet. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't start when discarding advanced settings."); - - [self scrollToElementAndAssertVisibility:GetYesImInButton()]; - [[EarlGrey selectElementWithMatcher:GetYesImInButton()] - performAction:grey_tap()]; - - // Check sync did start. - GREYAssertTrue([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync should start when turning on sync in FRE."); - - DismissDefaultBrowserPromo(); - [ChromeEarlGreyUI openSettingsMenu]; - [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; - [SigninEarlGrey verifySyncUIEnabled:YES]; - - // Go to the sync settings. - [ChromeEarlGreyUI - tapSettingsMenuButton:chrome_test_util::ManageSyncSettingsButton()]; - - // Check that the correct sync options are toggled OFF. - [self verifySwitchWithIdentifier:kSyncEverythingItemAccessibilityIdentifier - toValue:NO]; - [self verifySwitchWithIdentifier:kSyncOmniboxHistoryIdentifier toValue:NO]; - - // Revert back sync options to Sync Everything ON. - [self toggleSwitchWithIdentifier:kSyncEverythingItemAccessibilityIdentifier - toValue:YES]; - - // Close opened settings for proper tear down. - [[self class] removeAnyOpenMenusAndInfoBars]; -} - -// Checks that the user is signed in, but no sync options is selected. -- (void)testCustomSyncOff { - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - [[EarlGrey selectElementWithMatcher:GetSyncSettings()] - performAction:grey_tap()]; - - // Check that Sync hasn't started yet, allowing the user to change some - // settings. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't have finished its original setup yet"); - - // Turn OFF sync. - NSArray* switchesIdentifier = @[ - kSyncEverythingItemAccessibilityIdentifier, - kSyncAutofillIdentifier, - kSyncBookmarksIdentifier, - kSyncOmniboxHistoryIdentifier, - kSyncOpenTabsIdentifier, - kSyncPasswordsIdentifier, - kSyncReadingListIdentifier, - kSyncPreferencesIdentifier, - ]; - for (NSString* identifier in switchesIdentifier) { - [self toggleSwitchWithIdentifier:identifier toValue:NO]; - } - - [self scrollToElementAndAssertVisibility: - AdvancedSyncSettingsDoneButtonMatcher()]; - [[EarlGrey selectElementWithMatcher:AdvancedSyncSettingsDoneButtonMatcher()] - performAction:grey_tap()]; - - // Check sync did not start yet. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't start when discarding advanced settings."); - - [self scrollToElementAndAssertVisibility:GetYesImInButton()]; - [[EarlGrey selectElementWithMatcher:GetYesImInButton()] - performAction:grey_tap()]; - - // Check sync did start. - GREYAssertTrue([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync should start when turning on sync in FRE."); - - DismissDefaultBrowserPromo(); - [ChromeEarlGreyUI openSettingsMenu]; - [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; - - // Go to the sync settings. - [ChromeEarlGreyUI - tapSettingsMenuButton:chrome_test_util::ManageSyncSettingsButton()]; - - // Check that the all sync options are toggled OFF. - for (NSString* identifier in switchesIdentifier) { - [self verifySwitchWithIdentifier:identifier toValue:NO]; - } - - // Revert back sync options to Sync Everything ON. - [self toggleSwitchWithIdentifier:kSyncEverythingItemAccessibilityIdentifier - toValue:YES]; - - // Close opened settings for proper tear down. - [[self class] removeAnyOpenMenusAndInfoBars]; -} - -// Checks that the user is not signed in and that sync is turned off after the -// user chose to not sign-in even though they selected some sync options in the -// advanced sync settings screen. -- (void)testCustomSyncSignout { - FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - [self verifyWelcomeScreenIsDisplayed]; - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - [self verifySignInSyncScreenIsDisplayed]; - [[EarlGrey selectElementWithMatcher:GetSyncSettings()] - performAction:grey_tap()]; - - // Check that Sync hasn't started yet, allowing the user to change some - // settings. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't have finished its original setup yet"); - - // Toggle OFF Sync Everything and History. - [self toggleSwitchWithIdentifier:kSyncEverythingItemAccessibilityIdentifier - toValue:NO]; - [self toggleSwitchWithIdentifier:kSyncOmniboxHistoryIdentifier toValue:NO]; - - [self scrollToElementAndAssertVisibility: - AdvancedSyncSettingsDoneButtonMatcher()]; - [[EarlGrey selectElementWithMatcher:AdvancedSyncSettingsDoneButtonMatcher()] - performAction:grey_tap()]; - - // Check sync did not start yet. - GREYAssertFalse([FirstRunAppInterface isSyncFirstSetupComplete], - @"Sync shouldn't start when discarding advanced settings."); - - // Do not sign-in/sync. - [self scrollToElementAndAssertVisibility:GetNoThanksButton()]; - [[EarlGrey selectElementWithMatcher:GetNoThanksButton()] - performAction:grey_tap()]; - - // Verify that the browser isn't signed in by validating that there isn't a - // sync cell visible in settings. - DismissDefaultBrowserPromo(); - [ChromeEarlGreyUI openSettingsMenu]; - [SigninEarlGrey verifySyncUIIsHidden]; - - // Revert back sync options to Sync Everything ON. - [[self class] removeAnyOpenMenusAndInfoBars]; - [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity]; - [ChromeEarlGreyUI openSettingsMenu]; - [ChromeEarlGreyUI - tapSettingsMenuButton:chrome_test_util::ManageSyncSettingsButton()]; - [self toggleSwitchWithIdentifier:kSyncEverythingItemAccessibilityIdentifier - toValue:YES]; - - // Close opened settings for proper tear down. - [[self class] removeAnyOpenMenusAndInfoBars]; -} - -// Checks that the sync screen doesn't appear when the SyncDisabled policy is -// enabled. -- (void)testSyncDisabled { - policy_test_utils::SetPolicy(true, policy::key::kSyncDisabled); - - // Go to the sign-in screen. - [self scrollToElementAndAssertVisibility:GetAcceptButton()]; - [[EarlGrey selectElementWithMatcher:GetAcceptButton()] - performAction:grey_tap()]; - - // The Sync screen should not be displayed, so the NTP should be visible. - [self verifyDefaultBrowserScreenIsDisplayed]; -} - -@end
diff --git a/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm b/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm index 4884d85..9fdd935 100644 --- a/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm +++ b/ios/chrome/browser/ui/first_run/first_run_screen_provider.mm
@@ -5,7 +5,6 @@ #import "ios/chrome/browser/ui/first_run/first_run_screen_provider.h" #import "base/notreached.h" -#import "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/screen/screen_provider+protected.h" #import "ios/chrome/browser/ui/screen/screen_type.h" @@ -17,17 +16,8 @@ - (instancetype)init { NSMutableArray* screens = [NSMutableArray array]; - - switch (fre_field_trial::GetNewMobileIdentityConsistencyFRE()) { - case NewMobileIdentityConsistencyFRE::kTangibleSyncA: - [screens addObject:@(kSignIn)]; - [screens addObject:@(kTangibleSync)]; - break; - case NewMobileIdentityConsistencyFRE::kOld: - [screens addObject:@(kWelcomeAndConsent)]; - [screens addObject:@(kSignInAndSync)]; - break; - } + [screens addObject:@(kSignIn)]; + [screens addObject:@(kTangibleSync)]; [screens addObject:@(kDefaultBrowserPromo)]; [screens addObject:@(kStepsCompleted)]; return [super initWithScreens:screens];
diff --git a/ios/chrome/browser/ui/first_run/fre_field_trial.cc b/ios/chrome/browser/ui/first_run/fre_field_trial.cc deleted file mode 100644 index 33eb79a..0000000 --- a/ios/chrome/browser/ui/first_run/fre_field_trial.cc +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/ui/first_run/fre_field_trial.h" - -#include "components/signin/ios/browser/features.h" - -namespace fre_field_trial { - -NewMobileIdentityConsistencyFRE GetNewMobileIdentityConsistencyFRE() { - return base::FeatureList::IsEnabled(signin::kNewMobileIdentityConsistencyFRE) - ? NewMobileIdentityConsistencyFRE::kTangibleSyncA - : NewMobileIdentityConsistencyFRE::kOld; -} - -} // namespace fre_field_trial
diff --git a/ios/chrome/browser/ui/first_run/fre_field_trial.h b/ios/chrome/browser/ui/first_run/fre_field_trial.h deleted file mode 100644 index 23818c2..0000000 --- a/ios/chrome/browser/ui/first_run/fre_field_trial.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_FIRST_RUN_FRE_FIELD_TRIAL_H_ -#define IOS_CHROME_BROWSER_UI_FIRST_RUN_FRE_FIELD_TRIAL_H_ - -// Version of the new MICE FRE to show. -enum class NewMobileIdentityConsistencyFRE { - // New MICE FRE with tangible sync (welcome with sign-in + tangible sync - // screens). - // Strings in TangibleSyncViewController are set according to the A, B or C - // variants. - kTangibleSyncA = 0, - // Old FRE. - kOld, -}; - -namespace fre_field_trial { - -// Returns the FRE to display according to the feature flag and experiment. -// See NewMobileIdentityConsistencyFRE. -NewMobileIdentityConsistencyFRE GetNewMobileIdentityConsistencyFRE(); - -} // namespace fre_field_trial - -#endif // IOS_CHROME_BROWSER_UI_FIRST_RUN_FRE_FIELD_TRIAL_H_
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_view_controller.mm b/ios/chrome/browser/ui/first_run/signin/signin_screen_view_controller.mm index 95356cd..c03e4d7 100644 --- a/ios/chrome/browser/ui/first_run/signin/signin_screen_view_controller.mm +++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_view_controller.mm
@@ -10,7 +10,6 @@ #import "ios/chrome/browser/ui/commands/tos_commands.h" #import "ios/chrome/browser/ui/elements/activity_overlay_view.h" #import "ios/chrome/browser/ui/first_run/first_run_constants.h" -#import "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.h" #import "ios/chrome/common/string_util.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" @@ -71,15 +70,7 @@ // Set `self.titleText` and `self.subtitleText`. switch (self.signinStatus) { case SigninScreenConsumerSigninStatusAvailable: { - switch (fre_field_trial::GetNewMobileIdentityConsistencyFRE()) { - case NewMobileIdentityConsistencyFRE::kTangibleSyncA: - self.titleText = - l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_TITLE); - break; - case NewMobileIdentityConsistencyFRE::kOld: - NOTREACHED(); - break; - } + self.titleText = l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_TITLE); self.subtitleText = l10n_util::GetNSString(IDS_IOS_FIRST_RUN_SIGNIN_SUBTITLE_SHORT); break;
diff --git a/ios/chrome/browser/ui/first_run/welcome/tos_coordinator.mm b/ios/chrome/browser/ui/first_run/welcome/tos_coordinator.mm index a7f7f15..08a7b34a 100644 --- a/ios/chrome/browser/ui/first_run/welcome/tos_coordinator.mm +++ b/ios/chrome/browser/ui/first_run/welcome/tos_coordinator.mm
@@ -14,7 +14,6 @@ #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/commands/tos_commands.h" -#import "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/first_run/welcome/tos_view_controller.h" #import "ios/chrome/browser/ui/util/terms_util.h" #import "ios/chrome/grit/ios_strings.h" @@ -62,26 +61,8 @@ // Creates a WKWebView and load the terms of services html page in it. - (WKWebView*)newWebViewDisplayingTOS { - NSURL* TOSURL = nil; - switch (fre_field_trial::GetNewMobileIdentityConsistencyFRE()) { - case NewMobileIdentityConsistencyFRE::kTangibleSyncA: { - TOSURL = - net::NSURLWithGURL(GetUnifiedTermsOfServiceURL(/*embbeded=*/true)); - break; - } - case NewMobileIdentityConsistencyFRE::kOld: { - // Craft ToS path. - std::string TOS = GetTermsOfServicePath(); - NSString* path = [[base::mac::FrameworkBundle() bundlePath] - stringByAppendingPathComponent:base::SysUTF8ToNSString(TOS)]; - NSURLComponents* components = [[NSURLComponents alloc] init]; - [components setScheme:@"file"]; - [components setHost:@""]; - [components setPath:path]; - TOSURL = [components URL]; - break; - } - } + NSURL* TOSURL = + net::NSURLWithGURL(GetUnifiedTermsOfServiceURL(/*embbeded=*/true)); DCHECK(TOSURL); // Create web view.
diff --git a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_coordinator.mm b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_coordinator.mm index dc2f82e..229115e1 100644 --- a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_coordinator.mm +++ b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_coordinator.mm
@@ -11,7 +11,6 @@ #import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/commands/tos_commands.h" #import "ios/chrome/browser/ui/first_run/first_run_util.h" -#import "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/first_run/uma/uma_coordinator.h" #import "ios/chrome/browser/ui/first_run/welcome/tos_coordinator.h" #import "ios/chrome/browser/ui/first_run/welcome/welcome_screen_mediator.h"
diff --git a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.mm b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.mm index af8557f..55db3fd9 100644 --- a/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.mm +++ b/ios/chrome/browser/ui/first_run/welcome/welcome_screen_view_controller.mm
@@ -8,7 +8,6 @@ #import "base/strings/sys_string_conversions.h" #import "ios/chrome/browser/ui/commands/tos_commands.h" #import "ios/chrome/browser/ui/first_run/first_run_constants.h" -#import "ios/chrome/browser/ui/first_run/fre_field_trial.h" #import "ios/chrome/browser/ui/first_run/welcome/checkbox_button.h" #import "ios/chrome/common/string_util.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" @@ -127,9 +126,7 @@ UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.titleLabel); [self.delegate logScrollButtonVisible:!self.didReachBottom - withUMACheckboxVisible: - fre_field_trial::GetNewMobileIdentityConsistencyFRE() == - NewMobileIdentityConsistencyFRE::kOld]; + withUMACheckboxVisible:false]; } #pragma mark - Private
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm index 0cbdad6..43616128 100644 --- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm +++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -57,7 +57,7 @@ #import "ios/chrome/browser/ui/omnibox/omnibox_focus_delegate.h" #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h" #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h" -#import "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h" +#import "ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate_impl.h" #import "ios/chrome/browser/ui/util/pasteboard_util.h" #import "ios/chrome/browser/url_loading/image_search_param_generator.h" #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h" @@ -89,7 +89,7 @@ OmniboxControllerDelegate, URLDragDataSource> { // API endpoint for omnibox. - std::unique_ptr<WebOmniboxEditControllerImpl> _editController; + std::unique_ptr<WebOmniboxEditModelDelegateImpl> _editModelDelegate; // Observer that updates `viewController` for fullscreen events. std::unique_ptr<FullscreenUIUpdater> _omniboxFullscreenUIUpdater; // Observer that updates BadgeViewController for fullscreen events. @@ -170,14 +170,14 @@ self.viewController.layoutGuideCenter = LayoutGuideCenterForBrowser(self.browser); - _editController = - std::make_unique<WebOmniboxEditControllerImpl>(self, self.delegate); - _editController->SetURLLoader(self); + _editModelDelegate = + std::make_unique<WebOmniboxEditModelDelegateImpl>(self, self.delegate); + _editModelDelegate->SetURLLoader(self); self.omniboxCoordinator = [[OmniboxCoordinator alloc] initWithBaseViewController:nil browser:self.browser]; - self.omniboxCoordinator.editController = _editController.get(); + self.omniboxCoordinator.editModelDelegate = _editModelDelegate.get(); self.omniboxCoordinator.presenterDelegate = self.popupPresenterDelegate; [self.omniboxCoordinator start]; @@ -249,7 +249,7 @@ [self.omniboxCoordinator stop]; [self.badgeMediator disconnect]; self.badgeMediator = nil; - _editController.reset(); + _editModelDelegate.reset(); self.viewController = nil; [self.mediator disconnect];
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn index ee02ca7..6ef66b1c 100644 --- a/ios/chrome/browser/ui/main/BUILD.gn +++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -139,6 +139,7 @@ "//base/ios", "//components/breadcrumbs/core", "//components/breadcrumbs/core:feature_flags", + "//components/feature_engagement/public", "//components/infobars/core", "//components/prefs", "//components/prefs/ios", @@ -165,6 +166,7 @@ "//ios/chrome/browser/crash_report:crash_report_internal", "//ios/chrome/browser/crash_report/breadcrumbs", "//ios/chrome/browser/default_browser", + "//ios/chrome/browser/feature_engagement", "//ios/chrome/browser/first_run", "//ios/chrome/browser/geolocation", "//ios/chrome/browser/infobars",
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index 60569f5..3f21cef 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -20,6 +20,8 @@ #import "components/breadcrumbs/core/breadcrumb_manager_keyed_service.h" #import "components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h" #import "components/breadcrumbs/core/features.h" +#import "components/feature_engagement/public/event_constants.h" +#import "components/feature_engagement/public/tracker.h" #import "components/infobars/core/infobar_manager.h" #import "components/prefs/pref_service.h" #import "components/previous_session_info/previous_session_info.h" @@ -50,6 +52,7 @@ #import "ios/chrome/browser/crash_report/crash_report_helper.h" #import "ios/chrome/browser/crash_report/crash_restore_helper.h" #import "ios/chrome/browser/default_browser/promo_source.h" +#import "ios/chrome/browser/feature_engagement/tracker_factory.h" #import "ios/chrome/browser/first_run/first_run.h" #import "ios/chrome/browser/geolocation/geolocation_logger.h" #import "ios/chrome/browser/infobars/infobar_manager_impl.h" @@ -415,6 +418,7 @@ DefaultBrowserSceneAgent* sceneAgent = [DefaultBrowserSceneAgent agentFromScene:self.sceneState]; [sceneAgent.nonModalScheduler logUserEnteredAppViaFirstPartyScheme]; + [self notifyFETAppOpenedViaFirstParty]; } } @@ -1077,6 +1081,20 @@ [self maybeShowDefaultBrowserPromo:self.mainInterface.browser]; } +// Notifies the Feature Engagement Tracker that an eligibility criterion has +// been met for the default browser blue dot promo. +- (void)notifyFETAppOpenedViaFirstParty { + ChromeBrowserState* browserState = self.sceneState.appState.mainBrowserState; + if (!browserState || browserState->IsOffTheRecord()) { + return; + } + + if (HasRecentFirstPartyIntentLaunchesAndRecordsCurrentLaunch()) { + feature_engagement::TrackerFactory::GetForBrowserState(browserState) + ->NotifyEvent(feature_engagement::events::kBlueDotPromoCriterionMet); + } +} + // `YES` if Chrome is not the default browser, the app did not crash recently, // the user never saw the promo UI and is in the correct experiment groups. - (BOOL)potentiallyInterestedUser {
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_content_delegate.h b/ios/chrome/browser/ui/ntp/new_tab_page_content_delegate.h index fa83ed3..1836cda 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_content_delegate.h +++ b/ios/chrome/browser/ui/ntp/new_tab_page_content_delegate.h
@@ -23,6 +23,9 @@ // Signals to the receiver that the Fakebox is blurring. - (void)onFakeboxBlur; +// Signal to the Omnibox to enter the focused state. +- (void)focusOmnibox; + @end #endif // IOS_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_CONTENT_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm index 248a3c3..b18f591 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -1044,6 +1044,12 @@ [fakeboxFocuserHandler onFakeboxBlur]; } +- (void)focusOmnibox { + id<FakeboxFocuser> fakeboxFocuserHandler = + HandlerForProtocol(self.browser->GetCommandDispatcher(), FakeboxFocuser); + [fakeboxFocuserHandler fakeboxFocused]; +} + #pragma mark - NewTabPageDelegate - (void)updateFeedLayout {
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm index 8de87a0..7450ccbd 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
@@ -42,7 +42,7 @@ namespace { // Animation time for the shift up/down animations to focus/defocus omnibox. const CGFloat kShiftTilesDownAnimationDuration = 0.2; -const CGFloat kShiftTilesUpAnimationDuration = 0.25; +const CGFloat kShiftTilesUpAnimationDuration = 0.1; } // namespace @interface NewTabPageViewController () <NewTabPageOmniboxPositioning, @@ -229,7 +229,7 @@ [self updateFakeOmniboxForScrollPosition]; if (self.shouldFocusFakebox) { - [self focusFakebox]; + [self shiftTilesUpToFocusOmnibox]; self.shouldFocusFakebox = NO; } @@ -575,7 +575,7 @@ // action) needs to wait until it is ready. viewDidAppear: currently serves as // this proxy as there is no specific signal given from the feed that its // contents have loaded. - if (self.isFeedVisible && ![self collectionViewHasLoaded]) { + if (self.isFeedVisible && !self.viewDidAppear) { self.shouldFocusFakebox = YES; } else { [self shiftTilesUpToFocusOmnibox]; @@ -786,6 +786,7 @@ if (self.scrolledToMinimumHeight) { self.shouldAnimateHeader = NO; self.disableScrollAnimation = NO; + [self.ntpContentDelegate focusOmnibox]; [self.headerController completeHeaderFakeOmniboxFocusAnimationWithFinalPosition: UIViewAnimatingPositionEnd]; @@ -829,6 +830,7 @@ self.disableScrollAnimation = YES; [strongSelf.headerController expandHeaderForFocus]; shiftOmniboxToTop(); + [strongSelf.ntpContentDelegate focusOmnibox]; } }];
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn index a7d4649..aa3e2a6 100644 --- a/ios/chrome/browser/ui/omnibox/BUILD.gn +++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -8,8 +8,8 @@ sources = [ "omnibox_controller_delegate.h", "omnibox_focus_delegate.h", - "web_omnibox_edit_controller.cc", - "web_omnibox_edit_controller.h", + "web_omnibox_edit_model_delegate.cc", + "web_omnibox_edit_model_delegate.h", ] deps = [ "//base", @@ -136,8 +136,8 @@ "omnibox_view_controller.mm", "omnibox_view_ios.h", "omnibox_view_ios.mm", - "web_omnibox_edit_controller_impl.h", - "web_omnibox_edit_controller_impl.mm", + "web_omnibox_edit_model_delegate_impl.h", + "web_omnibox_edit_model_delegate_impl.mm", "zero_suggest_prefetch_helper.h", "zero_suggest_prefetch_helper.mm", ] @@ -150,6 +150,7 @@ "resources:omnibox_clear_icon", "//base", "//components/favicon/ios", + "//components/feature_engagement/public", "//components/open_from_clipboard:", "//components/resources", "//components/search_engines", @@ -162,6 +163,7 @@ "//ios/chrome/browser/bookmarks:bookmarks_utils", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/favicon", + "//ios/chrome/browser/feature_engagement", "//ios/chrome/browser/flags:system_flags", "//ios/chrome/browser/https_upgrades", "//ios/chrome/browser/main:public",
diff --git a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h index e75a3e4..f77f5ec2 100644 --- a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h +++ b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h
@@ -12,11 +12,11 @@ #include "ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.h" class ChromeBrowserState; -class WebOmniboxEditController; +class WebOmniboxEditModelDelegate; class ChromeOmniboxClientIOS : public OmniboxClient { public: - ChromeOmniboxClientIOS(WebOmniboxEditController* controller, + ChromeOmniboxClientIOS(WebOmniboxEditModelDelegate* edit_model_delegate, ChromeBrowserState* browser_state); ChromeOmniboxClientIOS(const ChromeOmniboxClientIOS&) = delete; @@ -46,6 +46,7 @@ const TemplateURL* template_url, const AutocompleteMatch& match, WindowOpenDisposition disposition) override; + void OnUserPastedInOmniboxResultingInValidURL() override; void OnFocusChanged(OmniboxFocusState state, OmniboxFocusChangeReason reason) override; void OnResultChanged(const AutocompleteResult& result, @@ -58,7 +59,7 @@ gfx::Image GetFavicon() const override; private: - WebOmniboxEditController* controller_; + WebOmniboxEditModelDelegate* edit_model_delegate_; ChromeBrowserState* browser_state_; AutocompleteSchemeClassifierImpl scheme_classifier_; };
diff --git a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm index 6ae422bb..5cc6f51b 100644 --- a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm +++ b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
@@ -5,13 +5,16 @@ #import "ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h" #import "base/feature_list.h" +#import "base/metrics/user_metrics.h" #import "base/strings/string_util.h" #import "base/strings/utf_string_conversions.h" #import "base/task/thread_pool.h" #import "components/favicon/ios/web_favicon_driver.h" +#import "components/feature_engagement/public/event_constants.h" +#import "components/feature_engagement/public/tracker.h" #import "components/omnibox/browser/autocomplete_match.h" #import "components/omnibox/browser/autocomplete_result.h" -#import "components/omnibox/browser/omnibox_edit_controller.h" +#import "components/omnibox/browser/omnibox_edit_model_delegate.h" #import "components/omnibox/browser/omnibox_log.h" #import "components/omnibox/common/omnibox_features.h" #import "components/search_engines/template_url_service.h" @@ -20,12 +23,14 @@ #import "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #import "ios/chrome/browser/bookmarks/bookmarks_utils.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/feature_engagement/tracker_factory.h" #import "ios/chrome/browser/https_upgrades/https_upgrade_service_factory.h" #import "ios/chrome/browser/prerender/prerender_service.h" #import "ios/chrome/browser/prerender/prerender_service_factory.h" #import "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h" -#import "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h" +#import "ios/chrome/browser/ui/default_promo/default_browser_utils.h" +#import "ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.h" #import "ios/chrome/browser/url/chrome_url_constants.h" #import "ios/chrome/common/intents/SearchInChromeIntent.h" #import "ios/chrome/grit/ios_strings.h" @@ -39,9 +44,10 @@ #endif ChromeOmniboxClientIOS::ChromeOmniboxClientIOS( - WebOmniboxEditController* controller, + WebOmniboxEditModelDelegate* edit_model_delegate, ChromeBrowserState* browser_state) - : controller_(controller), browser_state_(browser_state) {} + : edit_model_delegate_(edit_model_delegate), + browser_state_(browser_state) {} ChromeOmniboxClientIOS::~ChromeOmniboxClientIOS() {} @@ -51,16 +57,17 @@ } bool ChromeOmniboxClientIOS::CurrentPageExists() const { - return (controller_->GetWebState() != nullptr); + return (edit_model_delegate_->GetWebState() != nullptr); } const GURL& ChromeOmniboxClientIOS::GetURL() const { - return CurrentPageExists() ? controller_->GetWebState()->GetVisibleURL() - : GURL::EmptyGURL(); + return CurrentPageExists() + ? edit_model_delegate_->GetWebState()->GetVisibleURL() + : GURL::EmptyGURL(); } bool ChromeOmniboxClientIOS::IsLoading() const { - return controller_->GetWebState()->IsLoading(); + return edit_model_delegate_->GetWebState()->IsLoading(); } bool ChromeOmniboxClientIOS::IsPasteAndGoEnabled() const { @@ -73,7 +80,8 @@ } const SessionID& ChromeOmniboxClientIOS::GetSessionID() const { - return IOSChromeSessionTabHelper::FromWebState(controller_->GetWebState()) + return IOSChromeSessionTabHelper::FromWebState( + edit_model_delegate_->GetWebState()) ->session_id(); } @@ -140,6 +148,17 @@ } } +void ChromeOmniboxClientIOS::OnUserPastedInOmniboxResultingInValidURL() { + base::RecordAction( + base::UserMetricsAction("Mobile.Omnibox.iOS.PastedValidURL")); + + if (!browser_state_->IsOffTheRecord() && + HasRecentValidURLPastesAndRecordsCurrentPaste()) { + feature_engagement::TrackerFactory::GetForBrowserState(browser_state_) + ->NotifyEvent(feature_engagement::events::kBlueDotPromoCriterionMet); + } +} + void ChromeOmniboxClientIOS::OnResultChanged( const AutocompleteResult& result, bool default_match_changed, @@ -169,7 +188,8 @@ ui::PageTransition transition = ui::PageTransitionFromInt( match.transition | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); service->StartPrerender(match.destination_url, web::Referrer(), transition, - controller_->GetWebState(), is_inline_autocomplete); + edit_model_delegate_->GetWebState(), + is_inline_autocomplete); } else { service->CancelPrerender(); } @@ -204,17 +224,18 @@ } void ChromeOmniboxClientIOS::DiscardNonCommittedNavigations() { - controller_->GetWebState() + edit_model_delegate_->GetWebState() ->GetNavigationManager() ->DiscardNonCommittedItems(); } const std::u16string& ChromeOmniboxClientIOS::GetTitle() const { - return CurrentPageExists() ? controller_->GetWebState()->GetTitle() + return CurrentPageExists() ? edit_model_delegate_->GetWebState()->GetTitle() : base::EmptyString16(); } gfx::Image ChromeOmniboxClientIOS::GetFavicon() const { - return favicon::WebFaviconDriver::FromWebState(controller_->GetWebState()) + return favicon::WebFaviconDriver::FromWebState( + edit_model_delegate_->GetWebState()) ->GetFavicon(); }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.h b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.h index 349d134..934b5e7 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.h +++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.h
@@ -7,7 +7,7 @@ #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" -class WebOmniboxEditController; +class WebOmniboxEditModelDelegate; @protocol EditViewAnimatee; @class OmniboxPopupCoordinator; @class OmniboxTextFieldIOS; @@ -23,7 +23,7 @@ OmniboxPopupCoordinator* popupCoordinator; // The edit controller interfacing the `textField` and the omnibox components // code. Needs to be set before the coordinator is started. -@property(nonatomic, assign) WebOmniboxEditController* editController; +@property(nonatomic, assign) WebOmniboxEditModelDelegate* editModelDelegate; // Returns the animatee for the omnibox focus orchestrator. @property(nonatomic, strong, readonly) id<EditViewAnimatee> animatee; @@ -38,7 +38,7 @@ - (id<LocationBarOffsetProvider>)offsetProvider; // Start this coordinator. When it starts, it expects to have `textField` and -// `editController`. +// `editModelDelegate`. - (void)start; // Stop this coordinator. - (void)stop;
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm index f8ec30a2..a8817cc 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_coordinator.mm
@@ -92,7 +92,7 @@ // OmniboxPopupViewSuggestionsDelegate instead of OmniboxViewIOS. std::unique_ptr<OmniboxViewIOS> _editView; } -@synthesize editController = _editController; +@synthesize editModelDelegate = _editModelDelegate; @synthesize keyboardDelegate = _keyboardDelegate; @synthesize viewController = _viewController; @synthesize mediator = _mediator; @@ -134,12 +134,12 @@ UrlLoadingBrowserAgent::FromBrowser(self.browser); self.viewController.pasteDelegate = self.mediator; - DCHECK(self.editController); + DCHECK(self.editModelDelegate); id<OmniboxCommands> focuser = static_cast<id<OmniboxCommands>>(self.browser->GetCommandDispatcher()); _editView = std::make_unique<OmniboxViewIOS>( - self.textField, self.editController, self.browser->GetBrowserState(), + self.textField, self.editModelDelegate, self.browser->GetBrowserState(), focuser); self.pasteDelegate = [[OmniboxTextFieldPasteDelegate alloc] init]; [self.textField setPasteDelegate:self.pasteDelegate]; @@ -180,7 +180,7 @@ self.viewController.textChangeDelegate = nil; self.returnDelegate.acceptDelegate = nil; _editView.reset(); - self.editController = nil; + self.editModelDelegate = nil; self.viewController = nil; self.mediator.templateURLService = nullptr; // Unregister the observer. if (self.keyboardAccessoryView) {
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h index 6f65d4e..d2c76b1 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
@@ -19,7 +19,7 @@ class ChromeBrowserState; class GURL; -class WebOmniboxEditController; +class WebOmniboxEditModelDelegate; struct AutocompleteMatch; @class OmniboxTextFieldIOS; @protocol OmniboxCommands; @@ -33,7 +33,7 @@ public: // Retains `field`. OmniboxViewIOS(OmniboxTextFieldIOS* field, - WebOmniboxEditController* controller, + WebOmniboxEditModelDelegate* edit_model_delegate, ChromeBrowserState* browser_state, id<OmniboxCommands> omnibox_focuser); @@ -182,7 +182,7 @@ OmniboxTextFieldIOS* field_; - WebOmniboxEditController* controller_; // weak, owns us + WebOmniboxEditModelDelegate* edit_model_delegate_; // weak, owns us // Focuser, used to transition the location bar to focused/defocused state as // necessary. __weak id<OmniboxCommands> omnibox_focuser_;
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm index e3802c3..f5b0e2d 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -28,7 +28,7 @@ #import "ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h" #import "ios/chrome/browser/ui/omnibox/omnibox_ui_features.h" #import "ios/chrome/browser/ui/omnibox/omnibox_util.h" -#import "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h" +#import "ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.h" #import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/grit/ios_strings.h" @@ -50,16 +50,17 @@ #pragma mark - OminboxViewIOS OmniboxViewIOS::OmniboxViewIOS(OmniboxTextFieldIOS* field, - WebOmniboxEditController* controller, + WebOmniboxEditModelDelegate* edit_model_delegate, ChromeBrowserState* browser_state, id<OmniboxCommands> omnibox_focuser) - : OmniboxView(controller, - controller - ? std::make_unique<ChromeOmniboxClientIOS>(controller, - browser_state) - : nullptr), + : OmniboxView( + edit_model_delegate, + edit_model_delegate + ? std::make_unique<ChromeOmniboxClientIOS>(edit_model_delegate, + browser_state) + : nullptr), field_(field), - controller_(controller), + edit_model_delegate_(edit_model_delegate), omnibox_focuser_(omnibox_focuser), ignore_popup_updates_(false), popup_provider_(nullptr) { @@ -379,11 +380,11 @@ if (!popup_was_open_before_editing_began) [field_ enterPreEditState]; - // `controller_` is only forwarding the call to the BVC. This should only - // happen when the omnibox is being focused and it starts showing the popup; - // if the popup was already open, no need to call this. + // `edit_model_delegate_` is only forwarding the call to the BVC. This should + // only happen when the omnibox is being focused and it starts showing the + // popup; if the popup was already open, no need to call this. if (!popup_was_open_before_editing_began) - controller_->OnSetFocus(); + edit_model_delegate_->OnSetFocus(); } void OmniboxViewIOS::OnWillEndEditing() { @@ -674,7 +675,7 @@ } void OmniboxViewIOS::RemoveQueryRefinementChip() { - controller_->OnChanged(); + edit_model_delegate_->OnChanged(); } void OmniboxViewIOS::EndEditing() { @@ -688,7 +689,7 @@ // The controller looks at the current pre-edit state, so the call to // OnKillFocus() must come after exiting pre-edit. - controller_->OnKillFocus(); + edit_model_delegate_->OnKillFocus(); // Blow away any in-progress edits. RevertAll();
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios_unittest.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios_unittest.mm index ca50ba0e..ffc34aa 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios_unittest.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios_unittest.mm
@@ -25,7 +25,7 @@ browser_state_ = test_cbs_builder.Build(); mockOmniboxTextfield_ = OCMClassMock([OmniboxTextFieldLegacy class]); view_ = std::make_unique<OmniboxViewIOS>( - mockOmniboxTextfield_, /* WebOmniboxEditController*/ nullptr, + mockOmniboxTextfield_, /* WebOmniboxEditModelDelegate*/ nullptr, browser_state_.get(), /*id<OmniboxCommands>*/ nil); }
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.cc b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.cc deleted file mode 100644 index a988feb4..0000000 --- a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.cc +++ /dev/null
@@ -1,9 +0,0 @@ -// Copyright 2015 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h" - -WebOmniboxEditController::WebOmniboxEditController() {} - -WebOmniboxEditController::~WebOmniboxEditController() {}
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h deleted file mode 100644 index 26cfdb5..0000000 --- a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2015 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_CONTROLLER_H_ - -#include "components/omnibox/browser/omnibox_edit_controller.h" - -namespace web { -class WebState; -} - -// iOS-specific extension of the OmniboxEditController base class. -class WebOmniboxEditController : public OmniboxEditController { - public: - WebOmniboxEditController(const WebOmniboxEditController&) = delete; - WebOmniboxEditController& operator=(const WebOmniboxEditController&) = delete; - - // Returns the WebState of the currently active tab. - virtual web::WebState* GetWebState() = 0; - - // The autocomplete edit lost focus. - virtual void OnKillFocus() = 0; - - // The autocomplete got focus. In UI Refresh, this is not called if the popup - // was already open when the omnibox is refocused. - virtual void OnSetFocus() = 0; - - protected: - WebOmniboxEditController(); - ~WebOmniboxEditController() override; -}; - -#endif // IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h deleted file mode 100644 index ed6933e9..0000000 --- a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_CONTROLLER_IMPL_H_ -#define IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_CONTROLLER_IMPL_H_ - -#include "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller.h" - -@protocol LocationBarURLLoader; -@protocol OmniboxControllerDelegate; -@protocol OmniboxFocusDelegate; - -// A minimal implementation of WebOmniboxEditController. Designed to work with -// LocationBarMediator and LocationBarCoordinator. -// TODO(crbug.com/818641): downgrade from WebOmniboxEditController subclass -// straight to OmniboxEditController subclass once OmniboxViewIOS doesn't need -// it. -class WebOmniboxEditControllerImpl : public WebOmniboxEditController { - public: - WebOmniboxEditControllerImpl(id<OmniboxControllerDelegate> delegate, - id<OmniboxFocusDelegate> focus_delegate); - ~WebOmniboxEditControllerImpl() override; - - void SetURLLoader(id<LocationBarURLLoader> URLLoader) { - URLLoader_ = URLLoader; - } - - // WebOmniboxEditController methods. - web::WebState* GetWebState() override; - void OnKillFocus() override; - void OnSetFocus() override; - - // OmniboxEditController methods. - void OnAutocompleteAccept( - const GURL& destination_url, - TemplateURLRef::PostContent* post_content, - WindowOpenDisposition disposition, - ui::PageTransition transition, - AutocompleteMatchType::Type match_type, - base::TimeTicks match_selection_timestamp, - bool destination_url_entered_without_scheme, - const std::u16string& text, - const AutocompleteMatch& match, - const AutocompleteMatch& alternative_nav_match, - IDNA2008DeviationCharacter deviation_char_in_hostname) override; - void OnInputInProgress(bool in_progress) override {} - void OnChanged() override; - void OnPopupVisibilityChanged() override {} - LocationBarModel* GetLocationBarModel() override; - const LocationBarModel* GetLocationBarModel() const override; - - private: - __weak id<OmniboxControllerDelegate> delegate_; - __weak id<OmniboxFocusDelegate> focus_delegate_; - __weak id<LocationBarURLLoader> URLLoader_; -}; - -#endif // IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_CONTROLLER_IMPL_H_
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.cc b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.cc new file mode 100644 index 0000000..ca169a6 --- /dev/null +++ b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.cc
@@ -0,0 +1,9 @@ +// Copyright 2015 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.h" + +WebOmniboxEditModelDelegate::WebOmniboxEditModelDelegate() {} + +WebOmniboxEditModelDelegate::~WebOmniboxEditModelDelegate() {}
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.h b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.h new file mode 100644 index 0000000..ddb03b8 --- /dev/null +++ b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.h
@@ -0,0 +1,36 @@ +// Copyright 2015 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_MODEL_DELEGATE_H_ +#define IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_MODEL_DELEGATE_H_ + +#include "components/omnibox/browser/omnibox_edit_model_delegate.h" + +namespace web { +class WebState; +} + +// iOS-specific extension of the OmniboxEditModelDelegate base class. +class WebOmniboxEditModelDelegate : public OmniboxEditModelDelegate { + public: + WebOmniboxEditModelDelegate(const WebOmniboxEditModelDelegate&) = delete; + WebOmniboxEditModelDelegate& operator=(const WebOmniboxEditModelDelegate&) = + delete; + + // Returns the WebState of the currently active tab. + virtual web::WebState* GetWebState() = 0; + + // The autocomplete edit lost focus. + virtual void OnKillFocus() = 0; + + // The autocomplete got focus. In UI Refresh, this is not called if the popup + // was already open when the omnibox is refocused. + virtual void OnSetFocus() = 0; + + protected: + WebOmniboxEditModelDelegate(); + ~WebOmniboxEditModelDelegate() override; +}; + +#endif // IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_MODEL_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate_impl.h b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate_impl.h new file mode 100644 index 0000000..596656b --- /dev/null +++ b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate_impl.h
@@ -0,0 +1,59 @@ +// Copyright 2018 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_MODEL_DELEGATE_IMPL_H_ +#define IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_MODEL_DELEGATE_IMPL_H_ + +#include "ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate.h" + +@protocol LocationBarURLLoader; +@protocol OmniboxControllerDelegate; +@protocol OmniboxFocusDelegate; + +// A minimal implementation of WebOmniboxEditModelDelegate. Designed to work +// with LocationBarMediator and LocationBarCoordinator. +// TODO(crbug.com/818641): downgrade from WebOmniboxEditModelDelegate subclass +// straight to OmniboxEditModelDelegate subclass once OmniboxViewIOS doesn't +// need it. +class WebOmniboxEditModelDelegateImpl : public WebOmniboxEditModelDelegate { + public: + WebOmniboxEditModelDelegateImpl(id<OmniboxControllerDelegate> delegate, + id<OmniboxFocusDelegate> focus_delegate); + ~WebOmniboxEditModelDelegateImpl() override; + + void SetURLLoader(id<LocationBarURLLoader> URLLoader) { + URLLoader_ = URLLoader; + } + + // WebOmniboxEditModelDelegate methods. + web::WebState* GetWebState() override; + void OnKillFocus() override; + void OnSetFocus() override; + + // OmniboxEditModelDelegate methods. + void OnAutocompleteAccept( + const GURL& destination_url, + TemplateURLRef::PostContent* post_content, + WindowOpenDisposition disposition, + ui::PageTransition transition, + AutocompleteMatchType::Type match_type, + base::TimeTicks match_selection_timestamp, + bool destination_url_entered_without_scheme, + const std::u16string& text, + const AutocompleteMatch& match, + const AutocompleteMatch& alternative_nav_match, + IDNA2008DeviationCharacter deviation_char_in_hostname) override; + void OnInputInProgress(bool in_progress) override {} + void OnChanged() override; + void OnPopupVisibilityChanged() override {} + LocationBarModel* GetLocationBarModel() override; + const LocationBarModel* GetLocationBarModel() const override; + + private: + __weak id<OmniboxControllerDelegate> delegate_; + __weak id<OmniboxFocusDelegate> focus_delegate_; + __weak id<LocationBarURLLoader> URLLoader_; +}; + +#endif // IOS_CHROME_BROWSER_UI_OMNIBOX_WEB_OMNIBOX_EDIT_MODEL_DELEGATE_IMPL_H_
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.mm b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate_impl.mm similarity index 77% rename from ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.mm rename to ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate_impl.mm index 1e245775..218c04a 100644 --- a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.mm +++ b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate_impl.mm
@@ -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 "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h" +#import "ios/chrome/browser/ui/omnibox/web_omnibox_edit_model_delegate_impl.h" #import "components/omnibox/browser/location_bar_model.h" #import "ios/chrome/browser/ui/location_bar/location_bar_url_loader.h" @@ -14,30 +14,30 @@ #error "This file requires ARC support." #endif -WebOmniboxEditControllerImpl::WebOmniboxEditControllerImpl( +WebOmniboxEditModelDelegateImpl::WebOmniboxEditModelDelegateImpl( id<OmniboxControllerDelegate> delegate, id<OmniboxFocusDelegate> focus_delegate) : delegate_(delegate), focus_delegate_(focus_delegate) { // TODO(crbug.com/818645): add security icon and its a11y labels } -WebOmniboxEditControllerImpl::~WebOmniboxEditControllerImpl() {} +WebOmniboxEditModelDelegateImpl::~WebOmniboxEditModelDelegateImpl() {} -web::WebState* WebOmniboxEditControllerImpl::GetWebState() { +web::WebState* WebOmniboxEditModelDelegateImpl::GetWebState() { return [delegate_ webState]; } -void WebOmniboxEditControllerImpl::OnKillFocus() { +void WebOmniboxEditModelDelegateImpl::OnKillFocus() { // TODO(crbug.com/818648): disable fullscreen in LocationBarMediator. [focus_delegate_ omniboxDidResignFirstResponder]; } -void WebOmniboxEditControllerImpl::OnSetFocus() { +void WebOmniboxEditModelDelegateImpl::OnSetFocus() { // TODO(crbug.com/818648): reenable fullscreen in LocationBarMediator. [focus_delegate_ omniboxDidBecomeFirstResponder]; } -void WebOmniboxEditControllerImpl::OnAutocompleteAccept( +void WebOmniboxEditModelDelegateImpl::OnAutocompleteAccept( const GURL& destination_url, TemplateURLRef::PostContent* post_content, WindowOpenDisposition disposition, @@ -61,17 +61,17 @@ } } -void WebOmniboxEditControllerImpl::OnChanged() { +void WebOmniboxEditModelDelegateImpl::OnChanged() { // Called when anything is changed. Since the Mediator already observes the // WebState for security status changes, no need to do anything. // TODO(crbug.com/818645): update the security icon in LocationBarMediator. } -LocationBarModel* WebOmniboxEditControllerImpl::GetLocationBarModel() { +LocationBarModel* WebOmniboxEditModelDelegateImpl::GetLocationBarModel() { return [delegate_ locationBarModel]; } -const LocationBarModel* WebOmniboxEditControllerImpl::GetLocationBarModel() +const LocationBarModel* WebOmniboxEditModelDelegateImpl::GetLocationBarModel() const { return [delegate_ locationBarModel]; }
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm index 9315ae9..7264a04e 100644 --- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
@@ -26,7 +26,7 @@ #import "ios/chrome/browser/bookmarks/bookmark_model_bridge_observer.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/commerce/push_notification/push_notification_feature.h" -#import "ios/chrome/browser/find_in_page/java_script_find_tab_helper.h" +#import "ios/chrome/browser/find_in_page/abstract_find_tab_helper.h" #import "ios/chrome/browser/flags/system_flags.h" #import "ios/chrome/browser/follow/follow_browser_agent.h" #import "ios/chrome/browser/follow/follow_menu_updater.h" @@ -1044,7 +1044,7 @@ NSMutableArray<OverflowMenuDestination*>* newDestinations = [[NSMutableArray alloc] init]; - if (IsWhatsNewOverflowMenuUsed()) { + if (WasWhatsNewUsed()) { // Place What's New at the bottom of the overflow menu carousel. [newDestinations addObjectsFromArray:destinations]; [newDestinations addObject:self.whatsNewDestination]; @@ -1232,12 +1232,6 @@ self.helpActionsGroup.footer = nil; } - if (IsPinnedTabsOverflowEnabled()) { - // Enable/disable items based on page state. - self.pinTabAction.enabled = [self isCurrentURLWebURL]; - self.unpinTabAction.enabled = [self isCurrentURLWebURL]; - } - // The "Add to Reading List" functionality requires JavaScript execution, // which is paused while overlays are displayed over the web content area. self.readLaterAction.enabled = @@ -1305,7 +1299,7 @@ return NO; } - auto* helper = JavaScriptFindTabHelper::FromWebState(self.webState); + auto* helper = GetConcreteFindTabHelperFromWebState(self.webState); return (helper && helper->CurrentPageSupportsFindInPage() && !helper->IsFindUIActive()); } @@ -1836,7 +1830,10 @@ // Dismisses the menu and opens What's New. - (void)openWhatsNew { - SetWhatsNewOverflowMenuUsed(); + if (!WasWhatsNewUsed()) { + SetWhatsNewUsed(); + } + if (self.engagementTracker) { self.engagementTracker->NotifyEvent( feature_engagement::events::kViewedWhatsNew);
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm index 5519d5e3..ebbd95b 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -29,7 +29,7 @@ #import "ios/chrome/browser/bookmarks/bookmark_model_bridge_observer.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/commerce/push_notification/push_notification_feature.h" -#import "ios/chrome/browser/find_in_page/java_script_find_tab_helper.h" +#import "ios/chrome/browser/find_in_page/abstract_find_tab_helper.h" #import "ios/chrome/browser/follow/follow_browser_agent.h" #import "ios/chrome/browser/follow/follow_menu_updater.h" #import "ios/chrome/browser/follow/follow_tab_helper.h" @@ -881,7 +881,7 @@ - (BOOL)isFindInPageEnabled { if (!self.webState) return NO; - auto* helper = JavaScriptFindTabHelper::FromWebState(self.webState); + auto* helper = GetConcreteFindTabHelperFromWebState(self.webState); return (helper && helper->CurrentPageSupportsFindInPage() && !helper->IsFindUIActive()); }
diff --git a/ios/chrome/browser/ui/screen/screen_type.h b/ios/chrome/browser/ui/screen/screen_type.h index 89de0a8e..ef5cb4f 100644 --- a/ios/chrome/browser/ui/screen/screen_type.h +++ b/ios/chrome/browser/ui/screen/screen_type.h
@@ -7,12 +7,18 @@ // The types of the start up screens. typedef NS_ENUM(NSInteger, ScreenType) { - kWelcomeAndConsent, - kSignInAndSync, kSignIn, - kLegacySignIn, kTangibleSync, kDefaultBrowserPromo, + + // Deprecated. + // + // TODO(crbug.com/1407658) Remove the following entries and their + // corresponding screens as they are not obsolete. + kWelcomeAndConsent_DEPRECATED, + kSignInAndSync_DEPRECATED, + kLegacySignIn_DEPRECATED, + // It isn't a screen, but a signal that no more screen should be // presented. kStepsCompleted,
diff --git a/ios/chrome/browser/ui/sharing/activity_services/data/share_to_data_builder.mm b/ios/chrome/browser/ui/sharing/activity_services/data/share_to_data_builder.mm index bfb87b89..b48da63d 100644 --- a/ios/chrome/browser/ui/sharing/activity_services/data/share_to_data_builder.mm +++ b/ios/chrome/browser/ui/sharing/activity_services/data/share_to_data_builder.mm
@@ -8,7 +8,7 @@ #import "base/strings/sys_string_conversions.h" #import "components/send_tab_to_self/entry_point_display_reason.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" -#import "ios/chrome/browser/find_in_page/java_script_find_tab_helper.h" +#import "ios/chrome/browser/find_in_page/abstract_find_tab_helper.h" #import "ios/chrome/browser/signin/chrome_account_manager_service.h" #import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h" #import "ios/chrome/browser/sync/send_tab_to_self_sync_service_factory.h" @@ -69,8 +69,7 @@ userAgent = visibleItem->GetUserAgentType(); } - JavaScriptFindTabHelper* helper = - JavaScriptFindTabHelper::FromWebState(web_state); + auto* helper = GetConcreteFindTabHelperFromWebState(web_state); BOOL is_page_searchable = (helper && helper->CurrentPageSupportsFindInPage() && !helper->IsFindUIActive());
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_context_menu/tab_context_menu_helper.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_context_menu/tab_context_menu_helper.mm index c9c51ab..e9bcc47 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_context_menu/tab_context_menu_helper.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_context_menu/tab_context_menu_helper.mm
@@ -106,18 +106,6 @@ NSMutableArray<UIMenuElement*>* menuElements = [[NSMutableArray alloc] init]; - if (!IsURLNewTabPage(item.URL)) { - if ([self.contextMenuDelegate - respondsToSelector:@selector(shareURL:title:scenario:fromView:)]) { - [menuElements addObject:[actionFactory actionToShareWithBlock:^{ - [self.contextMenuDelegate - shareURL:item.URL - title:item.title - scenario:ActivityScenario::TabGridItem - fromView:cell]; - }]]; - } - if (IsPinnedTabsEnabled()) { if (pinned) { if ([self.contextMenuDelegate @@ -138,47 +126,59 @@ } } - if (item.URL.SchemeIsHTTPOrHTTPS() && - [self.contextMenuDelegate - respondsToSelector:@selector(addToReadingListURL:title:)]) { - [menuElements - addObject:[actionFactory actionToAddToReadingListWithBlock:^{ - [self.contextMenuDelegate addToReadingListURL:item.URL - title:item.title]; - }]]; - } + if (!IsURLNewTabPage(item.URL)) { + if ([self.contextMenuDelegate respondsToSelector:@selector + (shareURL:title:scenario:fromView:)]) { + [menuElements addObject:[actionFactory actionToShareWithBlock:^{ + [self.contextMenuDelegate + shareURL:item.URL + title:item.title + scenario:ActivityScenario::TabGridItem + fromView:cell]; + }]]; + } - UIAction* bookmarkAction; - const BOOL currentlyBookmarked = [self isTabItemBookmarked:item]; - if (currentlyBookmarked) { - if ([self.contextMenuDelegate - respondsToSelector:@selector(editBookmarkWithURL:)]) { - bookmarkAction = [actionFactory actionToEditBookmarkWithBlock:^{ - [self.contextMenuDelegate editBookmarkWithURL:item.URL]; - }]; + if (item.URL.SchemeIsHTTPOrHTTPS() && + [self.contextMenuDelegate + respondsToSelector:@selector(addToReadingListURL:title:)]) { + [menuElements + addObject:[actionFactory actionToAddToReadingListWithBlock:^{ + [self.contextMenuDelegate addToReadingListURL:item.URL + title:item.title]; + }]]; } - } else { - if ([self.contextMenuDelegate - respondsToSelector:@selector(bookmarkURL:title:)]) { - bookmarkAction = [actionFactory actionToBookmarkWithBlock:^{ - [self.contextMenuDelegate bookmarkURL:item.URL title:item.title]; - }]; + + UIAction* bookmarkAction; + const BOOL currentlyBookmarked = [self isTabItemBookmarked:item]; + if (currentlyBookmarked) { + if ([self.contextMenuDelegate + respondsToSelector:@selector(editBookmarkWithURL:)]) { + bookmarkAction = [actionFactory actionToEditBookmarkWithBlock:^{ + [self.contextMenuDelegate editBookmarkWithURL:item.URL]; + }]; + } + } else { + if ([self.contextMenuDelegate + respondsToSelector:@selector(bookmarkURL:title:)]) { + bookmarkAction = [actionFactory actionToBookmarkWithBlock:^{ + [self.contextMenuDelegate bookmarkURL:item.URL title:item.title]; + }]; + } + } + // Bookmarking can be disabled from prefs (from an enterprise policy), + // if that's the case grey out the option in the menu. + if (self.browser) { + BOOL isEditBookmarksEnabled = + self.browser->GetBrowserState()->GetPrefs()->GetBoolean( + bookmarks::prefs::kEditBookmarksEnabled); + if (!isEditBookmarksEnabled && bookmarkAction) { + bookmarkAction.attributes = UIMenuElementAttributesDisabled; + } + if (bookmarkAction) { + [menuElements addObject:bookmarkAction]; + } } } - // Bookmarking can be disabled from prefs (from an enterprise policy), - // if that's the case grey out the option in the menu. - if (self.browser) { - BOOL isEditBookmarksEnabled = - self.browser->GetBrowserState()->GetPrefs()->GetBoolean( - bookmarks::prefs::kEditBookmarksEnabled); - if (!isEditBookmarksEnabled && bookmarkAction) { - bookmarkAction.attributes = UIMenuElementAttributesDisabled; - } - if (bookmarkAction) { - [menuElements addObject:bookmarkAction]; - } - } - } // Thumb strip, pinned tabs and search results menus don't support tab // selection.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm index 9e1b502..f909d50 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -22,7 +22,7 @@ #import "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h" -#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" +#import "ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.h" #import "ios/chrome/browser/ui/bookmarks/editor/bookmarks_editor_coordinator.h" #import "ios/chrome/browser/ui/commands/application_commands.h" #import "ios/chrome/browser/ui/commands/bookmarks_commands.h" @@ -95,9 +95,9 @@ // ivar. Browser* _incognitoBrowser; - // The controller that shows the bookmarking UI after the user taps the Add + // The coordinator that shows the bookmarking UI after the user taps the Add // to Bookmarks button. - BookmarkInteractionController* _bookmarkInteractionController; + BookmarksCoordinator* _bookmarksCoordinator; // Coordinator to edit a bookmark. Used only if // kEnableNewBookmarksImplementation enabled. BookmarksEditorCoordinator* _bookmarksEditorCoordinator; @@ -235,7 +235,7 @@ [self.incognitoSnackbarCoordinator start]; [incognitoBrowser->GetCommandDispatcher() - startDispatchingToTarget:[self bookmarkInteractionController] + startDispatchingToTarget:[self bookmarksCoordinator] forProtocol:@protocol(BookmarksCommands)]; } @@ -282,8 +282,8 @@ [self dismissPopovers]; - if (_bookmarkInteractionController) { - [_bookmarkInteractionController dismissBookmarkModalControllerAnimated:YES]; + if (_bookmarksCoordinator) { + [_bookmarksCoordinator dismissBookmarkModalControllerAnimated:YES]; } // History may be presented on top of the tab grid. if (self.historyCoordinator) { @@ -516,14 +516,14 @@ #pragma mark - Private -// Lazily creates the bookmark interaction controller. -- (BookmarkInteractionController*)bookmarkInteractionController { - if (!_bookmarkInteractionController) { - _bookmarkInteractionController = [[BookmarkInteractionController alloc] - initWithBrowser:self.regularBrowser]; - _bookmarkInteractionController.parentController = self.baseViewController; +// Lazily creates the bookmarks coordinator. +- (BookmarksCoordinator*)bookmarksCoordinator { + if (!_bookmarksCoordinator) { + _bookmarksCoordinator = + [[BookmarksCoordinator alloc] initWithBrowser:self.regularBrowser]; + _bookmarksCoordinator.baseViewController = self.baseViewController; } - return _bookmarkInteractionController; + return _bookmarksCoordinator; } #pragma mark - Private (Thumb Strip) @@ -758,10 +758,10 @@ [self.incognitoSnackbarCoordinator start]; [_regularBrowser->GetCommandDispatcher() - startDispatchingToTarget:[self bookmarkInteractionController] + startDispatchingToTarget:[self bookmarksCoordinator] forProtocol:@protocol(BookmarksCommands)]; [_incognitoBrowser->GetCommandDispatcher() - startDispatchingToTarget:[self bookmarkInteractionController] + startDispatchingToTarget:[self bookmarksCoordinator] forProtocol:@protocol(BookmarksCommands)]; SceneState* sceneState = @@ -1148,7 +1148,7 @@ if (currentlyBookmarked) { [self editBookmarkWithURL:URL]; } else { - [self.bookmarkInteractionController bookmarkURL:URL title:title]; + [self.bookmarksCoordinator bookmarkURL:URL title:title]; } } @@ -1161,7 +1161,7 @@ _bookmarksEditorCoordinator.delegate = self; [_bookmarksEditorCoordinator start]; } else { - [self.bookmarkInteractionController presentBookmarkEditorForURL:URL]; + [self.bookmarksCoordinator presentBookmarkEditorForURL:URL]; } }
diff --git a/ios/chrome/browser/ui/whats_new/BUILD.gn b/ios/chrome/browser/ui/whats_new/BUILD.gn index 5a2cdfa..1367434 100644 --- a/ios/chrome/browser/ui/whats_new/BUILD.gn +++ b/ios/chrome/browser/ui/whats_new/BUILD.gn
@@ -65,6 +65,10 @@ deps = [ ":feature_flags", "//base", + "//ios/chrome/browser/application_context", + "//ios/chrome/browser/promos_manager", + "//ios/chrome/browser/promos_manager:constants", + "//ios/chrome/browser/promos_manager:features", "//ios/chrome/browser/ui:feature_flags", ] }
diff --git a/ios/chrome/browser/ui/whats_new/promo/whats_new_promo_display_handler.mm b/ios/chrome/browser/ui/whats_new/promo/whats_new_promo_display_handler.mm index ff234f5e..73bab27 100644 --- a/ios/chrome/browser/ui/whats_new/promo/whats_new_promo_display_handler.mm +++ b/ios/chrome/browser/ui/whats_new/promo/whats_new_promo_display_handler.mm
@@ -7,6 +7,7 @@ #import "base/check.h" #import "base/metrics/user_metrics.h" #import "ios/chrome/browser/promos_manager/constants.h" +#import "ios/chrome/browser/ui/whats_new/whats_new_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -17,7 +18,13 @@ #pragma mark - StandardPromoDisplayHandler - (void)handleDisplay { + // Don't show the promo if What's New has been previously open. + if (WasWhatsNewUsed()) { + return; + } + DCHECK(self.handler); + SetWhatsNewUsed(); [self.handler showWhatsNewPromo]; }
diff --git a/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent_unittest.mm b/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent_unittest.mm index 482c2e17..27d86bd6 100644 --- a/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent_unittest.mm +++ b/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent_unittest.mm
@@ -22,7 +22,6 @@ #import "testing/platform_test.h" #import "third_party/ocmock/OCMock/OCMock.h" #import "third_party/ocmock/gtest_support.h" -// #import "base/values.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -49,6 +48,8 @@ forKey:kWhatsNewLaunchesAfterFre]; [[NSUserDefaults standardUserDefaults] setBool:NO forKey:kWhatsNewPromoRegistrationKey]; + [[NSUserDefaults standardUserDefaults] setBool:NO + forKey:kWhatsNewUsageEntryKey]; } } // namespace
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_util.h b/ios/chrome/browser/ui/whats_new/whats_new_util.h index 52663db..13c8072 100644 --- a/ios/chrome/browser/ui/whats_new/whats_new_util.h +++ b/ios/chrome/browser/ui/whats_new/whats_new_util.h
@@ -16,12 +16,16 @@ // Key to store the number of launches after FRE. extern NSString* const kWhatsNewLaunchesAfterFre; +// Key to store whether a user interacted with What's New from the overflow +// menu. +extern NSString* const kWhatsNewUsageEntryKey; + // Returns whether What's New was used in the overflow menu. This is used to // decide on the location of the What's New entry point in the overflow menu. -bool IsWhatsNewOverflowMenuUsed(); +bool WasWhatsNewUsed(); // Set that What's New was used in the overflow menu. -void SetWhatsNewOverflowMenuUsed(); +void SetWhatsNewUsed(); // Returns whether What's New is enabled. bool IsWhatsNewEnabled();
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_util.mm b/ios/chrome/browser/ui/whats_new/whats_new_util.mm index 81be6ae9..9e9f572 100644 --- a/ios/chrome/browser/ui/whats_new/whats_new_util.mm +++ b/ios/chrome/browser/ui/whats_new/whats_new_util.mm
@@ -6,6 +6,10 @@ #import "base/ios/ios_util.h" #import "base/mac/foundation_util.h" +#import "ios/chrome/browser/application_context/application_context.h" +#import "ios/chrome/browser/promos_manager/constants.h" +#import "ios/chrome/browser/promos_manager/features.h" +#import "ios/chrome/browser/promos_manager/promos_manager.h" #import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/whats_new/feature_flags.h" @@ -15,10 +19,6 @@ namespace { -// Key to store whether a user interacted with What's New from the overflow -// menu. -NSString* const kOverflowMenuEntryKey = @"userHasInteractedWithWhatsNew"; - // Time interval of 6 days. This is used to calculate 6 days after FRE to // trigger What's New Promo. const NSTimeInterval kSixDays = 6 * 24 * 60 * 60; @@ -71,17 +71,27 @@ NSString* const kWhatsNewLaunchesAfterFre = @"whatsNewLaunchesAfterFre"; -bool IsWhatsNewOverflowMenuUsed() { +NSString* const kWhatsNewUsageEntryKey = @"userHasInteractedWithWhatsNew"; + +bool WasWhatsNewUsed() { return - [[NSUserDefaults standardUserDefaults] boolForKey:kOverflowMenuEntryKey]; + [[NSUserDefaults standardUserDefaults] boolForKey:kWhatsNewUsageEntryKey]; } -void SetWhatsNewOverflowMenuUsed() { - if (IsWhatsNewOverflowMenuUsed()) +void SetWhatsNewUsed() { + if (WasWhatsNewUsed()) { return; + } + + // Deregister What's New promo. + if (IsFullscreenPromosManagerEnabled()) { + PromosManager* promosManager = GetApplicationContext()->GetPromosManager(); + DCHECK(promosManager); + promosManager->DeregisterPromo(promos_manager::Promo::WhatsNew); + } [[NSUserDefaults standardUserDefaults] setBool:YES - forKey:kOverflowMenuEntryKey]; + forKey:kWhatsNewUsageEntryKey]; } bool IsWhatsNewEnabled() {
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn index 03020e6..4db83fc 100644 --- a/ios/chrome/test/BUILD.gn +++ b/ios/chrome/test/BUILD.gn
@@ -64,6 +64,8 @@ "//ios/chrome/browser/content_settings", "//ios/chrome/browser/policy:policy", "//ios/chrome/browser/prefs:browser_prefs", + "//ios/chrome/browser/promos_manager:features", + "//ios/chrome/browser/promos_manager:test_support", "//ios/chrome/browser/ui/util", "//ios/components/security_interstitials/safe_browsing:test_support", "//ios/components/webui:url_constants",
diff --git a/ios/chrome/test/testing_application_context.h b/ios/chrome/test/testing_application_context.h index 00ed182..0552a4e1 100644 --- a/ios/chrome/test/testing_application_context.h +++ b/ios/chrome/test/testing_application_context.h
@@ -16,6 +16,8 @@ class TestURLLoaderFactory; } // namespace network +class MockPromosManager; + class TestingApplicationContext : public ApplicationContext { public: TestingApplicationContext(); @@ -87,6 +89,7 @@ // hard dependency on the policy infrastructure. In order to outlive the pref // service, the policy connector must live outside the keyed services. std::unique_ptr<BrowserPolicyConnectorIOS> browser_policy_connector_; + std::unique_ptr<MockPromosManager> promos_manager_; ios::ChromeBrowserStateManager* chrome_browser_state_manager_; std::unique_ptr<network_time::NetworkTimeTracker> network_time_tracker_;
diff --git a/ios/chrome/test/testing_application_context.mm b/ios/chrome/test/testing_application_context.mm index a13899c..96391ff 100644 --- a/ios/chrome/test/testing_application_context.mm +++ b/ios/chrome/test/testing_application_context.mm
@@ -13,6 +13,8 @@ #import "components/network_time/network_time_tracker.h" #import "ios/chrome/browser/policy/browser_policy_connector_ios.h" #import "ios/chrome/browser/policy/configuration_policy_handler_list_factory.h" +#import "ios/chrome/browser/promos_manager/features.h" +#import "ios/chrome/browser/promos_manager/mock_promos_manager.h" #import "ios/components/security_interstitials/safe_browsing/fake_safe_browsing_service.h" #import "ios/public/provider/chrome/browser/push_notification/push_notification_api.h" #import "ios/public/provider/chrome/browser/signin/signin_identity_api.h" @@ -223,6 +225,12 @@ PromosManager* TestingApplicationContext::GetPromosManager() { DCHECK(thread_checker_.CalledOnValidThread()); + + if (IsFullscreenPromosManagerEnabled()) { + promos_manager_ = std::make_unique<MockPromosManager>(); + return promos_manager_.get(); + } + return nullptr; }
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index e51943b..78b615a 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -148b317f0d9d199b99b8ac465a0a07e303878bd4 \ No newline at end of file +2cab26a7a9815317bb99dddef6f32ae05306aff7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index da9b827..715a3ae 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -0ce167e7c9d10014bef96ecca2a66f78606486e4 \ No newline at end of file +1855d4d0a1a00ba7cf177b5199916e3fd29a93c8 \ No newline at end of file
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 f33de40a..49e5f2a 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 @@ -03de11a2ac36d2a70298de9c8fdabc13a0e55249 \ No newline at end of file +9d6e7e795bda2fe508a3d1be3069d5e5bca96e0d \ 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 eef1482..9db1f4d 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 @@ -5e0a3940755e0407131b9e7b25460d96e08255c9 \ No newline at end of file +d6c5789fa6765c148cae31b6682647b2b2c0e2d6 \ 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 47ab4a87..e33d74b 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 @@ -21cd01402ab9edef7b3e4835bffb250d0711637a \ No newline at end of file +711b8b31db2d3f38c89801241967e729241b30db \ 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 446c74b..c6a0c596 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 @@ -f0781e55de2b53b6c41eb11d544c9c1ee894d9c3 \ No newline at end of file +a26acdacd28144be9ca6f3a8544c6a79ae4b6471 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index c8fd59a92..dd0b7af 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -e9f429feab788dcbdc09341199f73733db83b78f \ No newline at end of file +cbe347e98cf4f398c9b3fad21abdd6931ab99a8d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index d8fe0b9..e91f0cb5 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -feb84aaef04c6fa896b05d1be69be5fe468b211b \ No newline at end of file +c05ca88c6cfe5e6410f860e9e1f427b6569ade16 \ 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 32f264d..f997dc65 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 @@ -87135b7ae1df06f5fa1b5bc81c0ac7c8176b7454 \ No newline at end of file +281bfe5361cd75a154dc4ae60cb00a36cd11bdb2 \ 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 355eb70..13039ba7e 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 @@ -9a2758b79a11e8231199ec549964753980b03871 \ No newline at end of file +021955a811301d90595fca897dcd93fec6d60d7b \ 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 e26ce1e9..7473126 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 @@ -9dae4cb0ee832cff5f90321667061d8035abe447 \ No newline at end of file +55d2acd3a570161369aeb78d94e376f4fb96f8f0 \ 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 d4afdf6..a42c05bb 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 @@ -2046a5df9f84ec9bc981aff0553c9bd66f94bdc0 \ No newline at end of file +cf32b2530892522d0f1842fd60001ed63b88144c \ No newline at end of file
diff --git a/ios/web/js_messaging/BUILD.gn b/ios/web/js_messaging/BUILD.gn index 33be392..3b32136 100644 --- a/ios/web/js_messaging/BUILD.gn +++ b/ios/web/js_messaging/BUILD.gn
@@ -31,8 +31,6 @@ "crw_js_window_id_manager.mm", "page_script_util.h", "page_script_util.mm", - "script_command_java_script_feature.h", - "script_command_java_script_feature.mm", "web_frame_impl.h", "web_frame_impl.mm", "web_frame_internal.h",
diff --git a/ios/web/js_messaging/java_script_feature_inttest.mm b/ios/web/js_messaging/java_script_feature_inttest.mm index 2d28e8e..57cbe67 100644 --- a/ios/web/js_messaging/java_script_feature_inttest.mm +++ b/ios/web/js_messaging/java_script_feature_inttest.mm
@@ -104,6 +104,65 @@ EXPECT_STREQ(kFakeJavaScriptFeaturePostMessageReplyValue, reply->c_str()); } +// Tests that a page which overrides the window.webkit object does not break the +// JavaScriptFeature JS->native messaging system when the feature script is +// using `sendWebKitMessage` from ios/web/public/js_messaging/resources/utils.ts +TEST_F(JavaScriptFeaturePageContentWorldTest, + MessagingWithOverriddenWebkitObject) { + LoadHtml(kPageHTML); + ExecuteJavaScript(@"webkit = undefined;"); + + ASSERT_FALSE(feature()->last_received_web_state()); + ASSERT_FALSE(feature()->last_received_message()); + + std::vector<base::Value> parameters; + parameters.push_back( + base::Value(kFakeJavaScriptFeaturePostMessageReplyValue)); + feature()->ReplyWithPostMessage(GetMainFrame(web_state()), parameters); + + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^bool { + return feature()->last_received_web_state(); + })); + + EXPECT_EQ(web_state(), feature()->last_received_web_state()); + + ASSERT_TRUE(feature()->last_received_message()->body()); + const std::string* reply = + feature()->last_received_message()->body()->GetIfString(); + ASSERT_TRUE(reply); + EXPECT_STREQ(kFakeJavaScriptFeaturePostMessageReplyValue, reply->c_str()); +} + +// Tests that a page which overrides the window.webkit object does not break the +// JavaScriptFeature JS->native messaging system when the feature script is +// using `__gCrWeb.common.sendWebKitMessage` +TEST_F(JavaScriptFeaturePageContentWorldTest, + MessagingWithOverriddenWebkitObjectCommonJS) { + LoadHtml(kPageHTML); + ExecuteJavaScript(@"webkit = undefined;"); + + ASSERT_FALSE(feature()->last_received_web_state()); + ASSERT_FALSE(feature()->last_received_message()); + + std::vector<base::Value> parameters; + parameters.push_back( + base::Value(kFakeJavaScriptFeaturePostMessageReplyValue)); + feature()->ReplyWithPostMessageCommonJS(GetMainFrame(web_state()), + parameters); + + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^bool { + return feature()->last_received_web_state(); + })); + + EXPECT_EQ(web_state(), feature()->last_received_web_state()); + + ASSERT_TRUE(feature()->last_received_message()->body()); + const std::string* reply = + feature()->last_received_message()->body()->GetIfString(); + ASSERT_TRUE(reply); + EXPECT_STREQ(kFakeJavaScriptFeaturePostMessageReplyValue, reply->c_str()); +} + // Tests that a JavaScriptFeature with // ReinjectionBehavior::kReinjectOnDocumentRecreation re-injects JavaScript in // the page content world.
diff --git a/ios/web/js_messaging/java_script_feature_util_impl.mm b/ios/web/js_messaging/java_script_feature_util_impl.mm index eef513a..6613ddb 100644 --- a/ios/web/js_messaging/java_script_feature_util_impl.mm +++ b/ios/web/js_messaging/java_script_feature_util_impl.mm
@@ -18,7 +18,6 @@ #import "ios/web/js_features/error_page/error_page_java_script_feature.h" #import "ios/web/js_features/scroll_helper/scroll_helper_java_script_feature.h" #import "ios/web/js_features/window_error/window_error_java_script_feature.h" -#import "ios/web/js_messaging/script_command_java_script_feature.h" #import "ios/web/js_messaging/web_frames_manager_java_script_feature.h" #import "ios/web/navigation/navigation_java_script_feature.h" #import "ios/web/navigation/session_restore_java_script_feature.h" @@ -135,7 +134,6 @@ GetShareWorkaroundJavaScriptFeature(), GetWindowErrorJavaScriptFeature(), NavigationJavaScriptFeature::GetInstance(), - ScriptCommandJavaScriptFeature::GetInstance(), SessionRestoreJavaScriptFeature::FromBrowserState(browser_state), TextFragmentsJavaScriptFeature::GetInstance(), WebFramesManagerJavaScriptFeature::FromBrowserState(browser_state),
diff --git a/ios/web/js_messaging/resources/message.js b/ios/web/js_messaging/resources/message.js index 3005bb74..c78c3a8 100644 --- a/ios/web/js_messaging/resources/message.js +++ b/ios/web/js_messaging/resources/message.js
@@ -20,31 +20,6 @@ __gCrWeb['message'] = __gCrWeb.message; /** - * Boolean to track if messaging is suspended. While suspended, messages will be - * queued and sent once messaging is no longer suspended. - * @type {boolean} - * @private - */ -var messaging_suspended_ = true; - -/** - * Object to manage queue of messages waiting to be sent to the main - * application for asynchronous processing. - * @type {Object} - * @private - */ -var messageQueue_ = { - scheme: 'crwebinvoke', - reset: function() { - messageQueue_.queue = []; - // Since the array will be JSON serialized, protect against non-standard - // custom versions of Array.prototype.toJSON. - delete messageQueue_.queue.toJSON; - } -}; -messageQueue_.reset(); - -/** * Unique identifier for this frame. * @type {?string} * @private @@ -52,68 +27,6 @@ var frameId_ = null; /** - * Invokes a command on the Objective-C side. - * @param {Object} command The command in a JavaScript object. - * @public - */ -__gCrWeb.message.invokeOnHost = function(command) { - messageQueue_.queue.push(command); - sendQueue_(messageQueue_); -}; - -/** - * Sends both queues if they contain messages. - */ -__gCrWeb.message.invokeQueues = function() { - if (messageQueue_.queue.length > 0) sendQueue_(messageQueue_); -}; - -function sendQueue_(queueObject) { - if (messaging_suspended_) { - // Leave messages queued if messaging is suspended. - return; - } - - var windowId = null; - try { - windowId = window.top.__gCrWeb['windowId']; - // Do nothing if windowId has not been set. - if (typeof windowId != 'string') { - return; - } - } catch (e) { - // A SecurityError will be thrown if this is a cross origin iframe. Allow - // sending the message in this case and it will be filtered by frameID. - if (e.name !== 'SecurityError') { - throw e; - } - } - - // Some pages/plugins implement Object.prototype.toJSON, which can result - // in serializing messageQueue_ to an invalid format. - var originalObjectToJSON = Object.prototype.toJSON; - if (originalObjectToJSON) delete Object.prototype.toJSON; - - queueObject.queue.forEach(function(command) { - var message = { - 'crwCommand': command, - 'crwFrameId': __gCrWeb.message['getFrameId']() - }; - if (windowId) { - message['crwWindowId'] = windowId; - } - __gCrWeb.common.sendWebKitMessage(queueObject.scheme, message); - }); - queueObject.reset(); - - if (originalObjectToJSON) { - // Restore Object.prototype.toJSON to prevent from breaking any - // functionality on the page that depends on its custom implementation. - Object.prototype.toJSON = originalObjectToJSON; - } -} - -/** * Returns the frameId associated with this frame. A new value will be created * for this frame the first time it is called. The frameId will persist as long * as this JavaScript context lives. For example, the frameId will be the same @@ -140,10 +53,6 @@ __gCrWeb.message['registerFrame'] = function() { __gCrWeb.common.sendWebKitMessage( 'FrameBecameAvailable', {'crwFrameId': __gCrWeb.message['getFrameId']()}); - // Allow messaging now that the frame has been registered and send any - // already queued messages. - messaging_suspended_ = false; - __gCrWeb.message.invokeQueues(); }; /**
diff --git a/ios/web/js_messaging/resources/window_id.js b/ios/web/js_messaging/resources/window_id.js index 6fee09f3..44bffdc 100644 --- a/ios/web/js_messaging/resources/window_id.js +++ b/ios/web/js_messaging/resources/window_id.js
@@ -11,9 +11,6 @@ // injection. __gCrWeb['windowId'] = '$(WINDOW_ID)'; -// Send messages queued since message.js injection. -__gCrWeb.message.invokeQueues(); - const event = new Event('__gCrWebWindowIdInjected'); window.dispatchEvent(event);
diff --git a/ios/web/js_messaging/script_command_java_script_feature.h b/ios/web/js_messaging/script_command_java_script_feature.h deleted file mode 100644 index b3f32ccf..0000000 --- a/ios/web/js_messaging/script_command_java_script_feature.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_WEB_JS_MESSAGING_SCRIPT_COMMAND_JAVA_SCRIPT_FEATURE_H_ -#define IOS_WEB_JS_MESSAGING_SCRIPT_COMMAND_JAVA_SCRIPT_FEATURE_H_ - -#include "base/no_destructor.h" -#import "ios/web/public/js_messaging/java_script_feature.h" - -namespace web { - -// Listens for script command messages and forwards them to the associated -// WebState. -class ScriptCommandJavaScriptFeature : public JavaScriptFeature { - public: - // This feature holds no state, so only a single static instance is ever - // needed. - static ScriptCommandJavaScriptFeature* GetInstance(); - - private: - friend class base::NoDestructor<ScriptCommandJavaScriptFeature>; - - // JavaScriptFeature overrides - absl::optional<std::string> GetScriptMessageHandlerName() const override; - void ScriptMessageReceived(WebState* web_state, - const ScriptMessage& script_message) override; - - ScriptCommandJavaScriptFeature(); - ~ScriptCommandJavaScriptFeature() override; - - ScriptCommandJavaScriptFeature(const ScriptCommandJavaScriptFeature&) = - delete; - ScriptCommandJavaScriptFeature& operator=( - const ScriptCommandJavaScriptFeature&) = delete; -}; - -} // namespace web - -#endif // IOS_WEB_JS_MESSAGING_SCRIPT_COMMAND_JAVA_SCRIPT_FEATURE_H_
diff --git a/ios/web/js_messaging/script_command_java_script_feature.mm b/ios/web/js_messaging/script_command_java_script_feature.mm deleted file mode 100644 index 385f1f73..0000000 --- a/ios/web/js_messaging/script_command_java_script_feature.mm +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/web/js_messaging/script_command_java_script_feature.h" - -#import <string> - -#import "base/logging.h" -#import "base/no_destructor.h" -#import "base/values.h" -#import "ios/web/public/js_messaging/script_message.h" -#import "ios/web/public/js_messaging/web_frame_util.h" -#import "ios/web/web_state/ui/crw_web_controller.h" -#import "ios/web/web_state/web_state_impl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -const char kScriptCommandHandlerName[] = "crwebinvoke"; - -const char kScriptMessageFrameIdKey[] = "crwFrameId"; -const char kScriptMessageCommandDictKey[] = "crwCommand"; -const char kScriptMessageCommandKey[] = "command"; - -} // namespace - -namespace web { - -// static -ScriptCommandJavaScriptFeature* ScriptCommandJavaScriptFeature::GetInstance() { - static base::NoDestructor<ScriptCommandJavaScriptFeature> instance; - return instance.get(); -} - -ScriptCommandJavaScriptFeature::ScriptCommandJavaScriptFeature() - : JavaScriptFeature(ContentWorld::kPageContentWorld, {}) {} -ScriptCommandJavaScriptFeature::~ScriptCommandJavaScriptFeature() = default; - -absl::optional<std::string> -ScriptCommandJavaScriptFeature::GetScriptMessageHandlerName() const { - return kScriptCommandHandlerName; -} - -void ScriptCommandJavaScriptFeature::ScriptMessageReceived( - WebState* web_state, - const ScriptMessage& script_message) { - if (!script_message.body() || !script_message.body()->is_dict()) { - return; - } - - web::WebFrame* sender_frame = nullptr; - std::string* frame_id = - script_message.body()->FindStringKey(kScriptMessageFrameIdKey); - if (frame_id) { - sender_frame = web::GetWebFrameWithId(web_state, *frame_id); - } - // Message must be associated with a current frame. - if (!sender_frame) { - DLOG(WARNING) << "Message from JS not handled due to no matching frame"; - return; - } - - base::Value* crw_command_dict = - script_message.body()->FindDictKey(kScriptMessageCommandDictKey); - if (!crw_command_dict || !crw_command_dict->is_dict()) { - DLOG(WARNING) << "JS message parameter not found: crwCommand"; - return; - } - - std::string* command = - crw_command_dict->FindStringKey(kScriptMessageCommandKey); - if (!command) { - DLOG(WARNING) << "JS message parameter not found: command"; - return; - } - - WebStateImpl* web_state_impl = WebStateImpl::FromWebState(web_state); - if (!web_state_impl) { - return; - } - - BOOL user_interacting = - [web_state_impl->GetWebController() isUserInteracting]; - absl::optional<GURL> request_url = script_message.request_url(); - GURL url = request_url ? request_url.value() : GURL(); - web_state_impl->OnScriptCommandReceived(*command, *crw_command_dict, url, - user_interacting, sender_frame); -} - -} // namespace web
diff --git a/ios/web/js_messaging/web_frame_impl_inttest.mm b/ios/web/js_messaging/web_frame_impl_inttest.mm index 5d662ae..00c5edb5 100644 --- a/ios/web/js_messaging/web_frame_impl_inttest.mm +++ b/ios/web/js_messaging/web_frame_impl_inttest.mm
@@ -131,68 +131,6 @@ })); } -// Tests that the main WebFrame is passed to the callback when sending a -// JS -> native message. -TEST_F(WebFrameImplIntTest, JavaScriptMessageFromMainFrame) { - ASSERT_TRUE(LoadHtml("<p>")); - __block bool command_received = false; - // The callback doesn't care about any of the parameters not related to - // frames. - auto callback = base::BindRepeating( - ^(const base::Value& /* json */, const GURL& /* origin_url */, - bool /* user_is_interacting */, WebFrame* sender_frame) { - command_received = true; - EXPECT_TRUE(sender_frame->IsMainFrame()); - EXPECT_EQ(web_state()->GetWebFramesManager()->GetMainWebFrame(), - sender_frame); - }); - - auto subscription = - web_state()->AddScriptCommandCallback(callback, "senderFrameTestCommand"); - EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ - return web_state()->GetWebFramesManager()->GetAllWebFrames().size() == 1; - })); - - base::Value message_dict(base::Value::Type::DICTIONARY); - message_dict.SetKey("command", - base::Value("senderFrameTestCommand.mainframe")); - std::vector<base::Value> params; - params.push_back(std::move(message_dict)); - CallJavaScriptFunction("message.invokeOnHost", params); - - EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ - return command_received; - })); -} - -// Tests that an iframe WebFrame is passed to the callback when sending a -// JS -> native message. -TEST_F(WebFrameImplIntTest, JavaScriptMessageFromFrame) { - ASSERT_TRUE(LoadHtml("<p><iframe>")); - __block bool command_received = false; - // The callback doesn't care about any of the parameters not related to - // frames. - auto callback = base::BindRepeating( - ^(const base::Value& /* json */, const GURL& /* origin_url */, - bool /* user_is_interacting */, WebFrame* sender_frame) { - command_received = true; - EXPECT_FALSE(sender_frame->IsMainFrame()); - EXPECT_EQ(GetChildWebFrameForWebState(web_state()), sender_frame); - }); - - auto subscription = - web_state()->AddScriptCommandCallback(callback, "senderFrameTestCommand"); - EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ - return web_state()->GetWebFramesManager()->GetAllWebFrames().size() == 2; - })); - ExecuteJavaScript( - @"window.frames[0].__gCrWeb.message.invokeOnHost({'command':'" - @"senderFrameTestCommand.iframe'});"); - EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ - return command_received; - })); -} - // Tests that the expected result is received from executing a JavaScript // function via `CallJavaScriptFunction` on the main frame in the page content // world.
diff --git a/ios/web/navigation/resources/navigation.js b/ios/web/navigation/resources/navigation.js index f6894b6..0f21c89e 100644 --- a/ios/web/navigation/resources/navigation.js +++ b/ios/web/navigation/resources/navigation.js
@@ -118,8 +118,3 @@ window.addEventListener('__gCrWebWindowIdInjected', function() { sendQueuedMessages(); }); - -/** Flush the message queue. */ -if (__gCrWeb.message) { - __gCrWeb.message.invokeQueues(); -}
diff --git a/ios/web/test/BUILD.gn b/ios/web/test/BUILD.gn index 3a8803fc..63112b9 100644 --- a/ios/web/test/BUILD.gn +++ b/ios/web/test/BUILD.gn
@@ -112,6 +112,8 @@ primary_script = "resources/java_script_feature_test_inject_once.js" sources = [ "resources/java_script_feature_test_inject_once.js" ] + + deps = [ "//ios/web/public/js_messaging:util_scripts" ] } optimize_js("java_script_feature_test_reinject_js") {
diff --git a/ios/web/test/fakes/fake_java_script_feature.h b/ios/web/test/fakes/fake_java_script_feature.h index 0c07585..5caea96 100644 --- a/ios/web/test/fakes/fake_java_script_feature.h +++ b/ios/web/test/fakes/fake_java_script_feature.h
@@ -43,6 +43,11 @@ void ReplyWithPostMessage(WebFrame* web_frame, const std::vector<base::Value>& parameters); + // Executes `kJavaScriptFeatureTestScriptReplyWithPostMessage` with + // `parameters` in `web_frame` using __gCrWeb.common.sendWebKitMessage. + void ReplyWithPostMessageCommonJS(WebFrame* web_frame, + const std::vector<base::Value>& parameters); + // Returns the number of errors received void GetErrorCount(WebFrame* web_frame, base::OnceCallback<void(const base::Value*)> callback);
diff --git a/ios/web/test/fakes/fake_java_script_feature.mm b/ios/web/test/fakes/fake_java_script_feature.mm index 1221fd2..f738091 100644 --- a/ios/web/test/fakes/fake_java_script_feature.mm +++ b/ios/web/test/fakes/fake_java_script_feature.mm
@@ -37,6 +37,8 @@ // `kFakeJavaScriptFeatureScriptHandlerName`. const char kScriptReplyWithPostMessage[] = "javaScriptFeatureTest.replyWithPostMessage"; +const char kScriptReplyWithPostMessageCommonJS[] = + "javaScriptFeatureTest.replyWithPostMessageCommonHelper"; // The function exposed by the feature JS which returns the count of errors // received in the JS error listener. @@ -73,6 +75,13 @@ CallJavaScriptFunction(web_frame, kScriptReplyWithPostMessage, parameters); } +void FakeJavaScriptFeature::ReplyWithPostMessageCommonJS( + WebFrame* web_frame, + const std::vector<base::Value>& parameters) { + CallJavaScriptFunction(web_frame, kScriptReplyWithPostMessageCommonJS, + parameters); +} + void FakeJavaScriptFeature::GetErrorCount( WebFrame* web_frame, base::OnceCallback<void(const base::Value*)> callback) {
diff --git a/ios/web/test/resources/java_script_feature_test_inject_once.js b/ios/web/test/resources/java_script_feature_test_inject_once.js index 8a72451..9076bca 100644 --- a/ios/web/test/resources/java_script_feature_test_inject_once.js +++ b/ios/web/test/resources/java_script_feature_test_inject_once.js
@@ -7,6 +7,8 @@ * will be executed once for a given |window| JS object. */ +import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js'; + /** * Namespace for this file. It depends on |__gCrWeb| having already been * injected. @@ -30,9 +32,15 @@ }; __gCrWeb.javaScriptFeatureTest.replyWithPostMessage = function(messageBody) { - window.webkit.messageHandlers['FakeHandlerName'].postMessage(messageBody); + sendWebKitMessage('FakeHandlerName', messageBody); }; -document.getElementsByTagName("body")[0].appendChild( - document.createTextNode("injected_script_loaded") -); \ No newline at end of file +// This function offers the same functionality as `replyWithPostMessage`, but +// uses the sendWebKitMessage implementation in __gCrWeb.common. +__gCrWeb.javaScriptFeatureTest.replyWithPostMessageCommonHelper = function( + messageBody) { + __gCrWeb.common.sendWebKitMessage('FakeHandlerName', messageBody); +}; + +document.getElementsByTagName('body')[0].appendChild( + document.createTextNode('injected_script_loaded'));
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index 2a1b999..e3172c89 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -465,22 +465,6 @@ EXPECT_EQ(url, web_state()->GetLastCommittedURL()); } -// Real WKWebView is required for CRWWebControllerMessageFromIFrame. -typedef WebTestWithWebState CRWWebControllerMessageFromIFrame; - -// Tests that invalid message from iframe does not cause a crash. -TEST_F(CRWWebControllerMessageFromIFrame, InvalidMessage) { - static NSString* const kHTMLIFrameSendsInvalidMessage = - @"<body><iframe name='f'></iframe></body>"; - - LoadHtml(kHTMLIFrameSendsInvalidMessage); - - // Sending unknown command from iframe should not cause a crash. - ExecuteJavaScript( - @"var bad_message = {'command' : 'unknown.command'};" - "frames['f'].__gCrWeb.message.invokeOnHost(bad_message);"); -} - // Real WKWebView is required for CRWWebControllerJSExecutionTest. typedef WebTestWithWebController CRWWebControllerJSExecutionTest;
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm index 4ce1f60..767c1f0 100644 --- a/ios/web/web_state/web_state_unittest.mm +++ b/ios/web/web_state/web_state_unittest.mm
@@ -106,31 +106,6 @@ }); } -// Tests that page which overrides window.webkit object does not break the -// messaging system. -TEST_F(WebStateTest, OverridingWebKitObject) { - // Add a script command handler. - __block bool message_received = false; - const web::WebState::ScriptCommandCallback callback = base::BindRepeating( - ^(const base::Value&, const GURL&, - /*interacted*/ bool, /*is_main_frame*/ web::WebFrame*) { - message_received = true; - }); - auto subscription = web_state()->AddScriptCommandCallback(callback, "test"); - - // Load the page which overrides window.webkit object and wait until the - // test message is received. - ASSERT_TRUE(LoadHtml( - "<script>" - " webkit = undefined;" - " __gCrWeb.message.invokeOnHost({'command': 'test.webkit-overriding'});" - "</script>")); - - WaitForCondition(^{ - return message_received; - }); -} - // Tests that reload with web::ReloadType::NORMAL is no-op when navigation // manager is empty. TEST_F(WebStateTest, ReloadWithNormalTypeWithEmptyNavigationManager) { @@ -366,74 +341,6 @@ ASSERT_FALSE(callback_data); } -// Tests that message sent from main frame triggers the ScriptCommandCallback -// with `is_main_frame` = true. -TEST_F(WebStateTest, MessageFromMainFrame) { - // Add a script command handler. - __block bool message_received = false; - __block bool message_from_main_frame = false; - __block base::Value message_value; - const web::WebState::ScriptCommandCallback callback = - base::BindRepeating(^(const base::Value& value, const GURL&, - bool user_interacted, WebFrame* sender_frame) { - message_received = true; - message_from_main_frame = sender_frame->IsMainFrame(); - message_value = value.Clone(); - }); - auto subscription = web_state()->AddScriptCommandCallback(callback, "test"); - - ASSERT_TRUE(LoadHtml( - "<script>" - " __gCrWeb.message.invokeOnHost({'command': 'test.from-main-frame'});" - "</script>")); - - WaitForCondition(^{ - return message_received; - }); - EXPECT_TRUE(message_from_main_frame); - EXPECT_TRUE(message_value.is_dict()); - EXPECT_EQ(message_value.DictSize(), size_t(1)); - base::Value* command = message_value.FindKey("command"); - EXPECT_NE(command, nullptr); - EXPECT_TRUE(command->is_string()); - EXPECT_EQ(command->GetString(), "test.from-main-frame"); -} - -// Tests that message sent from main frame triggers the ScriptCommandCallback -// with `is_main_frame` = false. -TEST_F(WebStateTest, MessageFromIFrame) { - // Add a script command handler. - __block bool message_received = false; - __block bool message_from_main_frame = false; - __block base::Value message_value; - const web::WebState::ScriptCommandCallback callback = - base::BindRepeating(^(const base::Value& value, const GURL&, - bool user_interacted, WebFrame* sender_frame) { - message_received = true; - message_from_main_frame = sender_frame->IsMainFrame(); - message_value = value.Clone(); - }); - auto subscription = web_state()->AddScriptCommandCallback(callback, "test"); - - ASSERT_TRUE(LoadHtml( - "<iframe srcdoc='" - "<script>" - " __gCrWeb.message.invokeOnHost({\"command\": \"test.from-iframe\"});" - "</script>" - "'/>")); - - WaitForCondition(^{ - return message_received; - }); - EXPECT_FALSE(message_from_main_frame); - EXPECT_TRUE(message_value.is_dict()); - EXPECT_EQ(message_value.DictSize(), size_t(1)); - base::Value* command = message_value.FindKey("command"); - EXPECT_NE(command, nullptr); - EXPECT_TRUE(command->is_string()); - EXPECT_EQ(command->GetString(), "test.from-iframe"); -} - // Tests that the web state has an opener after calling SetHasOpener(). TEST_F(WebStateTest, SetHasOpener) { ASSERT_FALSE(web_state()->HasOpener());
diff --git a/media/audio/cras/audio_manager_cras.cc b/media/audio/cras/audio_manager_cras.cc index 2b3ef7c..e51b1a20 100644 --- a/media/audio/cras/audio_manager_cras.cc +++ b/media/audio/cras/audio_manager_cras.cc
@@ -214,9 +214,12 @@ (tuned_system_apm_available && tuned_system_aec_allowed) || enforce_system_aec; - // TODO(hychao): query from CRAS - bool system_ns_supported = true; - bool system_agc_supported = true; + // TODO(b/266242770): Reintroduce the scheme for setting this to follow what + // was previously done in (the now removed) + // media/audio/cras/audio_manager_chromeos.cc. Until then, the NS and AGC + // effects are hardcoded to never run in CRAS. + bool system_ns_supported = false; + bool system_agc_supported = false; int aec_group_id = cras_util_->CrasGetAecGroupId(); if (!use_system_aec || IsSystemAecDeactivated(aec_group_id)) {
diff --git a/media/audio/cras/audio_manager_cras_unittest.cc b/media/audio/cras/audio_manager_cras_unittest.cc index f2b65bc..be86d33 100644 --- a/media/audio/cras/audio_manager_cras_unittest.cc +++ b/media/audio/cras/audio_manager_cras_unittest.cc
@@ -397,16 +397,6 @@ params.effects() & AudioParameters::ECHO_CANCELLER; } -bool DspNsAllowed(const AudioParameters& params) { - return params.effects() & AudioParameters::ALLOW_DSP_NOISE_SUPPRESSION && - params.effects() & AudioParameters::NOISE_SUPPRESSION; -} - -bool DspAgcAllowed(const AudioParameters& params) { - return params.effects() & AudioParameters::ALLOW_DSP_AUTOMATIC_GAIN_CONTROL && - params.effects() & AudioParameters::AUTOMATIC_GAIN_CONTROL; -} - class AudioManagerCrasTestAEC : public AudioManagerCrasTest, public ::testing::WithParamInterface<std::tuple<bool, bool>> { @@ -570,8 +560,6 @@ AudioParameters params = audio_manager_->GetInputStreamParameters(""); EXPECT_FALSE(DspAecAllowed(params)); - EXPECT_FALSE(DspNsAllowed(params)); - EXPECT_FALSE(DspAgcAllowed(params)); } TEST_P(AudioManagerCrasTestDSP, BehaviorWithCrOSEnforceSystemAec) { @@ -582,10 +570,6 @@ EXPECT_TRUE(DspAecAllowed(params) && aec_on_dsp_allowed_ || !DspAecAllowed(params) && !aec_on_dsp_allowed_); - EXPECT_TRUE(DspNsAllowed(params) && ns_on_dsp_allowed_ || - !DspNsAllowed(params) && !ns_on_dsp_allowed_); - EXPECT_TRUE(DspAgcAllowed(params) && agc_on_dsp_allowed_ || - !DspAgcAllowed(params) && !agc_on_dsp_allowed_); } TEST_P(AudioManagerCrasTestDSP, BehaviorWithCrOSEnforceSystemAecNs) { @@ -596,10 +580,6 @@ EXPECT_TRUE(DspAecAllowed(params) && aec_on_dsp_allowed_ || !DspAecAllowed(params) && !aec_on_dsp_allowed_); - EXPECT_TRUE(DspNsAllowed(params) && ns_on_dsp_allowed_ || - !DspNsAllowed(params) && !ns_on_dsp_allowed_); - EXPECT_TRUE(DspAgcAllowed(params) && agc_on_dsp_allowed_ || - !DspAgcAllowed(params) && !agc_on_dsp_allowed_); } TEST_P(AudioManagerCrasTestDSP, BehaviorWithCrOSEnforceSystemAecAgc) { @@ -610,10 +590,6 @@ EXPECT_TRUE(DspAecAllowed(params) && aec_on_dsp_allowed_ || !DspAecAllowed(params) && !aec_on_dsp_allowed_); - EXPECT_TRUE(DspNsAllowed(params) && ns_on_dsp_allowed_ || - !DspNsAllowed(params) && !ns_on_dsp_allowed_); - EXPECT_TRUE(DspAgcAllowed(params) && agc_on_dsp_allowed_ || - !DspAgcAllowed(params) && !agc_on_dsp_allowed_); } TEST_P(AudioManagerCrasTestDSP, BehaviorWithCrOSEnforceSystemAecNsAgc) { @@ -624,10 +600,6 @@ EXPECT_TRUE(DspAecAllowed(params) && aec_on_dsp_allowed_ || !DspAecAllowed(params) && !aec_on_dsp_allowed_); - EXPECT_TRUE(DspNsAllowed(params) && ns_on_dsp_allowed_ || - !DspNsAllowed(params) && !ns_on_dsp_allowed_); - EXPECT_TRUE(DspAgcAllowed(params) && agc_on_dsp_allowed_ || - !DspAgcAllowed(params) && !agc_on_dsp_allowed_); } } // namespace
diff --git a/media/cdm/json_web_key.cc b/media/cdm/json_web_key.cc index e2e1784..50fad26 100644 --- a/media/cdm/json_web_key.cc +++ b/media/cdm/json_web_key.cc
@@ -296,8 +296,8 @@ CdmSessionType session_type, std::vector<uint8_t>* license) { // Create the license request. - base::Value request(base::Value::Type::DICT); - base::Value list(base::Value::Type::LIST); + base::Value::Dict request; + base::Value::List list; for (const auto& key_id : key_ids) { std::string key_id_string; base::Base64UrlEncode( @@ -307,14 +307,14 @@ list.Append(key_id_string); } - request.SetKey(kKeyIdsTag, std::move(list)); + request.Set(kKeyIdsTag, std::move(list)); switch (session_type) { case CdmSessionType::kTemporary: - request.SetStringKey(kTypeTag, kTemporarySession); + request.Set(kTypeTag, kTemporarySession); break; case CdmSessionType::kPersistentLicense: - request.SetStringKey(kTypeTag, kPersistentLicenseSession); + request.Set(kTypeTag, kPersistentLicenseSession); break; } @@ -328,9 +328,9 @@ license->swap(result); } -base::Value MakeKeyIdsDictionary(const KeyIdList& key_ids) { - base::Value dictionary(base::Value::Type::DICT); - base::Value list(base::Value::Type::LIST); +base::Value::Dict MakeKeyIdsDictionary(const KeyIdList& key_ids) { + base::Value::Dict dictionary; + base::Value::List list; for (const auto& key_id : key_ids) { std::string key_id_string; base::Base64UrlEncode( @@ -340,12 +340,12 @@ list.Append(key_id_string); } - dictionary.SetKey(kKeyIdsTag, std::move(list)); + dictionary.Set(kKeyIdsTag, std::move(list)); return dictionary; } std::vector<uint8_t> SerializeDictionaryToVector( - const base::Value& dictionary) { + const base::Value::Dict& dictionary) { // Serialize the dictionary as a string. std::string json; JSONStringValueSerializer serializer(&json);
diff --git a/media/filters/hls_demuxer.cc b/media/filters/hls_demuxer.cc index 13f893f..dab68081 100644 --- a/media/filters/hls_demuxer.cc +++ b/media/filters/hls_demuxer.cc
@@ -87,6 +87,11 @@ // and give it `status_cb`. } +bool HlsDemuxer::IsSeekable() const { + // The underlying wrapping ChunkDemuxer is seekable. + return true; +} + void HlsDemuxer::Stop() { DVLOG(1) << __func__; DCHECK(task_runner_->RunsTasksInCurrentSequence());
diff --git a/media/filters/hls_demuxer.h b/media/filters/hls_demuxer.h index 905448a0..b7cb48b1 100644 --- a/media/filters/hls_demuxer.h +++ b/media/filters/hls_demuxer.h
@@ -46,6 +46,7 @@ void StartWaitingForSeek(base::TimeDelta seek_time) override; void CancelPendingSeek(base::TimeDelta seek_time) override; void Seek(base::TimeDelta time, PipelineStatusCallback status_cb) override; + bool IsSeekable() const override; void Stop() override; base::TimeDelta GetStartTime() const override; base::Time GetTimelineOffset() const override;
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.cc b/media/gpu/mac/vt_video_decode_accelerator_mac.cc index 05ec0ba..d0340d70 100644 --- a/media/gpu/mac/vt_video_decode_accelerator_mac.cc +++ b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
@@ -1058,12 +1058,31 @@ if (result != H264Parser::kOk) break; for (auto& sei_msg : sei.msgs) { - if (sei_msg.type == H264SEIMessage::kSEIRecoveryPoint && - sei_msg.recovery_point.recovery_frame_cnt == 0) { - // We only support immediate recovery points. Supporting - // future points would require dropping |recovery_frame_cnt| - // frames when needed. - frame->has_recovery_point = true; + switch (sei_msg.type) { + case H264SEIMessage::kSEIRecoveryPoint: + if (sei_msg.recovery_point.recovery_frame_cnt == 0) { + // We only support immediate recovery points. Supporting + // future points would require dropping |recovery_frame_cnt| + // frames when needed. + frame->has_recovery_point = true; + } + break; + case H264SEIMessage::kSEIMasteringDisplayInfo: + if (!config_.hdr_metadata) { + config_.hdr_metadata = gfx::HDRMetadata(); + } + sei_msg.mastering_display_info.PopulateColorVolumeMetadata( + config_.hdr_metadata->color_volume_metadata); + break; + case H264SEIMessage::kSEIContentLightLevelInfo: + if (!config_.hdr_metadata) { + config_.hdr_metadata = gfx::HDRMetadata(); + } + sei_msg.content_light_level_info.PopulateHDRMetadata( + config_.hdr_metadata.value()); + break; + default: + break; } } break; @@ -1151,6 +1170,7 @@ if (frame->is_idr || frame->has_recovery_point) waiting_for_idr_ = false; + frame->hdr_metadata = config_.hdr_metadata; // If no IDR has been seen yet, skip decoding. Note that Flash sends // configuration changes as a bitstream with only SPS/PPS; we don't print
diff --git a/media/gpu/v4l2/v4l2_unittest.cc b/media/gpu/v4l2/v4l2_unittest.cc index 616b28e..3fc4663 100644 --- a/media/gpu/v4l2/v4l2_unittest.cc +++ b/media/gpu/v4l2/v4l2_unittest.cc
@@ -145,12 +145,8 @@ const auto gbm_format = ToGBMFormat(chosen_v4l2_pixel_format); ASSERT_NE(gbm_format, static_cast<uint32_t>(DRM_FORMAT_INVALID)); - // We expect that the V4L2 device will round the resolution height to the - // nearest multiple of 32. Round GBM height to the nearest multiple of 32 - // to compare to the V4L2 coded size. - const auto adjusted_height = base::bits::AlignUp(resolution.height(), 32); struct gbm_bo* bo = gbm_bo_create( - gbm, resolution.width(), adjusted_height, gbm_format, + gbm, coded_size.width(), coded_size.height(), gbm_format, GBM_BO_USE_SCANOUT | GBM_BO_USE_TEXTURING | GBM_BO_USE_HW_VIDEO_DECODER); ASSERT_TRUE(bo);
diff --git a/media/mojo/mojom/remoting.mojom b/media/mojo/mojom/remoting.mojom index c0fbf50..b437b24 100644 --- a/media/mojo/mojom/remoting.mojom +++ b/media/mojo/mojom/remoting.mojom
@@ -20,9 +20,13 @@ // from a data pipe and then sent to the remote endpoint. There is one // RemotingDataStreamSender per data pipe. interface RemotingDataStreamSender { - // Enqueues another frame for transmission to the remote endpoint, whose - // payload is |frame_size| bytes, to be read from the data pipe. - SendFrame(uint32 frame_size); + // Enqueues a frame for transmission to the remote endpoint, with payload to + // be read from the data pipe. The callback will be invoked once the receiver + // is ready to read another frame, immediately following the writing of the + // sent |frame| to the underlying Openscreen sender. + // + // Only one such call may be in flight at a time. + SendFrame(media.mojom.DecoderBuffer frame) => (); // Cancels the transmission of all in-flight data to the remote, up to and // including the last SendFrame() call; and also discard any data chunks
diff --git a/media/remoting/BUILD.gn b/media/remoting/BUILD.gn index 50671ee3..c7987bdc 100644 --- a/media/remoting/BUILD.gn +++ b/media/remoting/BUILD.gn
@@ -104,6 +104,7 @@ ":remoting_sender", "//base", "//base/test:test_support", + "//components/cast_streaming/public:decoder_buffer_reader", "//components/cast_streaming/public:remoting_utils", "//media:test_support", "//media/mojo/common",
diff --git a/media/remoting/demuxer_stream_adapter.cc b/media/remoting/demuxer_stream_adapter.cc index d0d0a22..cbc3321 100644 --- a/media/remoting/demuxer_stream_adapter.cc +++ b/media/remoting/demuxer_stream_adapter.cc
@@ -16,6 +16,7 @@ #include "media/base/bind_to_current_loop.h" #include "media/base/decoder_buffer.h" #include "media/base/timestamp_constants.h" +#include "media/mojo/common/media_type_converters.h" // Convenience logging macro used throughout this file. #define DEMUXER_VLOG(level) VLOG(level) << __func__ << "[" << name_ << "]: " @@ -69,7 +70,6 @@ read_until_count_(0), last_count_(0), pending_flush_(false), - pending_frame_is_eos_(false), media_status_(DemuxerStream::kOk), data_pipe_writer_(std::move(producer_handle)), bytes_written_to_pipe_(0) { @@ -107,8 +107,6 @@ if (pending_flush_ == flushing) return absl::nullopt; - // Cleans up pending frame data. - pending_frame_is_eos_ = false; // Invalidates pending Read() tasks. request_buffer_weak_factory_.InvalidateWeakPtrs(); @@ -322,12 +320,10 @@ return; case DemuxerStream::kOk: { media_status_ = status; - DCHECK(pending_frame_.empty()); + DCHECK(!pending_frame_); if (!data_pipe_writer_.IsPipeValid()) return; // Do not start sending (due to previous fatal error). - pending_frame_ = - cast_streaming::remoting::DecoderBufferToByteArray(*input); - pending_frame_is_eos_ = input->end_of_stream(); + pending_frame_ = std::move(input); WriteFrame(); } break; } @@ -337,17 +333,27 @@ DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); DCHECK(!pending_flush_); DCHECK(is_processing_read_request()); - DCHECK(!pending_frame_.empty()); + DCHECK(pending_frame_); if (!stream_sender_ || !data_pipe_writer_.IsPipeValid()) { DEMUXER_VLOG(1) << "Ignore since data pipe stream sender is invalid"; return; } - stream_sender_->SendFrame(pending_frame_.size()); - data_pipe_writer_.Write(pending_frame_.data(), pending_frame_.size(), - base::BindOnce(&DemuxerStreamAdapter::OnFrameWritten, - base::Unretained(this))); + // Unretained is safe because `this` owns the mojo::Remote. + stream_sender_->SendFrame( + media::mojom::DecoderBuffer::From(*pending_frame_), + base::BindOnce(&DemuxerStreamAdapter::OnWrittenFrameRead, + base::Unretained(this))); + + if (!pending_frame_->end_of_stream()) { + data_pipe_writer_.Write( + pending_frame_->data(), pending_frame_->data_size(), + base::BindOnce(&DemuxerStreamAdapter::OnFrameWritten, + base::Unretained(this))); + } else { + DemuxerStreamAdapter::OnFrameWritten(true); + } } void DemuxerStreamAdapter::OnFrameWritten(bool success) { @@ -356,9 +362,26 @@ return; } - bytes_written_to_pipe_ += pending_frame_.size(); + was_pending_frame_written_ = true; + TryCompleteFrameWrite(); +} + +void DemuxerStreamAdapter::OnWrittenFrameRead() { + was_pending_frame_read_ = true; + TryCompleteFrameWrite(); +} + +void DemuxerStreamAdapter::TryCompleteFrameWrite() { + if (!was_pending_frame_written_ || !was_pending_frame_read_) { + return; + } + // Resets frame buffer variables. - bool pending_frame_is_eos = pending_frame_is_eos_; + const bool pending_frame_is_eos = pending_frame_->end_of_stream(); + if (!pending_frame_is_eos) { + bytes_written_to_pipe_ += pending_frame_->data_size(); + } + ++last_count_; ResetPendingFrame(); @@ -431,8 +454,9 @@ void DemuxerStreamAdapter::ResetPendingFrame() { DCHECK(media_task_runner_->RunsTasksInCurrentSequence()); - pending_frame_.clear(); - pending_frame_is_eos_ = false; + pending_frame_.reset(); + was_pending_frame_read_ = false; + was_pending_frame_written_ = false; } void DemuxerStreamAdapter::OnFatalError(StopTrigger stop_trigger) {
diff --git a/media/remoting/demuxer_stream_adapter.h b/media/remoting/demuxer_stream_adapter.h index 04e4bb9..c35b5dbe 100644 --- a/media/remoting/demuxer_stream_adapter.h +++ b/media/remoting/demuxer_stream_adapter.h
@@ -105,7 +105,7 @@ // Indicates whether there is data waiting to be written to the mojo data // pipe. - bool is_data_pending() const { return !pending_frame_.empty(); } + bool is_data_pending() const { return !!pending_frame_; } private: friend class MockDemuxerStreamAdapter; @@ -127,9 +127,13 @@ scoped_refptr<DecoderBuffer> input); // Write the current frame into the mojo data pipe. OnFrameWritten() will be - // called when the writing has finished. + // called when the writing has finished. OnWrittenFrameRead() will be called + // once the mojo call completes. TryCompleteFrameWrite() will be called + // following both of the above. void WriteFrame(); void OnFrameWritten(bool success); + void OnWrittenFrameRead(); + void TryCompleteFrameWrite(); void ResetPendingFrame(); // Callback function when a fatal runtime error occurs. @@ -179,6 +183,11 @@ // valid handle while in reading state. int read_until_callback_handle_; + // Used for synchronization and validation of writing and reading both the + // writing of a frame to the mojo pipe and the acknowledgement of its reading. + bool was_pending_frame_written_ = false; + bool was_pending_frame_read_ = false; + // Current frame count issued by RPC_DS_READUNTIL RPC message. It should send // all frame data with count id smaller than |read_until_count_| before // sending RPC_DS_READUNTIL_CALLBACK back to receiver. @@ -193,8 +202,7 @@ // Frame buffer and its information that is currently in process of writing to // Mojo data pipe. - std::vector<uint8_t> pending_frame_; - bool pending_frame_is_eos_; + scoped_refptr<media::DecoderBuffer> pending_frame_; // Keeps latest demuxer stream status and audio/video decoder config. DemuxerStream::Status media_status_;
diff --git a/media/remoting/end2end_test_renderer.cc b/media/remoting/end2end_test_renderer.cc index 471821c..7dc34631 100644 --- a/media/remoting/end2end_test_renderer.cc +++ b/media/remoting/end2end_test_renderer.cc
@@ -13,7 +13,9 @@ #include "base/functional/callback_helpers.h" #include "base/notreached.h" #include "base/task/single_thread_task_runner.h" +#include "components/cast_streaming/public/decoder_buffer_reader.h" #include "components/cast_streaming/public/remoting_proto_utils.h" +#include "media/base/decoder_buffer.h" #include "media/base/demuxer_stream.h" #include "media/mojo/common/mojo_data_pipe_read_write.h" #include "media/mojo/common/mojo_decoder_buffer_converter.h" @@ -42,17 +44,23 @@ public: using SendFrameToSinkCallback = base::RepeatingCallback<void(uint32_t frame_count, - const std::vector<uint8_t>& data, - DemuxerStream::Type type)>; + scoped_refptr<media::DecoderBuffer>, + DemuxerStream::Type)>; TestStreamSender( mojo::PendingReceiver<mojom::RemotingDataStreamSender> receiver, mojo::ScopedDataPipeConsumerHandle handle, DemuxerStream::Type type, SendFrameToSinkCallback callback) : receiver_(this, std::move(receiver)), - data_pipe_reader_(std::move(handle)), + decoder_buffer_reader_( + std::make_unique<cast_streaming::DecoderBufferReader>( + base::BindRepeating(&TestStreamSender::OnFrameRead, + base::Unretained(this)), + std::move(handle))), type_(type), - send_frame_to_sink_cb_(std::move(callback)) {} + send_frame_to_sink_cb_(std::move(callback)) { + decoder_buffer_reader_->ReadBufferAsync(); + } TestStreamSender(const TestStreamSender&) = delete; TestStreamSender& operator=(const TestStreamSender&) = delete; @@ -60,30 +68,36 @@ ~TestStreamSender() override = default; // mojom::RemotingDataStreamSender implementation. - void SendFrame(uint32_t frame_size) override { - next_frame_data_.resize(frame_size); - data_pipe_reader_.Read( - next_frame_data_.data(), frame_size, - base::BindOnce(&TestStreamSender::OnFrameRead, base::Unretained(this), - frame_count_++)); + void SendFrame(media::mojom::DecoderBufferPtr buffer, + SendFrameCallback callback) override { + DCHECK(decoder_buffer_reader_); + DCHECK(!read_complete_cb_); + read_complete_cb_ = std::move(callback); + decoder_buffer_reader_->ProvideBuffer(std::move(buffer)); } - void CancelInFlightData() override { next_frame_data_.resize(0); } + void CancelInFlightData() override {} private: - void OnFrameRead(uint32_t count, bool success) { - DCHECK(success); - if (send_frame_to_sink_cb_) - send_frame_to_sink_cb_.Run(count, next_frame_data_, type_); - next_frame_data_.resize(0); + void OnFrameRead(scoped_refptr<media::DecoderBuffer> buffer) { + DCHECK(decoder_buffer_reader_); + DCHECK(read_complete_cb_); + DCHECK(buffer); + + std::move(read_complete_cb_).Run(); + + if (send_frame_to_sink_cb_) { + send_frame_to_sink_cb_.Run(frame_count_++, std::move(buffer), type_); + } + decoder_buffer_reader_->ReadBufferAsync(); } uint32_t frame_count_ = 0; mojo::Receiver<RemotingDataStreamSender> receiver_; - MojoDataPipeReader data_pipe_reader_; + std::unique_ptr<cast_streaming::DecoderBufferReader> decoder_buffer_reader_; + SendFrameCallback read_complete_cb_; const DemuxerStream::Type type_; const SendFrameToSinkCallback send_frame_to_sink_cb_; - std::vector<uint8_t> next_frame_data_; }; class TestRemoter final : public mojom::Remoter { @@ -178,6 +192,7 @@ void OnAudioFrame(uint32_t frame_count, scoped_refptr<DecoderBuffer> decoder_buffer) { + DCHECK(decoder_buffer); ::media::mojom::DecoderBufferPtr mojo_buffer = audio_buffer_writer_->WriteDecoderBuffer(std::move(decoder_buffer)); audio_stream_->ReceiveFrame(frame_count, std::move(mojo_buffer)); @@ -185,6 +200,7 @@ void OnVideoFrame(uint32_t frame_count, scoped_refptr<DecoderBuffer> decoder_buffer) { + DCHECK(decoder_buffer); ::media::mojom::DecoderBufferPtr mojo_buffer = video_buffer_writer_->WriteDecoderBuffer(std::move(decoder_buffer)); video_stream_->ReceiveFrame(frame_count, std::move(mojo_buffer)); @@ -409,12 +425,12 @@ media_remotee_->OnMessage(message); } -void End2EndTestRenderer::SendFrameToSink(uint32_t frame_count, - const std::vector<uint8_t>& frame, - DemuxerStream::Type type) { - scoped_refptr<DecoderBuffer> decoder_buffer = - cast_streaming::remoting::ByteArrayToDecoderBuffer(frame.data(), - frame.size()); +void End2EndTestRenderer::SendFrameToSink( + uint32_t frame_count, + scoped_refptr<media::DecoderBuffer> decoder_buffer, + DemuxerStream::Type type) { + DCHECK(decoder_buffer); + if (type == DemuxerStream::Type::AUDIO) { media_remotee_->OnAudioFrame(frame_count, decoder_buffer); } else if (type == DemuxerStream::Type::VIDEO) {
diff --git a/media/remoting/end2end_test_renderer.h b/media/remoting/end2end_test_renderer.h index aee7526..c9c7290 100644 --- a/media/remoting/end2end_test_renderer.h +++ b/media/remoting/end2end_test_renderer.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "media/base/demuxer_stream.h" #include "media/base/renderer.h" @@ -16,6 +17,9 @@ #include "third_party/openscreen/src/cast/streaming/rpc_messenger.h" namespace media { + +class DecoderBuffer; + namespace remoting { class RendererController; @@ -60,7 +64,7 @@ // Called to send frame data to |receiver_|. void SendFrameToSink(uint32_t frame_count, - const std::vector<uint8_t>& data, + scoped_refptr<media::DecoderBuffer> decoder_buffer, DemuxerStream::Type type); // Called when receives RPC messages from |receiver_|.
diff --git a/media/remoting/fake_remoter.cc b/media/remoting/fake_remoter.cc index 55b5fd48..eccff68c 100644 --- a/media/remoting/fake_remoter.cc +++ b/media/remoting/fake_remoter.cc
@@ -11,6 +11,7 @@ #include "base/functional/callback_helpers.h" #include "base/task/single_thread_task_runner.h" #include "build/buildflag.h" +#include "components/cast_streaming/public/decoder_buffer_reader.h" #include "media/media_buildflags.h" #include "media/remoting/renderer_controller.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" @@ -27,33 +28,33 @@ mojo::PendingReceiver<mojom::RemotingDataStreamSender> stream_sender, mojo::ScopedDataPipeConsumerHandle consumer_handle) : receiver_(this, std::move(stream_sender)), - data_pipe_reader_(std::move(consumer_handle)), - send_frame_count_(0), - cancel_in_flight_count_(0) {} + decoder_buffer_reader_( + std::make_unique<cast_streaming::DecoderBufferReader>( + base::BindRepeating(&FakeRemotingDataStreamSender::OnFrameRead, + base::Unretained(this)), + std::move(consumer_handle))) { + decoder_buffer_reader_->ReadBufferAsync(); +} FakeRemotingDataStreamSender::~FakeRemotingDataStreamSender() = default; void FakeRemotingDataStreamSender::ResetHistory() { send_frame_count_ = 0; cancel_in_flight_count_ = 0; - next_frame_data_.resize(0); - received_frame_list.clear(); + received_frame_list_.clear(); } bool FakeRemotingDataStreamSender::ValidateFrameBuffer(size_t index, size_t size, bool key_frame, int pts_ms) { - if (index >= received_frame_list.size()) { + if (index >= received_frame_list_.size()) { VLOG(1) << "There is no such frame"; return false; } #if BUILDFLAG(ENABLE_MEDIA_REMOTING_RPC) - const std::vector<uint8_t>& data = received_frame_list[index]; - scoped_refptr<DecoderBuffer> media_buffer = - cast_streaming::remoting::ByteArrayToDecoderBuffer(data.data(), - data.size()); + scoped_refptr<DecoderBuffer> media_buffer = received_frame_list_[index]; // Checks if pts is correct or not if (media_buffer->timestamp().InMilliseconds() != pts_ms) { @@ -95,24 +96,32 @@ } void FakeRemotingDataStreamSender::CloseDataPipe() { - data_pipe_reader_.Close(); + decoder_buffer_reader_.reset(); } -void FakeRemotingDataStreamSender::SendFrame(uint32_t frame_size) { - next_frame_data_.resize(frame_size); - data_pipe_reader_.Read( - next_frame_data_.data(), frame_size, - base::BindOnce(&FakeRemotingDataStreamSender::OnFrameRead, - base::Unretained(this))); -} - -void FakeRemotingDataStreamSender::OnFrameRead(bool success) { - if (!success) +void FakeRemotingDataStreamSender::SendFrame( + media::mojom::DecoderBufferPtr buffer, + SendFrameCallback callback) { + if (!decoder_buffer_reader_) { + std::move(callback).Run(); return; + } + + DCHECK(!send_frame_callback_); + send_frame_callback_ = std::move(callback); + decoder_buffer_reader_->ProvideBuffer(std::move(buffer)); +} + +void FakeRemotingDataStreamSender::OnFrameRead( + scoped_refptr<media::DecoderBuffer> buffer) { + DCHECK(decoder_buffer_reader_); + DCHECK(send_frame_callback_); + + decoder_buffer_reader_->ReadBufferAsync(); + std::move(send_frame_callback_).Run(); ++send_frame_count_; - received_frame_list.push_back(std::move(next_frame_data_)); - EXPECT_EQ(send_frame_count_, received_frame_list.size()); + received_frame_list_.push_back(std::move(buffer)); } void FakeRemotingDataStreamSender::CancelInFlightData() {
diff --git a/media/remoting/fake_remoter.h b/media/remoting/fake_remoter.h index b1c5999..d319461 100644 --- a/media/remoting/fake_remoter.h +++ b/media/remoting/fake_remoter.h
@@ -5,6 +5,7 @@ #ifndef MEDIA_REMOTING_FAKE_REMOTER_H_ #define MEDIA_REMOTING_FAKE_REMOTER_H_ +#include "base/memory/scoped_refptr.h" #include "media/base/decoder_buffer.h" #include "media/mojo/common/mojo_data_pipe_read_write.h" #include "media/mojo/mojom/remoting.mojom.h" @@ -13,8 +14,11 @@ #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" -namespace media { -namespace remoting { +namespace cast_streaming { +class DecoderBufferReader; +} // namespace cast_streaming + +namespace media::remoting { class RendererController; @@ -41,18 +45,19 @@ private: // mojom::RemotingDataStreamSender implementation. - void SendFrame(uint32_t frame_size) final; + void SendFrame(media::mojom::DecoderBufferPtr buffer, + SendFrameCallback callback) final; void CancelInFlightData() final; - void OnFrameRead(bool success); + void OnFrameRead(scoped_refptr<media::DecoderBuffer> buffer); mojo::Receiver<RemotingDataStreamSender> receiver_; - MojoDataPipeReader data_pipe_reader_; + std::unique_ptr<cast_streaming::DecoderBufferReader> decoder_buffer_reader_; + SendFrameCallback send_frame_callback_; - std::vector<uint8_t> next_frame_data_; - std::vector<std::vector<uint8_t>> received_frame_list; - uint32_t send_frame_count_; - uint32_t cancel_in_flight_count_; + std::vector<scoped_refptr<media::DecoderBuffer>> received_frame_list_; + uint32_t send_frame_count_ = 0; + uint32_t cancel_in_flight_count_ = 0; }; class FakeRemoter final : public mojom::Remoter { @@ -115,7 +120,6 @@ bool start_will_fail_; }; -} // namespace remoting -} // namespace media +} // namespace media::remoting #endif // MEDIA_REMOTING_FAKE_REMOTER_H_
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md index b959fdd..2244f5a 100644 --- a/mojo/public/cpp/bindings/README.md +++ b/mojo/public/cpp/bindings/README.md
@@ -975,9 +975,9 @@ // db::mojom::Table: void AddRow(int32_t key, const std::string& data) override { rows_.insert({key, data}); - listeners_.ForEach([key, &data](db::mojom::TableListener* listener) { + for (auto& listener : listeners_) { listener->OnRowAdded(key, data); - }); + } } void AddListener(mojo::PendingRemote<db::mojom::TableListener> listener) {
diff --git a/mojo/public/cpp/bindings/tests/js_interface_binder_unittest.cc b/mojo/public/cpp/bindings/tests/js_interface_binder_unittest.cc index a15add7d..c52b004 100644 --- a/mojo/public/cpp/bindings/tests/js_interface_binder_unittest.cc +++ b/mojo/public/cpp/bindings/tests/js_interface_binder_unittest.cc
@@ -2,13 +2,80 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/test/bind.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "mojo/public/cpp/bindings/remote_set.h" #include "mojo/public/cpp/bindings/tests/bindings_test_base.h" #include "mojo/public/cpp/bindings/tests/js_interface_binder_unittest.test-mojom-js-interface-binder-impl.h" namespace mojo::test::js_interface_binder { +namespace { + +class FooPageHandler : public mojom::FooPageHandler { + public: + FooPageHandler(mojo::PendingReceiver<mojom::FooPageHandler> receiver, + mojo::PendingRemote<mojom::FooPage> remote) + : receiver_(this, std::move(receiver)), remote_(std::move(remote)) {} + ~FooPageHandler() override = default; + + const mojo::Receiver<mojom::FooPageHandler>& receiver() { return receiver_; } + const mojo::Remote<mojom::FooPage>& remote() { return remote_; } + + private: + mojo::Receiver<mojom::FooPageHandler> receiver_; + mojo::Remote<mojom::FooPage> remote_; +}; + +class FooPage : public mojom::FooPage { + public: + FooPage() = default; + ~FooPage() override = default; + + mojo::Receiver<mojom::FooPage>& receiver() { return receiver_; } + + private: + mojo::Receiver<mojom::FooPage> receiver_{this}; +}; + +class Bar : public mojom::Bar { + public: + Bar() = default; + ~Bar() override = default; + + void BindBar(mojo::PendingReceiver<mojom::Bar> receiver) { + receivers_.Add(this, std::move(receiver)); + } + + void BindObserver(mojo::PendingRemote<mojom::BarObserver> remote) { + observers_.Add(std::move(remote)); + } + + const mojo::ReceiverSet<mojom::Bar>& receivers() { return receivers_; } + const mojo::RemoteSet<mojom::BarObserver>& observers() { return observers_; } + + private: + mojo::ReceiverSet<mojom::Bar> receivers_; + mojo::RemoteSet<mojom::BarObserver> observers_; +}; + +class BarObserver : public mojom::BarObserver { + public: + BarObserver() = default; + ~BarObserver() override = default; + + mojo::Receiver<mojom::BarObserver>& receiver() { return receiver_; } + + private: + mojo::Receiver<mojom::BarObserver> receiver_{this}; +}; + +} // namespace + class JsInterfaceBinderTest : public BindingsTestBase { public: JsInterfaceBinderTest() = default; @@ -18,13 +85,38 @@ // Tests binder methods are overridden and can be called. Calling them does // nothing for now. TEST_P(JsInterfaceBinderTest, Bind) { - mojom::FooJsInterfaceBinderImpl binder; + std::unique_ptr<FooPageHandler> page_handler; + auto page_handler_binder = base::BindLambdaForTesting( + [&page_handler](mojo::PendingReceiver<mojom::FooPageHandler> receiver, + mojo::PendingRemote<mojom::FooPage> remote) { + page_handler = std::make_unique<FooPageHandler>(std::move(receiver), + std::move(remote)); + }); + Bar bar; - binder.BindFooPageHandler(mojo::PendingReceiver<mojom::FooPageHandler>(), - mojo::PendingRemote<mojom::FooPage>()); + mojom::FooJsInterfaceBinderImpl binder( + page_handler_binder, + base::BindRepeating(&Bar::BindBar, base::Unretained(&bar)), + base::BindRepeating(&Bar::BindObserver, base::Unretained(&bar))); - binder.BindBar(mojo::PendingReceiver<mojom::Bar>()); - binder.BindBarObserver(mojo::PendingRemote<mojom::BarObserver>()); + mojo::Remote<mojom::FooPageHandler> page_handler_remote; + FooPage page; + binder.BindFooPageHandler(page_handler_remote.BindNewPipeAndPassReceiver(), + page.receiver().BindNewPipeAndPassRemote()); + EXPECT_TRUE(page_handler_remote.is_bound()); + EXPECT_TRUE(page.receiver().is_bound()); + EXPECT_TRUE(page_handler->receiver().is_bound()); + EXPECT_TRUE(page_handler->remote().is_bound()); + + mojo::Remote<mojom::Bar> bar_remote; + binder.BindBar(bar_remote.BindNewPipeAndPassReceiver()); + EXPECT_TRUE(bar_remote.is_bound()); + EXPECT_EQ(1u, bar.receivers().size()); + + BarObserver observer; + binder.BindBarObserver(observer.receiver().BindNewPipeAndPassRemote()); + EXPECT_TRUE(observer.receiver().is_bound()); + EXPECT_EQ(1u, bar.observers().size()); } INSTANTIATE_MOJO_BINDINGS_TEST_SUITE_P(JsInterfaceBinderTest);
diff --git a/mojo/public/tools/bindings/BUILD.gn b/mojo/public/tools/bindings/BUILD.gn index bed56e6..59700cb 100644 --- a/mojo/public/tools/bindings/BUILD.gn +++ b/mojo/public/tools/bindings/BUILD.gn
@@ -61,7 +61,9 @@ "$mojom_generator_root/generators/java_templates/interface_internal.java.tmpl", "$mojom_generator_root/generators/java_templates/struct.java.tmpl", "$mojom_generator_root/generators/java_templates/union.java.tmpl", + "$mojom_generator_root/generators/js_interface_binder_templates/js_interface_binder_impl.cc.tmpl", "$mojom_generator_root/generators/js_interface_binder_templates/js_interface_binder_impl.h.tmpl", + "$mojom_generator_root/generators/js_interface_binder_templates/js_interface_binder_macros.tmpl", "$mojom_generator_root/generators/js_templates/enum_definition.tmpl", "$mojom_generator_root/generators/js_templates/fuzzing.tmpl", "$mojom_generator_root/generators/js_templates/interface_definition.tmpl",
diff --git a/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_impl.cc.tmpl b/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_impl.cc.tmpl new file mode 100644 index 0000000..0ca0765 --- /dev/null +++ b/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_impl.cc.tmpl
@@ -0,0 +1,39 @@ +{%- import "js_interface_binder_macros.tmpl" as macros -%} +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "{{module.path}}-js-interface-binder-impl.h" + +namespace {{module.namespace}} { + +{% for interface_binder in interface_binders -%} + +{%- set class_name = "%sImpl" % interface_binder.name -%} + +{{class_name}}::{{class_name}}( + {{- macros.constructor_params(interface_binder) -}} +) : +{%- for method in interface_binder.methods %} + {{method|binder_variable_name}}_({{method|binder_variable_name}}) + {{-"," if not loop.last else ""}} + {%- endfor %} {} + +{{class_name}}::~{{class_name}}() = default; + +{% for method in interface_binder.methods %} + void {{class_name}}::{{method.name}}( +{%- for param in method.parameters %} + {{param.kind|cpp_type}} {{param.name}}{{", " if not loop.last else ""}} +{%- endfor -%} + ) { + {{method|binder_variable_name}}_.Run( +{%- for param in method.parameters %} + std::move({{param.name}}){{", " if not loop.last else ""}} +{%- endfor -%} + ); +} +{% endfor %} +{% endfor %} + +} // {{module.namespace}}
diff --git a/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_impl.h.tmpl b/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_impl.h.tmpl index ea7a250b..6749111 100644 --- a/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_impl.h.tmpl +++ b/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_impl.h.tmpl
@@ -1,3 +1,4 @@ +{%- import "js_interface_binder_macros.tmpl" as macros -%} // Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -18,22 +19,38 @@ {% for interface_binder in interface_binders -%} -class {{interface_binder.name}}Impl : public {{interface_binder.name}} { +{%- set class_name = "%sImpl" % interface_binder.name %} + +class {{class_name}} : public {{interface_binder.name}} { public: - {{interface_binder.name}}Impl() = default; - ~{{interface_binder.name}}Impl() = default; +{% for method in interface_binder.methods %} + using BinderFor{{method.name}} = base::RepeatingCallback<void( +{%- for param in method.parameters %} + {{param.kind|cpp_type}}{{"," if not loop.last else ""}} +{%- endfor -%} + )>; +{% endfor %} + + {{class_name}}( + {{- macros.constructor_params(interface_binder) -}} + ); + + ~{{class_name}}(); {% for method in interface_binder.methods %} void {{method.name}}( {%- for param in method.parameters %} - {{param.kind|cpp_type}} {{param.name}}{{", " if not loop.last else ""}} + {{param.kind|cpp_type}} {{param.name}}{{"," if not loop.last else ""}} {%- endfor -%} - ) override {} + ) override; +{% endfor %} + + private: +{% for method in interface_binder.methods %} + BinderFor{{method.name}} {{method|binder_variable_name}}_; {% endfor %} }; - {% endfor %} - } // {{module.namespace}} #endif // {{header_guard}}
diff --git a/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_macros.tmpl b/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_macros.tmpl new file mode 100644 index 0000000..d2dfc257 --- /dev/null +++ b/mojo/public/tools/bindings/generators/js_interface_binder_templates/js_interface_binder_macros.tmpl
@@ -0,0 +1,10 @@ +{#--- + Macro for JsInterfaceBinder declarations and definitions. +---#} + +{%- macro constructor_params(interface_binder) -%} +{%- for method in interface_binder.methods %} + BinderFor{{method.name}} {{method|binder_variable_name}} + {{- "," if not loop.last else "" -}} +{%- endfor -%} +{%- endmacro -%}
diff --git a/mojo/public/tools/bindings/generators/mojom_js_interface_binder_generator.py b/mojo/public/tools/bindings/generators/mojom_js_interface_binder_generator.py index b025e63..c0fb0df2 100644 --- a/mojo/public/tools/bindings/generators/mojom_js_interface_binder_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_js_interface_binder_generator.py
@@ -80,9 +80,14 @@ if mojom.IsPendingReceiverKind(kind): return "::mojo::PendingReceiver<%s>" % kind.kind.name + def _GetBinderMemberVariableName(self, bind_method): + """Return the variable name of the binder corresponding to `bind_method`.""" + return "binder_for_%s" % generator.ToLowerSnakeCase(bind_method.name) + def GetFilters(self): return { "cpp_type": self._GetCppType, + "binder_variable_name": self._GetBinderMemberVariableName, } def _GetInterfaceBinders(self): @@ -123,10 +128,16 @@ } @UseJinja("js_interface_binder_impl.h.tmpl") - def _GenerateJsInterfaceBinderImpl(self): + def _GenerateJsInterfaceBinderImplDeclaration(self): + return self._GetParameters() + + @UseJinja("js_interface_binder_impl.cc.tmpl") + def _GenerateJsInterfaceBinderImplDefinition(self): return self._GetParameters() def GenerateFiles(self, args): self.module.Stylize(JsInterfaceBinderImplStylizer()) - self.WriteWithComment(self._GenerateJsInterfaceBinderImpl(), + self.WriteWithComment(self._GenerateJsInterfaceBinderImplDeclaration(), "%s-js-interface-binder-impl.h" % self.module.path) + self.WriteWithComment(self._GenerateJsInterfaceBinderImplDefinition(), + "%s-js-interface-binder-impl.cc" % self.module.path)
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni index cfac2c1..c2344a41 100644 --- a/mojo/public/tools/bindings/mojom.gni +++ b/mojo/public/tools/bindings/mojom.gni
@@ -1776,7 +1776,10 @@ outputs = [] foreach(base_path, output_file_base_paths) { - outputs += [ "$root_gen_dir/${base_path}-js-interface-binder-impl.h" ] + outputs += [ + "$root_gen_dir/${base_path}-js-interface-binder-impl.cc", + "$root_gen_dir/${base_path}-js-interface-binder-impl.h", + ] } response_file_contents = filelist @@ -1797,7 +1800,10 @@ sources = [] foreach(base_path, output_file_base_paths) { - sources = [ "$root_gen_dir/${base_path}-js-interface-binder-impl.h" ] + sources = [ + "$root_gen_dir/${base_path}-js-interface-binder-impl.cc", + "$root_gen_dir/${base_path}-js-interface-binder-impl.h", + ] } deps = [ ":$cpp_target_name",
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc index 2634c6ca..9b2fb1e 100644 --- a/net/cert/cert_verify_proc_builtin.cc +++ b/net/cert/cert_verify_proc_builtin.cc
@@ -82,13 +82,13 @@ } #endif -base::Value PEMCertListValue(const ParsedCertificateList& certs) { - base::Value value(base::Value::Type::LIST); +base::Value::List PEMCertValueList(const ParsedCertificateList& certs) { + base::Value::List value; for (const auto& cert : certs) { std::string pem; X509Certificate::GetPEMEncodedFromDER(cert->der_cert().AsStringPiece(), &pem); - value.GetList().Append(std::move(pem)); + value.Append(std::move(pem)); } return value; } @@ -98,7 +98,7 @@ base::Value::Dict dict; dict.Set("is_valid", result_path.IsValid()); dict.Set("last_cert_trust", result_path.last_cert_trust.ToDebugString()); - dict.Set("certificates", PEMCertListValue(result_path.certs)); + dict.Set("certificates", PEMCertValueList(result_path.certs)); // TODO(crbug.com/634484): netlog user_constrained_policy_set. std::string errors_string = result_path.errors.ToDebugString(result_path.certs);
diff --git a/net/cert/cert_verify_proc_ios.cc b/net/cert/cert_verify_proc_ios.cc index cfd7a34d..fa7337d 100644 --- a/net/cert/cert_verify_proc_ios.cc +++ b/net/cert/cert_verify_proc_ios.cc
@@ -23,14 +23,6 @@ using base::ScopedCFTypeRef; -extern "C" { -// Declared in <Security/SecTrust.h>, available in iOS 12.1.1+ -// TODO(mattm): Remove this weak_import once chromium requires a new enough -// iOS SDK. -OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef, CFArrayRef) - __attribute__((weak_import)); -} // extern "C" - namespace net { namespace {
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc index f50e131..1fb8e3c 100644 --- a/net/cert/cert_verify_proc_unittest.cc +++ b/net/cert/cert_verify_proc_unittest.cc
@@ -1713,62 +1713,6 @@ testing::UnorderedElementsAreArray(public_key_hash_strings)); } -// A regression test for http://crbug.com/70293. -// The certificate in question has a key purpose of clientAuth, and also lacks -// the required key usage for serverAuth. -// TODO(mattm): This cert fails for many reasons, replace with a generated one -// that tests only the desired case. -// -// Disabled on Android, crbug.com/1167663. -#if BUILDFLAG(IS_ANDROID) -#define MAYBE_WrongKeyPurpose DISABLED_WrongKeyPurpose -#else -#define MAYBE_WrongKeyPurpose WrongKeyPurpose -#endif -TEST_P(CertVerifyProcInternalTest, MAYBE_WrongKeyPurpose) { - base::FilePath certs_dir = GetTestCertsDirectory(); - - scoped_refptr<X509Certificate> server_cert = - ImportCertFromFile(certs_dir, "invalid_key_usage_cert.der"); - ASSERT_NE(static_cast<X509Certificate*>(nullptr), server_cert.get()); - - int flags = 0; - CertVerifyResult verify_result; - int error = - Verify(server_cert.get(), "jira.aquameta.com", flags, - CRLSet::BuiltinCRLSet().get(), CertificateList(), &verify_result); - - EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_COMMON_NAME_INVALID); - -#if BUILDFLAG(IS_IOS) - if (verify_proc_type() == CERT_VERIFY_PROC_IOS) { - if (base::ios::IsRunningOnIOS13OrLater() || - !base::ios::IsRunningOnIOS12OrLater()) { - EXPECT_THAT(error, IsError(ERR_CERT_INVALID)); - } else { - EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID)); - } - return; - } -#endif - - // TODO(crbug.com/649017): Don't special-case builtin verifier. - if (!VerifyProcTypeIsBuiltin()) - EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID); - - if (verify_proc_type() != CERT_VERIFY_PROC_ANDROID) { - // The certificate is issued by an unknown CA. - EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_AUTHORITY_INVALID); - } - - // TODO(crbug.com/649017): Don't special-case builtin verifier. - if (VerifyProcTypeIsBuiltin()) { - EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID)); - } else { - EXPECT_THAT(error, IsError(ERR_CERT_INVALID)); - } -} - // Tests that a Netscape Server Gated crypto is accepted in place of a // serverAuth EKU. // TODO(crbug.com/843735): Deprecate support for this. @@ -5528,6 +5472,37 @@ } } +TEST_P(CertVerifyProcConstraintsTrustedLeafTest, WeakSignatureAlgorithm) { + chain_[0]->SetSignatureAlgorithm(SignatureAlgorithm::kEcdsaSha1); + + if (VerifyProcTypeIsBuiltin()) { + // Since no chain is found, signature is not checked, fails with generic + // error for untrusted chain. + EXPECT_THAT(Verify(), IsError(ERR_CERT_AUTHORITY_INVALID)); + + // Valid since signature on directly trusted leaf is not checked. + EXPECT_THAT(VerifyAsTrustedLeaf(), IsOk()); + + // Cert is not self-signed so directly trusted leaf with + // require_leaf_selfsigned should fail. + EXPECT_THAT( + VerifyWithTrust( + CertificateTrust::ForTrustedLeaf().WithRequireLeafSelfSigned()), + IsError(ERR_CERT_AUTHORITY_INVALID)); + } else if (verify_proc_type() == CERT_VERIFY_PROC_WIN) { + EXPECT_THAT(Verify(), IsError(ERR_CERT_AUTHORITY_INVALID)); + } else if (verify_proc_type() == CERT_VERIFY_PROC_MAC || + verify_proc_type() == CERT_VERIFY_PROC_IOS) { + if (VerifyProcTypeIsMacAtMostOS10_14()) { + EXPECT_THAT(Verify(), IsOk()); + } else { + EXPECT_THAT(Verify(), IsError(ERR_CERT_INVALID)); + } + } else { + EXPECT_THAT(Verify(), IsOk()); + } +} + TEST_P(CertVerifyProcConstraintsTrustedLeafTest, UnknownExtension) { for (bool critical : {true, false}) { SCOPED_TRACE(critical); @@ -5802,6 +5777,28 @@ } } +TEST_P(CertVerifyProcConstraintsTrustedSelfSignedTest, WeakSignatureAlgorithm) { + cert_->SetSignatureAlgorithm(SignatureAlgorithm::kEcdsaSha1); + if (VerifyProcTypeIsBuiltin()) { + // Attempts to verify as anchor of itself, which fails due to the weak + // signature algorithm. + EXPECT_THAT(Verify(), IsError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM)); + + // Signature not checked when verified as a directly trusted leaf without + // require_leaf_selfsigned. + EXPECT_THAT(VerifyWithTrust(CertificateTrust::ForTrustedLeaf()), IsOk()); + + // require_leaf_selfsigned allows any supported signature algorithm when + // doing the self-signed check, so this is okay. + EXPECT_THAT(VerifyAsTrustedSelfSignedLeaf(), IsOk()); + EXPECT_THAT(VerifyWithTrust(CertificateTrust::ForTrustAnchorOrLeaf() + .WithRequireLeafSelfSigned()), + IsOk()); + } else { + EXPECT_THAT(Verify(), IsOk()); + } +} + TEST_P(CertVerifyProcConstraintsTrustedSelfSignedTest, UnknownExtension) { for (bool critical : {true, false}) { SCOPED_TRACE(critical);
diff --git a/net/cert/ct_signed_certificate_timestamp_log_param.cc b/net/cert/ct_signed_certificate_timestamp_log_param.cc index c75f5a1..beb7176 100644 --- a/net/cert/ct_signed_certificate_timestamp_log_param.cc +++ b/net/cert/ct_signed_certificate_timestamp_log_param.cc
@@ -58,11 +58,11 @@ // Given a list of SCTs and their statuses, return a list Value where each item // is a dictionary created by SCTToDictionary. -base::Value SCTListToPrintableValues( +base::Value::List SCTListToPrintableValues( const SignedCertificateTimestampAndStatusList& sct_and_status_list) { - base::Value output_scts(base::Value::Type::LIST); + base::Value::List output_scts; for (const auto& sct_and_status : sct_and_status_list) { - output_scts.GetList().Append( + output_scts.Append( SCTToDictionary(*(sct_and_status.sct.get()), sct_and_status.status)); }
diff --git a/net/cert/x509_certificate_net_log_param.cc b/net/cert/x509_certificate_net_log_param.cc index 2a32576..db3d071 100644 --- a/net/cert/x509_certificate_net_log_param.cc +++ b/net/cert/x509_certificate_net_log_param.cc
@@ -16,12 +16,12 @@ namespace net { base::Value NetLogX509CertificateList(const X509Certificate* certificate) { - base::Value certs(base::Value::Type::LIST); + base::Value::List certs; std::vector<std::string> encoded_chain; certificate->GetPEMEncodedChain(&encoded_chain); for (auto& pem : encoded_chain) certs.Append(std::move(pem)); - return certs; + return base::Value(std::move(certs)); } } // namespace net
diff --git a/net/docs/net-log.md b/net/docs/net-log.md index 2a8a455..c7f7b5a1 100644 --- a/net/docs/net-log.md +++ b/net/docs/net-log.md
@@ -124,7 +124,7 @@ ``` net_log.AddEvent(NetLogEventType::SSL_CERTIFICATES_RECEIVED, [&] { base::Value::Dict dict; - base::Value certs(base::Value::Type::LIST); + base::Value::List certs; std::vector<std::string> encoded_chain; server_cert_->GetPEMEncodedChain(&encoded_chain); for (auto& pem : encoded_chain)
diff --git a/net/proxy_resolution/configured_proxy_resolution_service.cc b/net/proxy_resolution/configured_proxy_resolution_service.cc index cd91e01c..2a4da7f38 100644 --- a/net/proxy_resolution/configured_proxy_resolution_service.cc +++ b/net/proxy_resolution/configured_proxy_resolution_service.cc
@@ -302,7 +302,7 @@ base::Value NetLogBadProxyListParams(const ProxyRetryInfoMap* retry_info) { base::Value::Dict dict; - base::Value list(base::Value::Type::LIST); + base::Value::List list; for (const auto& retry_info_pair : *retry_info) list.Append(retry_info_pair.first); @@ -1320,7 +1320,7 @@ // Log Bad Proxies. { - base::Value list(base::Value::Type::LIST); + base::Value::List list; for (const auto& it : proxy_retry_info_) { const std::string& proxy_uri = it.first;
diff --git a/net/proxy_resolution/proxy_config.cc b/net/proxy_resolution/proxy_config.cc index ee992d8..58f5011 100644 --- a/net/proxy_resolution/proxy_config.cc +++ b/net/proxy_resolution/proxy_config.cc
@@ -271,7 +271,7 @@ if (proxy_rules_.reverse_bypass) dict.Set("reverse_bypass", true); - base::Value list(base::Value::Type::LIST); + base::Value::List list; for (const auto& bypass_rule : bypass.rules()) list.Append(bypass_rule->ToString());
diff --git a/net/proxy_resolution/proxy_list.cc b/net/proxy_resolution/proxy_list.cc index 80a276d..1343507 100644 --- a/net/proxy_resolution/proxy_list.cc +++ b/net/proxy_resolution/proxy_list.cc
@@ -150,10 +150,10 @@ } base::Value ProxyList::ToValue() const { - base::Value list(base::Value::Type::LIST); + base::Value::List list; for (const auto& proxy : proxies_) list.Append(ProxyServerToProxyUri(proxy)); - return list; + return base::Value(std::move(list)); } bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info,
diff --git a/net/quic/crypto/proof_verifier_chromium_test.cc b/net/quic/crypto/proof_verifier_chromium_test.cc index ad67134..6b3f8be 100644 --- a/net/quic/crypto/proof_verifier_chromium_test.cc +++ b/net/quic/crypto/proof_verifier_chromium_test.cc
@@ -723,6 +723,8 @@ EXPECT_EQ(report_uri, report_sender.latest_report_uri()); EXPECT_EQ(network_anonymization_key, report_sender.latest_network_anonymization_key()); + + transport_security_state_.SetReportSender(nullptr); } // Test that when CT is required (in this case, by the delegate), the @@ -775,6 +777,8 @@ verify_details = static_cast<ProofVerifyDetailsChromium*>(details_.get()); EXPECT_TRUE(verify_details->cert_verify_result.cert_status & CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED); + + transport_security_state_.SetRequireCTDelegate(nullptr); } // Test that CT is considered even when PKP fails. @@ -838,6 +842,8 @@ CERT_STATUS_PINNED_KEY_MISSING); EXPECT_TRUE(verify_details->cert_verify_result.cert_status & CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED); + + transport_security_state_.SetRequireCTDelegate(nullptr); } TEST_F(ProofVerifierChromiumTest, UnknownRootRejected) {
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index 6d15414..7827020 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -286,7 +286,7 @@ dict.Set("url", original_url().possibly_invalid_spec()); if (url_chain_.size() > 1) { - base::Value list(base::Value::Type::LIST); + base::Value::List list; for (const GURL& url : url_chain_) { list.Append(url.possibly_invalid_spec()); }
diff --git a/printing/backend/cups_jobs.cc b/printing/backend/cups_jobs.cc index efc65bda1..a67dfc1 100644 --- a/printing/backend/cups_jobs.cc +++ b/printing/backend/cups_jobs.cc
@@ -45,7 +45,6 @@ "oauth-authorization-server-uri"; constexpr base::StringPiece kOauthAuthorizationScope = "oauth-authorization-scope"; -constexpr base::StringPiece kClientInfoSupported = "client-info-supported"; // job attributes constexpr char kJobUri[] = "job-uri"; @@ -123,12 +122,11 @@ constexpr std::array<const char* const, 3> kPrinterAttributes{ {kPrinterState, kPrinterStateReasons, kPrinterStateMessage}}; -constexpr std::array<const char* const, 10> kPrinterInfoAndStatus{ +constexpr std::array<const char* const, 9> kPrinterInfoAndStatus{ {kPrinterMakeAndModel.data(), kIppVersionsSupported.data(), kIppFeaturesSupported.data(), kDocumentFormatSupported.data(), kPrinterState, kPrinterStateReasons, kPrinterStateMessage, - kOauthAuthorizationServerUri.data(), kOauthAuthorizationScope.data(), - kClientInfoSupported.data()}}; + kOauthAuthorizationServerUri.data(), kOauthAuthorizationScope.data()}}; // Converts an IPP attribute `attr` to the appropriate JobState enum. CupsJob::JobState ToJobState(ipp_attribute_t* attr) { @@ -381,8 +379,6 @@ oauth_error = true; LOG(WARNING) << "Cannot parse oauth-authorization-scope."; } - } else if (name == kClientInfoSupported) { - ParseCollection(attr, &printer_info->client_info_supported); } }
diff --git a/printing/backend/cups_jobs.h b/printing/backend/cups_jobs.h index fa850df4..05b789b1 100644 --- a/printing/backend/cups_jobs.h +++ b/printing/backend/cups_jobs.h
@@ -92,10 +92,6 @@ // URI of OAuth2 Authorization Server and scope. Empty strings if not set. std::string oauth_server; std::string oauth_scope; - - // client-info-supported - // A collection of supported 'client-info' member attributes. - std::vector<std::string> client_info_supported; }; // Specifies classes of jobs.
diff --git a/remoting/codec/webrtc_video_encoder_av1.cc b/remoting/codec/webrtc_video_encoder_av1.cc index 2a6679f..867fa976 100644 --- a/remoting/codec/webrtc_video_encoder_av1.cc +++ b/remoting/codec/webrtc_video_encoder_av1.cc
@@ -4,6 +4,7 @@ #include "remoting/codec/webrtc_video_encoder_av1.h" +#include "base/cxx17_backports.h" #include "base/functional/callback.h" #include "base/logging.h" #include "base/notreached.h" @@ -35,11 +36,16 @@ // TODO(joedow): Perform some additional testing to see if this needs tweaking. constexpr int kAv1MinimumTargetBitrateKbpsPerMegapixel = 2500; +// A value of 9 provides higher-quality and decent performance based on +// experimentation. +constexpr int kAv1DefaultEncoderSpeed = 9; + } // namespace WebrtcVideoEncoderAV1::WebrtcVideoEncoderAV1() : codec_(nullptr, DestroyAomCodecContext), image_(nullptr, aom_img_free), + av1_encoder_speed_(kAv1DefaultEncoderSpeed), bitrate_filter_(kAv1MinimumTargetBitrateKbpsPerMegapixel) { ConfigureCodecParams(); } @@ -52,6 +58,14 @@ } } +void WebrtcVideoEncoderAV1::SetEncoderSpeed(int encoder_speed) { + // Clamp values are based on the lowest and highest values available when + // realtime encoding with AV1. This allows for client-driven experimentation, + // however in practice, a value of 9 or 10 should be chosen as that will give + // the best performance. + av1_encoder_speed_ = base::clamp<int>(encoder_speed, 7, 10); +} + bool WebrtcVideoEncoderAV1::InitializeCodec(const webrtc::DesktopSize& size) { // Set the width, height, and thread count now that the frame size is known. config_.g_w = size.width(); @@ -83,7 +97,7 @@ active_map_.Initialize(size); } - error = aom_codec_control(codec.get(), AOME_SET_CPUUSED, 10); + error = aom_codec_control(codec.get(), AOME_SET_CPUUSED, av1_encoder_speed_); DCHECK_EQ(error, AOM_CODEC_OK) << "Failed to set AOME_SET_CPUUSED"; error = aom_codec_control(codec.get(), AV1E_SET_AQ_MODE, 3);
diff --git a/remoting/codec/webrtc_video_encoder_av1.h b/remoting/codec/webrtc_video_encoder_av1.h index 6440f19..9d771ed 100644 --- a/remoting/codec/webrtc_video_encoder_av1.h +++ b/remoting/codec/webrtc_video_encoder_av1.h
@@ -32,6 +32,7 @@ // WebrtcVideoEncoder interface. void SetLosslessColor(bool want_lossless) override; + void SetEncoderSpeed(int encoder_speed) override; void Encode(std::unique_ptr<webrtc::DesktopFrame> frame, const FrameParams& params, EncodeCallback done) override; @@ -55,6 +56,7 @@ // Indicates whether the frames provided to the encoder will use I420 (lossy) // or I444 (lossless) format. bool lossless_color_ = false; + int av1_encoder_speed_ = -1; // Active map used to optimize out processing of unchanged macroblocks. VideoEncoderActiveMap active_map_;
diff --git a/remoting/codec/webrtc_video_encoder_vpx.cc b/remoting/codec/webrtc_video_encoder_vpx.cc index 14edcd0f..c95b4c0 100644 --- a/remoting/codec/webrtc_video_encoder_vpx.cc +++ b/remoting/codec/webrtc_video_encoder_vpx.cc
@@ -57,7 +57,7 @@ const webrtc::DesktopSize& size) { // Use millisecond granularity time base. config->g_timebase.num = 1; - config->g_timebase.den = base::Time::kMicrosecondsPerSecond; + config->g_timebase.den = base::Time::kMillisecondsPerSecond; config->g_w = size.width(); config->g_h = size.height(); @@ -481,7 +481,7 @@ updated_region->IntersectWith( webrtc::DesktopRect::MakeWH(image_->d_w, image_->d_h)); } else { - vpx_img_fmt_t fmt = lossless_color_ ? VPX_IMG_FMT_I444 : VPX_IMG_FMT_YV12; + vpx_img_fmt_t fmt = lossless_color_ ? VPX_IMG_FMT_I444 : VPX_IMG_FMT_I420; image_.reset(vpx_img_alloc(nullptr, fmt, frame->size().width(), frame->size().height(), GetSimdMemoryAlignment())); @@ -513,7 +513,7 @@ rect.width(), rect.height()); } break; - case VPX_IMG_FMT_YV12: + case VPX_IMG_FMT_I420: for (webrtc::DesktopRegion::Iterator r(*updated_region); !r.IsAtEnd(); r.Advance()) { webrtc::DesktopRect rect = GetRowAlignedRect(r.rect(), image_->d_w);
diff --git a/remoting/host/installer/win/chromoting.wxs b/remoting/host/installer/win/chromoting.wxs index 55dd7f6..c672d7f 100644 --- a/remoting/host/installer/win/chromoting.wxs +++ b/remoting/host/installer/win/chromoting.wxs
@@ -98,9 +98,11 @@ <PropertyRef Id="WIX_ACCOUNT_LOCALSYSTEM" /> <PropertyRef Id="WIX_ACCOUNT_ADMINISTRATORS" /> + <!-- Note that Windows10 reports its version as 6.3 rather than 10.0 via + the VersionNT WXS var for back-compat reasons. --> <Condition Message="$(var.ChromotingHost) is only supported on Windows 10 and above."> - <![CDATA[Installed OR (VersionNT >= 1000)]]> + <![CDATA[Installed OR (VersionNT >= 603)]]> </Condition> <!-- The upgrade rules below could be expressed with MajorUpgrade element.
diff --git a/remoting/host/linux/remote_desktop_portal_injector.cc b/remoting/host/linux/remote_desktop_portal_injector.cc index d1f92ef..1e35535 100644 --- a/remoting/host/linux/remote_desktop_portal_injector.cc +++ b/remoting/host/linux/remote_desktop_portal_injector.cc
@@ -26,6 +26,27 @@ RemoteDesktopPortalInjector::~RemoteDesktopPortalInjector() {} +// static +void RemoteDesktopPortalInjector::ValidateGDPBusProxyResult( + GObject* proxy, + GAsyncResult* result, + gpointer user_data) { + RemoteDesktopPortalInjector* that = + static_cast<RemoteDesktopPortalInjector*>(user_data); + DCHECK(that); + DCHECK_CALLED_ON_VALID_SEQUENCE(that->sequence_checker_); + + Scoped<GError> error; + Scoped<GVariant> variant(g_dbus_proxy_call_finish( + reinterpret_cast<GDBusProxy*>(proxy), result, error.receive())); + if (!variant) { + if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + return; + } + LOG(ERROR) << "Error in input injection"; + } +} + void RemoteDesktopPortalInjector::InjectMouseButton(int code, bool pressed) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(proxy_); @@ -34,17 +55,11 @@ DCHECK(pipewire_stream_node_id_); GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - Scoped<GError> error; - g_dbus_proxy_call_sync(proxy_, "NotifyPointerButton", - g_variant_new("(oa{sv}iu)", session_handle_.c_str(), - &builder, code, pressed), - G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, - error.receive()); - if (error.get()) { - LOG(ERROR) << "Failed to " << (pressed ? "press" : "release") - << " the mouse button, button code: " << code - << ", error: " << error->message; - } + g_dbus_proxy_call(proxy_, "NotifyPointerButton", + g_variant_new("(oa{sv}iu)", session_handle_.c_str(), + &builder, code, pressed), + G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, + ValidateGDPBusProxyResult, this); } void RemoteDesktopPortalInjector::InjectMouseScroll(int axis, int steps) { @@ -55,18 +70,11 @@ DCHECK(pipewire_stream_node_id_); GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - Scoped<GError> error; - g_dbus_proxy_call_sync(proxy_, "NotifyPointerAxisDiscrete", - g_variant_new("(oa{sv}ui)", session_handle_.c_str(), - &builder, axis, steps), - G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, - error.receive()); - if (error.get()) { - LOG(ERROR) << "Failed to scroll " - << (axis == ScrollType::VERTICAL_SCROLL ? "vertically" - : "horizontally") - << ". Error: " << error->message; - } + g_dbus_proxy_call(proxy_, "NotifyPointerAxisDiscrete", + g_variant_new("(oa{sv}ui)", session_handle_.c_str(), + &builder, axis, steps), + G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, + ValidateGDPBusProxyResult, this); } void RemoteDesktopPortalInjector::MovePointerBy(int delta_x, int delta_y) { @@ -77,16 +85,12 @@ DCHECK(pipewire_stream_node_id_); GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - Scoped<GError> error; - g_dbus_proxy_call_sync( + g_dbus_proxy_call( proxy_, "NotifyPointerMotion", g_variant_new("(oa{sv}dd)", session_handle_.c_str(), &builder, static_cast<double>(delta_x), static_cast<double>(delta_y)), - G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, error.receive()); - if (error.get()) { - LOG(ERROR) << "Failed to move pointer by delta_x: " << delta_x - << ", delta_y: " << delta_y << ", error: " << error->message; - } + G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, + ValidateGDPBusProxyResult, this); } void RemoteDesktopPortalInjector::MovePointerTo(int x, int y) { @@ -97,19 +101,15 @@ DCHECK(pipewire_stream_node_id_); GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - Scoped<GError> error; VLOG(6) << "session handle: " << session_handle_ << ", stream node id: " << pipewire_stream_node_id_; - g_dbus_proxy_call_sync( + g_dbus_proxy_call( proxy_, "NotifyPointerMotionAbsolute", g_variant_new("(oa{sv}udd)", session_handle_.c_str(), &builder, pipewire_stream_node_id_, static_cast<double>(x), static_cast<double>(y)), - G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, error.receive()); - if (error.get()) { - LOG(ERROR) << "Failed to move pointer to x: " << x << ", y: " << y - << ", error: " << error->message; - } + G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, + ValidateGDPBusProxyResult, this); } void RemoteDesktopPortalInjector::InjectKeyPress(int code, @@ -122,16 +122,13 @@ DCHECK(pipewire_stream_node_id_); GVariantBuilder builder; g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - Scoped<GError> error; VLOG(6) << "session handle: " << session_handle_; - g_dbus_proxy_call_sync( - proxy_, is_code ? "NotifyKeyboardKeycode" : "NotifyKeyboardKeysym", - g_variant_new("(oa{sv}iu)", session_handle_.c_str(), &builder, code, - pressed), - G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, error.receive()); - if (error.get()) { - LOG(ERROR) << "Failed to inject key press"; - } + g_dbus_proxy_call(proxy_, + is_code ? "NotifyKeyboardKeycode" : "NotifyKeyboardKeysym", + g_variant_new("(oa{sv}iu)", session_handle_.c_str(), + &builder, code, pressed), + G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_, + ValidateGDPBusProxyResult, this); } void RemoteDesktopPortalInjector::SetSessionDetails(
diff --git a/remoting/host/linux/remote_desktop_portal_injector.h b/remoting/host/linux/remote_desktop_portal_injector.h index a5c6548..a65b7756 100644 --- a/remoting/host/linux/remote_desktop_portal_injector.h +++ b/remoting/host/linux/remote_desktop_portal_injector.h
@@ -49,6 +49,11 @@ private: SEQUENCE_CHECKER(sequence_checker_); + + static void ValidateGDPBusProxyResult(GObject* proxy, + GAsyncResult* result, + gpointer user_data); + raw_ptr<GDBusConnection> connection_ GUARDED_BY_CONTEXT(sequence_checker_) = nullptr; raw_ptr<GDBusProxy> proxy_ GUARDED_BY_CONTEXT(sequence_checker_) = nullptr;
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index 8924a19..1d027ce 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc
@@ -19,6 +19,7 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/message_loop/message_pump_type.h" +#include "base/metrics/field_trial.h" #include "base/notreached.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" @@ -436,6 +437,9 @@ bool security_key_extension_supported_ = true; absl::optional<int> max_session_duration_minutes_; + // Allows us to override field trials which are causing issues for chromoting. + std::unique_ptr<base::FieldTrialList> field_trial_list_; + // Used to specify which window to stream, if enabled. webrtc::WindowId window_id_ = 0; @@ -1710,6 +1714,15 @@ // This thread is used as a network thread in WebRTC. webrtc::ThreadWrapper::EnsureForCurrentMessageLoop(); + // Initialize global field trials. + field_trial_list_ = std::make_unique<base::FieldTrialList>(); + + // Override LossBasedBweV2 trial. + // TODO(b/266103942): Remove this override once we figure out why the BWE is + // crashing for some users and have a fix available. + base::FieldTrialList::CreateTrialsFromString( + "WebRTC-Bwe-LossBasedBweV2/Enabled:false/"); + SetState(HOST_STARTED); InitializeSignaling();
diff --git a/remoting/protocol/webrtc_frame_scheduler_constant_rate.cc b/remoting/protocol/webrtc_frame_scheduler_constant_rate.cc index fa03532..59a05192 100644 --- a/remoting/protocol/webrtc_frame_scheduler_constant_rate.cc +++ b/remoting/protocol/webrtc_frame_scheduler_constant_rate.cc
@@ -7,11 +7,32 @@ #include <algorithm> #include "base/logging.h" +#include "base/system/sys_info.h" #include "base/time/time.h" namespace remoting::protocol { -WebrtcFrameSchedulerConstantRate::WebrtcFrameSchedulerConstantRate() { +namespace { +base::TimeDelta GetPostTaskAdjustment() { + int proccessor_count = base::SysInfo::NumberOfProcessors(); + if (proccessor_count < 16) { + // Don't change the scheduler timing on these machines as we don't want to + // overload the machine. + return base::Milliseconds(0); + } + + // We've observed the encoding rate in the client as being a couple of frames + // lower than the target. By adjusting the capture rate by ~2ms, the host will + // generate frames at, or slightly above, the target frame rate. If a value of + // 1ms is used, then the host will generate frames at, or slightly below, the + // target. They higher of the two was chosen for better performance on high- + // CPU machines. + return base::Milliseconds(2); +} +} // namespace + +WebrtcFrameSchedulerConstantRate::WebrtcFrameSchedulerConstantRate() + : post_task_adjustment_(GetPostTaskAdjustment()) { DETACH_FROM_SEQUENCE(sequence_checker_); } @@ -48,8 +69,21 @@ void WebrtcFrameSchedulerConstantRate::SetMaxFramerateFps(int max_framerate) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_GE(max_framerate, 0); - max_framerate_fps_ = max_framerate; + max_framerate_fps_ = std::min(max_framerate, 1000); + if (max_framerate_fps_ > 0) { + // Calculate the interval used to schedule each frame capture and account + // for the time used when posting tasks (~1-2ms per frame). We also set a + // floor at 1ms as some of our dependencies have problems when frames are + // delivered with the same timestamp. + capture_interval_ = + std::max(base::Hertz(max_framerate_fps_) - post_task_adjustment_, + base::Milliseconds(1)); + } else { + capture_interval_ = {}; + } + ScheduleNextFrame(); } @@ -99,25 +133,25 @@ return; } - // Captures should be scheduled at least 1ms apart, otherwise WebRTC's video - // stream encoder complains about non-increasing frame timestamps, which can - // affect some unittests. - base::TimeDelta capture_interval = - std::max(base::Seconds(1) / max_framerate_fps_, base::Milliseconds(1)); - - // Use the boosted capture interval if we are within |boost_window_|. - if (!boost_window_.is_null()) { - if (boost_window_ > now) { - capture_interval = boost_capture_interval_; - } else { - boost_window_ = {}; - } - } - base::TimeDelta delay; if (!last_capture_started_time_.is_null()) { + auto capture_interval = capture_interval_; + + // Use the boosted capture interval if we are within |boost_window_|. + if (!boost_window_.is_null()) { + if (boost_window_ > now) { + capture_interval = boost_capture_interval_; + } else { + boost_window_ = {}; + } + } + base::TimeTicks target_capture_time = - std::max(last_capture_started_time_ + capture_interval, now); + last_capture_started_time_ + capture_interval; + + // Captures should be scheduled at least 1ms apart, otherwise WebRTC's video + // stream logic will complain about non-increasing frame timestamps, which + // can affect some unittests. delay = std::max(target_capture_time - now, base::Milliseconds(1)); } @@ -134,4 +168,10 @@ capture_callback_.Run(); } +void WebrtcFrameSchedulerConstantRate::SetPostTaskAdjustmentForTest( + base::TimeDelta post_task_adjustment) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + post_task_adjustment_ = post_task_adjustment; +} + } // namespace remoting::protocol
diff --git a/remoting/protocol/webrtc_frame_scheduler_constant_rate.h b/remoting/protocol/webrtc_frame_scheduler_constant_rate.h index b4b40e9a..419114e5 100644 --- a/remoting/protocol/webrtc_frame_scheduler_constant_rate.h +++ b/remoting/protocol/webrtc_frame_scheduler_constant_rate.h
@@ -38,6 +38,8 @@ void BoostCaptureRate(base::TimeDelta capture_interval, base::TimeDelta duration); + void SetPostTaskAdjustmentForTest(base::TimeDelta post_task_adjustment); + private: void ScheduleNextFrame(); void CaptureNextFrame(); @@ -56,6 +58,8 @@ // Framerate for scheduling frames. Initially 0 to prevent scheduling before // the output sink has been added. int max_framerate_fps_ GUARDED_BY_CONTEXT(sequence_checker_) = 0; + base::TimeDelta capture_interval_ GUARDED_BY_CONTEXT(sequence_checker_); + base::TimeDelta post_task_adjustment_ GUARDED_BY_CONTEXT(sequence_checker_); base::TimeDelta boost_capture_interval_ GUARDED_BY_CONTEXT(sequence_checker_); base::TimeTicks boost_window_ GUARDED_BY_CONTEXT(sequence_checker_);
diff --git a/remoting/protocol/webrtc_frame_scheduler_unittest.cc b/remoting/protocol/webrtc_frame_scheduler_unittest.cc index 452be5b..dd672c2 100644 --- a/remoting/protocol/webrtc_frame_scheduler_unittest.cc +++ b/remoting/protocol/webrtc_frame_scheduler_unittest.cc
@@ -27,6 +27,7 @@ void InitConstantRateScheduler() { scheduler_ = std::make_unique<WebrtcFrameSchedulerConstantRate>(); + scheduler_->SetPostTaskAdjustmentForTest(base::Milliseconds(0)); scheduler_->Start(base::BindRepeating( &WebrtcFrameSchedulerTest::CaptureCallback, base::Unretained(this))); } @@ -43,7 +44,7 @@ base::test::TaskEnvironment task_environment_{ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; - std::unique_ptr<WebrtcFrameScheduler> scheduler_; + std::unique_ptr<WebrtcFrameSchedulerConstantRate> scheduler_; int capture_callback_count_ = 0; bool simulate_capture_ = true; @@ -71,6 +72,19 @@ EXPECT_LE(capture_callback_count_, 61); } +TEST_F(WebrtcFrameSchedulerTest, PostTaskAdjustmentApplied) { + InitConstantRateScheduler(); + scheduler_->SetPostTaskAdjustmentForTest(base::Milliseconds(3)); + scheduler_->SetMaxFramerateFps(30); + + task_environment_.FastForwardBy(base::Seconds(1)); + + // There should be approximately ~33 captures in 1 second, making an allowance + // for any off-by-one artifacts in timing. + EXPECT_GE(capture_callback_count_, 32); + EXPECT_LE(capture_callback_count_, 34); +} + TEST_F(WebrtcFrameSchedulerTest, NoCaptureWhileCapturePending) { InitConstantRateScheduler(); simulate_capture_ = false;
diff --git a/remoting/protocol/webrtc_video_encoder_wrapper.cc b/remoting/protocol/webrtc_video_encoder_wrapper.cc index c602ac94..5e5f09d 100644 --- a/remoting/protocol/webrtc_video_encoder_wrapper.cc +++ b/remoting/protocol/webrtc_video_encoder_wrapper.cc
@@ -154,6 +154,12 @@ << (lossless_color ? "true" : "false"); encoder_ = std::make_unique<WebrtcVideoEncoderAV1>(); encoder_->SetLosslessColor(lossless_color); + absl::optional<int> encoder_speed = + session_options.GetInt("Av1-Encoder-Speed"); + if (encoder_speed) { + VLOG(0) << "Setting AV1 encoder speed to " << encoder_speed.value(); + encoder_->SetEncoderSpeed(encoder_speed.value()); + } break; } case webrtc::kVideoCodecH264:
diff --git a/sandbox/policy/linux/sandbox_seccomp_bpf_linux.h b/sandbox/policy/linux/sandbox_seccomp_bpf_linux.h index 2d42a279..165ca85 100644 --- a/sandbox/policy/linux/sandbox_seccomp_bpf_linux.h +++ b/sandbox/policy/linux/sandbox_seccomp_bpf_linux.h
@@ -29,7 +29,6 @@ bool use_intel_specific_policies = false; // For ChromiumOS. bool use_virtio_specific_policies = false; // For ChromiumOS VM. bool use_nvidia_specific_policies = false; // For Linux. - bool use_asahi_specific_policies = false; // For Linux. // Options for GPU's PreSandboxHook. bool accelerated_video_decode_enabled = false;
diff --git a/sandbox/win/tests/integration_tests/integration_tests_test.cc b/sandbox/win/tests/integration_tests/integration_tests_test.cc index e0eefc28..78f92b5 100644 --- a/sandbox/win/tests/integration_tests/integration_tests_test.cc +++ b/sandbox/win/tests/integration_tests/integration_tests_test.cc
@@ -9,9 +9,6 @@ #include <windows.h> -// Must be after windows.h. -#include <versionhelpers.h> - #include "base/memory/raw_ptr.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -361,17 +358,10 @@ // Running from inside job that doesn't allow us to escape from it should fail // on any windows prior to 8. TEST(IntegrationTestsTest, RunChildFromInsideJobNoEscape) { - int expect_result = 4; // Means the runner has failed to execute the child. - // Check if we are on Win8 or newer and expect a success as newer windows - // versions support nested jobs. - if (IsWindows8OrGreater()) { - expect_result = SBOX_TEST_SUCCEEDED; - } - TestRunner runner; runner.SetUnsandboxed(true); runner.SetTimeout(TestTimeouts::action_timeout()); - ASSERT_EQ(expect_result, + ASSERT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"IntegrationTestsTest_job with_job")); }
diff --git a/content/browser/compute_pressure/README.md b/services/device/compute_pressure/README.md similarity index 63% rename from content/browser/compute_pressure/README.md rename to services/device/compute_pressure/README.md index 721a68f..84a7f65 100644 --- a/content/browser/compute_pressure/README.md +++ b/services/device/compute_pressure/README.md
@@ -1,27 +1,28 @@ # Compute Pressure API -This directory contains the browser-side implementation of the -[Compute Pressure API](https://github.com/wicg/compute-pressure/). +This directory contains the service-side implementation of the +[Compute Pressure API](https://github.com/w3c/compute-pressure/). ## Code map The system is made up of the following components. -`blink::mojom::PressureService`, defined in Blink, is the interface between -the renderer and the browser sides of the API implementation. - `device::mojom::PressureManager`, defined in Services, is the interface -between the browser and the services sides of the API implementation. +between the renderer and the services sides of the API implementation. `device::PressureManagerImpl` is the top-level class for the services side implementation. The class is responsible for handling the communication -between the browser process and services. +between the renderer process and services. + +`device::mojom::PressureClient` is the interface that client of the +`device::mojom::PressureManager` interface must implement to receive +`device::mojom::PressureUpdate`. `device::mojom::PressureUpdate` represents the device's compute pressure update, composed of the `device::mojom::PressureState` and the timestamp. This information is collected by `device::CpuProbe` and bubbled up by `device::PlatformCollector` to `device::PressureManagerImpl`, which broadcasts -the information to the `content::PressureServiceImpl` instances. +the information to the `blink::PressureObserverManager` instances. `device::PlatformCollector` drives measuring the device's compute pressure state. The class is responsible for invoking platform-specific measurement @@ -33,15 +34,10 @@ compute pressure state from the operating system. This interface is also a dependency injection point for tests. -`content::PressureServiceImpl` serves the mojo connection for a frame. -Each instance is owned by a `content::RenderFrameHostImpl`. The class receives -`device::mojom::PressureUpdate` from `device::PressureManagerImpl` and -broadcasts the information to the `blink::PressureObserverManager` instance. - `blink::PressureObserver` implements bindings for the PressureObserver interface. There can be more than one PressureObserver per frame. `blink::PressureObserverManager` maintains the list of active observers. The class receives `device::mojom::PressureUpdate` from -`content::PressureServiceImpl` and broadcasts the information to active +`device::PressureManagerImpl` and broadcasts the information to active observers.
diff --git a/services/device/compute_pressure/pressure_manager_impl.cc b/services/device/compute_pressure/pressure_manager_impl.cc index 489ddcd2..e075fe17 100644 --- a/services/device/compute_pressure/pressure_manager_impl.cc +++ b/services/device/compute_pressure/pressure_manager_impl.cc
@@ -66,12 +66,12 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!collector_.has_probe()) { - std::move(callback).Run(false); + std::move(callback).Run(mojom::PressureStatus::kNotSupported); return; } clients_.Add(std::move(client)); collector_.EnsureStarted(); - std::move(callback).Run(true); + std::move(callback).Run(mojom::PressureStatus::kOk); } void PressureManagerImpl::UpdateClients(mojom::PressureState state) { @@ -83,7 +83,7 @@ mojom::PressureUpdate update(state, {}, timestamp); for (auto& client : clients_) { - client->PressureStateChanged(update.Clone()); + client->OnPressureUpdated(update.Clone()); } }
diff --git a/services/device/compute_pressure/pressure_manager_impl_unittest.cc b/services/device/compute_pressure/pressure_manager_impl_unittest.cc index 7bcaaf9..715eff80 100644 --- a/services/device/compute_pressure/pressure_manager_impl_unittest.cc +++ b/services/device/compute_pressure/pressure_manager_impl_unittest.cc
@@ -38,8 +38,9 @@ PressureManagerImplSync(const PressureManagerImplSync&) = delete; PressureManagerImplSync& operator=(const PressureManagerImplSync&) = delete; - bool AddClient(mojo::PendingRemote<mojom::PressureClient> client) { - base::test::TestFuture<bool> future; + mojom::PressureStatus AddClient( + mojo::PendingRemote<mojom::PressureClient> client) { + base::test::TestFuture<mojom::PressureStatus> future; manager_->AddClient(std::move(client), future.GetCallback()); return future.Get(); } @@ -60,7 +61,7 @@ FakePressureClient& operator=(const FakePressureClient&) = delete; // device::mojom::PressureClient implementation. - void PressureStateChanged(device::mojom::PressureUpdatePtr update) override { + void OnPressureUpdated(device::mojom::PressureUpdatePtr update) override { updates_.emplace_back(*update); if (update_callback_) { std::move(update_callback_).Run(); @@ -139,7 +140,8 @@ TEST_F(PressureManagerImplTest, OneClient) { FakePressureClient client; - ASSERT_TRUE(manager_impl_sync_->AddClient(client.BindNewPipeAndPassRemote())); + ASSERT_EQ(manager_impl_sync_->AddClient(client.BindNewPipeAndPassRemote()), + mojom::PressureStatus::kOk); client.WaitForUpdate(); ASSERT_EQ(client.updates().size(), 1u); @@ -148,14 +150,14 @@ TEST_F(PressureManagerImplTest, ThreeClients) { FakePressureClient client1; - ASSERT_TRUE( - manager_impl_sync_->AddClient(client1.BindNewPipeAndPassRemote())); + ASSERT_EQ(manager_impl_sync_->AddClient(client1.BindNewPipeAndPassRemote()), + mojom::PressureStatus::kOk); FakePressureClient client2; - ASSERT_TRUE( - manager_impl_sync_->AddClient(client2.BindNewPipeAndPassRemote())); + ASSERT_EQ(manager_impl_sync_->AddClient(client2.BindNewPipeAndPassRemote()), + mojom::PressureStatus::kOk); FakePressureClient client3; - ASSERT_TRUE( - manager_impl_sync_->AddClient(client3.BindNewPipeAndPassRemote())); + ASSERT_EQ(manager_impl_sync_->AddClient(client3.BindNewPipeAndPassRemote()), + mojom::PressureStatus::kOk); FakePressureClient::WaitForUpdates({&client1, &client2, &client3}); ASSERT_EQ(client1.updates().size(), 1u); @@ -170,8 +172,8 @@ CreateConnection(nullptr, kDefaultSamplingIntervalForTesting); FakePressureClient client; - ASSERT_FALSE( - manager_impl_sync_->AddClient(client.BindNewPipeAndPassRemote())); + ASSERT_EQ(manager_impl_sync_->AddClient(client.BindNewPipeAndPassRemote()), + mojom::PressureStatus::kNotSupported); } } // namespace device
diff --git a/services/device/public/cpp/test/scoped_pressure_manager_overrider.cc b/services/device/public/cpp/test/scoped_pressure_manager_overrider.cc index 0c5aff2..7a19f86 100644 --- a/services/device/public/cpp/test/scoped_pressure_manager_overrider.cc +++ b/services/device/public/cpp/test/scoped_pressure_manager_overrider.cc
@@ -28,15 +28,15 @@ AddClientCallback callback) { if (is_supported_) { clients_.Add(std::move(client)); - std::move(callback).Run(true); + std::move(callback).Run(mojom::PressureStatus::kOk); } else { - std::move(callback).Run(false); + std::move(callback).Run(mojom::PressureStatus::kNotSupported); } } void FakePressureManager::UpdateClients(const mojom::PressureUpdate& update) { for (auto& client : clients_) - client->PressureStateChanged(update.Clone()); + client->OnPressureUpdated(update.Clone()); } void FakePressureManager::set_is_supported(bool is_supported) {
diff --git a/services/device/public/mojom/pressure_manager.mojom b/services/device/public/mojom/pressure_manager.mojom index 0a79755..017eb4b6 100644 --- a/services/device/public/mojom/pressure_manager.mojom +++ b/services/device/public/mojom/pressure_manager.mojom
@@ -6,23 +6,33 @@ import "services/device/public/mojom/pressure_update.mojom"; -// This interface is used to get the PressureState. +// Result of PressureManager.AddClient(). +enum PressureStatus { + kOk, + + // The underlying platform does not report compute pressure information or + // the renderer is not allowed access to the feature. + kNotSupported, +}; + +// This interface is used to subscribe to notification about OnPressureUpdated. // -// This interface is implemented by PressureManagerImpl and lives in the Device -// Service. PressureServiceImpl in content/browser uses this interface to -// subscribe to notification about PressureStateChanged. +// This interface is implemented by PressureServiceImpl in content/browser and +// PressureManagerImpl in services/device. PressureObserverManager in Blink +// uses this interface to make a PressureClient subscribe to notification +// about OnPressureUpdated. interface PressureManager { - // Add a client that will be notified on PressureStateChanged. - AddClient(pending_remote<PressureClient> client) => (bool success); + // Add a client that will be notified when a new PressureUpdate is obtained. + AddClient(pending_remote<PressureClient> client) => (PressureStatus status); }; // Interface that client of the PressureManager interface must -// implement to observe PressureState changes. +// implement to receive PressureUpdate. // -// This interface is implemented by PressureServiceImpl in content/browser. -// PressureManagerImpl uses this interface to notify PressureServiceImpl about -// PressureStateChanged. +// This interface is implemented by PressureObserverManager in Blink. +// PressureManagerImpl uses this interface to deliver PressureUpdate to +// its client. interface PressureClient { - // Interface used to notify PressureState changes. - PressureStateChanged(PressureUpdate update); + // Interface used to deliver PressureUpdate. + OnPressureUpdated(PressureUpdate update); };
diff --git a/services/network/oblivious_http_request_handler.cc b/services/network/oblivious_http_request_handler.cc index d9e36221..e64a8ac 100644 --- a/services/network/oblivious_http_request_handler.cc +++ b/services/network/oblivious_http_request_handler.cc
@@ -32,12 +32,14 @@ namespace { -constexpr size_t kMaxResponseSize = 10 * 1024; // Response size limit is 10kB +constexpr size_t kMaxResponseSize = + 5 * 1024 * 1024; // Response size limit is 5MB constexpr base::TimeDelta kRequestTimeout = base::Minutes(1); constexpr char kObliviousHttpRequestMimeType[] = "message/ohttp-req"; constexpr size_t kMaxMethodSize = 16; -constexpr size_t kMaxRequestBodySize = 10 * 1024; // Request size limit is 10kB +constexpr size_t kMaxRequestBodySize = + 5 * 1024 * 1024; // Request size limit is 5MB constexpr size_t kMaxContentTypeSize = 256; // Per RFC6838 const std::array<char, 2> kHeaderForbiddenChars = {'\n', '\r'}; @@ -500,4 +502,4 @@ return url_loader_factory_.get(); } -} // namespace network \ No newline at end of file +} // namespace network
diff --git a/services/network/oblivious_http_request_handler_unittest.cc b/services/network/oblivious_http_request_handler_unittest.cc index 0e9b7510..ee3ebb60 100644 --- a/services/network/oblivious_http_request_handler_unittest.cc +++ b/services/network/oblivious_http_request_handler_unittest.cc
@@ -291,7 +291,7 @@ mojo::test::BadMessageObserver obs; TestOhttpClient client(absl::nullopt, net::ERR_INVALID_ARGUMENT); network::mojom::ObliviousHttpRequestPtr request = CreateRequest(); - request->request_body->content = std::string(10 * 1024 + 1, ' '); + request->request_body->content = std::string(5 * 1024 * 1024 + 1, ' '); handler->StartRequest(std::move(request), client.CreatePendingRemote()); EXPECT_EQ("Request body too large", obs.WaitForBadMessage()); @@ -544,4 +544,4 @@ } EXPECT_FALSE(has_bad_bits) << "Got non-power of 2 body size " << body_size; } -} \ No newline at end of file +}
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 3d0d7fe..3cb3c295 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -137,10 +137,8 @@ */ #define SK_PDF_USE_HARFBUZZ_SUBSET -#if !defined(SK_API) // Handle exporting using base/component_export.h #define SK_API COMPONENT_EXPORT(SKIA) -#endif // Chromium does not use these fonts. This define causes type1 fonts to be // converted to type3 when producing PDFs, and reduces build size.
diff --git a/styleguide/web/web.md b/styleguide/web/web.md index f41de47c..8ed0a3a 100644 --- a/styleguide/web/web.md +++ b/styleguide/web/web.md
@@ -341,10 +341,10 @@ feature when the code needs to handle null/undefined gracefully. -### Closure compiler +### Closure compiler (ChromeOS Ash code only) -* Closure compiler should only be used by legacy code that has not yet been - converted to use TypeScript. +* Closure compiler can only be used on ChromeOS Ash. All other platforms + are required to use TypeScript to add type checking. * Use the [closure compiler](https://chromium.googlesource.com/chromium/src/+/main/docs/closure_compilation.md)
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json index cf0b216..b6d702e 100644 --- a/testing/buildbot/chrome.json +++ b/testing/buildbot/chrome.json
@@ -1892,7 +1892,7 @@ { "args": [], "cros_board": "dedede", - "cros_img": "dedede-release/R110-15278.21.0", + "cros_img": "dedede-release/R111-15320.0.0", "name": "lacros_all_tast_tests DEDEDE_RELEASE_DEV", "resultdb": { "enable": true, @@ -1956,7 +1956,7 @@ { "args": [], "cros_board": "eve", - "cros_img": "eve-release/R110-15278.21.0", + "cros_img": "eve-release/R111-15320.0.0", "name": "lacros_all_tast_tests EVE_RELEASE_DEV", "resultdb": { "enable": true, @@ -2099,7 +2099,7 @@ { "args": [], "cros_board": "jacuzzi", - "cros_img": "jacuzzi-release/R110-15278.21.0", + "cros_img": "jacuzzi-release/R111-15320.0.0", "name": "lacros_all_tast_tests JACUZZI_RELEASE_DEV", "resultdb": { "enable": true,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index e08568b..8c151e8 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -1628,6 +1628,26 @@ } ] }, + "lacros-arm-generic-rel-skylab": { + "additional_compile_targets": [ + "chrome" + ], + "skylab_tests": [ + { + "args": [], + "bucket": "chromiumos-image-archive", + "cros_board": "jacuzzi", + "cros_img": "jacuzzi-public/R109-15222.0.0", + "name": "lacros_all_tast_tests JACUZZI_PUBLIC", + "swarming": {}, + "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)", + "test": "lacros_all_tast_tests", + "test_id_prefix": "ninja://chromeos/lacros:lacros_all_tast_tests/", + "timeout_sec": 10800, + "variant_id": "JACUZZI_PUBLIC" + } + ] + }, "lacros-arm64-generic-rel": { "additional_compile_targets": [ "chrome" @@ -5839,9 +5859,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -5853,8 +5873,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -6010,9 +6030,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -6024,8 +6044,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -6162,9 +6182,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -6176,8 +6196,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 5d42d74..9abffd9 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -80772,9 +80772,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -80786,8 +80786,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -80913,9 +80913,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -80927,8 +80927,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" @@ -81040,9 +81040,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -81054,8 +81054,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", @@ -82388,9 +82388,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -82401,8 +82401,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -82559,9 +82559,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -82572,8 +82572,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -82711,9 +82711,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -82724,8 +82724,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -84249,9 +84249,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -84262,8 +84262,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -84420,9 +84420,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -84433,8 +84433,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -84572,9 +84572,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -84585,8 +84585,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -85358,9 +85358,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -85371,8 +85371,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -94077,6 +94077,38 @@ } ] }, + "mac11-wpt-content-shell-fyi-rel": { + "isolated_scripts": [ + { + "args": [ + "--log-wptreport", + "--xvfb" + ], + "experiment_percentage": 100, + "isolate_name": "wpt_tests_isolate_content_shell", + "merge": { + "args": [ + "--verbose" + ], + "script": "//third_party/blink/tools/merge_web_test_results.py" + }, + "name": "wpt_tests_suite", + "results_handler": "layout tests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Mac-11|Mac-10.16" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 15 + }, + "test_id_prefix": "ninja://:wpt_tests_isolate_content_shell/" + } + ] + }, "mac12-wpt-content-shell-fyi-rel": { "isolated_scripts": [ {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 60dd7c7..89cf01dbb 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -18532,12 +18532,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18549,8 +18549,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -18723,12 +18723,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18740,8 +18740,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [ @@ -18890,12 +18890,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 111.0.5555.0", + "description": "Run with ash-chrome version 111.0.5556.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18907,8 +18907,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v111.0.5555.0", - "revision": "version:111.0.5555.0" + "location": "lacros_version_skew_tests_v111.0.5556.0", + "revision": "version:111.0.5556.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/filters/mac.mac12-arm64-rel.browser_tests.filter b/testing/buildbot/filters/mac.mac12-arm64-rel.browser_tests.filter index 66c37a8..9a4f71f 100644 --- a/testing/buildbot/filters/mac.mac12-arm64-rel.browser_tests.filter +++ b/testing/buildbot/filters/mac.mac12-arm64-rel.browser_tests.filter
@@ -107,6 +107,7 @@ -IntentChipButtonSkipIntentPickerBrowserTest.ShowsIntentChipCollapsed -LiveCaptionControllerTest.OnAudioStreamEnd -ManagementUITest.ManagementStateChange +-MaybeSetMetadata/V4SafeBrowsingServiceMetadataTest.MalwareIFrame/2 -MediaEngagementBrowserTest.SessionMultipleTabsClosingParent -MediaGalleriesGalleryWatchApiTest.SetupGalleryWatchWithoutListeners -MediaInternalsUIBrowserTest.Integration
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json index 45debe6..55806f12 100644 --- a/testing/buildbot/internal.chromeos.fyi.json +++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1153,7 +1153,7 @@ { "args": [], "cros_board": "octopus", - "cros_img": "octopus-release/R110-15278.21.0", + "cros_img": "octopus-release/R111-15320.0.0", "name": "lacros_fyi_tast_tests OCTOPUS_RELEASE_DEV", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)", @@ -1200,7 +1200,7 @@ { "args": [], "cros_board": "octopus", - "cros_img": "octopus-release/R110-15278.21.0", + "cros_img": "octopus-release/R111-15320.0.0", "name": "ozone_unittests OCTOPUS_RELEASE_DEV", "swarming": {}, "test": "ozone_unittests", @@ -1252,7 +1252,7 @@ { "args": [], "cros_board": "hana", - "cros_img": "hana-release/R110-15278.21.0", + "cros_img": "hana-release/R111-15320.0.0", "name": "lacros_all_tast_tests HANA_RELEASE_DEV", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)", @@ -1300,7 +1300,7 @@ { "args": [], "cros_board": "strongbad", - "cros_img": "strongbad-release/R110-15278.21.0", + "cros_img": "strongbad-release/R111-15320.0.0", "name": "lacros_all_tast_tests strongbad_RELEASE_DEV", "swarming": {}, "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)", @@ -1347,7 +1347,7 @@ { "args": [], "cros_board": "hana", - "cros_img": "hana-release/R110-15278.21.0", + "cros_img": "hana-release/R111-15320.0.0", "name": "ozone_unittests HANA_RELEASE_DEV", "swarming": {}, "test": "ozone_unittests", @@ -1391,7 +1391,7 @@ { "args": [], "cros_board": "strongbad", - "cros_img": "strongbad-release/R110-15278.21.0", + "cros_img": "strongbad-release/R111-15320.0.0", "name": "ozone_unittests strongbad_RELEASE_DEV", "swarming": {}, "test": "ozone_unittests", @@ -1435,7 +1435,7 @@ { "args": [], "cros_board": "hana", - "cros_img": "hana-release/R110-15278.21.0", + "cros_img": "hana-release/R111-15320.0.0", "name": "viz_unittests HANA_RELEASE_DEV", "swarming": {}, "test": "viz_unittests", @@ -1479,7 +1479,7 @@ { "args": [], "cros_board": "strongbad", - "cros_img": "strongbad-release/R110-15278.21.0", + "cros_img": "strongbad-release/R111-15320.0.0", "name": "viz_unittests strongbad_RELEASE_DEV", "swarming": {}, "test": "viz_unittests",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index b9ec175..d832c4e1 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -7125,6 +7125,14 @@ }, }, + 'lacros_arm_generic_rel_skylab': { + 'lacros_skylab': { + 'variants': [ + 'CROS_JACUZZI_PUBLIC', + ] + }, + }, + 'lacros_arm_generic_rel_skylab_fyi': { 'lacros_skylab': { 'variants': [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 9b803b99..6bcb5b4 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5555.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v111.0.5556.0/test_ash_chrome', ], - 'description': 'Run with ash-chrome version 111.0.5555.0', + 'description': 'Run with ash-chrome version 111.0.5556.0', 'identifier': 'Lacros version skew testing ash canary', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v111.0.5555.0', - 'revision': 'version:111.0.5555.0', + 'location': 'lacros_version_skew_tests_v111.0.5556.0', + 'revision': 'version:111.0.5556.0', }, ], }, @@ -479,8 +479,8 @@ 'CROS_DEDEDE_RELEASE_DEV': { 'skylab': { 'cros_board': 'dedede', - 'cros_chrome_version': '110.0.5481.21', - 'cros_img': 'dedede-release/R110-15278.21.0', + 'cros_chrome_version': '111.0.5544.0', + 'cros_img': 'dedede-release/R111-15320.0.0', }, 'enabled': True, 'identifier': 'DEDEDE_RELEASE_DEV', @@ -515,8 +515,8 @@ 'CROS_EVE_RELEASE_DEV': { 'skylab': { 'cros_board': 'eve', - 'cros_chrome_version': '110.0.5481.21', - 'cros_img': 'eve-release/R110-15278.21.0', + 'cros_chrome_version': '111.0.5544.0', + 'cros_img': 'eve-release/R111-15320.0.0', }, 'enabled': True, 'identifier': 'EVE_RELEASE_DEV', @@ -561,8 +561,8 @@ 'CROS_HANA_RELEASE_DEV': { 'skylab': { 'cros_board': 'hana', - 'cros_chrome_version': '110.0.5481.21', - 'cros_img': 'hana-release/R110-15278.21.0', + 'cros_chrome_version': '111.0.5544.0', + 'cros_img': 'hana-release/R111-15320.0.0', }, 'enabled': True, 'identifier': 'HANA_RELEASE_DEV', @@ -606,8 +606,8 @@ 'CROS_JACUZZI_RELEASE_DEV': { 'skylab': { 'cros_board': 'jacuzzi', - 'cros_chrome_version': '110.0.5481.21', - 'cros_img': 'jacuzzi-release/R110-15278.21.0', + 'cros_chrome_version': '111.0.5544.0', + 'cros_img': 'jacuzzi-release/R111-15320.0.0', }, 'enabled': True, 'identifier': 'JACUZZI_RELEASE_DEV', @@ -682,8 +682,8 @@ 'CROS_OCTOPUS_RELEASE_DEV': { 'skylab': { 'cros_board': 'octopus', - 'cros_chrome_version': '110.0.5481.21', - 'cros_img': 'octopus-release/R110-15278.21.0', + 'cros_chrome_version': '111.0.5544.0', + 'cros_img': 'octopus-release/R111-15320.0.0', }, 'enabled': True, 'identifier': 'OCTOPUS_RELEASE_DEV', @@ -718,8 +718,8 @@ 'CROS_STRONGBAD_RELEASE_DEV': { 'skylab': { 'cros_board': 'strongbad', - 'cros_chrome_version': '110.0.5481.21', - 'cros_img': 'strongbad-release/R110-15278.21.0', + 'cros_chrome_version': '111.0.5544.0', + 'cros_img': 'strongbad-release/R111-15320.0.0', }, 'enabled': True, 'identifier': 'strongbad_RELEASE_DEV',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 70eb6b71..6669703 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -1460,6 +1460,15 @@ }, 'os_type': 'chromeos' }, + 'lacros-arm-generic-rel-skylab': { + 'additional_compile_targets': [ + 'chrome', + ], + 'test_suites': { + 'skylab_tests': 'lacros_arm_generic_rel_skylab', + }, + 'os_type': 'chromeos' + }, 'lacros-arm64-generic-rel': { 'additional_compile_targets': [ 'chrome', @@ -3665,6 +3674,15 @@ }, 'os_type': 'mac', }, + 'mac11-wpt-content-shell-fyi-rel': { + 'mixins': [ + 'mac_11_x64', + ], + 'test_suites': { + 'isolated_scripts': 'wpt_web_tests_content_shell', + }, + 'os_type': 'mac', + }, 'mac12-wpt-content-shell-fyi-rel': { 'mixins': [ 'mac_12_x64',
diff --git a/testing/unexpected_passes_common/expectations.py b/testing/unexpected_passes_common/expectations.py index 93a86a6..6197394 100644 --- a/testing/unexpected_passes_common/expectations.py +++ b/testing/unexpected_passes_common/expectations.py
@@ -31,6 +31,16 @@ FINDER_GROUP_COMMENT_START = 'finder:group-start' FINDER_GROUP_COMMENT_END = 'finder:group-end' +ALL_FINDER_START_ANNOTATION_BASES = frozenset([ + FINDER_DISABLE_COMMENT_BASE, + FINDER_GROUP_COMMENT_START, +]) + +ALL_FINDER_END_ANNOTATION_BASES = frozenset([ + FINDER_ENABLE_COMMENT_BASE, + FINDER_GROUP_COMMENT_END, +]) + ALL_FINDER_DISABLE_SUFFIXES = frozenset([ FINDER_COMMENT_SUFFIX_GENERAL, FINDER_COMMENT_SUFFIX_STALE, @@ -69,6 +79,13 @@ FINDER_ENABLE_COMMENT_NARROWING, ]) +FINDER_ENABLE_DISABLE_PAIRS = frozenset([ + (FINDER_DISABLE_COMMENT_GENERAL, FINDER_ENABLE_COMMENT_GENERAL), + (FINDER_DISABLE_COMMENT_STALE, FINDER_ENABLE_COMMENT_STALE), + (FINDER_DISABLE_COMMENT_UNUSED, FINDER_ENABLE_COMMENT_UNUSED), + (FINDER_DISABLE_COMMENT_NARROWING, FINDER_ENABLE_COMMENT_NARROWING), +]) + FINDER_GROUP_COMMENTS = frozenset([ FINDER_GROUP_COMMENT_START, FINDER_GROUP_COMMENT_END, @@ -82,11 +99,32 @@ r'^[\w\s]+\(.+(?P<date>\d\d\d\d-\d\d-\d\d)[^\)]+\)(?P<content>.*)$', re.DOTALL) TAG_GROUP_REGEX = re.compile(r'# tags: \[([^\]]*)\]', re.MULTILINE | re.DOTALL) + +# Annotation comment start (with optional leading whitespace) pattern. +ANNOTATION_COMMENT_START_PATTERN = r' *# ' +# Pattern for matching optional description text after an annotation. +ANNOTATION_OPTIONAL_TRAILING_TEXT_PATTERN = r'[^\n]*\n' +# Pattern for matching required description text after an annotation. +ANNOTATION_REQUIRED_TRAILING_TEXT_PATTERN = r'[^\n]+\n' +# Pattern for matching blank or comment lines. +BLANK_OR_COMMENT_LINES_PATTERN = r'(?:\s*| *#[^\n]*\n)*' # Looks for cases of the group start and end comments with nothing but optional # whitespace between them. -STALE_GROUP_COMMENT_REGEX = re.compile( - r'# ' + FINDER_GROUP_COMMENT_START + r'[^\n]+\s*# ' + - FINDER_GROUP_COMMENT_END + r'\n', re.MULTILINE | re.DOTALL) +ALL_STALE_COMMENT_REGEXES = set() +for start_comment, end_comment in FINDER_ENABLE_DISABLE_PAIRS: + ALL_STALE_COMMENT_REGEXES.add( + re.compile( + ANNOTATION_COMMENT_START_PATTERN + start_comment + + ANNOTATION_OPTIONAL_TRAILING_TEXT_PATTERN + + BLANK_OR_COMMENT_LINES_PATTERN + ANNOTATION_COMMENT_START_PATTERN + + end_comment + r'\n', re.MULTILINE | re.DOTALL)) +ALL_STALE_COMMENT_REGEXES.add( + re.compile( + ANNOTATION_COMMENT_START_PATTERN + FINDER_GROUP_COMMENT_START + + ANNOTATION_REQUIRED_TRAILING_TEXT_PATTERN + + BLANK_OR_COMMENT_LINES_PATTERN + ANNOTATION_COMMENT_START_PATTERN + + FINDER_GROUP_COMMENT_END + r'\n', re.MULTILINE | re.DOTALL)) +ALL_STALE_COMMENT_REGEXES = frozenset(ALL_STALE_COMMENT_REGEXES) # pylint: disable=useless-object-inheritance @@ -270,7 +308,8 @@ output_contents = '' removed_urls = set() - for line in input_contents.splitlines(True): + removed_lines = set() + for line_number, line in enumerate(input_contents.splitlines(True)): # Auto-add any comments or empty lines stripped_line = line.strip() if _IsCommentOrBlankLine(stripped_line): @@ -310,10 +349,19 @@ # It's possible to have multiple whitespace-separated bugs per # expectation, so treat each one separately. removed_urls |= set(bug.split()) + # Record that we've removed this line. By subtracting the number of + # lines we've already removed, we keep the line numbers relative to + # the content we're outputting rather than relative to the input + # content. This also has the effect of automatically compressing + # contiguous blocks of removal into a single line number. + removed_lines.add(line_number - len(removed_lines)) else: output_contents += line - output_contents = _RemoveStaleComments(output_contents) + header_length = len( + self._GetExpectationFileTagHeader(expectation_file).splitlines(True)) + output_contents = _RemoveStaleComments(output_contents, removed_lines, + header_length) with open(expectation_file, 'w') as f: f.write(output_contents) @@ -899,17 +947,77 @@ return not (all_expectations_in_group <= removable_expectations) -def _RemoveStaleComments(content: str) -> str: +def _RemoveStaleComments(content: str, removed_lines: Set[int], + header_length: int) -> str: """Attempts to remove stale contents from the given expectation file content. Args: content: A string containing the contents of an expectation file. + removed_lines: A set of ints denoting which line numbers were removed in + the process of creating |content|. + header_length: An int denoting how many lines long the tag header is. Returns: A copy of |content| with various stale comments removed, e.g. group blocks if the group has been removed. """ - for match in STALE_GROUP_COMMENT_REGEX.findall(content): - content = content.replace(match, '') + # Look for the case where we've removed an entire block of expectations that + # were preceded by a comment, which we should remove. + comment_line_numbers_to_remove = [] + split_content = content.splitlines(True) + for rl in removed_lines: + found_trailing_annotation = False + found_starting_annotation = False + # Check for the end of the file, a blank line, or a comment after the block + # we've removed. + if rl < len(split_content): + stripped_line = split_content[rl].strip() + if stripped_line and not stripped_line.startswith('#'): + # We found an expectation, so the entire expectation block wasn't + # removed. + continue + if any(annotation in stripped_line + for annotation in ALL_FINDER_END_ANNOTATION_BASES): + found_trailing_annotation = True + # Look for a comment block immediately preceding the block we removed. + comment_line_number = rl - 1 + while comment_line_number != header_length - 1: + stripped_line = split_content[comment_line_number].strip() + if stripped_line.startswith('#'): + # If we find what should be a trailing annotation, stop immediately so + # we don't accidentally remove it and create an orphan earlier in the + # file. + if any(annotation in stripped_line + for annotation in ALL_FINDER_END_ANNOTATION_BASES): + break + if any(annotation in stripped_line + for annotation in ALL_FINDER_START_ANNOTATION_BASES): + found_starting_annotation = True + # If we found a starting annotation but not a trailing annotation, we + # shouldn't remove the starting one, as that would cause the trailing + # one that is later in the file to be orphaned. We also don't want to + # continue and remove comments above that since it is assumedly still + # valid. + if found_starting_annotation and not found_trailing_annotation: + break + comment_line_numbers_to_remove.append(comment_line_number) + comment_line_number -= 1 + else: + break + # In the event that we found both a start and trailing annotation, we need + # to also remove the trailing one. + if found_trailing_annotation and found_starting_annotation: + comment_line_numbers_to_remove.append(rl) + + # Actually remove the comments we found above. + for i in comment_line_numbers_to_remove: + split_content[i] = '' + if comment_line_numbers_to_remove: + content = ''.join(split_content) + + # Remove any lingering cases of stale annotations that we can easily detect. + for regex in ALL_STALE_COMMENT_REGEXES: + for match in regex.findall(content): + content = content.replace(match, '') return content
diff --git a/testing/unexpected_passes_common/expectations_unittest.py b/testing/unexpected_passes_common/expectations_unittest.py index b9cec94..3e81e537 100755 --- a/testing/unexpected_passes_common/expectations_unittest.py +++ b/testing/unexpected_passes_common/expectations_unittest.py
@@ -444,8 +444,6 @@ # finder:disable-stale crbug.com/2345 [ win ] disabled_stale [ Failure ] # finder:enable-stale -# finder:disable-unused -# finder:enable-unused crbug.com/4567 [ win ] also_do_not_remove [ Failure ] """ with open(self.filename, 'w') as f: @@ -458,8 +456,6 @@ expected_contents = self.header + """ crbug.com/1234 [ win ] do_not_remove [ Failure ] -# finder:disable-stale -# finder:enable-stale # finder:disable-unused crbug.com/3456 [ win ] disabled_unused [ Failure ] # finder:enable-unused @@ -571,6 +567,7 @@ crbug.com/2345 [ win ] foo/test [ RetryOnFailure ] # Another comment + # finder:group-start some group name [ linux ] bar/test [ RetryOnFailure ] crbug.com/1234 [ win ] foo/test [ Failure ] @@ -590,6 +587,7 @@ crbug.com/2345 [ win ] foo/test [ RetryOnFailure ] # Another comment + [ win ] bar/test [ RetryOnFailure ] """ @@ -640,6 +638,7 @@ crbug.com/2345 [ win ] foo/test [ RetryOnFailure ] # Another comment + # finder:group-start some group name [ linux ] bar/test [ RetryOnFailure ] # finder:group-end @@ -663,6 +662,7 @@ # Another comment + [ win ] bar/test [ RetryOnFailure ] """ @@ -716,6 +716,7 @@ crbug.com/2345 [ win ] foo/test [ RetryOnFailure ] # Another comment + # finder:group-start some group name [ linux ] bar/test [ RetryOnFailure ] # finder:group-end @@ -739,6 +740,7 @@ # Another comment + [ win ] bar/test [ RetryOnFailure ] """ @@ -759,6 +761,7 @@ crbug.com/2345 [ win ] foo/test [ RetryOnFailure ] # Another comment + # finder:group-start some group name [ linux ] bar/test [ RetryOnFailure ] # finder:group-end @@ -783,6 +786,7 @@ # Another comment + # finder:group-start another group name crbug.com/1234 [ win ] foo/test [ Failure ] crbug.com/1234 [ linux ] foo/test [ Failure ] @@ -864,6 +868,314 @@ self.instance.RemoveExpectationsFromFile([], self.filename, expectations.RemovalType.STALE) + def testRemoveCommentBlockSimpleTrailingWhitespace(self): + """Tests stale comment removal in a simple case with trailing whitespace.""" + contents = self.header + """ +# Comment line 1 +# Comment line 2 +crbug.com/1234 [ linux ] foo/test [ Failure ] + +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + stale_expectations = [ + data_types.Expectation('foo/test', ['linux'], ['Failure'], + 'crbug.com/1234'), + ] + + expected_contents = self.header + """ + +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, {'crbug.com/1234'}) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + + def testRemoveCommentBlockSimpleTrailingComment(self): + """Tests stale comment removal in a simple case with trailing comment.""" + contents = self.header + """ +# Comment line 1 +# Comment line 2 +crbug.com/1234 [ linux ] foo/test [ Failure ] +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + stale_expectations = [ + data_types.Expectation('foo/test', ['linux'], ['Failure'], + 'crbug.com/1234'), + ] + + expected_contents = self.header + """ +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, {'crbug.com/1234'}) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + + def testRemoveCommentBlockSimpleEndOfFile(self): + """Tests stale comment removal in a simple case at file end.""" + contents = self.header + """ +crbug.com/2345 [ win ] bar/test [ Failure ] + +# Comment line 1 +# Comment line 2 +crbug.com/1234 [ linux ] foo/test [ Failure ]""" + + stale_expectations = [ + data_types.Expectation('foo/test', ['linux'], ['Failure'], + 'crbug.com/1234'), + ] + + expected_contents = self.header + """ +crbug.com/2345 [ win ] bar/test [ Failure ] + +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, {'crbug.com/1234'}) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + + def testRemoveCommentBlockWithAnnotations(self): + """Tests stale comment removal with annotations on both ends.""" + contents = self.header + """ +# Comment line 1 +# Comment line 2 +# finder:disable-unused +crbug.com/1234 [ linux ] foo/test [ Failure ] +# finder:enable-unused +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + stale_expectations = [ + data_types.Expectation('foo/test', ['linux'], ['Failure'], + 'crbug.com/1234'), + ] + + expected_contents = self.header + """ +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, {'crbug.com/1234'}) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + + def testRemoveCommentBlockWithMissingTrailingAnnotation(self): + """Tests stale comment removal with a missing trailing annotation.""" + contents = self.header + """ +# Comment line 1 +# Comment line 2 +# finder:disable-unused +crbug.com/1234 [ linux ] foo/test [ Failure ] + +crbug.com/1234 [ win ] foo/test [ Failure ] +# finder:enable-unused + +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + stale_expectations = [ + data_types.Expectation('foo/test', ['linux'], ['Failure'], + 'crbug.com/1234'), + ] + + expected_contents = self.header + """ +# Comment line 1 +# Comment line 2 +# finder:disable-unused + +crbug.com/1234 [ win ] foo/test [ Failure ] +# finder:enable-unused + +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, {'crbug.com/1234'}) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + + def testRemoveCommentBlockWithMissingStartAnnotation(self): + """Tests stale comment removal with a missing start annotation.""" + contents = self.header + """ +# finder:disable-unused +crbug.com/1234 [ win ] foo/test [ Failure ] +# Comment line 1 +# Comment line 2 +crbug.com/1234 [ linux ] foo/test [ Failure ] +# finder:enable-unused +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + stale_expectations = [ + data_types.Expectation('foo/test', ['linux'], ['Failure'], + 'crbug.com/1234'), + ] + + expected_contents = self.header + """ +# finder:disable-unused +crbug.com/1234 [ win ] foo/test [ Failure ] +# finder:enable-unused +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, {'crbug.com/1234'}) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + + def testRemoveCommentBlockMultipleExpectations(self): + """Tests stale comment removal with multiple expectations in a block.""" + contents = self.header + """ +# Comment line 1 +# Comment line 2 +# finder:disable-unused +crbug.com/1234 [ linux ] foo/test [ Failure ] +crbug.com/3456 [ mac ] foo/test [ Failure ] +# finder:enable-unused + +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + stale_expectations = [ + data_types.Expectation('foo/test', ['linux'], ['Failure'], + 'crbug.com/1234'), + data_types.Expectation('foo/test', ['mac'], ['Failure'], + 'crbug.com/3456'), + ] + + expected_contents = self.header + """ + +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, {'crbug.com/1234', 'crbug.com/3456'}) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + + def testRemoveCommentBlockMultipleBlocks(self): + """Tests stale comment removal with expectations in multiple blocks.""" + contents = self.header + """ +# Comment line 1 +# Comment line 2 +# finder:disable-unused +crbug.com/1234 [ linux ] foo/test [ Failure ] +# finder:enable-unused + +# Comment line 4 +# finder:disable-unused +crbug.com/3456 [ mac ] foo/test [ Failure ] +# finder:enable-unused +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + stale_expectations = [ + data_types.Expectation('foo/test', ['linux'], ['Failure'], + 'crbug.com/1234'), + data_types.Expectation('foo/test', ['mac'], ['Failure'], + 'crbug.com/3456'), + ] + + expected_contents = self.header + """ + +# Comment line 3 +crbug.com/2345 [ win ] bar/test [ Failure ] +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, {'crbug.com/1234', 'crbug.com/3456'}) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + + def testRemoveStaleAnnotationBlocks(self): + """Tests removal of annotation blocks not associated with removals.""" + contents = self.header + """ +# finder:disable-general +# finder:enable-general + +# finder:disable-stale + +# finder:enable-stale + +# finder:disable-unused +# comment +# finder:enable-unused + +# finder:disable-narrowing description +# comment +# finder:enable-narrowing + +# finder:group-start name +# finder:group-end +""" + + stale_expectations = [] + + expected_contents = self.header + """ + + + + +""" + + with open(self.filename, 'w') as f: + f.write(contents) + + removed_urls = self.instance.RemoveExpectationsFromFile( + stale_expectations, self.filename, expectations.RemovalType.STALE) + self.assertEqual(removed_urls, set()) + with open(self.filename) as f: + self.assertEqual(f.read(), expected_contents) + def testGroupNameExtraction(self): """Tests that group names are properly extracted.""" group_name = expectations._GetGroupNameFromCommentLine( @@ -955,6 +1267,7 @@ def testInlineComments(self) -> None: """Tests that inline disable comments are properly parsed.""" + # pylint: disable=line-too-long contents = """ crbug.com/1234 [ win ] foo/test [ Failure ] # finder:disable-general general-reason @@ -966,6 +1279,7 @@ crbug.com/1234 [ mac ] bar/test [ Failure ] """ + # pylint: enable=line-too-long annotated_expectations = ( self.instance._GetDisableAnnotatedExpectationsFromFile( 'expectation_file', contents))
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 0aa284c..49d2d23 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -374,7 +374,6 @@ "CacheSiteIsolationMemoryThreshold", "MojoAvoidRandomPipeId", "NewSigninRequestHeaderCheckOrder", - "ToolbarPhoneOptimizations", "UseGetrandomForRandBytes" ] } @@ -3319,6 +3318,21 @@ ] } ], + "CrOSEventSequenceLogging": [ + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "EnableEventSequenceLogging" + ] + } + ] + } + ], "CrOSFederatedServiceV0Task": [ { "platforms": [ @@ -4127,21 +4141,6 @@ ] } ], - "DisableIPH": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Disabled", - "disable_features": [ - "EnableIPH" - ] - } - ] - } - ], "DisableResourceScheduler": [ { "platforms": [ @@ -6167,8 +6166,7 @@ "name": "EnableMetaExperiment", "params": { "AllowedRandomTypes": "0", - "EnableActiveSampling": "true", - "Gen": "9", + "Gen": "10", "Rho": "1" }, "enable_features": [ @@ -6753,16 +6751,16 @@ ], "experiments": [ { - "name": "EnabledWithNewFlowAndIPH_V2", + "name": "EnabledWithDecisionInBrowser_V2", "enable_features": [ "AppIconInIntentChip", - "IPH_IntentChip", - "IntentChipSkipsPicker", - "LinkCapturingInfoBar", "LinkCapturingUiUpdate" ], "disable_features": [ - "LinkCapturingAutoDisplayIntentPicker" + "IPH_IntentChip", + "IntentChipSkipsPicker", + "LinkCapturingAutoDisplayIntentPicker", + "LinkCapturingInfoBar" ] } ] @@ -7661,6 +7659,7 @@ { "name": "Enabled", "enable_features": [ + "EnableSuggestionsScrollingOnIPad", "OmniboxFocusTriggersContextualWebZeroSuggest", "OmniboxFocusTriggersSRPZeroSuggest", "OmniboxMostVisitedTiles" @@ -8891,6 +8890,7 @@ { "platforms": [ "android", + "android_webview", "chromeos", "fuchsia", "linux", @@ -9188,6 +9188,8 @@ "FencedFrames", "FencedFramesAPIChanges", "InterestGroupStorage", + "KAnonymityService", + "KAnonymityServiceOHTTPRequests", "NoncedPartitionedCookies", "PrivacySandboxAdsAPIs", "PrivateAggregationApi", @@ -10869,16 +10871,10 @@ "IPH_DownloadHome_event_trigger": "name:download_home_iph_trigger;comparator:==0;window:90;storage:360", "IPH_DownloadHome_event_used": "name:download_home_opened;comparator:==0;window:90;storage:360", "IPH_DownloadHome_session_rate": "==0", - "IPH_TabSwitcherButton_availability": ">=14", - "IPH_TabSwitcherButton_event_trigger": "name:tab_switcher_iph_triggered;comparator:==0;window:90;storage:90", - "IPH_TabSwitcherButton_event_used": "name:tab_switcher_button_clicked;comparator:==0;window:14;storage:90", - "IPH_TabSwitcherButton_session_rate": "<1", "snooze_params": "max_limit:3,snooze_interval:7" }, "enable_features": [ - "IPH_DownloadHome", - "IPH_Snooze", - "IPH_TabSwitcherButton" + "IPH_DownloadHome" ] } ] @@ -13557,6 +13553,24 @@ ] } ], + "WhatsNewIOS": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled_Module_Based_UI", + "params": { + "whats_new_module_based_layout": "true" + }, + "enable_features": [ + "WhatsNewIOS" + ] + } + ] + } + ], "Win10UnattendedDefault": [ { "platforms": [
diff --git a/third_party/abseil-cpp/symbols_arm64_dbg.def b/third_party/abseil-cpp/symbols_arm64_dbg.def index 4ea21fb..d1b7d89 100644 --- a/third_party/abseil-cpp/symbols_arm64_dbg.def +++ b/third_party/abseil-cpp/symbols_arm64_dbg.def
@@ -58,6 +58,11 @@ ??$?0$00X@?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAA@$$T@Z ??$?0$00X@?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAA@PEAVZoneInfoSource@cctz@time_internal@absl@@@Z ??$?0$0A@$00$$ZAEBVstring_view@absl@@AEBH$$Z$S$$Z$$V$$ZAEBV01@AEBH@?$__tuple_impl@U?$__tuple_indices@$0A@$00@Cr@std@@AEBVstring_view@absl@@AEBH@Cr@std@@QEAA@U?$__tuple_indices@$0A@$00@12@U?$__tuple_types@AEBVstring_view@absl@@AEBH@12@U?$__tuple_indices@$S@12@U?$__tuple_types@$$V@12@AEBVstring_view@absl@@AEBH@Z + ??$?0AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEAPEBV01234@$0A@@?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@QEAA@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$?0AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV01234@$0A@@?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@QEAA@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAPEAPEAPEBV34567@@Z + ??$?0AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@AEAPEAPEAU0123@$0A@@?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@QEAA@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$?0AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU0123@$0A@@?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@QEAA@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAPEAU3456@@Z + ??$?0AEAPEAPEAVLogSink@absl@@PEAPEAV01@$0A@@?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@QEAA@AEAPEAPEAVLogSink@absl@@$$QEAPEAPEAV34@@Z ??$?0AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@@?$__compressed_pair@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@@Cr@std@@QEAA@AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAV?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@12@@Z ??$?0AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0AEAPEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@V?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@@Cr@std@@@12@@?$__compressed_pair@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@V?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@@Cr@std@@@23@@Cr@std@@QEAA@AEAPEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@12@$$QEAV?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@@Cr@std@@@12@@Z @@ -68,6 +73,10 @@ ??$?0AEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@X@?$__compressed_pair_elem@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$?0AEAPEAUThreadIdentity@base_internal@absl@@AEBQ6AXPEAX@Z@?$__compressed_pair@PEAUThreadIdentity@base_internal@absl@@P6AXPEAX@Z@Cr@std@@QEAA@AEAPEAUThreadIdentity@base_internal@absl@@AEBQ6AXPEAX@Z@Z ??$?0AEAPEAUThreadIdentity@base_internal@absl@@X@?$__compressed_pair_elem@PEAUThreadIdentity@base_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAUThreadIdentity@base_internal@absl@@@Z + ??$?0AEAPEAUTransition@cctz@time_internal@absl@@AEAPEAU0123@$0A@@?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEAUTransition@cctz@time_internal@absl@@0@Z + ??$?0AEAPEAUTransition@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEAUTransition@cctz@time_internal@absl@@$$QEAPEAU3456@@Z + ??$?0AEAPEAUTransitionType@cctz@time_internal@absl@@AEAPEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEAUTransitionType@cctz@time_internal@absl@@0@Z + ??$?0AEAPEAUTransitionType@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEAUTransitionType@cctz@time_internal@absl@@$$QEAPEAU3456@@Z ??$?0AEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QEAA@AEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$$QEAU__value_init_tag@12@@Z ??$?0AEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@X@?$__compressed_pair_elem@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Z ??$?0AEAPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PEAVFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAA@AEAPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@$$QEAU__value_init_tag@12@@Z @@ -78,6 +87,8 @@ ??$?0AEAPEAVTimeZoneInfo@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEAVTimeZoneInfo@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAVTimeZoneInfo@cctz@time_internal@absl@@@Z ??$?0AEAPEAVZoneInfoSource@cctz@time_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PEAVZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAA@AEAPEAVZoneInfoSource@cctz@time_internal@absl@@$$QEAU__value_init_tag@12@@Z ??$?0AEAPEAVZoneInfoSource@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEAVZoneInfoSource@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAVZoneInfoSource@cctz@time_internal@absl@@@Z + ??$?0AEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU0123@$0A@@?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAU3456@@Z + ??$?0AEAPEBVFormatArgImpl@str_format_internal@absl@@PEAV012@$0A@@?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@Cr@std@@QEAA@AEAPEBVFormatArgImpl@str_format_internal@absl@@$$QEAPEAV345@@Z ??$?0AEAPEBVImpl@time_zone@cctz@time_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PEBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAA@AEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAU__value_init_tag@12@@Z ??$?0AEAPEBVImpl@time_zone@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEBVImpl@time_zone@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QEAA@AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@@Z @@ -98,13 +109,6 @@ ??$?0AEAV?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AEAV?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QEAA@AEAV?$allocator@UTransition@cctz@time_internal@absl@@@12@@Z ??$?0AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QEAA@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QEAA@AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@@Z - ??$?0AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@12@$$QEAV312@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@3@AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@_K@container_internal@absl@@QEAA@AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@$$QEAI@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@I@?$CompressedTupleImpl@V?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@_K@container_internal@absl@@U?$integer_sequence@_K$0A@$00@3@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@3@AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@$$QEAI@Z @@ -127,17 +131,13 @@ ??$?0PEAI@?$SaltedSeedSeq@Vseed_seq@Cr@std@@@random_internal@absl@@QEAA@PEAI0@Z ??$?0PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV01234@$0A@@?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@QEAA@$$QEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z ??$?0PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU0123@$0A@@?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@QEAA@$$QEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z - ??$?0PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV012@$0A@@?$pair@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@@Cr@std@@QEAA@$$QEAPEAPEAVCordzHandle@cord_internal@absl@@0@Z ??$?0PEAPEAVLogSink@absl@@@?$__wrap_iter@PEBQEAVLogSink@absl@@@Cr@std@@QEAA@AEBV?$__wrap_iter@PEAPEAVLogSink@absl@@@12@PEAX@Z ??$?0PEAPEAVLogSink@absl@@PEAPEAV01@$0A@@?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@QEAA@$$QEAPEAPEAVLogSink@absl@@0@Z - ??$?0PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV012@$0A@@?$pair@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@@Cr@std@@QEAA@$$QEAPEAPEBVCordzHandle@cord_internal@absl@@0@Z - ??$?0PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU0123@$0A@@?$pair@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@@Cr@std@@QEAA@$$QEAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@0@Z ??$?0PEAUPrefixCrc@CrcCordState@crc_internal@absl@@AEAU0123@PEAPEAU0123@@?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@Cr@std@@QEAA@AEBV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@PEAX@Z ??$?0PEAUTransition@cctz@time_internal@absl@@@?$__wrap_iter@PEBUTransition@cctz@time_internal@absl@@@Cr@std@@QEAA@AEBV?$__wrap_iter@PEAUTransition@cctz@time_internal@absl@@@12@PEAX@Z ??$?0PEAUTransition@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@$$QEAPEAUTransition@cctz@time_internal@absl@@0@Z ??$?0PEAUTransitionType@cctz@time_internal@absl@@@?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEAA@AEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@PEAX@Z ??$?0PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@$$QEAPEAUTransitionType@cctz@time_internal@absl@@0@Z - ??$?0PEAUViableSubstitution@strings_internal@absl@@PEAU012@$0A@@?$pair@PEAUViableSubstitution@strings_internal@absl@@PEAU123@@Cr@std@@QEAA@$$QEAPEAUViableSubstitution@strings_internal@absl@@0@Z ??$?0PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@?$__compressed_pair@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QEAA@$$QEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$$QEAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@12@@Z ??$?0PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@X@?$__compressed_pair_elem@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$0A@$0A@@Cr@std@@QEAA@$$QEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Z ??$?0PEAVFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@?$__compressed_pair@PEAVCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAA@$$QEAPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@$$QEAU?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@12@@Z @@ -264,8 +264,15 @@ ??$?8PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z ??$?8VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YA_NAEBV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@01@$$T@Z ??$?9PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z + ??$?9PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV012@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z ??$?9PEAPEAVLogSink@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEAPEAVLogSink@absl@@@01@0@Z + ??$?9PEAPEAVLogSink@absl@@PEAPEAV01@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAPEAVLogSink@absl@@@01@0@Z + ??$?9PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV012@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@0@Z + ??$?9PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU0123@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z + ??$?9PEAUTransition@cctz@time_internal@absl@@PEAU0123@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@0@Z ??$?9PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$?9PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$?9PEAUViableSubstitution@strings_internal@absl@@PEAU012@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@0@Z ??$?9PEBQEAVLogSink@absl@@PEAPEAV01@@Cr@std@@YA_NAEBV?$__wrap_iter@PEBQEAVLogSink@absl@@@01@AEBV?$__wrap_iter@PEAPEAVLogSink@absl@@@01@@Z ??$?9PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z ??$?BV?$allocator@D@Cr@std@@@string_view@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@XZ @@ -285,6 +292,8 @@ ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?PUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z + ??$?R$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U0123@$0A@@__copy_trivial@Cr@std@@QEBA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@12@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU4567@@Z + ??$?R$$CBVFormatArgImpl@str_format_internal@absl@@V012@$0A@@__copy_trivial@Cr@std@@QEBA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@12@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV456@@Z ??$?RAEAPEAXAEAY0MI@DAEBH@?$AtomicHook@P6A_NPEBXPEADH@Z@base_internal@absl@@QEBA_NAEAPEAXAEAY0MI@DAEBH@Z ??$?RAEAPEBDAEAHAEAY0LLI@DAEBQEBDPEAD@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@QEBAXAEAPEBDAEAHAEAY0LLI@DAEBQEBD$$QEAPEAD@Z ??$?RAEAW4LogSeverity@absl@@AEAPEBDAEAHPEAPEADPEAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@QEBA_NAEAW4LogSeverity@2@AEAPEBDAEAH$$QEAPEAPEAD$$QEAPEAH@Z @@ -302,7 +311,23 @@ ??$?RAEBQEAUTransition@cctz@time_internal@absl@@@__fn@__iter_move@ranges@Cr@std@@QEBA$$QEAUTransition@cctz@time_internal@absl@@AEBQEAU5678@@Z ??$?RAEBQEAUTransitionType@cctz@time_internal@absl@@@__fn@__iter_move@ranges@Cr@std@@QEBA$$QEAUTransitionType@cctz@time_internal@absl@@AEBQEAU5678@@Z ??$?RAEBUTransition@cctz@time_internal@absl@@@__identity@Cr@std@@QEBAAEBUTransition@cctz@time_internal@absl@@AEBU3456@@Z + ??$?RPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV01234@$0A@@__move_backward_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$?RPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV01234@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$?RPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU0123@$0A@@__move_backward_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@12@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$?RPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU0123@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@12@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$?RPEAVLogSink@absl@@PEAV01@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@12@PEAPEAVLogSink@absl@@00@Z ??$?RPEAVSpinLock@base_internal@absl@@AEB_J@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@QEBAX$$QEAPEAVSpinLock@12@AEB_J@Z + ??$?RUTransition@cctz@time_internal@absl@@U0123@$0A@@__move_backward_trivial@Cr@std@@QEBA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$?RUTransition@cctz@time_internal@absl@@U0123@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@__move_backward_trivial@Cr@std@@QEBA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$?RV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAPEAVLogSink@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@12@00@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CC@$$CBD@Z @@ -662,10 +687,19 @@ ??$__construct_one_at_end@AEBQEBVCordzHandle@cord_internal@absl@@@?$vector@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AEAAXAEBQEBVCordzHandle@cord_internal@absl@@@Z ??$__construct_one_at_end@AEBUTransition@cctz@time_internal@absl@@@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@AEAAXAEBUTransition@cctz@time_internal@absl@@@Z ??$__construct_one_at_end@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@?$vector@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@Cr@std@@AEAAX$$QEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Z - ??$__copy@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@PEAU1234@$0A@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z - ??$__copy@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@PEAV123@$0A@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z - ??$__copy_impl@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U1234@X@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z - ??$__copy_impl@$$CBVFormatArgImpl@str_format_internal@absl@@V123@X@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z + ??$__copy@U_ClassicAlgPolicy@Cr@std@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU4567@PEAU4567@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z + ??$__copy@U_ClassicAlgPolicy@Cr@std@@PEBVFormatArgImpl@str_format_internal@absl@@PEBV456@PEAV456@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z + ??$__copy_backward_trivial_impl@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@UTransition@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@UTransitionType@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z + ??$__copy_trivial_impl@$$CBVFormatArgImpl@str_format_internal@absl@@V123@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z + ??$__copy_trivial_impl@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__copy_trivial_impl@PEAVLogSink@absl@@PEAV12@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@PEAPEAVLogSink@absl@@00@Z + ??$__copy_trivial_impl@UTransition@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@UTransitionType@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$__cxx_atomic_compare_exchange_strong@PEAVTimeZone@absl@@@Cr@std@@YA_NPEAU?$__cxx_atomic_base_impl@PEAVTimeZone@absl@@@01@PEAPEAVTimeZone@absl@@PEAV34@W4memory_order@01@3@Z ??$__cxx_atomic_compare_exchange_weak@PEAUHashtablezInfo@container_internal@absl@@@Cr@std@@YA_NPEAU?$__cxx_atomic_base_impl@PEAUHashtablezInfo@container_internal@absl@@@01@PEAPEAUHashtablezInfo@container_internal@absl@@PEAU345@W4memory_order@01@3@Z ??$__cxx_atomic_load@P6AXAEBUHashtablezInfo@container_internal@absl@@@Z@Cr@std@@YAP6AXAEBUHashtablezInfo@container_internal@absl@@@ZPEBU?$__cxx_atomic_base_impl@P6AXAEBUHashtablezInfo@container_internal@absl@@@Z@01@W4memory_order@01@@Z @@ -718,6 +752,24 @@ ??$__destroy_at@UTransitionType@cctz@time_internal@absl@@$0A@@Cr@std@@YAXPEAUTransitionType@cctz@time_internal@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@$0A@@Cr@std@@YAXPEAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@VFormatArgImpl@str_format_internal@absl@@$0A@@Cr@std@@YAXPEAVFormatArgImpl@str_format_internal@absl@@@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV6789absl@@PEAPEAPEBV6789absl@@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU6789@PEAPEAU6789@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PEAUTransition@cctz@time_internal@absl@@PEAU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PEAUTransitionType@cctz@time_internal@absl@@PEAU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV6789absl@@PEAPEAPEBV6789absl@@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU6789@PEAPEAU6789@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAPEAVLogSink@absl@@PEAPEAV67@PEAPEAV67@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@PEAPEAVLogSink@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAUTransition@cctz@time_internal@absl@@PEAU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAUTransitionType@cctz@time_internal@absl@@PEAU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAPEAVLogSink@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVLogSink@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U__copy_loop@23@U__copy_trivial@23@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U__copy_loop@23@U__copy_trivial@23@PEBVFormatArgImpl@str_format_internal@absl@@PEBV678@PEAV678@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z ??$__distance@PEBUPayload@status_internal@absl@@@Cr@std@@YA_JPEBUPayload@status_internal@absl@@0Urandom_access_iterator_tag@01@@Z ??$__distance@PEBUTransition@cctz@time_internal@absl@@@Cr@std@@YA_JPEBUTransition@cctz@time_internal@absl@@0Urandom_access_iterator_tag@01@@Z ??$__distance@PEBVFormatArgImpl@str_format_internal@absl@@@Cr@std@@YA_JPEBVFormatArgImpl@str_format_internal@absl@@0Urandom_access_iterator_tag@01@@Z @@ -732,6 +784,13 @@ ??$__invoke@AEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@Cr@std@@YA_NAEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@Cr@std@@YA_NAEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAU__identity@Cr@std@@AEBUTransition@cctz@time_internal@absl@@@Cr@std@@YAAEBUTransition@cctz@time_internal@absl@@AEAU__identity@01@AEBU2345@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAPEAVCordzHandle@cord_internal@absl@@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAPEAVLogSink@absl@@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAPEBVCordzHandle@cord_internal@absl@@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAUTransition@cctz@time_internal@absl@@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAUTransitionType@cctz@time_internal@absl@@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAUViableSubstitution@strings_internal@absl@@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@12@@Z ??$__launder@$$CBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPEBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEBU201@@Z ??$__launder@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@@Z ??$__lower_bound_impl@U_ClassicAlgPolicy@Cr@std@@PEBUTransition@cctz@time_internal@absl@@PEBU4567@U4567@U__identity@23@UByUnixTime@4567@@Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@AEAUByUnixTime@2345@AEAU__identity@01@@Z @@ -747,30 +806,10 @@ ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@00@Z ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@00@Z ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV45678@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU4567@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@UTransition@cctz@time_internal@absl@@U4567@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@UTransitionType@cctz@time_internal@absl@@U4567@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEAVLogSink@absl@@PEAPEAV45@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVLogSink@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV45678@X@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU4567@X@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUViableSubstitution@strings_internal@absl@@PEAU456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAVCordzHandle@cord_internal@absl@@PEAV456@X@Cr@std@@YA?AU?$pair@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@@01@PEAPEAVCordzHandle@cord_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAVLogSink@absl@@PEAV45@X@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@PEAPEAVLogSink@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEBVCordzHandle@cord_internal@absl@@PEBV456@X@Cr@std@@YA?AU?$pair@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@@01@PEAPEBVCordzHandle@cord_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@@01@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UTransition@cctz@time_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UTransitionType@cctz@time_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UViableSubstitution@strings_internal@absl@@U456@X@Cr@std@@YA?AU?$pair@PEAUViableSubstitution@strings_internal@absl@@PEAU123@@01@PEAUViableSubstitution@strings_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@PEAU4567@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@PEAU4567@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$__push_back_slow_path@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AEAAXAEBQEAVCordzHandle@cord_internal@absl@@@Z ??$__push_back_slow_path@AEBQEAVLogSink@absl@@@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@Cr@std@@@Cr@std@@AEAAXAEBQEAVLogSink@absl@@@Z ??$__push_back_slow_path@AEBQEBVCordzHandle@cord_internal@absl@@@?$vector@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AEAAXAEBQEBVCordzHandle@cord_internal@absl@@@Z @@ -779,14 +818,10 @@ ??$__rehash@$00@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$allocator@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@23@@Cr@std@@AEAAX_K@Z ??$__rewrap_iter@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@U?$__unwrap_iter_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@0@Z ??$__rewrap_iter@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@U?$__unwrap_iter_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@0@Z - ??$__rewrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@U?$__unwrap_iter_impl@PEAPEAVCordzHandle@cord_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV234@0@Z ??$__rewrap_iter@PEAPEAVLogSink@absl@@PEAPEAV12@U?$__unwrap_iter_impl@PEAPEAVLogSink@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0@Z - ??$__rewrap_iter@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@U?$__unwrap_iter_impl@PEAPEBVCordzHandle@cord_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV234@0@Z - ??$__rewrap_iter@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@U?$__unwrap_iter_impl@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@0@Z ??$__rewrap_iter@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@U?$__unwrap_iter_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU2345@0@Z ??$__rewrap_iter@PEAUTransition@cctz@time_internal@absl@@PEAU1234@U?$__unwrap_iter_impl@PEAUTransition@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@0@Z ??$__rewrap_iter@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@U?$__unwrap_iter_impl@PEAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@0@Z - ??$__rewrap_iter@PEAUViableSubstitution@strings_internal@absl@@PEAU123@U?$__unwrap_iter_impl@PEAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUViableSubstitution@strings_internal@absl@@PEAU234@0@Z ??$__rewrap_iter@PEAVFormatArgImpl@str_format_internal@absl@@PEAV123@U?$__unwrap_iter_impl@PEAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAVFormatArgImpl@str_format_internal@absl@@PEAV234@0@Z ??$__rewrap_iter@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@U?$__unwrap_iter_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@0@Z ??$__rewrap_iter@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@U?$__unwrap_iter_impl@PEBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEBVFormatArgImpl@str_format_internal@absl@@PEBV234@0@Z @@ -797,8 +832,20 @@ ??$__rewrap_iter@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@V201@0@Z ??$__rewrap_iter@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@V201@0@Z ??$__rewrap_iter@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@PEAPEAPEBV12345@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@0@Z + ??$__rewrap_range@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@PEAPEAU1234@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@0@Z + ??$__rewrap_range@PEAPEAVLogSink@absl@@PEAPEAV12@PEAPEAV12@@Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0@Z + ??$__rewrap_range@PEAUTransition@cctz@time_internal@absl@@PEAU1234@PEAU1234@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@0@Z + ??$__rewrap_range@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@PEAU1234@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@0@Z ??$__rewrap_range@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@PEBU1234@@Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@0@Z ??$__rewrap_range@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@PEBV123@@Cr@std@@YAPEBVFormatArgImpl@str_format_internal@absl@@PEBV234@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAPEAVLogSink@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@V201@0@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@@Z ??$__to_address@$$CBVFormatArgImpl@str_format_internal@absl@@@Cr@std@@YAPEBVFormatArgImpl@str_format_internal@absl@@PEBV234@@Z ??$__to_address@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@@Z @@ -822,16 +869,30 @@ ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@U4567@X@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@01@PEAU2345@11@Z ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@UTransitionType@cctz@time_internal@absl@@X@Cr@std@@YA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@01@V201@11@Z ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@UViableSubstitution@strings_internal@absl@@X@Cr@std@@YA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@01@V201@11@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@$0A@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@$0A@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAPEAVLogSink@absl@@PEAPEAV45@PEAPEAV45@$0A@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@PEAPEAVLogSink@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAPEAVLogSink@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVLogSink@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U__copy_loop@Cr@std@@U__copy_trivial@23@@Cr@std@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z + ??$__unwrap_and_dispatch@U?$__overload@U__copy_loop@Cr@std@@U__copy_trivial@23@@Cr@std@@PEBVFormatArgImpl@str_format_internal@absl@@PEBV456@PEAV456@$0A@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z ??$__unwrap_iter@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@@Z ??$__unwrap_iter@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@@Z - ??$__unwrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@U?$__unwrap_iter_impl@PEAPEAVCordzHandle@cord_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV234@@Z ??$__unwrap_iter@PEAPEAVLogSink@absl@@U?$__unwrap_iter_impl@PEAPEAVLogSink@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@@Z - ??$__unwrap_iter@PEAPEBVCordzHandle@cord_internal@absl@@U?$__unwrap_iter_impl@PEAPEBVCordzHandle@cord_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV234@@Z - ??$__unwrap_iter@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@U?$__unwrap_iter_impl@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@@Z ??$__unwrap_iter@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU2345@@Z ??$__unwrap_iter@PEAUTransition@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PEAUTransition@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@@Z ??$__unwrap_iter@PEAUTransitionType@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PEAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@@Z - ??$__unwrap_iter@PEAUViableSubstitution@strings_internal@absl@@U?$__unwrap_iter_impl@PEAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUViableSubstitution@strings_internal@absl@@PEAU234@@Z ??$__unwrap_iter@PEAVFormatArgImpl@str_format_internal@absl@@U?$__unwrap_iter_impl@PEAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAVFormatArgImpl@str_format_internal@absl@@PEAV234@@Z ??$__unwrap_iter@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@@Z ??$__unwrap_iter@PEBVFormatArgImpl@str_format_internal@absl@@U?$__unwrap_iter_impl@PEBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEBVFormatArgImpl@str_format_internal@absl@@PEBV234@@Z @@ -842,10 +903,29 @@ ??$__unwrap_iter@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@V201@@Z ??$__unwrap_iter@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@V201@@Z ??$__unwrap_iter@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@V201@@Z + ??$__unwrap_range@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@YA?A?<auto>@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$__unwrap_range@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@YA?A?<auto>@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$__unwrap_range@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@YA?A?<auto>@@PEAPEAVLogSink@absl@@0@Z + ??$__unwrap_range@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?A?<auto>@@PEAUTransition@cctz@time_internal@absl@@0@Z + ??$__unwrap_range@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?A?<auto>@@PEAUTransitionType@cctz@time_internal@absl@@0@Z ??$__unwrap_range@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@Cr@std@@YA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$__unwrap_range@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@@Cr@std@@YA?A?<auto>@@PEBVFormatArgImpl@str_format_internal@absl@@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAPEAVLogSink@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@0@Z ??$__upper_bound@U_ClassicAlgPolicy@Cr@std@@UByCivilTime@Transition@cctz@time_internal@absl@@PEBU5678@PEBU5678@U5678@U__identity@23@@Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@$$QEAUByCivilTime@2345@$$QEAU__identity@01@@Z ??$__upper_bound@U_ClassicAlgPolicy@Cr@std@@UByUnixTime@Transition@cctz@time_internal@absl@@PEBU5678@PEBU5678@U5678@U__identity@23@@Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@$$QEAUByUnixTime@2345@$$QEAU__identity@01@@Z + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ ??$advance@PEBUTransition@cctz@time_internal@absl@@_J@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J_JX@Cr@std@@YAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@PEBVFormatArgImpl@str_format_internal@absl@@_K_KX@Cr@std@@YAXAEAPEBVFormatArgImpl@str_format_internal@absl@@_K@Z @@ -1010,22 +1090,22 @@ ??$launder@$$CBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPEBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEBU201@@Z ??$launder@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@@Z ??$lower_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByUnixTime@2345@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@$$QEAV301@@Z + ??$make_pair@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$make_pair@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAPEAPEAPEBV34567@@Z + ??$make_pair@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@AEAPEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$make_pair@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAPEAU3456@@Z + ??$make_pair@AEAPEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@AEAPEAPEAVLogSink@absl@@$$QEAPEAPEAV34@@Z + ??$make_pair@AEAPEAUTransition@cctz@time_internal@absl@@AEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@AEAPEAUTransition@cctz@time_internal@absl@@0@Z + ??$make_pair@AEAPEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@AEAPEAUTransition@cctz@time_internal@absl@@$$QEAPEAU3456@@Z + ??$make_pair@AEAPEAUTransitionType@cctz@time_internal@absl@@AEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@AEAPEAUTransitionType@cctz@time_internal@absl@@0@Z + ??$make_pair@AEAPEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@AEAPEAUTransitionType@cctz@time_internal@absl@@$$QEAPEAU3456@@Z + ??$make_pair@AEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@AEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAU3456@@Z + ??$make_pair@AEAPEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@AEAPEBVFormatArgImpl@str_format_internal@absl@@$$QEAPEAV345@@Z ??$make_pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@$$QEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z ??$make_pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@$$QEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z - ??$make_pair@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@@Cr@std@@YA?AU?$pair@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@@01@$$QEAPEAPEAVCordzHandle@cord_internal@absl@@0@Z ??$make_pair@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@$$QEAPEAPEAVLogSink@absl@@0@Z - ??$make_pair@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@@Cr@std@@YA?AU?$pair@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@@01@$$QEAPEAPEBVCordzHandle@cord_internal@absl@@0@Z - ??$make_pair@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@@01@$$QEAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@0@Z ??$make_pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@$$QEAPEAUTransition@cctz@time_internal@absl@@0@Z ??$make_pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@$$QEAPEAUTransitionType@cctz@time_internal@absl@@0@Z - ??$make_pair@PEAUViableSubstitution@strings_internal@absl@@PEAU123@@Cr@std@@YA?AU?$pair@PEAUViableSubstitution@strings_internal@absl@@PEAU123@@01@$$QEAPEAUViableSubstitution@strings_internal@absl@@0@Z ??$make_pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@$$QEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAU3456@@Z ??$make_pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@$$QEAPEBVFormatArgImpl@str_format_internal@absl@@$$QEAPEAV345@@Z ??$make_pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@$$QEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z @@ -1784,6 +1864,13 @@ ??D?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@QEBA$$QEAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEBA$$QEAUTransitionType@cctz@time_internal@absl@@XZ ??D?$optional@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@absl@@QEGAAAEAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@XZ + ??D?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@QEBAAEAPEAVCordzHandle@cord_internal@absl@@XZ + ??D?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@QEBAAEAPEAVLogSink@absl@@XZ + ??D?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@QEBAAEAPEBVCordzHandle@cord_internal@absl@@XZ + ??D?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@QEBAAEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@XZ + ??D?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@QEBAAEAUTransition@cctz@time_internal@absl@@XZ + ??D?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEBAAEAUTransitionType@cctz@time_internal@absl@@XZ + ??D?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@QEBAAEAUViableSubstitution@strings_internal@absl@@XZ ??D?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@Cr@std@@@Cr@std@@QEBAAEAULogMessageData@LogMessage@log_internal@absl@@XZ ??D?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QEBAAEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@XZ ??DChunkIterator@Cord@absl@@QEBA?AVstring_view@2@XZ @@ -1805,6 +1892,13 @@ ??E?$move_iterator@PEAUPayload@status_internal@absl@@@Cr@std@@QEAAAEAV012@XZ ??E?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@QEAAAEAV012@XZ ??E?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@QEAAAEAV012@XZ ??EChunkIterator@Cord@absl@@QEAAAEAV012@XZ ??E__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAAAEAU0123@XZ ??Euint128@absl@@QEAAAEAV01@XZ @@ -3534,14 +3628,10 @@ ?__rehash_unique@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$allocator@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@23@@Cr@std@@QEAAX_K@Z ?__rewrap@?$__unwrap_iter_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@SAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@0@Z - ?__rewrap@?$__unwrap_iter_impl@PEAPEAVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV456@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAPEAVLogSink@absl@@$00@Cr@std@@SAPEAPEAVLogSink@absl@@PEAPEAV45@0@Z - ?__rewrap@?$__unwrap_iter_impl@PEAPEBVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV456@0@Z - ?__rewrap@?$__unwrap_iter_impl@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@SAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAUTransition@cctz@time_internal@absl@@$00@Cr@std@@SAPEAUTransition@cctz@time_internal@absl@@PEAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@SAPEAUTransitionType@cctz@time_internal@absl@@PEAU4567@0@Z - ?__rewrap@?$__unwrap_iter_impl@PEAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@SAPEAUViableSubstitution@strings_internal@absl@@PEAU456@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPEAVFormatArgImpl@str_format_internal@absl@@PEAV456@0@Z ?__rewrap@?$__unwrap_iter_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PEBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPEBVFormatArgImpl@str_format_internal@absl@@PEBV456@0@Z @@ -3552,8 +3642,20 @@ ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V423@0@Z ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@0@Z ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@SA?A?<auto>@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@SA?A?<auto>@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@SA?A?<auto>@@PEAPEAVLogSink@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@SA?A?<auto>@@PEAUTransition@cctz@time_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@SA?A?<auto>@@PEAUTransitionType@cctz@time_internal@absl@@0@Z ?__rewrap@?$__unwrap_range_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@Cr@std@@SA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ?__rewrap@?$__unwrap_range_impl@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@@Cr@std@@SA?A?<auto>@@PEBVFormatArgImpl@str_format_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEAVLogSink@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@0@Z ?__size@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAAAEA_KXZ ?__size@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEBAAEB_KXZ ?__size@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAAAEA_KXZ @@ -3577,14 +3679,10 @@ ?__throw_length_error@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@AEBAXXZ ?__unwrap@?$__unwrap_iter_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@SAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@@Z ?__unwrap@?$__unwrap_iter_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@@Z - ?__unwrap@?$__unwrap_iter_impl@PEAPEAVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV456@@Z ?__unwrap@?$__unwrap_iter_impl@PEAPEAVLogSink@absl@@$00@Cr@std@@SAPEAPEAVLogSink@absl@@PEAPEAV45@@Z - ?__unwrap@?$__unwrap_iter_impl@PEAPEBVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV456@@Z - ?__unwrap@?$__unwrap_iter_impl@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@SAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PEAUTransition@cctz@time_internal@absl@@$00@Cr@std@@SAPEAUTransition@cctz@time_internal@absl@@PEAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PEAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@SAPEAUTransitionType@cctz@time_internal@absl@@PEAU4567@@Z - ?__unwrap@?$__unwrap_iter_impl@PEAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@SAPEAUViableSubstitution@strings_internal@absl@@PEAU456@@Z ?__unwrap@?$__unwrap_iter_impl@PEAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPEAVFormatArgImpl@str_format_internal@absl@@PEAV456@@Z ?__unwrap@?$__unwrap_iter_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PEBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPEBVFormatArgImpl@str_format_internal@absl@@PEBV456@@Z @@ -3595,8 +3693,20 @@ ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V423@@Z ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@@Z ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@@Z + ?__unwrap@?$__unwrap_range_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@SA?A?<auto>@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@SA?A?<auto>@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@SA?A?<auto>@@PEAPEAVLogSink@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@SA?A?<auto>@@PEAUTransition@cctz@time_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@SA?A?<auto>@@PEAUTransitionType@cctz@time_internal@absl@@0@Z ?__unwrap@?$__unwrap_range_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@Cr@std@@SA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ?__unwrap@?$__unwrap_range_impl@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@@Cr@std@@SA?A?<auto>@@PEBVFormatArgImpl@str_format_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEAVLogSink@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@0@Z ?__upcast@?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@@Cr@std@@QEAAPEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@23@XZ ?__vallocate@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@AEAAX_K@Z ?__vdeallocate@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@AEAAXXZ
diff --git a/third_party/abseil-cpp/symbols_x64_dbg.def b/third_party/abseil-cpp/symbols_x64_dbg.def index d0f3d0b..0bf6edc 100644 --- a/third_party/abseil-cpp/symbols_x64_dbg.def +++ b/third_party/abseil-cpp/symbols_x64_dbg.def
@@ -58,6 +58,11 @@ ??$?0$00X@?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAA@$$T@Z ??$?0$00X@?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAA@PEAVZoneInfoSource@cctz@time_internal@absl@@@Z ??$?0$0A@$00$$ZAEBVstring_view@absl@@AEBH$$Z$S$$Z$$V$$ZAEBV01@AEBH@?$__tuple_impl@U?$__tuple_indices@$0A@$00@Cr@std@@AEBVstring_view@absl@@AEBH@Cr@std@@QEAA@U?$__tuple_indices@$0A@$00@12@U?$__tuple_types@AEBVstring_view@absl@@AEBH@12@U?$__tuple_indices@$S@12@U?$__tuple_types@$$V@12@AEBVstring_view@absl@@AEBH@Z + ??$?0AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEAPEBV01234@$0A@@?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@QEAA@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$?0AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV01234@$0A@@?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@QEAA@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAPEAPEAPEBV34567@@Z + ??$?0AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@AEAPEAPEAU0123@$0A@@?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@QEAA@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$?0AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU0123@$0A@@?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@QEAA@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAPEAU3456@@Z + ??$?0AEAPEAPEAVLogSink@absl@@PEAPEAV01@$0A@@?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@QEAA@AEAPEAPEAVLogSink@absl@@$$QEAPEAPEAV34@@Z ??$?0AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@@?$__compressed_pair@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@@Cr@std@@QEAA@AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAV?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@12@@Z ??$?0AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0AEAPEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@V?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@@Cr@std@@@12@@?$__compressed_pair@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@V?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@@Cr@std@@@23@@Cr@std@@QEAA@AEAPEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@12@$$QEAV?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@@Cr@std@@@12@@Z @@ -68,6 +73,10 @@ ??$?0AEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@X@?$__compressed_pair_elem@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$?0AEAPEAUThreadIdentity@base_internal@absl@@AEBQ6AXPEAX@Z@?$__compressed_pair@PEAUThreadIdentity@base_internal@absl@@P6AXPEAX@Z@Cr@std@@QEAA@AEAPEAUThreadIdentity@base_internal@absl@@AEBQ6AXPEAX@Z@Z ??$?0AEAPEAUThreadIdentity@base_internal@absl@@X@?$__compressed_pair_elem@PEAUThreadIdentity@base_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAUThreadIdentity@base_internal@absl@@@Z + ??$?0AEAPEAUTransition@cctz@time_internal@absl@@AEAPEAU0123@$0A@@?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEAUTransition@cctz@time_internal@absl@@0@Z + ??$?0AEAPEAUTransition@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEAUTransition@cctz@time_internal@absl@@$$QEAPEAU3456@@Z + ??$?0AEAPEAUTransitionType@cctz@time_internal@absl@@AEAPEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEAUTransitionType@cctz@time_internal@absl@@0@Z + ??$?0AEAPEAUTransitionType@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEAUTransitionType@cctz@time_internal@absl@@$$QEAPEAU3456@@Z ??$?0AEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QEAA@AEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$$QEAU__value_init_tag@12@@Z ??$?0AEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@X@?$__compressed_pair_elem@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Z ??$?0AEAPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PEAVFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAA@AEAPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@$$QEAU__value_init_tag@12@@Z @@ -78,6 +87,8 @@ ??$?0AEAPEAVTimeZoneInfo@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEAVTimeZoneInfo@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAVTimeZoneInfo@cctz@time_internal@absl@@@Z ??$?0AEAPEAVZoneInfoSource@cctz@time_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PEAVZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAA@AEAPEAVZoneInfoSource@cctz@time_internal@absl@@$$QEAU__value_init_tag@12@@Z ??$?0AEAPEAVZoneInfoSource@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEAVZoneInfoSource@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEAVZoneInfoSource@cctz@time_internal@absl@@@Z + ??$?0AEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU0123@$0A@@?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@QEAA@AEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAU3456@@Z + ??$?0AEAPEBVFormatArgImpl@str_format_internal@absl@@PEAV012@$0A@@?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@Cr@std@@QEAA@AEAPEBVFormatArgImpl@str_format_internal@absl@@$$QEAPEAV345@@Z ??$?0AEAPEBVImpl@time_zone@cctz@time_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PEBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAA@AEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAU__value_init_tag@12@@Z ??$?0AEAPEBVImpl@time_zone@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PEBVImpl@time_zone@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QEAA@AEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QEAA@AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@@Z @@ -98,13 +109,6 @@ ??$?0AEAV?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AEAV?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QEAA@AEAV?$allocator@UTransition@cctz@time_internal@absl@@@12@@Z ??$?0AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QEAA@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QEAA@AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@@Z - ??$?0AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@12@$$QEAV312@@Z - ??$?0AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@QEAA@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@12@$$QEAV312@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@3@AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@_K@container_internal@absl@@QEAA@AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@$$QEAI@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@I@?$CompressedTupleImpl@V?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@_K@container_internal@absl@@U?$integer_sequence@_K$0A@$00@3@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@3@AEBV?$allocator@UPayload@status_internal@absl@@@Cr@std@@$$QEAI@Z @@ -127,17 +131,13 @@ ??$?0PEAI@?$SaltedSeedSeq@Vseed_seq@Cr@std@@@random_internal@absl@@QEAA@PEAI0@Z ??$?0PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV01234@$0A@@?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@QEAA@$$QEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z ??$?0PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU0123@$0A@@?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@QEAA@$$QEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z - ??$?0PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV012@$0A@@?$pair@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@@Cr@std@@QEAA@$$QEAPEAPEAVCordzHandle@cord_internal@absl@@0@Z ??$?0PEAPEAVLogSink@absl@@@?$__wrap_iter@PEBQEAVLogSink@absl@@@Cr@std@@QEAA@AEBV?$__wrap_iter@PEAPEAVLogSink@absl@@@12@PEAX@Z ??$?0PEAPEAVLogSink@absl@@PEAPEAV01@$0A@@?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@QEAA@$$QEAPEAPEAVLogSink@absl@@0@Z - ??$?0PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV012@$0A@@?$pair@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@@Cr@std@@QEAA@$$QEAPEAPEBVCordzHandle@cord_internal@absl@@0@Z - ??$?0PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU0123@$0A@@?$pair@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@@Cr@std@@QEAA@$$QEAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@0@Z ??$?0PEAUPrefixCrc@CrcCordState@crc_internal@absl@@AEAU0123@PEAPEAU0123@@?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@Cr@std@@QEAA@AEBV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@PEAX@Z ??$?0PEAUTransition@cctz@time_internal@absl@@@?$__wrap_iter@PEBUTransition@cctz@time_internal@absl@@@Cr@std@@QEAA@AEBV?$__wrap_iter@PEAUTransition@cctz@time_internal@absl@@@12@PEAX@Z ??$?0PEAUTransition@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@$$QEAPEAUTransition@cctz@time_internal@absl@@0@Z ??$?0PEAUTransitionType@cctz@time_internal@absl@@@?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEAA@AEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@PEAX@Z ??$?0PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@QEAA@$$QEAPEAUTransitionType@cctz@time_internal@absl@@0@Z - ??$?0PEAUViableSubstitution@strings_internal@absl@@PEAU012@$0A@@?$pair@PEAUViableSubstitution@strings_internal@absl@@PEAU123@@Cr@std@@QEAA@$$QEAPEAUViableSubstitution@strings_internal@absl@@0@Z ??$?0PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@?$__compressed_pair@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QEAA@$$QEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$$QEAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@12@@Z ??$?0PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@X@?$__compressed_pair_elem@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$0A@$0A@@Cr@std@@QEAA@$$QEAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Z ??$?0PEAVFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@?$__compressed_pair@PEAVCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAA@$$QEAPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@$$QEAU?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@12@@Z @@ -264,8 +264,15 @@ ??$?8PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z ??$?8VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YA_NAEBV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@01@$$T@Z ??$?9PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z + ??$?9PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV012@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z ??$?9PEAPEAVLogSink@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEAPEAVLogSink@absl@@@01@0@Z + ??$?9PEAPEAVLogSink@absl@@PEAPEAV01@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAPEAVLogSink@absl@@@01@0@Z + ??$?9PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV012@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@0@Z + ??$?9PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU0123@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z + ??$?9PEAUTransition@cctz@time_internal@absl@@PEAU0123@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@0@Z ??$?9PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$?9PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$?9PEAUViableSubstitution@strings_internal@absl@@PEAU012@@Cr@std@@YA_NAEBV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@0@Z ??$?9PEBQEAVLogSink@absl@@PEAPEAV01@@Cr@std@@YA_NAEBV?$__wrap_iter@PEBQEAVLogSink@absl@@@01@AEBV?$__wrap_iter@PEAPEAVLogSink@absl@@@01@@Z ??$?9PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@YA_NAEBV?$__wrap_iter@PEBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z ??$?BV?$allocator@D@Cr@std@@@string_view@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@XZ @@ -285,6 +292,8 @@ ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?PUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z + ??$?R$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U0123@$0A@@__copy_trivial@Cr@std@@QEBA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@12@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU4567@@Z + ??$?R$$CBVFormatArgImpl@str_format_internal@absl@@V012@$0A@@__copy_trivial@Cr@std@@QEBA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@12@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV456@@Z ??$?RAEAPEAXAEAY0MI@DAEBH@?$AtomicHook@P6A_NPEBXPEADH@Z@base_internal@absl@@QEBA_NAEAPEAXAEAY0MI@DAEBH@Z ??$?RAEAPEBDAEAHAEAY0LLI@DAEBQEBDPEAD@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@QEBAXAEAPEBDAEAHAEAY0LLI@DAEBQEBD$$QEAPEAD@Z ??$?RAEAW4LogSeverity@absl@@AEAPEBDAEAHPEAPEADPEAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@QEBA_NAEAW4LogSeverity@2@AEAPEBDAEAH$$QEAPEAPEAD$$QEAPEAH@Z @@ -302,7 +311,23 @@ ??$?RAEBQEAUTransition@cctz@time_internal@absl@@@__fn@__iter_move@ranges@Cr@std@@QEBA$$QEAUTransition@cctz@time_internal@absl@@AEBQEAU5678@@Z ??$?RAEBQEAUTransitionType@cctz@time_internal@absl@@@__fn@__iter_move@ranges@Cr@std@@QEBA$$QEAUTransitionType@cctz@time_internal@absl@@AEBQEAU5678@@Z ??$?RAEBUTransition@cctz@time_internal@absl@@@__identity@Cr@std@@QEBAAEBUTransition@cctz@time_internal@absl@@AEBU3456@@Z + ??$?RPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV01234@$0A@@__move_backward_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$?RPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV01234@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$?RPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU0123@$0A@@__move_backward_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@12@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$?RPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU0123@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@12@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$?RPEAVLogSink@absl@@PEAV01@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@12@PEAPEAVLogSink@absl@@00@Z ??$?RPEAVSpinLock@base_internal@absl@@AEB_J@?$AtomicHook@P6AXPEBX_J@Z@base_internal@absl@@QEBAX$$QEAPEAVSpinLock@12@AEB_J@Z + ??$?RUTransition@cctz@time_internal@absl@@U0123@$0A@@__move_backward_trivial@Cr@std@@QEBA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$?RUTransition@cctz@time_internal@absl@@U0123@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@__move_backward_trivial@Cr@std@@QEBA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@__move_trivial@Cr@std@@QEBA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$?RV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAPEAVLogSink@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QEBA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@12@00@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CC@$$CBD@Z @@ -661,10 +686,19 @@ ??$__construct_one_at_end@AEBQEBVCordzHandle@cord_internal@absl@@@?$vector@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AEAAXAEBQEBVCordzHandle@cord_internal@absl@@@Z ??$__construct_one_at_end@AEBUTransition@cctz@time_internal@absl@@@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@AEAAXAEBUTransition@cctz@time_internal@absl@@@Z ??$__construct_one_at_end@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@?$vector@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@Cr@std@@AEAAX$$QEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Z - ??$__copy@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@PEAU1234@$0A@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z - ??$__copy@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@PEAV123@$0A@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z - ??$__copy_impl@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U1234@X@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z - ??$__copy_impl@$$CBVFormatArgImpl@str_format_internal@absl@@V123@X@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z + ??$__copy@U_ClassicAlgPolicy@Cr@std@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU4567@PEAU4567@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z + ??$__copy@U_ClassicAlgPolicy@Cr@std@@PEBVFormatArgImpl@str_format_internal@absl@@PEBV456@PEAV456@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z + ??$__copy_backward_trivial_impl@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@UTransition@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@UTransitionType@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z + ??$__copy_trivial_impl@$$CBVFormatArgImpl@str_format_internal@absl@@V123@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z + ??$__copy_trivial_impl@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__copy_trivial_impl@PEAVLogSink@absl@@PEAV12@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@PEAPEAVLogSink@absl@@00@Z + ??$__copy_trivial_impl@UTransition@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@UTransitionType@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$__cxx_atomic_compare_exchange_strong@PEAVTimeZone@absl@@@Cr@std@@YA_NPEAU?$__cxx_atomic_base_impl@PEAVTimeZone@absl@@@01@PEAPEAVTimeZone@absl@@PEAV34@W4memory_order@01@3@Z ??$__cxx_atomic_compare_exchange_weak@PEAUHashtablezInfo@container_internal@absl@@@Cr@std@@YA_NPEAU?$__cxx_atomic_base_impl@PEAUHashtablezInfo@container_internal@absl@@@01@PEAPEAUHashtablezInfo@container_internal@absl@@PEAU345@W4memory_order@01@3@Z ??$__cxx_atomic_load@P6AXAEBUHashtablezInfo@container_internal@absl@@@Z@Cr@std@@YAP6AXAEBUHashtablezInfo@container_internal@absl@@@ZPEBU?$__cxx_atomic_base_impl@P6AXAEBUHashtablezInfo@container_internal@absl@@@Z@01@W4memory_order@01@@Z @@ -717,6 +751,24 @@ ??$__destroy_at@UTransitionType@cctz@time_internal@absl@@$0A@@Cr@std@@YAXPEAUTransitionType@cctz@time_internal@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@$0A@@Cr@std@@YAXPEAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@VFormatArgImpl@str_format_internal@absl@@$0A@@Cr@std@@YAXPEAVFormatArgImpl@str_format_internal@absl@@@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV6789absl@@PEAPEAPEBV6789absl@@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU6789@PEAPEAU6789@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PEAUTransition@cctz@time_internal@absl@@PEAU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PEAUTransitionType@cctz@time_internal@absl@@PEAU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV6789absl@@PEAPEAPEBV6789absl@@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU6789@PEAPEAU6789@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAPEAVLogSink@absl@@PEAPEAV67@PEAPEAV67@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@PEAPEAVLogSink@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAUTransition@cctz@time_internal@absl@@PEAU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PEAUTransitionType@cctz@time_internal@absl@@PEAU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAPEAVLogSink@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVLogSink@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U__copy_loop@23@U__copy_trivial@23@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU6789@PEAU6789@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U__copy_loop@23@U__copy_trivial@23@PEBVFormatArgImpl@str_format_internal@absl@@PEBV678@PEAV678@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z ??$__distance@PEBUPayload@status_internal@absl@@@Cr@std@@YA_JPEBUPayload@status_internal@absl@@0Urandom_access_iterator_tag@01@@Z ??$__distance@PEBUTransition@cctz@time_internal@absl@@@Cr@std@@YA_JPEBUTransition@cctz@time_internal@absl@@0Urandom_access_iterator_tag@01@@Z ??$__distance@PEBVFormatArgImpl@str_format_internal@absl@@@Cr@std@@YA_JPEBVFormatArgImpl@str_format_internal@absl@@0Urandom_access_iterator_tag@01@@Z @@ -731,6 +783,13 @@ ??$__invoke@AEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@Cr@std@@YA_NAEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@Cr@std@@YA_NAEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAU__identity@Cr@std@@AEBUTransition@cctz@time_internal@absl@@@Cr@std@@YAAEBUTransition@cctz@time_internal@absl@@AEAU__identity@01@AEBU2345@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAPEAVCordzHandle@cord_internal@absl@@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAPEAVLogSink@absl@@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAPEBVCordzHandle@cord_internal@absl@@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAUTransition@cctz@time_internal@absl@@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAUTransitionType@cctz@time_internal@absl@@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@12@@Z + ??$__iter_move@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QEAUViableSubstitution@strings_internal@absl@@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@12@@Z ??$__launder@$$CBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPEBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEBU201@@Z ??$__launder@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@@Z ??$__lower_bound_impl@U_ClassicAlgPolicy@Cr@std@@PEBUTransition@cctz@time_internal@absl@@PEBU4567@U4567@U__identity@23@UByUnixTime@4567@@Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@AEAUByUnixTime@2345@AEAU__identity@01@@Z @@ -746,30 +805,10 @@ ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@00@Z ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@00@Z ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV45678@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU4567@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@UTransition@cctz@time_internal@absl@@U4567@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@UTransitionType@cctz@time_internal@absl@@U4567@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEAVLogSink@absl@@PEAPEAV45@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVLogSink@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV45678@X@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU4567@X@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAUViableSubstitution@strings_internal@absl@@PEAU456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAVCordzHandle@cord_internal@absl@@PEAV456@X@Cr@std@@YA?AU?$pair@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@@01@PEAPEAVCordzHandle@cord_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEAVLogSink@absl@@PEAV45@X@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@PEAPEAVLogSink@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PEBVCordzHandle@cord_internal@absl@@PEBV456@X@Cr@std@@YA?AU?$pair@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@@01@PEAPEBVCordzHandle@cord_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@@01@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UTransition@cctz@time_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UTransitionType@cctz@time_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UViableSubstitution@strings_internal@absl@@U456@X@Cr@std@@YA?AU?$pair@PEAUViableSubstitution@strings_internal@absl@@PEAU123@@01@PEAUViableSubstitution@strings_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@PEAU4567@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@PEAU4567@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$__push_back_slow_path@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AEAAXAEBQEAVCordzHandle@cord_internal@absl@@@Z ??$__push_back_slow_path@AEBQEAVLogSink@absl@@@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@Cr@std@@@Cr@std@@AEAAXAEBQEAVLogSink@absl@@@Z ??$__push_back_slow_path@AEBQEBVCordzHandle@cord_internal@absl@@@?$vector@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AEAAXAEBQEBVCordzHandle@cord_internal@absl@@@Z @@ -778,14 +817,10 @@ ??$__rehash@$00@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$allocator@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@23@@Cr@std@@AEAAX_K@Z ??$__rewrap_iter@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@U?$__unwrap_iter_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@0@Z ??$__rewrap_iter@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@U?$__unwrap_iter_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@0@Z - ??$__rewrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@U?$__unwrap_iter_impl@PEAPEAVCordzHandle@cord_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV234@0@Z ??$__rewrap_iter@PEAPEAVLogSink@absl@@PEAPEAV12@U?$__unwrap_iter_impl@PEAPEAVLogSink@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0@Z - ??$__rewrap_iter@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@U?$__unwrap_iter_impl@PEAPEBVCordzHandle@cord_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV234@0@Z - ??$__rewrap_iter@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@U?$__unwrap_iter_impl@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@0@Z ??$__rewrap_iter@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@U?$__unwrap_iter_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU2345@0@Z ??$__rewrap_iter@PEAUTransition@cctz@time_internal@absl@@PEAU1234@U?$__unwrap_iter_impl@PEAUTransition@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@0@Z ??$__rewrap_iter@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@U?$__unwrap_iter_impl@PEAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@0@Z - ??$__rewrap_iter@PEAUViableSubstitution@strings_internal@absl@@PEAU123@U?$__unwrap_iter_impl@PEAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAUViableSubstitution@strings_internal@absl@@PEAU234@0@Z ??$__rewrap_iter@PEAVFormatArgImpl@str_format_internal@absl@@PEAV123@U?$__unwrap_iter_impl@PEAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEAVFormatArgImpl@str_format_internal@absl@@PEAV234@0@Z ??$__rewrap_iter@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@U?$__unwrap_iter_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@0@Z ??$__rewrap_iter@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@U?$__unwrap_iter_impl@PEBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPEBVFormatArgImpl@str_format_internal@absl@@PEBV234@0@Z @@ -796,8 +831,20 @@ ??$__rewrap_iter@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@V201@0@Z ??$__rewrap_iter@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@V201@0@Z ??$__rewrap_iter@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@PEAPEAPEBV12345@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@0@Z + ??$__rewrap_range@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@PEAPEAU1234@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@0@Z + ??$__rewrap_range@PEAPEAVLogSink@absl@@PEAPEAV12@PEAPEAV12@@Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0@Z + ??$__rewrap_range@PEAUTransition@cctz@time_internal@absl@@PEAU1234@PEAU1234@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@0@Z + ??$__rewrap_range@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@PEAU1234@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@0@Z ??$__rewrap_range@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@PEBU1234@@Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@0@Z ??$__rewrap_range@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@PEBV123@@Cr@std@@YAPEBVFormatArgImpl@str_format_internal@absl@@PEBV234@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAPEAVLogSink@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@V201@0@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@@Z ??$__to_address@$$CBVFormatArgImpl@str_format_internal@absl@@@Cr@std@@YAPEBVFormatArgImpl@str_format_internal@absl@@PEBV234@@Z ??$__to_address@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@@Z @@ -821,16 +868,30 @@ ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@U4567@X@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@01@PEAU2345@11@Z ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@UTransitionType@cctz@time_internal@absl@@X@Cr@std@@YA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@AEAV?$allocator@UTransitionType@cctz@time_internal@absl@@@01@V201@11@Z ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@UViableSubstitution@strings_internal@absl@@X@Cr@std@@YA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@01@V201@11@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@$0A@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@$0A@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAPEAVLogSink@absl@@PEAPEAV45@PEAPEAV45@$0A@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@PEAPEAVLogSink@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAUTransition@cctz@time_internal@absl@@PEAU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransition@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PEAUTransitionType@cctz@time_internal@absl@@PEAU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@PEAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAPEAVLogSink@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEAVLogSink@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U__copy_loop@Cr@std@@U__copy_trivial@23@@Cr@std@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU4567@PEAU4567@$0A@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0PEAU3456@@Z + ??$__unwrap_and_dispatch@U?$__overload@U__copy_loop@Cr@std@@U__copy_trivial@23@@Cr@std@@PEBVFormatArgImpl@str_format_internal@absl@@PEBV456@PEAV456@$0A@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@PEBVFormatArgImpl@str_format_internal@absl@@0PEAV345@@Z ??$__unwrap_iter@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@@Z ??$__unwrap_iter@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@@Z - ??$__unwrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@U?$__unwrap_iter_impl@PEAPEAVCordzHandle@cord_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV234@@Z ??$__unwrap_iter@PEAPEAVLogSink@absl@@U?$__unwrap_iter_impl@PEAPEAVLogSink@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@@Z - ??$__unwrap_iter@PEAPEBVCordzHandle@cord_internal@absl@@U?$__unwrap_iter_impl@PEAPEBVCordzHandle@cord_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV234@@Z - ??$__unwrap_iter@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@U?$__unwrap_iter_impl@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@@Z ??$__unwrap_iter@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU2345@@Z ??$__unwrap_iter@PEAUTransition@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PEAUTransition@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUTransition@cctz@time_internal@absl@@PEAU2345@@Z ??$__unwrap_iter@PEAUTransitionType@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PEAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUTransitionType@cctz@time_internal@absl@@PEAU2345@@Z - ??$__unwrap_iter@PEAUViableSubstitution@strings_internal@absl@@U?$__unwrap_iter_impl@PEAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAUViableSubstitution@strings_internal@absl@@PEAU234@@Z ??$__unwrap_iter@PEAVFormatArgImpl@str_format_internal@absl@@U?$__unwrap_iter_impl@PEAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEAVFormatArgImpl@str_format_internal@absl@@PEAV234@@Z ??$__unwrap_iter@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@@Z ??$__unwrap_iter@PEBVFormatArgImpl@str_format_internal@absl@@U?$__unwrap_iter_impl@PEBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPEBVFormatArgImpl@str_format_internal@absl@@PEBV234@@Z @@ -841,10 +902,29 @@ ??$__unwrap_iter@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@V201@@Z ??$__unwrap_iter@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@V201@@Z ??$__unwrap_iter@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@V201@@Z + ??$__unwrap_range@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@YA?A?<auto>@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$__unwrap_range@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@YA?A?<auto>@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$__unwrap_range@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@YA?A?<auto>@@PEAPEAVLogSink@absl@@0@Z + ??$__unwrap_range@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?A?<auto>@@PEAUTransition@cctz@time_internal@absl@@0@Z + ??$__unwrap_range@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?A?<auto>@@PEAUTransitionType@cctz@time_internal@absl@@0@Z ??$__unwrap_range@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@Cr@std@@YA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$__unwrap_range@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@@Cr@std@@YA?A?<auto>@@PEBVFormatArgImpl@str_format_internal@absl@@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAPEAVLogSink@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@0@Z ??$__upper_bound@U_ClassicAlgPolicy@Cr@std@@UByCivilTime@Transition@cctz@time_internal@absl@@PEBU5678@PEBU5678@U5678@U__identity@23@@Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@$$QEAUByCivilTime@2345@$$QEAU__identity@01@@Z ??$__upper_bound@U_ClassicAlgPolicy@Cr@std@@UByUnixTime@Transition@cctz@time_internal@absl@@PEBU5678@PEBU5678@U5678@U__identity@23@@Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@$$QEAUByUnixTime@2345@$$QEAU__identity@01@@Z + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ ??$advance@PEBUTransition@cctz@time_internal@absl@@_J@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J_JX@Cr@std@@YAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@PEBVFormatArgImpl@str_format_internal@absl@@_K_KX@Cr@std@@YAXAEAPEBVFormatArgImpl@str_format_internal@absl@@_K@Z @@ -1010,22 +1090,22 @@ ??$launder@$$CBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPEBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEBU201@@Z ??$launder@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@@Z ??$lower_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByUnixTime@2345@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAPEAVLogSink@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@$$QEAV301@@Z - ??$make_pair@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@AEAV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@01@$$QEAV301@@Z + ??$make_pair@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$make_pair@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@AEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAPEAPEAPEBV34567@@Z + ??$make_pair@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@AEAPEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$make_pair@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@AEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAPEAU3456@@Z + ??$make_pair@AEAPEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@AEAPEAPEAVLogSink@absl@@$$QEAPEAPEAV34@@Z + ??$make_pair@AEAPEAUTransition@cctz@time_internal@absl@@AEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@AEAPEAUTransition@cctz@time_internal@absl@@0@Z + ??$make_pair@AEAPEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@AEAPEAUTransition@cctz@time_internal@absl@@$$QEAPEAU3456@@Z + ??$make_pair@AEAPEAUTransitionType@cctz@time_internal@absl@@AEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@AEAPEAUTransitionType@cctz@time_internal@absl@@0@Z + ??$make_pair@AEAPEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@AEAPEAUTransitionType@cctz@time_internal@absl@@$$QEAPEAU3456@@Z + ??$make_pair@AEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@AEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAU3456@@Z + ??$make_pair@AEAPEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@AEAPEBVFormatArgImpl@str_format_internal@absl@@$$QEAPEAV345@@Z ??$make_pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@YA?AU?$pair@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@$$QEAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z ??$make_pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@YA?AU?$pair@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@$$QEAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z - ??$make_pair@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@@Cr@std@@YA?AU?$pair@PEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV123@@01@$$QEAPEAPEAVCordzHandle@cord_internal@absl@@0@Z ??$make_pair@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@YA?AU?$pair@PEAPEAVLogSink@absl@@PEAPEAV12@@01@$$QEAPEAPEAVLogSink@absl@@0@Z - ??$make_pair@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@@Cr@std@@YA?AU?$pair@PEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV123@@01@$$QEAPEAPEBVCordzHandle@cord_internal@absl@@0@Z - ??$make_pair@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU1234@@01@$$QEAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@0@Z ??$make_pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@01@$$QEAPEAUTransition@cctz@time_internal@absl@@0@Z ??$make_pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@01@$$QEAPEAUTransitionType@cctz@time_internal@absl@@0@Z - ??$make_pair@PEAUViableSubstitution@strings_internal@absl@@PEAU123@@Cr@std@@YA?AU?$pair@PEAUViableSubstitution@strings_internal@absl@@PEAU123@@01@$$QEAPEAUViableSubstitution@strings_internal@absl@@0@Z ??$make_pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@Cr@std@@YA?AU?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@01@$$QEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QEAPEAU3456@@Z ??$make_pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@Cr@std@@YA?AU?$pair@PEBVFormatArgImpl@str_format_internal@absl@@PEAV123@@01@$$QEAPEBVFormatArgImpl@str_format_internal@absl@@$$QEAPEAV345@@Z ??$make_pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@$$QEAV?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@01@0@Z @@ -1784,6 +1864,13 @@ ??D?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@QEBA$$QEAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEBA$$QEAUTransitionType@cctz@time_internal@absl@@XZ ??D?$optional@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@absl@@QEGAAAEAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@XZ + ??D?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@QEBAAEAPEAVCordzHandle@cord_internal@absl@@XZ + ??D?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@QEBAAEAPEAVLogSink@absl@@XZ + ??D?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@QEBAAEAPEBVCordzHandle@cord_internal@absl@@XZ + ??D?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@QEBAAEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@XZ + ??D?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@QEBAAEAUTransition@cctz@time_internal@absl@@XZ + ??D?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEBAAEAUTransitionType@cctz@time_internal@absl@@XZ + ??D?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@QEBAAEAUViableSubstitution@strings_internal@absl@@XZ ??D?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@Cr@std@@@Cr@std@@QEBAAEAULogMessageData@LogMessage@log_internal@absl@@XZ ??D?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QEBAAEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@XZ ??DChunkIterator@Cord@absl@@QEBA?AVstring_view@2@XZ @@ -1805,6 +1892,13 @@ ??E?$move_iterator@PEAUPayload@status_internal@absl@@@Cr@std@@QEAAAEAV012@XZ ??E?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@QEAAAEAV012@XZ ??E?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QEAAAEAV012@XZ + ??E?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@QEAAAEAV012@XZ ??EChunkIterator@Cord@absl@@QEAAAEAV012@XZ ??E__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAAAEAU0123@XZ ??Euint128@absl@@QEAAAEAV01@XZ @@ -3532,14 +3626,10 @@ ?__rehash_unique@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$allocator@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@23@@Cr@std@@QEAAX_K@Z ?__rewrap@?$__unwrap_iter_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@SAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@0@Z - ?__rewrap@?$__unwrap_iter_impl@PEAPEAVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV456@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAPEAVLogSink@absl@@$00@Cr@std@@SAPEAPEAVLogSink@absl@@PEAPEAV45@0@Z - ?__rewrap@?$__unwrap_iter_impl@PEAPEBVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV456@0@Z - ?__rewrap@?$__unwrap_iter_impl@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@SAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAUTransition@cctz@time_internal@absl@@$00@Cr@std@@SAPEAUTransition@cctz@time_internal@absl@@PEAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@SAPEAUTransitionType@cctz@time_internal@absl@@PEAU4567@0@Z - ?__rewrap@?$__unwrap_iter_impl@PEAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@SAPEAUViableSubstitution@strings_internal@absl@@PEAU456@0@Z ?__rewrap@?$__unwrap_iter_impl@PEAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPEAVFormatArgImpl@str_format_internal@absl@@PEAV456@0@Z ?__rewrap@?$__unwrap_iter_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PEBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPEBVFormatArgImpl@str_format_internal@absl@@PEBV456@0@Z @@ -3550,8 +3640,20 @@ ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V423@0@Z ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@0@Z ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@SA?A?<auto>@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@SA?A?<auto>@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@SA?A?<auto>@@PEAPEAVLogSink@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@SA?A?<auto>@@PEAUTransition@cctz@time_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@SA?A?<auto>@@PEAUTransitionType@cctz@time_internal@absl@@0@Z ?__rewrap@?$__unwrap_range_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@Cr@std@@SA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ?__rewrap@?$__unwrap_range_impl@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@@Cr@std@@SA?A?<auto>@@PEBVFormatArgImpl@str_format_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEAVLogSink@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@0@Z ?__size@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAAAEA_KXZ ?__size@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEBAAEB_KXZ ?__size@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAAAEA_KXZ @@ -3575,14 +3677,10 @@ ?__throw_length_error@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@AEBAXXZ ?__unwrap@?$__unwrap_iter_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@SAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@@Z ?__unwrap@?$__unwrap_iter_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@@Z - ?__unwrap@?$__unwrap_iter_impl@PEAPEAVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPEAPEAVCordzHandle@cord_internal@absl@@PEAPEAV456@@Z ?__unwrap@?$__unwrap_iter_impl@PEAPEAVLogSink@absl@@$00@Cr@std@@SAPEAPEAVLogSink@absl@@PEAPEAV45@@Z - ?__unwrap@?$__unwrap_iter_impl@PEAPEBVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPEAPEBVCordzHandle@cord_internal@absl@@PEAPEBV456@@Z - ?__unwrap@?$__unwrap_iter_impl@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@SAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PEAUTransition@cctz@time_internal@absl@@$00@Cr@std@@SAPEAUTransition@cctz@time_internal@absl@@PEAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PEAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@SAPEAUTransitionType@cctz@time_internal@absl@@PEAU4567@@Z - ?__unwrap@?$__unwrap_iter_impl@PEAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@SAPEAUViableSubstitution@strings_internal@absl@@PEAU456@@Z ?__unwrap@?$__unwrap_iter_impl@PEAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPEAVFormatArgImpl@str_format_internal@absl@@PEAV456@@Z ?__unwrap@?$__unwrap_iter_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PEBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPEBVFormatArgImpl@str_format_internal@absl@@PEBV456@@Z @@ -3593,8 +3691,20 @@ ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@V423@@Z ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@V423@@Z ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@V423@@Z + ?__unwrap@?$__unwrap_range_impl@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@Cr@std@@SA?A?<auto>@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@Cr@std@@SA?A?<auto>@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PEAPEAVLogSink@absl@@PEAPEAV12@@Cr@std@@SA?A?<auto>@@PEAPEAVLogSink@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PEAUTransition@cctz@time_internal@absl@@PEAU1234@@Cr@std@@SA?A?<auto>@@PEAUTransition@cctz@time_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@Cr@std@@SA?A?<auto>@@PEAUTransitionType@cctz@time_internal@absl@@0@Z ?__unwrap@?$__unwrap_range_impl@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@Cr@std@@SA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ?__unwrap@?$__unwrap_range_impl@PEBVFormatArgImpl@str_format_internal@absl@@PEBV123@@Cr@std@@SA?A?<auto>@@PEBVFormatArgImpl@str_format_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEAVCordzHandle@cord_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEAVLogSink@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAPEBVCordzHandle@cord_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUTransition@cctz@time_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUTransitionType@cctz@time_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PEAUViableSubstitution@strings_internal@absl@@@23@0@Z ?__upcast@?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@Cr@std@@@Cr@std@@QEAAPEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PEAX@23@XZ ?__vallocate@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@AEAAX_K@Z ?__vdeallocate@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@AEAAXXZ
diff --git a/third_party/abseil-cpp/symbols_x64_rel.def b/third_party/abseil-cpp/symbols_x64_rel.def index f5ebb253..873ae66 100644 --- a/third_party/abseil-cpp/symbols_x64_rel.def +++ b/third_party/abseil-cpp/symbols_x64_rel.def
@@ -1,7 +1,6 @@ EXPORTS ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@3@PEIAXPEIBX_KV43@_N@Z@4HA ??$?0AEBVCord@absl@@@?$optional_data_dtor_base@VCord@absl@@$0A@@optional_internal@absl@@IEAA@Uin_place_t@2@AEBVCord@2@@Z - ??$?0PEAI@?$SaltedSeedSeq@Vseed_seq@Cr@std@@@random_internal@absl@@QEAA@PEAI0@Z ??$?0V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z ??$?6C$0A@@LogMessage@log_internal@absl@@QEAAAEAV012@AEBC@Z ??$?6D$0A@@LogMessage@log_internal@absl@@QEAAAEAV012@AEBD@Z @@ -1183,9 +1182,6 @@ ?push_back@?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAAXAEBQEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ?push_back@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAAXAEBQEBVImpl@time_zone@cctz@time_internal@absl@@@Z ?push_back@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAAX$$QEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z - ?push_back@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@QEAAXAEBQEAVCordzHandle@cord_internal@absl@@@Z - ?push_back@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@Cr@std@@@Cr@std@@QEAAXAEBQEAVLogSink@absl@@@Z - ?push_back@?$vector@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@QEAAXAEBQEBVCordzHandle@cord_internal@absl@@@Z ?push_front@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAAXAEBQEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ?push_front@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QEAAX$$QEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ?push_front@?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@AEAV?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QEAAXAEBQEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z
diff --git a/third_party/abseil-cpp/symbols_x86_dbg.def b/third_party/abseil-cpp/symbols_x86_dbg.def index 727a5cd..c9d9c380 100644 --- a/third_party/abseil-cpp/symbols_x86_dbg.def +++ b/third_party/abseil-cpp/symbols_x86_dbg.def
@@ -58,6 +58,11 @@ ??$?0$00X@?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QAE@$$T@Z ??$?0$00X@?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QAE@PAVZoneInfoSource@cctz@time_internal@absl@@@Z ??$?0$0A@$00$$ZABVstring_view@absl@@ABH$$Z$S$$Z$$V$$ZABV01@ABH@?$__tuple_impl@U?$__tuple_indices@$0A@$00@Cr@std@@ABVstring_view@absl@@ABH@Cr@std@@QAE@U?$__tuple_indices@$0A@$00@12@U?$__tuple_types@ABVstring_view@absl@@ABH@12@U?$__tuple_indices@$S@12@U?$__tuple_types@$$V@12@ABVstring_view@absl@@ABH@Z + ??$?0AAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@AAPAPAPBV01234@$0A@@?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@Cr@std@@QAE@AAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$?0AAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV01234@$0A@@?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@Cr@std@@QAE@AAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@$$QAPAPAPBV34567@@Z + ??$?0AAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@AAPAPAU0123@$0A@@?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@Cr@std@@QAE@AAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$?0AAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU0123@$0A@@?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@Cr@std@@QAE@AAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@$$QAPAPAU3456@@Z + ??$?0AAPAPAVLogSink@absl@@PAPAV01@$0A@@?$pair@PAPAVLogSink@absl@@PAPAV12@@Cr@std@@QAE@AAPAPAVLogSink@absl@@$$QAPAPAV34@@Z ??$?0AAPAPBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@@?$__compressed_pair@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@@Cr@std@@QAE@AAPAPBVImpl@time_zone@cctz@time_internal@absl@@$$QAV?$__allocator_destructor@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@12@@Z ??$?0AAPAPBVImpl@time_zone@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PAPBVImpl@time_zone@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QAE@AAPAPBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0AAPAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PAX@Cr@std@@V?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PAX@Cr@std@@@Cr@std@@@12@@?$__compressed_pair@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PAX@Cr@std@@V?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PAX@Cr@std@@@Cr@std@@@23@@Cr@std@@QAE@AAPAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PAX@12@$$QAV?$__hash_node_destructor@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PAX@Cr@std@@@Cr@std@@@12@@Z @@ -68,6 +73,10 @@ ??$?0AAPAUPrefixCrc@CrcCordState@crc_internal@absl@@X@?$__compressed_pair_elem@PAUPrefixCrc@CrcCordState@crc_internal@absl@@$0A@$0A@@Cr@std@@QAE@AAPAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$?0AAPAUThreadIdentity@base_internal@absl@@ABQ6AXPAX@Z@?$__compressed_pair@PAUThreadIdentity@base_internal@absl@@P6AXPAX@Z@Cr@std@@QAE@AAPAUThreadIdentity@base_internal@absl@@ABQ6AXPAX@Z@Z ??$?0AAPAUThreadIdentity@base_internal@absl@@X@?$__compressed_pair_elem@PAUThreadIdentity@base_internal@absl@@$0A@$0A@@Cr@std@@QAE@AAPAUThreadIdentity@base_internal@absl@@@Z + ??$?0AAPAUTransition@cctz@time_internal@absl@@AAPAU0123@$0A@@?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@Cr@std@@QAE@AAPAUTransition@cctz@time_internal@absl@@0@Z + ??$?0AAPAUTransition@cctz@time_internal@absl@@PAU0123@$0A@@?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@Cr@std@@QAE@AAPAUTransition@cctz@time_internal@absl@@$$QAPAU3456@@Z + ??$?0AAPAUTransitionType@cctz@time_internal@absl@@AAPAU0123@$0A@@?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@Cr@std@@QAE@AAPAUTransitionType@cctz@time_internal@absl@@0@Z + ??$?0AAPAUTransitionType@cctz@time_internal@absl@@PAU0123@$0A@@?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@Cr@std@@QAE@AAPAUTransitionType@cctz@time_internal@absl@@$$QAPAU3456@@Z ??$?0AAPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QAE@AAPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$$QAU__value_init_tag@12@@Z ??$?0AAPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@X@?$__compressed_pair_elem@PAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$0A@$0A@@Cr@std@@QAE@AAPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Z ??$?0AAPAVFallbackCrcMemcpyEngine@crc_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PAVFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@Cr@std@@QAE@AAPAVFallbackCrcMemcpyEngine@crc_internal@absl@@$$QAU__value_init_tag@12@@Z @@ -78,6 +87,8 @@ ??$?0AAPAVTimeZoneInfo@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PAVTimeZoneInfo@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QAE@AAPAVTimeZoneInfo@cctz@time_internal@absl@@@Z ??$?0AAPAVZoneInfoSource@cctz@time_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PAVZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QAE@AAPAVZoneInfoSource@cctz@time_internal@absl@@$$QAU__value_init_tag@12@@Z ??$?0AAPAVZoneInfoSource@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PAVZoneInfoSource@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QAE@AAPAVZoneInfoSource@cctz@time_internal@absl@@@Z + ??$?0AAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU0123@$0A@@?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@Cr@std@@QAE@AAPBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QAPAU3456@@Z + ??$?0AAPBVFormatArgImpl@str_format_internal@absl@@PAV012@$0A@@?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@Cr@std@@QAE@AAPBVFormatArgImpl@str_format_internal@absl@@$$QAPAV345@@Z ??$?0AAPBVImpl@time_zone@cctz@time_internal@absl@@U__value_init_tag@Cr@std@@@?$__compressed_pair@PBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QAE@AAPBVImpl@time_zone@cctz@time_internal@absl@@$$QAU__value_init_tag@12@@Z ??$?0AAPBVImpl@time_zone@cctz@time_internal@absl@@X@?$__compressed_pair_elem@PBVImpl@time_zone@cctz@time_internal@absl@@$0A@$0A@@Cr@std@@QAE@AAPBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0AAV?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AAV?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QAE@AAV?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@12@@Z @@ -98,13 +109,6 @@ ??$?0AAV?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AAV?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QAE@AAV?$allocator@UTransition@cctz@time_internal@absl@@@12@@Z ??$?0AAV?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AAV?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QAE@AAV?$allocator@UTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0AAV?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@X@?$__compressed_pair_elem@AAV?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@$00$0A@@Cr@std@@QAE@AAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@@Z - ??$?0AAV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@QAE@AAV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@12@$$QAV312@@Z - ??$?0AAV?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@QAE@AAV?$reverse_iterator@PAPAVLogSink@absl@@@12@$$QAV312@@Z - ??$?0AAV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@QAE@AAV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@12@$$QAV312@@Z - ??$?0AAV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@QAE@AAV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@$$QAV312@@Z - ??$?0AAV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@QAE@AAV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@12@$$QAV312@@Z - ??$?0AAV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@QAE@AAV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@12@$$QAV312@@Z - ??$?0AAV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V012@$0A@@?$pair@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@QAE@AAV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@12@$$QAV312@@Z ??$?0ABV?$allocator@UPayload@status_internal@absl@@@Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@$0A@$00@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@3@ABV?$allocator@UPayload@status_internal@absl@@@Cr@std@@@Z ??$?0ABV?$allocator@UPayload@status_internal@absl@@@Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@I@container_internal@absl@@QAE@ABV?$allocator@UPayload@status_internal@absl@@@Cr@std@@$$QAI@Z ??$?0ABV?$allocator@UPayload@status_internal@absl@@@Cr@std@@I@?$CompressedTupleImpl@V?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@Cr@std@@I@container_internal@absl@@U?$integer_sequence@I$0A@$00@3@$00@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@3@ABV?$allocator@UPayload@status_internal@absl@@@Cr@std@@$$QAI@Z @@ -127,17 +131,13 @@ ??$?0PAI@?$SaltedSeedSeq@Vseed_seq@Cr@std@@@random_internal@absl@@QAE@PAI0@Z ??$?0PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV01234@$0A@@?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@Cr@std@@QAE@$$QAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@0@Z ??$?0PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU0123@$0A@@?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@Cr@std@@QAE@$$QAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z - ??$?0PAPAVCordzHandle@cord_internal@absl@@PAPAV012@$0A@@?$pair@PAPAVCordzHandle@cord_internal@absl@@PAPAV123@@Cr@std@@QAE@$$QAPAPAVCordzHandle@cord_internal@absl@@0@Z ??$?0PAPAVLogSink@absl@@@?$__wrap_iter@PBQAVLogSink@absl@@@Cr@std@@QAE@ABV?$__wrap_iter@PAPAVLogSink@absl@@@12@PAX@Z ??$?0PAPAVLogSink@absl@@PAPAV01@$0A@@?$pair@PAPAVLogSink@absl@@PAPAV12@@Cr@std@@QAE@$$QAPAPAVLogSink@absl@@0@Z - ??$?0PAPBVCordzHandle@cord_internal@absl@@PAPBV012@$0A@@?$pair@PAPBVCordzHandle@cord_internal@absl@@PAPBV123@@Cr@std@@QAE@$$QAPAPBVCordzHandle@cord_internal@absl@@0@Z - ??$?0PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU0123@$0A@@?$pair@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU1234@@Cr@std@@QAE@$$QAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@0@Z ??$?0PAUPrefixCrc@CrcCordState@crc_internal@absl@@AAU0123@PAPAU0123@@?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@Cr@std@@QAE@ABV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@PAX@Z ??$?0PAUTransition@cctz@time_internal@absl@@@?$__wrap_iter@PBUTransition@cctz@time_internal@absl@@@Cr@std@@QAE@ABV?$__wrap_iter@PAUTransition@cctz@time_internal@absl@@@12@PAX@Z ??$?0PAUTransition@cctz@time_internal@absl@@PAU0123@$0A@@?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@Cr@std@@QAE@$$QAPAUTransition@cctz@time_internal@absl@@0@Z ??$?0PAUTransitionType@cctz@time_internal@absl@@@?$__wrap_iter@PBUTransitionType@cctz@time_internal@absl@@@Cr@std@@QAE@ABV?$__wrap_iter@PAUTransitionType@cctz@time_internal@absl@@@12@PAX@Z ??$?0PAUTransitionType@cctz@time_internal@absl@@PAU0123@$0A@@?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@Cr@std@@QAE@$$QAPAUTransitionType@cctz@time_internal@absl@@0@Z - ??$?0PAUViableSubstitution@strings_internal@absl@@PAU012@$0A@@?$pair@PAUViableSubstitution@strings_internal@absl@@PAU123@@Cr@std@@QAE@$$QAPAUViableSubstitution@strings_internal@absl@@0@Z ??$?0PAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@?$__compressed_pair@PAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QAE@$$QAPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$$QAU?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@12@@Z ??$?0PAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@X@?$__compressed_pair_elem@PAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@$0A@$0A@@Cr@std@@QAE@$$QAPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Z ??$?0PAVFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@?$__compressed_pair@PAVCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VCrcMemcpyEngine@crc_internal@absl@@@Cr@std@@@Cr@std@@QAE@$$QAPAVFallbackCrcMemcpyEngine@crc_internal@absl@@$$QAU?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@12@@Z @@ -262,8 +262,15 @@ ??$?8PBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@YA_NABV?$__wrap_iter@PBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z ??$?8VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YA_NABV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@Cr@std@@@01@$$T@Z ??$?9PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@YA_NABV?$__wrap_iter@PAPAVCordzHandle@cord_internal@absl@@@01@0@Z + ??$?9PAPAVCordzHandle@cord_internal@absl@@PAPAV012@@Cr@std@@YA_NABV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@01@0@Z ??$?9PAPAVLogSink@absl@@@Cr@std@@YA_NABV?$__wrap_iter@PAPAVLogSink@absl@@@01@0@Z + ??$?9PAPAVLogSink@absl@@PAPAV01@@Cr@std@@YA_NABV?$reverse_iterator@PAPAVLogSink@absl@@@01@0@Z + ??$?9PAPBVCordzHandle@cord_internal@absl@@PAPBV012@@Cr@std@@YA_NABV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@01@0@Z + ??$?9PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU0123@@Cr@std@@YA_NABV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z + ??$?9PAUTransition@cctz@time_internal@absl@@PAU0123@@Cr@std@@YA_NABV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@0@Z ??$?9PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@YA_NABV?$__wrap_iter@PAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$?9PAUTransitionType@cctz@time_internal@absl@@PAU0123@@Cr@std@@YA_NABV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$?9PAUViableSubstitution@strings_internal@absl@@PAU012@@Cr@std@@YA_NABV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@0@Z ??$?9PBQAVLogSink@absl@@PAPAV01@@Cr@std@@YA_NABV?$__wrap_iter@PBQAVLogSink@absl@@@01@ABV?$__wrap_iter@PAPAVLogSink@absl@@@01@@Z ??$?9PBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@YA_NABV?$__wrap_iter@PBUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z ??$?BV?$allocator@D@Cr@std@@@string_view@absl@@QBE?AV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@XZ @@ -283,6 +290,8 @@ ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?PUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z + ??$?R$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U0123@$0A@@__copy_trivial@Cr@std@@QBE?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@12@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0PAU4567@@Z + ??$?R$$CBVFormatArgImpl@str_format_internal@absl@@V012@$0A@@__copy_trivial@Cr@std@@QBE?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@12@PBVFormatArgImpl@str_format_internal@absl@@0PAV456@@Z ??$?RAAPAXAAY0MI@DABH@?$AtomicHook@P6A_NPBXPADH@Z@base_internal@absl@@QBE_NAAPAXAAY0MI@DABH@Z ??$?RAAPBDAAHAAY0LLI@DABQBDPAD@?$AtomicHook@P6AXPBDH000@Z@base_internal@absl@@QBEXAAPBDAAHAAY0LLI@DABQBD$$QAPAD@Z ??$?RAAW4LogSeverity@absl@@AAPBDAAHPAPADPAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PBDHPAPADPAH@Z@base_internal@absl@@QBE_NAAW4LogSeverity@2@AAPBDAAH$$QAPAPAD$$QAPAH@Z @@ -300,7 +309,23 @@ ??$?RABQAUTransition@cctz@time_internal@absl@@@__fn@__iter_move@ranges@Cr@std@@QBE$$QAUTransition@cctz@time_internal@absl@@ABQAU5678@@Z ??$?RABQAUTransitionType@cctz@time_internal@absl@@@__fn@__iter_move@ranges@Cr@std@@QBE$$QAUTransitionType@cctz@time_internal@absl@@ABQAU5678@@Z ??$?RABUTransition@cctz@time_internal@absl@@@__identity@Cr@std@@QBEABUTransition@cctz@time_internal@absl@@ABU3456@@Z + ??$?RPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV01234@$0A@@__move_backward_trivial@Cr@std@@QBE?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@12@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$?RPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV01234@$0A@@__move_trivial@Cr@std@@QBE?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@12@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$?RPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU0123@$0A@@__move_backward_trivial@Cr@std@@QBE?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@12@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$?RPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU0123@$0A@@__move_trivial@Cr@std@@QBE?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@12@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$?RPAVLogSink@absl@@PAV01@$0A@@__move_trivial@Cr@std@@QBE?AU?$pair@PAPAVLogSink@absl@@PAPAV12@@12@PAPAVLogSink@absl@@00@Z ??$?RPAVSpinLock@base_internal@absl@@AB_J@?$AtomicHook@P6AXPBX_J@Z@base_internal@absl@@QBEX$$QAPAVSpinLock@12@AB_J@Z + ??$?RUTransition@cctz@time_internal@absl@@U0123@$0A@@__move_backward_trivial@Cr@std@@QBE?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@12@PAUTransition@cctz@time_internal@absl@@00@Z + ??$?RUTransition@cctz@time_internal@absl@@U0123@$0A@@__move_trivial@Cr@std@@QBE?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@12@PAUTransition@cctz@time_internal@absl@@00@Z + ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@__move_backward_trivial@Cr@std@@QBE?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@12@PAUTransitionType@cctz@time_internal@absl@@00@Z + ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@__move_trivial@Cr@std@@QBE?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@12@PAUTransitionType@cctz@time_internal@absl@@00@Z + ??$?RV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QBE?AU?$pair@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QBE?AU?$pair@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PAPAVLogSink@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QBE?AU?$pair@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QBE?AU?$pair@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QBE?AU?$pair@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QBE?AU?$pair@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@12@00@Z + ??$?RV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V012@V012@@?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@QBE?AU?$pair@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@12@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@12@00@Z ??$?RW4LogSeverity@absl@@ABQBDHAAPBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAPBD@Z ??$?RW4LogSeverity@absl@@ABQBDHAAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z ??$?RW4LogSeverity@absl@@ABQBDHAAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAY0CC@$$CBD@Z @@ -657,10 +682,19 @@ ??$__construct_one_at_end@ABQBVCordzHandle@cord_internal@absl@@@?$vector@PBVCordzHandle@cord_internal@absl@@V?$allocator@PBVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AAEXABQBVCordzHandle@cord_internal@absl@@@Z ??$__construct_one_at_end@ABUTransition@cctz@time_internal@absl@@@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@AAEXABUTransition@cctz@time_internal@absl@@@Z ??$__construct_one_at_end@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@?$vector@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@Cr@std@@AAEX$$QAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Z - ??$__copy@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@PAU1234@$0A@@Cr@std@@YA?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@01@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0PAU3456@@Z - ??$__copy@PBVFormatArgImpl@str_format_internal@absl@@PBV123@PAV123@$0A@@Cr@std@@YA?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@01@PBVFormatArgImpl@str_format_internal@absl@@0PAV345@@Z - ??$__copy_impl@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U1234@X@Cr@std@@YA?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@01@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0PAU3456@@Z - ??$__copy_impl@$$CBVFormatArgImpl@str_format_internal@absl@@V123@X@Cr@std@@YA?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@01@PBVFormatArgImpl@str_format_internal@absl@@0PAV345@@Z + ??$__copy@U_ClassicAlgPolicy@Cr@std@@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU4567@PAU4567@@Cr@std@@YA?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@01@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0PAU3456@@Z + ??$__copy@U_ClassicAlgPolicy@Cr@std@@PBVFormatArgImpl@str_format_internal@absl@@PBV456@PAV456@@Cr@std@@YA?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@01@PBVFormatArgImpl@str_format_internal@absl@@0PAV345@@Z + ??$__copy_backward_trivial_impl@PAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV12345@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@PAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@UTransition@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@PAUTransition@cctz@time_internal@absl@@00@Z + ??$__copy_backward_trivial_impl@UTransitionType@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@PAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@01@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0PAU3456@@Z + ??$__copy_trivial_impl@$$CBVFormatArgImpl@str_format_internal@absl@@V123@@Cr@std@@YA?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@01@PBVFormatArgImpl@str_format_internal@absl@@0PAV345@@Z + ??$__copy_trivial_impl@PAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV12345@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@PAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__copy_trivial_impl@PAVLogSink@absl@@PAV12@@Cr@std@@YA?AU?$pair@PAPAVLogSink@absl@@PAPAV12@@01@PAPAVLogSink@absl@@00@Z + ??$__copy_trivial_impl@UTransition@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@PAUTransition@cctz@time_internal@absl@@00@Z + ??$__copy_trivial_impl@UTransitionType@cctz@time_internal@absl@@U1234@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@PAUTransitionType@cctz@time_internal@absl@@00@Z ??$__cxx_atomic_compare_exchange_strong@PAVTimeZone@absl@@@Cr@std@@YA_NPAU?$__cxx_atomic_base_impl@PAVTimeZone@absl@@@01@PAPAVTimeZone@absl@@PAV34@W4memory_order@01@3@Z ??$__cxx_atomic_compare_exchange_weak@PAUHashtablezInfo@container_internal@absl@@@Cr@std@@YA_NPAU?$__cxx_atomic_base_impl@PAUHashtablezInfo@container_internal@absl@@@01@PAPAUHashtablezInfo@container_internal@absl@@PAU345@W4memory_order@01@3@Z ??$__cxx_atomic_load@P6AXABUHashtablezInfo@container_internal@absl@@@Z@Cr@std@@YAP6AXABUHashtablezInfo@container_internal@absl@@@ZPBU?$__cxx_atomic_base_impl@P6AXABUHashtablezInfo@container_internal@absl@@@Z@01@W4memory_order@01@@Z @@ -713,6 +747,24 @@ ??$__destroy_at@UTransitionType@cctz@time_internal@absl@@$0A@@Cr@std@@YAXPAUTransitionType@cctz@time_internal@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@$0A@@Cr@std@@YAXPAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@VFormatArgImpl@str_format_internal@absl@@$0A@@Cr@std@@YAXPAVFormatArgImpl@str_format_internal@absl@@@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV6789absl@@PAPAPBV6789absl@@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU6789@PAPAU6789@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PAUTransition@cctz@time_internal@absl@@PAU6789@PAU6789@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@PAUTransition@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_backward_trivial@23@PAUTransitionType@cctz@time_internal@absl@@PAU6789@PAU6789@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@PAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV6789absl@@PAPAPBV6789absl@@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU6789@PAPAU6789@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PAPAVLogSink@absl@@PAPAV67@PAPAV67@@Cr@std@@YA?AU?$pair@PAPAVLogSink@absl@@PAPAV12@@01@PAPAVLogSink@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PAUTransition@cctz@time_internal@absl@@PAU6789@PAU6789@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@PAUTransition@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@PAUTransitionType@cctz@time_internal@absl@@PAU6789@PAU6789@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@PAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PAPAVLogSink@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPAVLogSink@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@23@U__move_trivial@23@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@23@V623@V623@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@00@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U__copy_loop@23@U__copy_trivial@23@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU6789@PAU6789@@Cr@std@@YA?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@01@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0PAU3456@@Z + ??$__dispatch_copy_or_move@U_ClassicAlgPolicy@Cr@std@@U__copy_loop@23@U__copy_trivial@23@PBVFormatArgImpl@str_format_internal@absl@@PBV678@PAV678@@Cr@std@@YA?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@01@PBVFormatArgImpl@str_format_internal@absl@@0PAV345@@Z ??$__distance@PBUPayload@status_internal@absl@@@Cr@std@@YAHPBUPayload@status_internal@absl@@0Urandom_access_iterator_tag@01@@Z ??$__distance@PBUTransition@cctz@time_internal@absl@@@Cr@std@@YAHPBUTransition@cctz@time_internal@absl@@0Urandom_access_iterator_tag@01@@Z ??$__distance@PBVFormatArgImpl@str_format_internal@absl@@@Cr@std@@YAHPBVFormatArgImpl@str_format_internal@absl@@0Urandom_access_iterator_tag@01@@Z @@ -727,6 +779,13 @@ ??$__invoke@AAUByCivilTime@Transition@cctz@time_internal@absl@@ABU2345@ABU2345@@Cr@std@@YA_NAAUByCivilTime@Transition@cctz@time_internal@absl@@ABU3456@1@Z ??$__invoke@AAUByUnixTime@Transition@cctz@time_internal@absl@@ABU2345@ABU2345@@Cr@std@@YA_NAAUByUnixTime@Transition@cctz@time_internal@absl@@ABU3456@1@Z ??$__invoke@AAU__identity@Cr@std@@ABUTransition@cctz@time_internal@absl@@@Cr@std@@YAABUTransition@cctz@time_internal@absl@@AAU__identity@01@ABU2345@@Z + ??$__iter_move@AAV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QAPAVCordzHandle@cord_internal@absl@@AAV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@12@@Z + ??$__iter_move@AAV?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QAPAVLogSink@absl@@AAV?$reverse_iterator@PAPAVLogSink@absl@@@12@@Z + ??$__iter_move@AAV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QAPBVCordzHandle@cord_internal@absl@@AAV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@12@@Z + ??$__iter_move@AAV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QAUConversionItem@ParsedFormatBase@str_format_internal@absl@@AAV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@@Z + ??$__iter_move@AAV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QAUTransition@cctz@time_internal@absl@@AAV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@12@@Z + ??$__iter_move@AAV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QAUTransitionType@cctz@time_internal@absl@@AAV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@12@@Z + ??$__iter_move@AAV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SA$$QAUViableSubstitution@strings_internal@absl@@AAV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@12@@Z ??$__launder@$$CBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@01@PBU201@@Z ??$__launder@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@01@PAU201@@Z ??$__lower_bound_impl@U_ClassicAlgPolicy@Cr@std@@PBUTransition@cctz@time_internal@absl@@PBU4567@U4567@U__identity@23@UByUnixTime@4567@@Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@AAUByUnixTime@2345@AAU__identity@01@@Z @@ -742,30 +801,10 @@ ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@00@Z ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@00@Z ??$__move@U_ClassicAlgPolicy@Cr@std@@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@23@V423@V423@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV45678@@Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU4567@@Cr@std@@YAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU2345@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PAUTransition@cctz@time_internal@absl@@PAU4567@@Cr@std@@YAPAUTransition@cctz@time_internal@absl@@PAU2345@00@Z - ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PAUTransitionType@cctz@time_internal@absl@@PAU4567@@Cr@std@@YAPAUTransitionType@cctz@time_internal@absl@@PAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@PAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV45678@@Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@PAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU4567@@Cr@std@@YAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@UTransition@cctz@time_internal@absl@@U4567@@Cr@std@@YAPAUTransition@cctz@time_internal@absl@@PAU2345@00@Z - ??$__move_backward_impl@U_ClassicAlgPolicy@Cr@std@@UTransitionType@cctz@time_internal@absl@@U4567@@Cr@std@@YAPAUTransitionType@cctz@time_internal@absl@@PAU2345@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAPAVCordzHandle@cord_internal@absl@@PAPAV456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAPAVLogSink@absl@@PAPAV45@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPAVLogSink@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAPBVCordzHandle@cord_internal@absl@@PAPBV456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV45678@X@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU4567@X@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAUTransition@cctz@time_internal@absl@@PAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAUTransitionType@cctz@time_internal@absl@@PAU4567@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAUViableSubstitution@strings_internal@absl@@PAU456@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAVCordzHandle@cord_internal@absl@@PAV456@X@Cr@std@@YA?AU?$pair@PAPAVCordzHandle@cord_internal@absl@@PAPAV123@@01@PAPAVCordzHandle@cord_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PAVLogSink@absl@@PAV45@X@Cr@std@@YA?AU?$pair@PAPAVLogSink@absl@@PAPAV12@@01@PAPAVLogSink@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@PBVCordzHandle@cord_internal@absl@@PBV456@X@Cr@std@@YA?AU?$pair@PAPBVCordzHandle@cord_internal@absl@@PAPBV123@@01@PAPBVCordzHandle@cord_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU1234@@01@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UTransition@cctz@time_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@PAUTransition@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UTransitionType@cctz@time_internal@absl@@U4567@X@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@PAUTransitionType@cctz@time_internal@absl@@00@Z - ??$__move_impl@U_ClassicAlgPolicy@Cr@std@@UViableSubstitution@strings_internal@absl@@U456@X@Cr@std@@YA?AU?$pair@PAUViableSubstitution@strings_internal@absl@@PAU123@@01@PAUViableSubstitution@strings_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV45678@PAPAPBV45678@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU4567@PAPAU4567@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PAUTransition@cctz@time_internal@absl@@PAU4567@PAU4567@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@PAUTransition@cctz@time_internal@absl@@00@Z + ??$__move_backward@U_ClassicAlgPolicy@Cr@std@@PAUTransitionType@cctz@time_internal@absl@@PAU4567@PAU4567@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@PAUTransitionType@cctz@time_internal@absl@@00@Z ??$__push_back_slow_path@ABQAVCordzHandle@cord_internal@absl@@@?$vector@PAVCordzHandle@cord_internal@absl@@V?$allocator@PAVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AAEXABQAVCordzHandle@cord_internal@absl@@@Z ??$__push_back_slow_path@ABQAVLogSink@absl@@@?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@Cr@std@@@Cr@std@@AAEXABQAVLogSink@absl@@@Z ??$__push_back_slow_path@ABQBVCordzHandle@cord_internal@absl@@@?$vector@PBVCordzHandle@cord_internal@absl@@V?$allocator@PBVCordzHandle@cord_internal@absl@@@Cr@std@@@Cr@std@@AAEXABQBVCordzHandle@cord_internal@absl@@@Z @@ -774,14 +813,10 @@ ??$__rehash@$00@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$allocator@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@23@@Cr@std@@AAEXI@Z ??$__rewrap_iter@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@U?$__unwrap_iter_impl@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@0@Z ??$__rewrap_iter@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@U?$__unwrap_iter_impl@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU2345@0@Z - ??$__rewrap_iter@PAPAVCordzHandle@cord_internal@absl@@PAPAV123@U?$__unwrap_iter_impl@PAPAVCordzHandle@cord_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAPAVCordzHandle@cord_internal@absl@@PAPAV234@0@Z ??$__rewrap_iter@PAPAVLogSink@absl@@PAPAV12@U?$__unwrap_iter_impl@PAPAVLogSink@absl@@$00@Cr@std@@@Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@0@Z - ??$__rewrap_iter@PAPBVCordzHandle@cord_internal@absl@@PAPBV123@U?$__unwrap_iter_impl@PAPBVCordzHandle@cord_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAPBVCordzHandle@cord_internal@absl@@PAPBV234@0@Z - ??$__rewrap_iter@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU1234@U?$__unwrap_iter_impl@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU2345@0@Z ??$__rewrap_iter@PAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@U?$__unwrap_iter_impl@PAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU2345@0@Z ??$__rewrap_iter@PAUTransition@cctz@time_internal@absl@@PAU1234@U?$__unwrap_iter_impl@PAUTransition@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAUTransition@cctz@time_internal@absl@@PAU2345@0@Z ??$__rewrap_iter@PAUTransitionType@cctz@time_internal@absl@@PAU1234@U?$__unwrap_iter_impl@PAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAUTransitionType@cctz@time_internal@absl@@PAU2345@0@Z - ??$__rewrap_iter@PAUViableSubstitution@strings_internal@absl@@PAU123@U?$__unwrap_iter_impl@PAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAUViableSubstitution@strings_internal@absl@@PAU234@0@Z ??$__rewrap_iter@PAVFormatArgImpl@str_format_internal@absl@@PAV123@U?$__unwrap_iter_impl@PAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPAVFormatArgImpl@str_format_internal@absl@@PAV234@0@Z ??$__rewrap_iter@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@U?$__unwrap_iter_impl@PBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@@Cr@std@@YAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU2345@0@Z ??$__rewrap_iter@PBVFormatArgImpl@str_format_internal@absl@@PBV123@U?$__unwrap_iter_impl@PBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@@Cr@std@@YAPBVFormatArgImpl@str_format_internal@absl@@PBV234@0@Z @@ -792,8 +827,20 @@ ??$__rewrap_iter@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@V201@0@Z ??$__rewrap_iter@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@V201@0@Z ??$__rewrap_iter@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@U?$__unwrap_iter_impl@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@23@@Cr@std@@YA?AV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@PAPAPBV12345@@Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@0@Z + ??$__rewrap_range@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@PAPAU1234@@Cr@std@@YAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU2345@0@Z + ??$__rewrap_range@PAPAVLogSink@absl@@PAPAV12@PAPAV12@@Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@0@Z + ??$__rewrap_range@PAUTransition@cctz@time_internal@absl@@PAU1234@PAU1234@@Cr@std@@YAPAUTransition@cctz@time_internal@absl@@PAU2345@0@Z + ??$__rewrap_range@PAUTransitionType@cctz@time_internal@absl@@PAU1234@PAU1234@@Cr@std@@YAPAUTransitionType@cctz@time_internal@absl@@PAU2345@0@Z ??$__rewrap_range@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@PBU1234@@Cr@std@@YAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU2345@0@Z ??$__rewrap_range@PBVFormatArgImpl@str_format_internal@absl@@PBV123@PBV123@@Cr@std@@YAPBVFormatArgImpl@str_format_internal@absl@@PBV234@0@Z + ??$__rewrap_range@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PAPAVLogSink@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@V201@0@Z + ??$__rewrap_range@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@V123@@Cr@std@@YA?AV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@V201@0@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@YAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU2345@@Z ??$__to_address@$$CBVFormatArgImpl@str_format_internal@absl@@@Cr@std@@YAPBVFormatArgImpl@str_format_internal@absl@@PBV234@@Z ??$__to_address@PAPBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@@Z @@ -817,16 +864,30 @@ ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@PAUTransitionType@cctz@time_internal@absl@@PAU4567@U4567@X@Cr@std@@YAPAUTransitionType@cctz@time_internal@absl@@AAV?$allocator@UTransitionType@cctz@time_internal@absl@@@01@PAU2345@11@Z ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UTransitionType@cctz@time_internal@absl@@@Cr@std@@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@23@V423@UTransitionType@cctz@time_internal@absl@@X@Cr@std@@YA?AV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@AAV?$allocator@UTransitionType@cctz@time_internal@absl@@@01@V201@11@Z ??$__uninitialized_allocator_move_if_noexcept@V?$allocator@UViableSubstitution@strings_internal@absl@@@Cr@std@@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@23@V423@UViableSubstitution@strings_internal@absl@@X@Cr@std@@YA?AV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@AAV?$allocator@UViableSubstitution@strings_internal@absl@@@01@V201@11@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV45678@PAPAPBV45678@$0A@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU4567@PAPAU4567@$0A@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PAUTransition@cctz@time_internal@absl@@PAU4567@PAU4567@$0A@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@PAUTransition@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_backward_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_backward_trivial@23@@Cr@std@@PAUTransitionType@cctz@time_internal@absl@@PAU4567@PAU4567@$0A@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@PAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV45678@PAPAPBV45678@$0A@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU4567@PAPAU4567@$0A@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PAPAVLogSink@absl@@PAPAV45@PAPAV45@$0A@@Cr@std@@YA?AU?$pair@PAPAVLogSink@absl@@PAPAV12@@01@PAPAVLogSink@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PAUTransition@cctz@time_internal@absl@@PAU4567@PAU4567@$0A@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@PAUTransition@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@PAUTransitionType@cctz@time_internal@absl@@PAU4567@PAU4567@$0A@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@PAUTransitionType@cctz@time_internal@absl@@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PAPAVLogSink@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPAVLogSink@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U?$__move_loop@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@U__move_trivial@23@@Cr@std@@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@23@V423@V423@$0A@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@00@Z + ??$__unwrap_and_dispatch@U?$__overload@U__copy_loop@Cr@std@@U__copy_trivial@23@@Cr@std@@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU4567@PAU4567@$0A@@Cr@std@@YA?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@01@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0PAU3456@@Z + ??$__unwrap_and_dispatch@U?$__overload@U__copy_loop@Cr@std@@U__copy_trivial@23@@Cr@std@@PBVFormatArgImpl@str_format_internal@absl@@PBV456@PAV456@$0A@@Cr@std@@YA?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@01@PBVFormatArgImpl@str_format_internal@absl@@0PAV345@@Z ??$__unwrap_iter@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@@Z ??$__unwrap_iter@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU2345@@Z - ??$__unwrap_iter@PAPAVCordzHandle@cord_internal@absl@@U?$__unwrap_iter_impl@PAPAVCordzHandle@cord_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAPAVCordzHandle@cord_internal@absl@@PAPAV234@@Z ??$__unwrap_iter@PAPAVLogSink@absl@@U?$__unwrap_iter_impl@PAPAVLogSink@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@@Z - ??$__unwrap_iter@PAPBVCordzHandle@cord_internal@absl@@U?$__unwrap_iter_impl@PAPBVCordzHandle@cord_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAPBVCordzHandle@cord_internal@absl@@PAPBV234@@Z - ??$__unwrap_iter@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@U?$__unwrap_iter_impl@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU2345@@Z ??$__unwrap_iter@PAUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU2345@@Z ??$__unwrap_iter@PAUTransition@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PAUTransition@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAUTransition@cctz@time_internal@absl@@PAU2345@@Z ??$__unwrap_iter@PAUTransitionType@cctz@time_internal@absl@@U?$__unwrap_iter_impl@PAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAUTransitionType@cctz@time_internal@absl@@PAU2345@@Z - ??$__unwrap_iter@PAUViableSubstitution@strings_internal@absl@@U?$__unwrap_iter_impl@PAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAUViableSubstitution@strings_internal@absl@@PAU234@@Z ??$__unwrap_iter@PAVFormatArgImpl@str_format_internal@absl@@U?$__unwrap_iter_impl@PAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPAVFormatArgImpl@str_format_internal@absl@@PAV234@@Z ??$__unwrap_iter@PBUPrefixCrc@CrcCordState@crc_internal@absl@@U?$__unwrap_iter_impl@PBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU2345@@Z ??$__unwrap_iter@PBVFormatArgImpl@str_format_internal@absl@@U?$__unwrap_iter_impl@PBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@$0A@@Cr@std@@YAPBVFormatArgImpl@str_format_internal@absl@@PBV234@@Z @@ -837,10 +898,29 @@ ??$__unwrap_iter@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@V201@@Z ??$__unwrap_iter@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@V201@@Z ??$__unwrap_iter@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@U?$__unwrap_iter_impl@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@23@$0A@@Cr@std@@YA?AV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@V201@@Z + ??$__unwrap_range@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@Cr@std@@YA?A?<auto>@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$__unwrap_range@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@Cr@std@@YA?A?<auto>@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$__unwrap_range@PAPAVLogSink@absl@@PAPAV12@@Cr@std@@YA?A?<auto>@@PAPAVLogSink@absl@@0@Z + ??$__unwrap_range@PAUTransition@cctz@time_internal@absl@@PAU1234@@Cr@std@@YA?A?<auto>@@PAUTransition@cctz@time_internal@absl@@0@Z + ??$__unwrap_range@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@Cr@std@@YA?A?<auto>@@PAUTransitionType@cctz@time_internal@absl@@0@Z ??$__unwrap_range@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@@Cr@std@@YA?A?<auto>@@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$__unwrap_range@PBVFormatArgImpl@str_format_internal@absl@@PBV123@@Cr@std@@YA?A?<auto>@@PBVFormatArgImpl@str_format_internal@absl@@0@Z + ??$__unwrap_range@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PAPAVLogSink@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@0@Z + ??$__unwrap_range@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?A?<auto>@@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@0@Z ??$__upper_bound@U_ClassicAlgPolicy@Cr@std@@UByCivilTime@Transition@cctz@time_internal@absl@@PBU5678@PBU5678@U5678@U__identity@23@@Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@$$QAUByCivilTime@2345@$$QAU__identity@01@@Z ??$__upper_bound@U_ClassicAlgPolicy@Cr@std@@UByUnixTime@Transition@cctz@time_internal@absl@@PBU5678@PBU5678@U5678@U__identity@23@@Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@$$QAUByUnixTime@2345@$$QAU__identity@01@@Z + ??$__validate_iter_reference@AAV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AAV?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AAV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AAV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AAV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AAV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ + ??$__validate_iter_reference@AAV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXXZ ??$advance@PBUTransition@cctz@time_internal@absl@@H@?$_IterOps@U_ClassicAlgPolicy@Cr@std@@@Cr@std@@SAXAAPBUTransition@cctz@time_internal@absl@@H@Z ??$advance@PBUTransition@cctz@time_internal@absl@@HHX@Cr@std@@YAXAAPBUTransition@cctz@time_internal@absl@@H@Z ??$advance@PBVFormatArgImpl@str_format_internal@absl@@IIX@Cr@std@@YAXAAPBVFormatArgImpl@str_format_internal@absl@@I@Z @@ -1004,22 +1084,22 @@ ??$launder@$$CBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPBU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@01@PBU201@@Z ??$launder@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@01@PAU201@@Z ??$lower_bound@PBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@UByUnixTime@2345@@Z - ??$make_pair@AAV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@AAV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@01@$$QAV301@@Z - ??$make_pair@AAV?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@01@AAV?$reverse_iterator@PAPAVLogSink@absl@@@01@$$QAV301@@Z - ??$make_pair@AAV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@AAV?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@01@$$QAV301@@Z - ??$make_pair@AAV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@01@AAV?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@01@$$QAV301@@Z - ??$make_pair@AAV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@01@AAV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@01@$$QAV301@@Z - ??$make_pair@AAV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@01@AAV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@$$QAV301@@Z - ??$make_pair@AAV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@01@AAV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@01@$$QAV301@@Z + ??$make_pair@AAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@AAPAPAPBV12345@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@AAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ??$make_pair@AAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@AAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@$$QAPAPAPBV34567@@Z + ??$make_pair@AAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@AAPAPAU1234@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@AAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ??$make_pair@AAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@AAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@$$QAPAPAU3456@@Z + ??$make_pair@AAPAPAVLogSink@absl@@PAPAV12@@Cr@std@@YA?AU?$pair@PAPAVLogSink@absl@@PAPAV12@@01@AAPAPAVLogSink@absl@@$$QAPAPAV34@@Z + ??$make_pair@AAPAUTransition@cctz@time_internal@absl@@AAPAU1234@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@AAPAUTransition@cctz@time_internal@absl@@0@Z + ??$make_pair@AAPAUTransition@cctz@time_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@AAPAUTransition@cctz@time_internal@absl@@$$QAPAU3456@@Z + ??$make_pair@AAPAUTransitionType@cctz@time_internal@absl@@AAPAU1234@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@AAPAUTransitionType@cctz@time_internal@absl@@0@Z + ??$make_pair@AAPAUTransitionType@cctz@time_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@AAPAUTransitionType@cctz@time_internal@absl@@$$QAPAU3456@@Z + ??$make_pair@AAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@01@AAPBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QAPAU3456@@Z + ??$make_pair@AAPBVFormatArgImpl@str_format_internal@absl@@PAV123@@Cr@std@@YA?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@01@AAPBVFormatArgImpl@str_format_internal@absl@@$$QAPAV345@@Z ??$make_pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@Cr@std@@YA?AU?$pair@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@$$QAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@0@Z ??$make_pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@Cr@std@@YA?AU?$pair@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@$$QAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z - ??$make_pair@PAPAVCordzHandle@cord_internal@absl@@PAPAV123@@Cr@std@@YA?AU?$pair@PAPAVCordzHandle@cord_internal@absl@@PAPAV123@@01@$$QAPAPAVCordzHandle@cord_internal@absl@@0@Z ??$make_pair@PAPAVLogSink@absl@@PAPAV12@@Cr@std@@YA?AU?$pair@PAPAVLogSink@absl@@PAPAV12@@01@$$QAPAPAVLogSink@absl@@0@Z - ??$make_pair@PAPBVCordzHandle@cord_internal@absl@@PAPBV123@@Cr@std@@YA?AU?$pair@PAPBVCordzHandle@cord_internal@absl@@PAPBV123@@01@$$QAPAPBVCordzHandle@cord_internal@absl@@0@Z - ??$make_pair@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU1234@@01@$$QAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@0@Z ??$make_pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PAUTransition@cctz@time_internal@absl@@PAU1234@@01@$$QAPAUTransition@cctz@time_internal@absl@@0@Z ??$make_pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@01@$$QAPAUTransitionType@cctz@time_internal@absl@@0@Z - ??$make_pair@PAUViableSubstitution@strings_internal@absl@@PAU123@@Cr@std@@YA?AU?$pair@PAUViableSubstitution@strings_internal@absl@@PAU123@@01@$$QAPAUViableSubstitution@strings_internal@absl@@0@Z ??$make_pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@Cr@std@@YA?AU?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@01@$$QAPBUPrefixCrc@CrcCordState@crc_internal@absl@@$$QAPAU3456@@Z ??$make_pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@Cr@std@@YA?AU?$pair@PBVFormatArgImpl@str_format_internal@absl@@PAV123@@01@$$QAPBVFormatArgImpl@str_format_internal@absl@@$$QAPAV345@@Z ??$make_pair@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@YA?AU?$pair@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@01@$$QAV?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@01@0@Z @@ -1774,6 +1854,13 @@ ??D?$move_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@QBE$$QAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QBE$$QAUTransitionType@cctz@time_internal@absl@@XZ ??D?$optional@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@absl@@QGAEAAV?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@XZ + ??D?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@QBEAAPAVCordzHandle@cord_internal@absl@@XZ + ??D?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@QBEAAPAVLogSink@absl@@XZ + ??D?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@QBEAAPBVCordzHandle@cord_internal@absl@@XZ + ??D?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@QBEAAUConversionItem@ParsedFormatBase@str_format_internal@absl@@XZ + ??D?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@QBEAAUTransition@cctz@time_internal@absl@@XZ + ??D?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QBEAAUTransitionType@cctz@time_internal@absl@@XZ + ??D?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@QBEAAUViableSubstitution@strings_internal@absl@@XZ ??D?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@Cr@std@@@Cr@std@@QBEAAULogMessageData@LogMessage@log_internal@absl@@XZ ??D?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@@Cr@std@@@Cr@std@@QBEAAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@Cr@std@@@absl@@XZ ??DChunkIterator@Cord@absl@@QBE?AVstring_view@2@XZ @@ -1795,6 +1882,13 @@ ??E?$move_iterator@PAUPayload@status_internal@absl@@@Cr@std@@QAEAAV012@XZ ??E?$move_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@QAEAAV012@XZ ??E?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QAEAAV012@XZ + ??E?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@QAEAAV012@XZ + ??E?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@QAEAAV012@XZ + ??E?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@QAEAAV012@XZ + ??E?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@QAEAAV012@XZ + ??E?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@QAEAAV012@XZ + ??E?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@QAEAAV012@XZ + ??E?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@QAEAAV012@XZ ??EChunkIterator@Cord@absl@@QAEAAV012@XZ ??E__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QAEAAU0123@XZ ??Euint128@absl@@QAEAAV01@XZ @@ -3522,14 +3616,10 @@ ?__rehash_unique@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@@23@$00@23@V?$allocator@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@23@@Cr@std@@QAEXI@Z ?__rewrap@?$__unwrap_iter_impl@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@SAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV45678@0@Z ?__rewrap@?$__unwrap_iter_impl@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU4567@0@Z - ?__rewrap@?$__unwrap_iter_impl@PAPAVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPAPAVCordzHandle@cord_internal@absl@@PAPAV456@0@Z ?__rewrap@?$__unwrap_iter_impl@PAPAVLogSink@absl@@$00@Cr@std@@SAPAPAVLogSink@absl@@PAPAV45@0@Z - ?__rewrap@?$__unwrap_iter_impl@PAPBVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPAPBVCordzHandle@cord_internal@absl@@PAPBV456@0@Z - ?__rewrap@?$__unwrap_iter_impl@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@SAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PAUTransition@cctz@time_internal@absl@@$00@Cr@std@@SAPAUTransition@cctz@time_internal@absl@@PAU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@SAPAUTransitionType@cctz@time_internal@absl@@PAU4567@0@Z - ?__rewrap@?$__unwrap_iter_impl@PAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@SAPAUViableSubstitution@strings_internal@absl@@PAU456@0@Z ?__rewrap@?$__unwrap_iter_impl@PAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPAVFormatArgImpl@str_format_internal@absl@@PAV456@0@Z ?__rewrap@?$__unwrap_iter_impl@PBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU4567@0@Z ?__rewrap@?$__unwrap_iter_impl@PBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPBVFormatArgImpl@str_format_internal@absl@@PBV456@0@Z @@ -3540,8 +3630,20 @@ ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@23@V423@0@Z ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@23@V423@0@Z ?__rewrap@?$__unwrap_iter_impl@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@23@V423@0@Z + ?__rewrap@?$__unwrap_range_impl@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@Cr@std@@SA?A?<auto>@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@Cr@std@@SA?A?<auto>@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PAPAVLogSink@absl@@PAPAV12@@Cr@std@@SA?A?<auto>@@PAPAVLogSink@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PAUTransition@cctz@time_internal@absl@@PAU1234@@Cr@std@@SA?A?<auto>@@PAUTransition@cctz@time_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@Cr@std@@SA?A?<auto>@@PAUTransitionType@cctz@time_internal@absl@@0@Z ?__rewrap@?$__unwrap_range_impl@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@@Cr@std@@SA?A?<auto>@@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ?__rewrap@?$__unwrap_range_impl@PBVFormatArgImpl@str_format_internal@absl@@PBV123@@Cr@std@@SA?A?<auto>@@PBVFormatArgImpl@str_format_internal@absl@@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAPAVLogSink@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@23@0@Z + ?__rewrap@?$__unwrap_range_impl@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@23@0@Z ?__size@?$deque@PBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QAEAAIXZ ?__size@?$deque@PBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@@Cr@std@@QBEABIXZ ?__size@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@Cr@std@@@Cr@std@@QAEAAIXZ @@ -3565,14 +3667,10 @@ ?__throw_length_error@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@ABEXXZ ?__unwrap@?$__unwrap_iter_impl@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@$00@Cr@std@@SAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV45678@@Z ?__unwrap@?$__unwrap_iter_impl@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU4567@@Z - ?__unwrap@?$__unwrap_iter_impl@PAPAVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPAPAVCordzHandle@cord_internal@absl@@PAPAV456@@Z ?__unwrap@?$__unwrap_iter_impl@PAPAVLogSink@absl@@$00@Cr@std@@SAPAPAVLogSink@absl@@PAPAV45@@Z - ?__unwrap@?$__unwrap_iter_impl@PAPBVCordzHandle@cord_internal@absl@@$00@Cr@std@@SAPAPBVCordzHandle@cord_internal@absl@@PAPBV456@@Z - ?__unwrap@?$__unwrap_iter_impl@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$00@Cr@std@@SAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PAUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PAUTransition@cctz@time_internal@absl@@$00@Cr@std@@SAPAUTransition@cctz@time_internal@absl@@PAU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PAUTransitionType@cctz@time_internal@absl@@$00@Cr@std@@SAPAUTransitionType@cctz@time_internal@absl@@PAU4567@@Z - ?__unwrap@?$__unwrap_iter_impl@PAUViableSubstitution@strings_internal@absl@@$00@Cr@std@@SAPAUViableSubstitution@strings_internal@absl@@PAU456@@Z ?__unwrap@?$__unwrap_iter_impl@PAVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPAVFormatArgImpl@str_format_internal@absl@@PAV456@@Z ?__unwrap@?$__unwrap_iter_impl@PBUPrefixCrc@CrcCordState@crc_internal@absl@@$00@Cr@std@@SAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU4567@@Z ?__unwrap@?$__unwrap_iter_impl@PBVFormatArgImpl@str_format_internal@absl@@$00@Cr@std@@SAPBVFormatArgImpl@str_format_internal@absl@@PBV456@@Z @@ -3583,8 +3681,20 @@ ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@23@V423@@Z ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@23@V423@@Z ?__unwrap@?$__unwrap_iter_impl@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@$0A@@Cr@std@@SA?AV?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@23@V423@@Z + ?__unwrap@?$__unwrap_range_impl@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@Cr@std@@SA?A?<auto>@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@Cr@std@@SA?A?<auto>@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PAPAVLogSink@absl@@PAPAV12@@Cr@std@@SA?A?<auto>@@PAPAVLogSink@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PAUTransition@cctz@time_internal@absl@@PAU1234@@Cr@std@@SA?A?<auto>@@PAUTransition@cctz@time_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@Cr@std@@SA?A?<auto>@@PAUTransitionType@cctz@time_internal@absl@@0@Z ?__unwrap@?$__unwrap_range_impl@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@@Cr@std@@SA?A?<auto>@@PBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ?__unwrap@?$__unwrap_range_impl@PBVFormatArgImpl@str_format_internal@absl@@PBV123@@Cr@std@@SA?A?<auto>@@PBVFormatArgImpl@str_format_internal@absl@@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAPAVCordzHandle@cord_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PAPAVLogSink@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAPAVLogSink@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAPBVCordzHandle@cord_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAUTransition@cctz@time_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAUTransitionType@cctz@time_internal@absl@@@23@0@Z + ?__unwrap@?$__unwrap_range_impl@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@Cr@std@@V123@@Cr@std@@SA?A?<auto>@@V?$reverse_iterator@PAUViableSubstitution@strings_internal@absl@@@23@0@Z ?__upcast@?$__hash_node_base@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PAX@Cr@std@@@Cr@std@@QAEPAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@Cr@std@@V?$allocator@D@23@@Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@Cr@std@@PAX@23@XZ ?__vallocate@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@AAEXI@Z ?__vdeallocate@?$vector@VFormatArgImpl@str_format_internal@absl@@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@Cr@std@@@Cr@std@@AAEXXZ
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn index 0dcaa70c..66f105d 100644 --- a/third_party/android_deps/BUILD.gn +++ b/third_party/android_deps/BUILD.gn
@@ -1421,6 +1421,14 @@ } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. + java_prebuilt("org_conscrypt_conscrypt_openjdk_uber_java") { + jar_path = "libs/org_conscrypt_conscrypt_openjdk_uber/conscrypt-openjdk-uber-2.5.2.jar" + output_name = "org_conscrypt_conscrypt_openjdk_uber" + enable_bytecode_checks = false + testonly = true + } + + # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. java_prebuilt("org_jetbrains_kotlin_kotlin_stdlib_jdk7_java") { jar_path = "libs/org_jetbrains_kotlin_kotlin_stdlib_jdk7/kotlin-stdlib-jdk7-1.8.0.jar" output_name = "org_jetbrains_kotlin_kotlin_stdlib_jdk7"
diff --git a/third_party/android_deps/additional_readme_paths.json b/third_party/android_deps/additional_readme_paths.json index 58a6ea5..049692e 100644 --- a/third_party/android_deps/additional_readme_paths.json +++ b/third_party/android_deps/additional_readme_paths.json
@@ -129,6 +129,7 @@ "libs/org_checkerframework_checker_util", "libs/org_checkerframework_dataflow_errorprone", "libs/org_codehaus_mojo_animal_sniffer_annotations", + "libs/org_conscrypt_conscrypt_openjdk_uber", "libs/org_eclipse_jgit_org_eclipse_jgit", "libs/org_hamcrest_hamcrest", "libs/org_jetbrains_annotations",
diff --git a/third_party/blink/common/associated_interfaces/associated_interface_provider.cc b/third_party/blink/common/associated_interfaces/associated_interface_provider.cc index 6abf3cab..9069310 100644 --- a/third_party/blink/common/associated_interfaces/associated_interface_provider.cc +++ b/third_party/blink/common/associated_interfaces/associated_interface_provider.cc
@@ -33,6 +33,8 @@ binders_[name] = binder; } + void ResetBinderForName(const std::string& name) { binders_.erase(name); } + bool HasInterface(const std::string& name) const { return binders_.find(name) != binders_.end(); } @@ -93,9 +95,14 @@ const std::string& name, const base::RepeatingCallback<void(mojo::ScopedInterfaceEndpointHandle)>& binder) { - if (!local_provider_) - local_provider_ = std::make_unique<LocalProvider>(task_runner_); - local_provider_->SetBinderForName(name, binder); + if (binder) { + if (!local_provider_) { + local_provider_ = std::make_unique<LocalProvider>(task_runner_); + } + local_provider_->SetBinderForName(name, binder); + } else if (local_provider_) { + local_provider_->ResetBinderForName(name); + } } AssociatedInterfaceProvider*
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 3745227..0105db1 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -314,6 +314,13 @@ &kSharedStorageSelectURLLimit, "SharedStorageMaxAllowedSelectURLCallsPerOriginPerPageLoad", 3}; +BASE_FEATURE(kSharedStorageReportEventLimit, + "SharedStorageReportEventLimit", + base::FEATURE_DISABLED_BY_DEFAULT); +const base::FeatureParam<int> kSharedStorageReportEventBitBudgetPerPageLoad = { + &kSharedStorageReportEventLimit, + "SharedStorageReportEventBitBudgetPerPageLoad", 9}; + BASE_FEATURE(kSameSiteCrossOriginForSpeculationRulesPrerender, "SameSiteCrossOriginForSpeculationRulesPrerender", base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/third_party/blink/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.cc b/third_party/blink/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.cc index c520864a..efe7e702 100644 --- a/third_party/blink/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.cc +++ b/third_party/blink/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.cc
@@ -168,6 +168,20 @@ const blink::FencedFrame::SharedStorageBudgetMetadata& input) { return input.budget_to_charge; } +// static +bool StructTraits<blink::mojom::SharedStorageBudgetMetadataDataView, + blink::FencedFrame::SharedStorageBudgetMetadata>:: + top_navigated( + const blink::FencedFrame::SharedStorageBudgetMetadata& input) { + return input.top_navigated; +} +// static +bool StructTraits<blink::mojom::SharedStorageBudgetMetadataDataView, + blink::FencedFrame::SharedStorageBudgetMetadata>:: + report_event_called( + const blink::FencedFrame::SharedStorageBudgetMetadata& input) { + return input.report_event_called; +} // static bool StructTraits<blink::mojom::SharedStorageBudgetMetadataDataView, @@ -178,6 +192,8 @@ return false; } out_data->budget_to_charge = data.budget_to_charge(); + out_data->top_navigated = data.top_navigated(); + out_data->report_event_called = data.report_event_called(); return true; }
diff --git a/third_party/blink/common/storage_key/storage_key.cc b/third_party/blink/common/storage_key/storage_key.cc index 2fb946e5..7459a4d 100644 --- a/third_party/blink/common/storage_key/storage_key.cc +++ b/third_party/blink/common/storage_key/storage_key.cc
@@ -271,6 +271,31 @@ ancestor_chain_bit_); } +StorageKey::StorageKey(const url::Origin& origin, + const net::SchemefulSite& top_level_site, + const base::UnguessableToken* nonce, + blink::mojom::AncestorChainBit ancestor_chain_bit) + : origin_(origin), + top_level_site_(IsThirdPartyStoragePartitioningEnabled() + ? top_level_site + : net::SchemefulSite(origin)), + top_level_site_if_third_party_enabled_(top_level_site), + nonce_(base::OptionalFromPtr(nonce)), + ancestor_chain_bit_(IsThirdPartyStoragePartitioningEnabled() + ? ancestor_chain_bit + : blink::mojom::AncestorChainBit::kSameSite), + ancestor_chain_bit_if_third_party_enabled_(ancestor_chain_bit) { + // If we're setting a `nonce`, the `top_level_site` must be the same as + // the `origin` and the `ancestor_chain_bit` must be kSameSite. We don't + // serialize those pieces of information so have to check to prevent + // mistaken reliance on what is supposed to be an invariant. + if (nonce) { + DCHECK(!nonce->is_empty()); + DCHECK_EQ(top_level_site, net::SchemefulSite(origin)); + DCHECK_EQ(ancestor_chain_bit, blink::mojom::AncestorChainBit::kSameSite); + } +} + std::string StorageKey::Serialize() const { using EncodedAttribute = StorageKey::EncodedAttribute; DCHECK(!origin_.opaque());
diff --git a/third_party/blink/common/storage_key/storage_key_unittest.cc b/third_party/blink/common/storage_key/storage_key_unittest.cc index be35d1118..147a42a3 100644 --- a/third_party/blink/common/storage_key/storage_key_unittest.cc +++ b/third_party/blink/common/storage_key/storage_key_unittest.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/feature_list.h" +#include "base/test/gtest_util.h" #include "base/test/scoped_feature_list.h" #include "base/unguessable_token.h" #include "net/base/features.h" @@ -780,4 +781,38 @@ } } +TEST(StorageKeyTest, NonceRequiresMatchingOriginSiteAndSameSite) { + const url::Origin origin = url::Origin::Create(GURL("https://foo.com")); + const net::SchemefulSite site(origin); + const net::SchemefulSite opaque_site; + const net::SchemefulSite other_site(GURL("https://notfoo.com")); + base::UnguessableToken nonce = base::UnguessableToken::Create(); + + for (const bool toggle : {false, true}) { + base::test::ScopedFeatureList scope_feature_list; + scope_feature_list.InitWithFeatureState( + net::features::kThirdPartyStoragePartitioning, toggle); + + // A nonce key with a matching origin/site that's SameSite works. + (void)StorageKey::CreateWithOptionalNonce( + origin, site, &nonce, mojom::AncestorChainBit::kSameSite); + + // A nonce key with a non-matching origin/site that's SameSite fails. + EXPECT_DCHECK_DEATH(StorageKey::CreateWithOptionalNonce( + origin, opaque_site, &nonce, mojom::AncestorChainBit::kSameSite)); + EXPECT_DCHECK_DEATH(StorageKey::CreateWithOptionalNonce( + origin, other_site, &nonce, mojom::AncestorChainBit::kSameSite)); + + // A nonce key with a matching origin/site that's CrossSite fails. + EXPECT_DCHECK_DEATH(StorageKey::CreateWithOptionalNonce( + origin, site, &nonce, mojom::AncestorChainBit::kCrossSite)); + + // A nonce key with a non-matching origin/site that's CrossSite fails. + EXPECT_DCHECK_DEATH(StorageKey::CreateWithOptionalNonce( + origin, opaque_site, &nonce, mojom::AncestorChainBit::kCrossSite)); + EXPECT_DCHECK_DEATH(StorageKey::CreateWithOptionalNonce( + origin, other_site, &nonce, mojom::AncestorChainBit::kCrossSite)); + } +} + } // namespace blink
diff --git a/third_party/blink/public/common/associated_interfaces/associated_interface_provider.h b/third_party/blink/public/common/associated_interfaces/associated_interface_provider.h index 58aeb2a..f1da4b9 100644 --- a/third_party/blink/public/common/associated_interfaces/associated_interface_provider.h +++ b/third_party/blink/public/common/associated_interfaces/associated_interface_provider.h
@@ -71,6 +71,8 @@ GetInterface(remote->BindNewEndpointAndPassReceiver(task_runner_)); } + // If there is an override for `name`, passing in a null `binder` removes the + // override. void OverrideBinderForTesting( const std::string& name, const base::RepeatingCallback<void(mojo::ScopedInterfaceEndpointHandle)>&
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 940f392f..597790bf 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -140,6 +140,17 @@ BLINK_COMMON_EXPORT extern const base::FeatureParam<int> kSharedStorageMaxAllowedSelectURLCallsPerOriginPerPageLoad; +// If enabled, limits the maximum bits of entropy per pageload that +// `fence.reportEvent()` is allowed to leak when called with +// `FencedFrame::ReportingDestination::kSharedStorageSelectUrl`. +BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSharedStorageReportEventLimit); +// Maximum number of bits of entropy per pageload that are allowed to leak via +// calls to `fence.reportEvent()` with +// `FencedFrame::ReportingDestination::kSharedStorageSelectUrl`, if +// `kSharedStorageReportEventLimit` is enabled. +BLINK_COMMON_EXPORT extern const base::FeatureParam<int> + kSharedStorageReportEventBitBudgetPerPageLoad; + // Enables the multiple prerendering in a sequential way: // https://crbug.com/1355151 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kPrerender2SequentialPrerendering);
diff --git a/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h b/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h index 125cbb2..04e6149 100644 --- a/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h +++ b/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h
@@ -71,12 +71,16 @@ // the `FencedFrameURLMapping`. struct BLINK_COMMON_EXPORT SharedStorageBudgetMetadata { url::Origin origin; + double budget_to_charge = 0; - // The `budget_to_charge` needs to be mutable because the overall - // `FencedFrameConfig`/`FencedFrameProperties` object is const in virtually - // all cases, except that we want to reduce this budget to 0 after it's used - // the first time. - mutable double budget_to_charge = 0; + // The bools `top_navigated` and `report_event_called` need to be mutable + // because the overall `FencedFrameConfig`/`FencedFrameProperties` object is + // const in virtually all cases, except that we want to change each of these + // bools to true after a frame with this config navigates the top for the + // first time or calls `fence.reportEvent() with a shared storage reporting + // destination for the first time, respectively. + mutable bool top_navigated = false; + mutable bool report_event_called = false; }; // Represents a potentially opaque (redacted) value.
diff --git a/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.h b/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.h index 798af82..df4262e3 100644 --- a/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.h +++ b/third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config_mojom_traits.h
@@ -76,6 +76,10 @@ const blink::FencedFrame::SharedStorageBudgetMetadata& input); static double budget_to_charge( const blink::FencedFrame::SharedStorageBudgetMetadata& input); + static bool top_navigated( + const blink::FencedFrame::SharedStorageBudgetMetadata& input); + static bool report_event_called( + const blink::FencedFrame::SharedStorageBudgetMetadata& input); static bool Read(blink::mojom::SharedStorageBudgetMetadataDataView data, blink::FencedFrame::SharedStorageBudgetMetadata* out_data);
diff --git a/third_party/blink/public/common/storage_key/storage_key.h b/third_party/blink/public/common/storage_key/storage_key.h index c1e647c..8670f19 100644 --- a/third_party/blink/public/common/storage_key/storage_key.h +++ b/third_party/blink/public/common/storage_key/storage_key.h
@@ -74,7 +74,9 @@ const url::Origin& origin, const base::UnguessableToken& nonce); - // Callers may specify an optional nonce by passing nullptr. + // Callers may specify an optional `nonce` by passing nullptr. + // If the `nonce` isn't null, `top_level_site` must be the same as `origin` + // and `ancestor_chain_bit` must be kSameSite. static StorageKey CreateWithOptionalNonce( const url::Origin& origin, const net::SchemefulSite& top_level_site, @@ -243,17 +245,7 @@ StorageKey(const url::Origin& origin, const net::SchemefulSite& top_level_site, const base::UnguessableToken* nonce, - blink::mojom::AncestorChainBit ancestor_chain_bit) - : origin_(origin), - top_level_site_(IsThirdPartyStoragePartitioningEnabled() - ? top_level_site - : net::SchemefulSite(origin)), - top_level_site_if_third_party_enabled_(top_level_site), - nonce_(nonce ? absl::make_optional(*nonce) : absl::nullopt), - ancestor_chain_bit_(IsThirdPartyStoragePartitioningEnabled() - ? ancestor_chain_bit - : blink::mojom::AncestorChainBit::kSameSite), - ancestor_chain_bit_if_third_party_enabled_(ancestor_chain_bit) {} + blink::mojom::AncestorChainBit ancestor_chain_bit); // Converts the attribute type into the separator + uint8_t byte // serialization. E.x.: kTopLevelSite becomes "^0"
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index 5e09f86b..f66cfb09 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -1273,7 +1273,7 @@ # substring in their name are extracted. An empty or absent query returns # all histograms. optional string query - # If true, retrieve delta since last call. + # If true, retrieve delta since last delta call. optional boolean delta returns @@ -1285,7 +1285,7 @@ parameters # Requested histogram name. string name - # If true, retrieve delta since last call. + # If true, retrieve delta since last delta call. optional boolean delta returns # Histogram.
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index ea852d4..aeb4ae4 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -46,7 +46,6 @@ "clipboard/clipboard.mojom", "close_watcher/close_listener.mojom", "commit_result/commit_result.mojom", - "compute_pressure/pressure_service.mojom", "content_index/content_index.mojom", "context_menu/context_menu.mojom", "conversions/attribution_data_host.mojom",
diff --git a/third_party/blink/public/mojom/compute_pressure/DIR_METADATA b/third_party/blink/public/mojom/compute_pressure/DIR_METADATA deleted file mode 100644 index dcc8a85..0000000 --- a/third_party/blink/public/mojom/compute_pressure/DIR_METADATA +++ /dev/null
@@ -1,2 +0,0 @@ -mixins: "//content/browser/compute_pressure/COMMON_METADATA" -
diff --git a/third_party/blink/public/mojom/compute_pressure/OWNERS b/third_party/blink/public/mojom/compute_pressure/OWNERS deleted file mode 100644 index 32024c4..0000000 --- a/third_party/blink/public/mojom/compute_pressure/OWNERS +++ /dev/null
@@ -1,4 +0,0 @@ -file://content/browser/compute_pressure/OWNERS - -per-file *.mojom=set noparent -per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/third_party/blink/public/mojom/compute_pressure/pressure_service.mojom b/third_party/blink/public/mojom/compute_pressure/pressure_service.mojom deleted file mode 100644 index 36a73eaab..0000000 --- a/third_party/blink/public/mojom/compute_pressure/pressure_service.mojom +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module blink.mojom; - -import "services/device/public/mojom/pressure_update.mojom"; - -// Implemented by renderers to receive compute pressure info from the browser. -// -interface PressureObserver { - // Updates to an observer are rate-limited. Observers receive updates at most - // once per second. - OnUpdate(device.mojom.PressureUpdate update); -}; - -// Result of PressureService.BindObserver(). -enum PressureStatus { - kOk, - - // The underlying platform does not report compute pressure information or - // the renderer is not allowed access to the feature. - kNotSupported, -}; - -// The interface is implemented in the browser and consumed by renderers. The -// interface is only accessible to frames (and not workers). Each frame that -// accesses the API creates a separate connection. -interface PressureService { - // Subscribes to updates on the device's PressureState. - // - // `observer` is active (eligible for notifications) as soon as - // binding completes. Observation is stopped by - // disconnecting the mojo pipe. - BindObserver(pending_remote<PressureObserver> observer) - => (PressureStatus status); -};
diff --git a/third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom b/third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom index cbd9042..d145e25a 100644 --- a/third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom +++ b/third_party/blink/public/mojom/fenced_frame/fenced_frame_config.mojom
@@ -91,6 +91,8 @@ struct SharedStorageBudgetMetadata { url.mojom.Origin origin; double budget_to_charge; + bool top_navigated; + bool report_event_called; }; union PotentiallyOpaqueSharedStorageBudgetMetadata {
diff --git a/third_party/blink/public/mojom/navigation/navigation_params.mojom b/third_party/blink/public/mojom/navigation/navigation_params.mojom index f2935198..85cbb65 100644 --- a/third_party/blink/public/mojom/navigation/navigation_params.mojom +++ b/third_party/blink/public/mojom/navigation/navigation_params.mojom
@@ -296,6 +296,15 @@ // taking into account the origin computed by the renderer. blink.mojom.StorageKey storage_key; + // The storage key here is the one the browser process believes the renderer + // should use when binding session storage. This may differ from `storage_key` + // as a deprecation trial can prevent the partitioning of session storage. + // The document loader should verify this storage key is (1) the same as + // `storage_key` or (2) a first-party storage key at `storage_key.origin`. + // + // TODO(crbug.com/1407150): Remove this when deprecation trial is complete. + blink.mojom.StorageKey session_storage_key; + // Whether or not the user agent override string should be used. bool is_overriding_user_agent = false;
diff --git a/third_party/blink/public/web/modules/media/audio/audio_device_factory.h b/third_party/blink/public/web/modules/media/audio/audio_device_factory.h index 69ddb5d..7a772428 100644 --- a/third_party/blink/public/web/modules/media/audio/audio_device_factory.h +++ b/third_party/blink/public/web/modules/media/audio/audio_device_factory.h
@@ -66,9 +66,11 @@ const media::AudioSinkParameters& params); // A helper to get device info in the absence of AudioOutputDevice. + // |device_id| identifies which device we are getting info from. + // |frame_token| is used to created a temporary sink to retrieve the info. virtual media::OutputDeviceInfo GetOutputDeviceInfo( const LocalFrameToken& frame_token, - const media::AudioSinkParameters& params); + const std::string& device_id); // Creates an AudioCapturerSource using the currently registered factory. // |frame_token| refers to the RenderFrame containing the entity
diff --git a/third_party/blink/public/web/web_navigation_params.h b/third_party/blink/public/web/web_navigation_params.h index 1683e5d..ba0e1e6 100644 --- a/third_party/blink/public/web/web_navigation_params.h +++ b/third_party/blink/public/web/web_navigation_params.h
@@ -350,6 +350,15 @@ // taking into account the origin computed by the renderer. StorageKey storage_key; + // The storage key here is the one the browser process believes the renderer + // should use when binding session storage. This may differ from `storage_key` + // as a deprecation trial can prevent the partitioning of session storage. + // The document loader should verify this storage key is (1) the same as + // `storage_key` or (2) a first-party storage key at `storage_key.origin`. + // + // TODO(crbug.com/1407150): Remove this when deprecation trial is complete. + StorageKey session_storage_key; + blink::DocumentToken document_token; // The devtools token for this navigation. See DocumentLoader // for details.
diff --git a/third_party/blink/renderer/core/css/css_font_face_source.cc b/third_party/blink/renderer/core/css/css_font_face_source.cc index e139e978c..14d201e2 100644 --- a/third_party/blink/renderer/core/css/css_font_face_source.cc +++ b/third_party/blink/renderer/core/css/css_font_face_source.cc
@@ -61,8 +61,9 @@ } bool is_unique_match = false; - FontCacheKey key = - font_description.CacheKey(FontFaceCreationParams(), is_unique_match); + bool is_generic_family = false; + FontCacheKey key = font_description.CacheKey( + FontFaceCreationParams(), is_unique_match, is_generic_family); // Get or create the font data. Take care to avoid dangling references into // font_data_table_, because it is modified below during pruning.
diff --git a/third_party/blink/renderer/core/css/css_font_face_source_test.cc b/third_party/blink/renderer/core/css/css_font_face_source_test.cc index bbd29566..32d197d2 100644 --- a/third_party/blink/renderer/core/css/css_font_face_source_test.cc +++ b/third_party/blink/renderer/core/css/css_font_face_source_test.cc
@@ -46,7 +46,9 @@ font_description.SetSizeAdjust(size); font_description.SetAdjustedSize(size); bool is_unique_match = false; - return font_description.CacheKey(FontFaceCreationParams(), is_unique_match) + bool is_generic_family = false; + return font_description + .CacheKey(FontFaceCreationParams(), is_unique_match, is_generic_family) .GetHash(); } } // namespace @@ -56,8 +58,8 @@ // Even if the hash value collide, fontface cache should return different // value for different fonts, values determined experimentally. - constexpr float kEqualHashesFirst = 11410; - constexpr float kEqualHashesSecond = 2598; + constexpr float kEqualHashesFirst = 2157; + constexpr float kEqualHashesSecond = 534; EXPECT_EQ(SimulateHashCalculation(kEqualHashesFirst), SimulateHashCalculation(kEqualHashesSecond)); EXPECT_NE(font_face_source.GetFontDataForSize(kEqualHashesFirst),
diff --git a/third_party/blink/renderer/core/css/css_segmented_font_face.cc b/third_party/blink/renderer/core/css/css_segmented_font_face.cc index 6f41c96d..72cbab1 100644 --- a/third_party/blink/renderer/core/css/css_segmented_font_face.cc +++ b/third_party/blink/renderer/core/css/css_segmented_font_face.cc
@@ -25,6 +25,7 @@ #include "third_party/blink/renderer/core/css/css_segmented_font_face.h" +#include "base/debug/dump_without_crashing.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "third_party/blink/renderer/core/css/cascade_layer_map.h" @@ -112,8 +113,9 @@ } bool is_unique_match = false; - FontCacheKey key = - font_description.CacheKey(FontFaceCreationParams(), is_unique_match); + bool is_generic_family = false; + FontCacheKey key = font_description.CacheKey( + FontFaceCreationParams(), is_unique_match, is_generic_family); // font_data_table_ caches FontData and SegmentedFontData instances, which // provide SimpleFontData objects containing FontPlatformData objects. In the @@ -266,7 +268,7 @@ // here, possibly caused by ExecutionContext or Document lifecycle issues. // TODO(crbug.com/1250831): Find out the root cause and fix it. if (!new_font_face.GetDocument() || !existing_font_face.GetDocument()) { - NOTREACHED(); + base::debug::DumpWithoutCrashing(); // In the buggy case, to ensure a stable ordering, font faces without a // document are considered higher priority. return !new_font_face.GetDocument();
diff --git a/third_party/blink/renderer/core/css/css_selector.h b/third_party/blink/renderer/core/css/css_selector.h index 04bb44c1..9beb399f 100644 --- a/third_party/blink/renderer/core/css/css_selector.h +++ b/third_party/blink/renderer/core/css/css_selector.h
@@ -35,7 +35,7 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/heap/visitor.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/core/css/cssom/css_numeric_value.cc b/third_party/blink/renderer/core/css/cssom/css_numeric_value.cc index ebee6668..d8cb0ff 100644 --- a/third_party/blink/renderer/core/css/cssom/css_numeric_value.cc +++ b/third_party/blink/renderer/core/css/cssom/css_numeric_value.cc
@@ -153,7 +153,10 @@ return CSSMathSum::Create(std::move(values)); } - DCHECK(root.IsOperation()); + // TODO(crbug.com/1376521): Implement Typed OM API for `anchor()`, and turn + // the CHECK below back into a DCHECK. + + CHECK(root.IsOperation()); CSSNumericValueVector values;
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index 75982c85..bdc2561 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -1952,6 +1952,10 @@ return nullptr; } + if (!args.AtEnd()) { + return nullptr; + } + cssvalue::CSSColorMixValue* result = MakeGarbageCollected<cssvalue::CSSColorMixValue>( color1, color2, p1, p2, color_space, hue_interpolation_method);
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index d0c89c0..0a53476 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -83,7 +83,7 @@ #include "third_party/blink/renderer/platform/timer.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/casting.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
diff --git a/third_party/blink/renderer/core/dom/events/event_path.cc b/third_party/blink/renderer/core/dom/events/event_path.cc index 8d18c89..8eeb091 100644 --- a/third_party/blink/renderer/core/dom/events/event_path.cc +++ b/third_party/blink/renderer/core/dom/events/event_path.cc
@@ -35,7 +35,6 @@ #include "third_party/blink/renderer/core/html/html_slot_element.h" #include "third_party/blink/renderer/core/input/touch.h" #include "third_party/blink/renderer/core/input/touch_list.h" -#include "third_party/blink/renderer/platform/instrumentation/histogram.h" namespace blink { @@ -121,10 +120,6 @@ } void EventPath::CalculatePath() { - // TODO(crbug.com/1394555): This histogram should be removed once the UMA - // study DocumentEventNodePathCaching is complete. - SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Blink.EventPath.CalculateTime"); - DCHECK(node_); DCHECK(node_event_contexts_.empty());
diff --git a/third_party/blink/renderer/core/execution_context/window_agent_factory.cc b/third_party/blink/renderer/core/execution_context/window_agent_factory.cc index 44b101e..6041c6c 100644 --- a/third_party/blink/renderer/core/execution_context/window_agent_factory.cc +++ b/third_party/blink/renderer/core/execution_context/window_agent_factory.cc
@@ -9,7 +9,6 @@ #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h" #include "third_party/blink/renderer/platform/wtf/hash_functions.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/text/string_hash.h" @@ -107,36 +106,4 @@ visitor->Trace(agent_group_scheduler_); } -// static -unsigned WindowAgentFactory::SchemeAndRegistrableDomainTraits::GetHash( - const SchemeAndRegistrableDomain& value) { - return WTF::HashInts(WTF::GetHash(value.scheme), - WTF::GetHash(value.registrable_domain)); -} - -// static -bool WindowAgentFactory::SchemeAndRegistrableDomainTraits::Equal( - const SchemeAndRegistrableDomain& x, - const SchemeAndRegistrableDomain& y) { - return x.scheme == y.scheme && x.registrable_domain == y.registrable_domain; -} - -// static -bool WindowAgentFactory::SchemeAndRegistrableDomainTraits::IsEmptyValue( - const SchemeAndRegistrableDomain& value) { - return HashTraits<String>::IsEmptyValue(value.scheme); -} - -// static -bool WindowAgentFactory::SchemeAndRegistrableDomainTraits::IsDeletedValue( - const SchemeAndRegistrableDomain& value) { - return HashTraits<String>::IsDeletedValue(value.scheme); -} - -// static -void WindowAgentFactory::SchemeAndRegistrableDomainTraits:: - ConstructDeletedValue(SchemeAndRegistrableDomain& slot) { - HashTraits<String>::ConstructDeletedValue(slot.scheme); -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/execution_context/window_agent_factory.h b/third_party/blink/renderer/core/execution_context/window_agent_factory.h index 2f74cbfd..3c3b63b 100644 --- a/third_party/blink/renderer/core/execution_context/window_agent_factory.h +++ b/third_party/blink/renderer/core/execution_context/window_agent_factory.h
@@ -9,7 +9,7 @@ #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/member.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -64,16 +64,9 @@ }; struct SchemeAndRegistrableDomainTraits - : SimpleClassHashTraits<SchemeAndRegistrableDomain> { - static constexpr bool kSafeToCompareToEmptyOrDeleted = false; - static unsigned GetHash(const SchemeAndRegistrableDomain&); - static bool Equal(const SchemeAndRegistrableDomain&, - const SchemeAndRegistrableDomain&); - - static bool IsEmptyValue(const SchemeAndRegistrableDomain&); - static bool IsDeletedValue(const SchemeAndRegistrableDomain& value); - static void ConstructDeletedValue(SchemeAndRegistrableDomain& slot); - }; + : TwoFieldsHashTraits<SchemeAndRegistrableDomain, + &SchemeAndRegistrableDomain::scheme, + &SchemeAndRegistrableDomain::registrable_domain> {}; // Use a shared instance of Agent for all frames if a frame may have the // universal access privilege. @@ -84,18 +77,14 @@ WeakMember<WindowAgent> file_url_agent_; // Use the SecurityOrigin itself as the key for opaque origins. - HeapHashMap<scoped_refptr<const SecurityOrigin>, - WeakMember<WindowAgent>, - SecurityOriginHashTraits> + HeapHashMap<scoped_refptr<const SecurityOrigin>, WeakMember<WindowAgent>> opaque_origin_agents_; // Use the SecurityOrigin itself as the key for origin-keyed origins. // TODO(wjmaclean,domenic): In future when logical cross-origin-isolation // (COI) is implemented, we should unify it with logical-OAC so that all the // origin-keyed isolation relies on a single mechanism. - HeapHashMap<scoped_refptr<const SecurityOrigin>, - WeakMember<WindowAgent>, - SecurityOriginHashTraits> + HeapHashMap<scoped_refptr<const SecurityOrigin>, WeakMember<WindowAgent>> origin_keyed_agent_cluster_agents_; // Use registerable domain as the key for general tuple origins.
diff --git a/third_party/blink/renderer/core/fetch/bytes_uploader.h b/third_party/blink/renderer/core/fetch/bytes_uploader.h index fb68056f..de4a34c7 100644 --- a/third_party/blink/renderer/core/fetch/bytes_uploader.h +++ b/third_party/blink/renderer/core/fetch/bytes_uploader.h
@@ -16,7 +16,7 @@ #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/heap/prefinalizer.h" #include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace base { class SingleThreadTaskRunner;
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 069ab9f..efb8a3d 100644 --- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc +++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -59,7 +59,7 @@ #include "third_party/blink/renderer/platform/network/http_names.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
diff --git a/third_party/blink/renderer/core/frame/dom_window.h b/third_party/blink/renderer/core/frame/dom_window.h index e0e3b7e5..0cd48970 100644 --- a/third_party/blink/renderer/core/frame/dom_window.h +++ b/third_party/blink/renderer/core/frame/dom_window.h
@@ -18,7 +18,7 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/forward.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink {
diff --git a/third_party/blink/renderer/core/frame/find_in_page.h b/third_party/blink/renderer/core/frame/find_in_page.h index 8f7794a6..46180f49 100644 --- a/third_party/blink/renderer/core/frame/find_in_page.h +++ b/third_party/blink/renderer/core/frame/find_in_page.h
@@ -20,7 +20,7 @@ #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index 0ca0cb7..c88166f 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -2401,6 +2401,11 @@ storage_key_ = storage_key; } +void LocalDOMWindow::SetSessionStorageKey( + const BlinkStorageKey& session_storage_key) { + session_storage_key_ = session_storage_key; +} + bool LocalDOMWindow::IsPaymentRequestTokenActive() const { return payment_request_token_.IsActive(); }
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h index f222a6e..5d5bac6 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.h +++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -467,6 +467,14 @@ const BlinkStorageKey& GetStorageKey() const { return storage_key_; } void SetStorageKey(const BlinkStorageKey& storage_key); + // This storage key must only be used when binding session storage. + // + // TODO(crbug.com/1407150): Remove this when deprecation trial is complete. + const BlinkStorageKey& GetSessionStorageKey() const { + return session_storage_key_; + } + void SetSessionStorageKey(const BlinkStorageKey& session_storage_key); + void DidReceiveUserActivation(); // Returns the state of the |PaymentRequestToken| in this document. @@ -623,6 +631,13 @@ // The storage key for this LocalDomWindow. BlinkStorageKey storage_key_; + // The storage key here is the one to use when binding session storage. This + // may differ from `storage_key_` as a deprecation trial can prevent the + // partitioning of session storage. + // + // TODO(crbug.com/1407150): Remove this when deprecation trial is complete. + BlinkStorageKey session_storage_key_; + // Fire "online" and "offline" events. Member<NetworkStateObserver> network_state_observer_;
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h index 21530c5..bbcc1a2 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client.h +++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -231,8 +231,7 @@ // Notifies the observers of the origins for which subresource redirect // optimizations can be preloaded. virtual void PreloadSubresourceOptimizationsForOrigins( - const WTF::HashSet<scoped_refptr<const SecurityOrigin>, - SecurityOriginHashTraits>& origins) {} + const WTF::HashSet<scoped_refptr<const SecurityOrigin>>& origins) {} // Transmits the change in the set of watched CSS selectors property that // match any element on the frame.
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc index 4cb6976..77850c10 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc +++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -774,8 +774,7 @@ } void LocalFrameClientImpl::PreloadSubresourceOptimizationsForOrigins( - const WTF::HashSet<scoped_refptr<const SecurityOrigin>, - SecurityOriginHashTraits>& origins) { + const WTF::HashSet<scoped_refptr<const SecurityOrigin>>& origins) { if (WebLocalFrameClient* client = web_frame_->Client()) { std::vector<WebSecurityOrigin> origins_list; for (const auto& origin : origins) {
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h index aac491c..d3f976c 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h +++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -159,8 +159,8 @@ void DidObserveSoftNavigation(uint32_t count) override; void DidObserveLayoutShift(double score, bool after_input_or_scroll) override; void PreloadSubresourceOptimizationsForOrigins( - const WTF::HashSet<scoped_refptr<const SecurityOrigin>, - SecurityOriginHashTraits>& origins) override; + const WTF::HashSet<scoped_refptr<const SecurityOrigin>>& origins) + override; void SelectorMatchChanged(const Vector<String>& added_selectors, const Vector<String>& removed_selectors) override;
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc index a50d7ad..0496574 100644 --- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc +++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -620,6 +620,11 @@ return *fullscreen; } +// static +bool Fullscreen::HasFullscreenElements() { + return !FullscreenParamsMap().empty(); +} + Element* Fullscreen::FullscreenElementFrom(Document& document) { // The fullscreen element is the topmost element in the document's top layer // whose fullscreen flag is set, if any, and null otherwise.
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.h b/third_party/blink/renderer/core/fullscreen/fullscreen.h index 2864727..a529d3f 100644 --- a/third_party/blink/renderer/core/fullscreen/fullscreen.h +++ b/third_party/blink/renderer/core/fullscreen/fullscreen.h
@@ -65,6 +65,7 @@ static Element* FullscreenElementForBindingFrom(TreeScope&); static bool IsFullscreenElement(const Element&); static bool IsInFullscreenElementStack(const Element&); + static bool HasFullscreenElements(); static void RequestFullscreen(Element&); static ScriptPromise RequestFullscreen( @@ -147,7 +148,8 @@ }; inline bool Fullscreen::IsFullscreenElement(const Element& element) { - return FullscreenElementFrom(element.GetDocument()) == &element; + return UNLIKELY(HasFullscreenElements()) && + FullscreenElementFrom(element.GetDocument()) == &element; } } // namespace blink
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_descriptor_hash.h b/third_party/blink/renderer/core/html/custom/custom_element_descriptor_hash.h index 1ba29ac..6d7521cb 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_descriptor_hash.h +++ b/third_party/blink/renderer/core/html/custom/custom_element_descriptor_hash.h
@@ -14,23 +14,9 @@ template <> struct HashTraits<blink::CustomElementDescriptor> - : SimpleClassHashTraits<blink::CustomElementDescriptor> { - STATIC_ONLY(HashTraits); - static unsigned GetHash(const blink::CustomElementDescriptor& descriptor) { - return WTF::HashInts(WTF::GetHash(descriptor.GetName()), - WTF::GetHash(descriptor.LocalName())); - } - static const bool kEmptyValueIsZero = - HashTraits<AtomicString>::kEmptyValueIsZero; - - static bool IsDeletedValue(const blink::CustomElementDescriptor& value) { - return HashTraits<AtomicString>::IsDeletedValue(value.name_); - } - - static void ConstructDeletedValue(blink::CustomElementDescriptor& slot) { - HashTraits<AtomicString>::ConstructDeletedValue(slot.name_); - } -}; + : TwoFieldsHashTraits<blink::CustomElementDescriptor, + &blink::CustomElementDescriptor::name_, + &blink::CustomElementDescriptor::local_name_> {}; } // namespace WTF
diff --git a/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h b/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h index 16e62bb6..63a4073 100644 --- a/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h +++ b/third_party/blink/renderer/core/html/forms/color_chooser_ui_controller.h
@@ -35,7 +35,7 @@ #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" #include "third_party/blink/renderer/platform/text/platform_locale.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/core/html/media/video_wake_lock.h b/third_party/blink/renderer/core/html/media/video_wake_lock.h index c8cd092d..e57346c 100644 --- a/third_party/blink/renderer/core/html/media/video_wake_lock.h +++ b/third_party/blink/renderer/core/html/media/video_wake_lock.h
@@ -14,7 +14,7 @@ #include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h" #include "third_party/blink/renderer/core/page/page_visibility_observer.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc index d191b75..cfcaa4c 100644 --- a/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc +++ b/third_party/blink/renderer/core/html/parser/html_document_parser_fastpath_test.cc
@@ -9,7 +9,9 @@ #include "third_party/blink/renderer/core/dom/document_fragment.h" #include "third_party/blink/renderer/core/html/html_div_element.h" #include "third_party/blink/renderer/core/html/html_document.h" +#include "third_party/blink/renderer/core/html/parser/html_construction_site.h" #include "third_party/blink/renderer/core/testing/null_execution_context.h" +#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { namespace { @@ -59,5 +61,32 @@ HtmlFastPathResult::kSucceeded, 0); } +TEST(HTMLDocumentParserFastpathTest, MaximumHTMLParserDOMTreeDepth) { + ScopedNullExecutionContext execution_context; + auto* document = + HTMLDocument::CreateForTest(execution_context.GetExecutionContext()); + document->write("<body></body>"); + auto* div = MakeGarbageCollected<HTMLDivElement>(*document); + StringBuilder string_builder; + const unsigned depth = + HTMLConstructionSite::kMaximumHTMLParserDOMTreeDepth + 2; + // Create a very nested tree, with the deepest containing the id `deepest`. + for (unsigned i = 0; i < depth - 1; ++i) { + string_builder.Append("<div>"); + } + string_builder.Append("<div id='deepest'>"); + string_builder.Append("</div>"); + for (unsigned i = 0; i < depth - 1; ++i) { + string_builder.Append("</div>"); + } + div->setInnerHTML(string_builder.ToString()); + + // Because kMaximumHTMLParserDOMTreeDepth was encountered, the deepest + // node should have siblings. + Element* deepest = div->getElementById("deepest"); + ASSERT_TRUE(deepest); + EXPECT_EQ(deepest->parentNode()->CountChildren(), 3u); +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc index ce984a6..3cd42ba 100644 --- a/third_party/blink/renderer/core/layout/layout_shift_tracker.cc +++ b/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
@@ -594,8 +594,7 @@ double input_timestamp = LastInputTimestamp(); LayoutShift* entry = LayoutShift::Create(performance->now(), score_delta, had_recent_input, - input_timestamp, CreateAttributionList(), - PerformanceEntry::GetNavigationId(window), window); + input_timestamp, CreateAttributionList(), window); // Add WPT for LayoutShift. See crbug.com/1320878.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index 7ca7df7..a553333a 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -648,10 +648,15 @@ // Ignore outside list markers because they are already set to // |container_builder_.UnpositionedListMarker| in the constructor, unless // |ListMarkerOccupiesWholeLine|, which is handled like a regular child. - } else if (child.IsColumnSpanAll() && ConstraintSpace().IsInColumnBfc()) { + } else if (child.IsColumnSpanAll() && ConstraintSpace().IsInColumnBfc() && + ConstraintSpace().HasBlockFragmentation()) { // The child is a column spanner. If we have no breaks inside (in parallel // flows), we now need to finish this fragmentainer, then abort and let - // the column layout algorithm handle the spanner as a child. + // the column layout algorithm handle the spanner as a child. The + // HasBlockFragmentation() check above may seem redundant, but this is + // important if we're overflowing a clipped container. In such cases, we + // won't treat the spanner as one, since we shouldn't insert any breaks in + // that mode. DCHECK(!container_builder_.DidBreakSelf()); DCHECK(!container_builder_.FoundColumnSpanner()); DCHECK(!IsBreakInside(To<NGBlockBreakToken>(child_break_token)));
diff --git a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc index 20154089..d044baa 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -1165,10 +1165,12 @@ LayoutUnit block_offset) { NGBoxFragment fragment(ConstraintSpace().GetWritingDirection(), child); - // Only propagate the first-baseline from the first-column. - if (child.IsFirstForNode() && !container_builder_.FirstBaseline()) { - if (auto first_baseline = fragment.FirstBaseline()) - container_builder_.SetFirstBaseline(block_offset + *first_baseline); + // The first-baseline is the highest first-baseline of all fragments. + if (auto first_baseline = fragment.FirstBaseline()) { + LayoutUnit baseline = std::min( + block_offset + *first_baseline, + container_builder_.FirstBaseline().value_or(LayoutUnit::Max())); + container_builder_.SetFirstBaseline(baseline); } // The last-baseline is the lowest last-baseline of all fragments.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_early_break.h b/third_party/blink/renderer/core/layout/ng/ng_early_break.h index 58ae9011..8743335 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_early_break.h +++ b/third_party/blink/renderer/core/layout/ng/ng_early_break.h
@@ -9,7 +9,7 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h" #include "third_party/blink/renderer/core/layout/ng/ng_break_appeal.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc index 10bc2a4..0916c816 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -1872,13 +1872,7 @@ const NGConstraintSpace* fragmentainer_constraint_space, bool is_last_fragmentainer_so_far) { const NodeInfo& node_info = oof_node_to_layout.node_info; - const WritingDirectionMode candidate_writing_direction = - node_info.node.Style().GetWritingDirection(); - LogicalSize container_content_size_in_candidate_writing_mode = - node_info.container_physical_content_size.ConvertToLogical( - candidate_writing_direction.GetWritingMode()); const OffsetInfo& offset_info = oof_node_to_layout.offset_info; - LogicalOffset offset = offset_info.offset; // Reset the |layout_result| computed earlier to allow fragmentation in the // next layout pass, if needed. @@ -1889,23 +1883,9 @@ // Skip this step if we produced a fragment that can be reused when // estimating the block-size. if (!layout_result) { - bool should_use_fixed_block_size = offset_info.block_estimate.has_value(); - - // In some cases we will need the fragment size in order to calculate the - // offset. We may have to lay out to get the fragment size. For block - // fragmentation, we *need* to know the block-offset before layout. In other - // words, in that case, we may have to lay out, calculate the offset, and - // then lay out again at the correct block-offset. - if (fragmentainer_constraint_space && offset_info.initial_layout_result) - should_use_fixed_block_size = false; - - layout_result = GenerateFragment( - oof_node_to_layout, container_content_size_in_candidate_writing_mode, - offset_info.block_estimate, offset_info.node_dimensions, - offset.block_offset, oof_node_to_layout.break_token, - fragmentainer_constraint_space, should_use_fixed_block_size, - node_info.requires_content_before_breaking, - is_last_fragmentainer_so_far); + layout_result = + GenerateFragment(oof_node_to_layout, fragmentainer_constraint_space, + is_last_fragmentainer_so_far); } if (layout_result->Status() != NGLayoutResult::kSuccess) { @@ -1925,11 +1905,11 @@ ->IsDisplayFlexibleOrGridBox()) { node_info.node.GetLayoutBox()->SetMargin( offset_info.node_dimensions.margins.ConvertToPhysical( - candidate_writing_direction)); + node_info.node.Style().GetWritingDirection())); } layout_result->GetMutableForOutOfFlow().SetOutOfFlowPositionedOffset( - offset, + offset_info.offset, allow_first_tier_oof_cache_ && !offset_info.disable_first_tier_cache); return layout_result; @@ -1961,24 +1941,21 @@ // 2. To compute final fragment, when block size is known from the absolute // position calculation. const NGLayoutResult* NGOutOfFlowLayoutPart::GenerateFragment( - // TODO(mstensho): Reduce the number of arguments. Now that we pass - // NodeToLayout, many of the others are redundant. const NodeToLayout& oof_node_to_layout, - const LogicalSize& container_content_size_in_candidate_writing_mode, - const absl::optional<LayoutUnit>& block_estimate, - const NGLogicalOutOfFlowDimensions& node_dimensions, - const LayoutUnit block_offset, - const NGBlockBreakToken* break_token, const NGConstraintSpace* fragmentainer_constraint_space, - bool should_use_fixed_block_size, - bool requires_content_before_breaking, bool is_last_fragmentainer_so_far) { const NodeInfo& node_info = oof_node_to_layout.node_info; + const OffsetInfo& offset_info = oof_node_to_layout.offset_info; + const NGBlockBreakToken* break_token = oof_node_to_layout.break_token; const NGBlockNode& node = node_info.node; const auto& style = node.Style(); + const LayoutUnit block_offset = offset_info.offset.block_offset; + LogicalSize container_content_size_in_candidate_writing_mode = + node_info.container_physical_content_size.ConvertToLogical( + style.GetWritingDirection().GetWritingMode()); - LayoutUnit inline_size = node_dimensions.size.inline_size; - LayoutUnit block_size = block_estimate.value_or( + LayoutUnit inline_size = offset_info.node_dimensions.size.inline_size; + LayoutUnit block_size = offset_info.block_estimate.value_or( container_content_size_in_candidate_writing_mode.block_size); LogicalSize logical_size(inline_size, block_size); // Convert from logical size in the writing mode of the child to the logical @@ -1997,8 +1974,17 @@ builder.SetPercentageResolutionSize( container_content_size_in_candidate_writing_mode); builder.SetIsFixedInlineSize(true); - if (should_use_fixed_block_size) + + // In some cases we will need the fragment size in order to calculate the + // offset. We may have to lay out to get the fragment size. For block + // fragmentation, we *need* to know the block-offset before layout. In other + // words, in that case, we may have to lay out, calculate the offset, and then + // lay out again at the correct block-offset. + if (offset_info.block_estimate.has_value() && + (!fragmentainer_constraint_space || !offset_info.initial_layout_result)) { builder.SetIsFixedBlockSize(true); + } + if (fragmentainer_constraint_space) { if (container_builder_->Node().IsPaginatedRoot() && style.GetPosition() == EPosition::kFixed && @@ -2014,7 +2000,7 @@ } else { SetupSpaceBuilderForFragmentation( *fragmentainer_constraint_space, node, block_offset, &builder, - /* is_new_fc */ true, requires_content_before_breaking); + /* is_new_fc */ true, node_info.requires_content_before_breaking); // Out-of-flow positioned elements whose containing block is inside // clipped overflow shouldn't generate any additional fragmentainers. Just
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h index 088bb527..1a54fd8c 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -350,14 +350,7 @@ const NGLayoutResult* GenerateFragment( const NodeToLayout& oof_node_to_layout, - const LogicalSize& container_content_size_in_candidate_writing_mode, - const absl::optional<LayoutUnit>& block_estimate, - const NGLogicalOutOfFlowDimensions& node_dimensions, - const LayoutUnit block_offset, - const NGBlockBreakToken* break_token, const NGConstraintSpace* fragmentainer_constraint_space, - bool should_use_fixed_block_size, - bool requires_content_before_breaking, bool is_last_fragmentainer_so_far); // Performs layout on the OOFs stored in |pending_descendants| and
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index c443b6d..247afc9 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -249,6 +249,7 @@ scoped_refptr<SecurityOrigin> origin_to_commit; AtomicString origin_calculation_debug_info; BlinkStorageKey storage_key; + BlinkStorageKey session_storage_key; WebNavigationType navigation_type; DocumentLoadTiming document_load_timing; base::TimeTicks time_of_last_data_received; @@ -468,6 +469,7 @@ ? nullptr : params_->origin_to_commit.Get()->IsolatedCopy()), storage_key_(std::move(params_->storage_key)), + session_storage_key_(std::move(params_->session_storage_key)), navigation_type_(navigation_type), document_load_timing_(*this), service_worker_network_provider_( @@ -2346,12 +2348,51 @@ // to preserve the information that is stripped due to the key being re-made. const auto& storage_key_with_3psp = storage_key_.CopyWithForceEnabledThirdPartyStoragePartitioning(); + + // If the nonce isn't null, we need to ensure the top level site matches + // origin and the ancestor chain bit is kSameSite. The ancestor chain bit + // should be fine as it's from the same StorageKey that already had a nonce, + // but it's possible `security_origin` doesn't match the StorageKey's site. + // TODO(https://crbug.com/888079): Just use the origin in the storage key. + BlinkSchemefulSite top_level_site(security_origin); + if (!storage_key_.GetNonce()) { + top_level_site = storage_key_with_3psp.GetTopLevelSite(); + } + // TODO(https://crbug.com/888079): Just use the storage key sent by the // browser once the browser will be able to compute the origin in all cases. frame_->DomWindow()->SetStorageKey( - BlinkStorageKey(security_origin, storage_key_with_3psp.GetTopLevelSite(), + BlinkStorageKey(security_origin, top_level_site, base::OptionalToPtr(storage_key_.GetNonce()), storage_key_with_3psp.GetAncestorChainBit())); + if (storage_key_ == session_storage_key_ || + storage_key_.GetSecurityOrigin()->IsOpaque() || + session_storage_key_.GetSecurityOrigin()->IsOpaque()) { + // If the `storage_key_` and `session_storage_key_` match (or either are + // opaque), we should just use whatever storage key was built above as we + // aren't preventing partition. + frame_->DomWindow()->SetSessionStorageKey( + frame_->DomWindow()->GetStorageKey()); + } else { + // Otherwise, we first must verify that the requested StorageKey to use for + // binding session storage has the same SecurityOrigin as the actual + // storage key. The purpose of this path is to change the partition for a + // given origin, not to allow access to another origin's data. + DCHECK(session_storage_key_ == + BlinkStorageKey(storage_key_.GetSecurityOrigin())); + // We use the renderer side origin when setting the StorageKey on the path + // above, so we check that the renderer's understanding of the origin + // matches the session storage StorageKey. This is another precaution to + // to prevent cross-origin partition binding. + // TODO(https://crbug.com/888079): Depend on the origin in the StorageKey. + if (session_storage_key_.GetSecurityOrigin()->IsSameOriginWith( + security_origin.get())) { + frame_->DomWindow()->SetSessionStorageKey(session_storage_key_); + } else { + frame_->DomWindow()->SetSessionStorageKey( + frame_->DomWindow()->GetStorageKey()); + } + } // Conceptually, SecurityOrigin doesn't have to be initialized after sandbox // flags are applied, but there's a UseCounter in SetSecurityOrigin() that
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h index ebd07ea..f8839bb 100644 --- a/third_party/blink/renderer/core/loader/document_loader.h +++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -85,7 +85,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" #include "third_party/blink/renderer/platform/storage/blink_storage_key.h" #include "third_party/blink/renderer/platform/weborigin/referrer.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/shared_buffer.h" @@ -661,6 +661,13 @@ AtomicString origin_calculation_debug_info_; blink::BlinkStorageKey storage_key_; + // The storage key here is the one the browser process believes the renderer + // should use when binding session storage. This may differ from + // `storage_key_` as a deprecation trial can prevent the partitioning of + // session storage. + // + // TODO(crbug.com/1407150): Remove this when deprecation trial is complete. + blink::BlinkStorageKey session_storage_key_; WebNavigationType navigation_type_; DocumentLoadTiming document_load_timing_;
diff --git a/third_party/blink/renderer/core/loader/document_loader_test.cc b/third_party/blink/renderer/core/loader/document_loader_test.cc index 9fac04fa..1112319 100644 --- a/third_party/blink/renderer/core/loader/document_loader_test.cc +++ b/third_party/blink/renderer/core/loader/document_loader_test.cc
@@ -603,12 +603,11 @@ SharedBuffer::Create(), other_origin_url); params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url)); - net::SchemefulSite top_level_site = - net::SchemefulSite(url::Origin::Create(GURL(other_origin_url))); + url::Origin origin; auto nonce = base::UnguessableToken::Create(); - StorageKey storage_key_to_commit = - StorageKey::CreateWithOptionalNonce(url::Origin(), top_level_site, &nonce, - mojom::AncestorChainBit::kSameSite); + StorageKey storage_key_to_commit = StorageKey::CreateWithOptionalNonce( + origin, net::SchemefulSite(origin), &nonce, + mojom::AncestorChainBit::kSameSite); params->storage_key = storage_key_to_commit; LocalFrame* local_frame =
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h index 2f18b69..08bba35e 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h +++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
@@ -18,7 +18,7 @@ #include "third_party/blink/renderer/platform/graphics/graphics_context.h" #include "third_party/blink/renderer/platform/transforms/affine_transform.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/core/timing/back_forward_cache_restoration.cc b/third_party/blink/renderer/core/timing/back_forward_cache_restoration.cc index f3bdd66b..9fe1e30d 100644 --- a/third_party/blink/renderer/core/timing/back_forward_cache_restoration.cc +++ b/third_party/blink/renderer/core/timing/back_forward_cache_restoration.cc
@@ -12,13 +12,8 @@ DOMHighResTimeStamp start_time, DOMHighResTimeStamp pageshow_event_start, DOMHighResTimeStamp pageshow_event_end, - uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(g_empty_atom, - start_time, - pageshow_event_start, - navigation_id, - source), + : PerformanceEntry(g_empty_atom, start_time, pageshow_event_start, source), pageshow_event_start_(pageshow_event_start), pageshow_event_end_(pageshow_event_end) {} BackForwardCacheRestoration::~BackForwardCacheRestoration() = default;
diff --git a/third_party/blink/renderer/core/timing/back_forward_cache_restoration.h b/third_party/blink/renderer/core/timing/back_forward_cache_restoration.h index f20da0b2..d5c879b8 100644 --- a/third_party/blink/renderer/core/timing/back_forward_cache_restoration.h +++ b/third_party/blink/renderer/core/timing/back_forward_cache_restoration.h
@@ -18,7 +18,6 @@ BackForwardCacheRestoration(DOMHighResTimeStamp start_time, DOMHighResTimeStamp pageshow_event_start, DOMHighResTimeStamp pageshow_event_end, - uint32_t navigation_id, DOMWindow* source); ~BackForwardCacheRestoration() override; const AtomicString& entryType() const override;
diff --git a/third_party/blink/renderer/core/timing/largest_contentful_paint.cc b/third_party/blink/renderer/core/timing/largest_contentful_paint.cc index 40b4a21..844950a 100644 --- a/third_party/blink/renderer/core/timing/largest_contentful_paint.cc +++ b/third_party/blink/renderer/core/timing/largest_contentful_paint.cc
@@ -20,13 +20,8 @@ const AtomicString& id, const String& url, Element* element, - uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(g_empty_atom, - start_time, - start_time, - navigation_id, - source), + : PerformanceEntry(g_empty_atom, start_time, start_time, source), size_(size), render_time_(render_time), load_time_(load_time),
diff --git a/third_party/blink/renderer/core/timing/largest_contentful_paint.h b/third_party/blink/renderer/core/timing/largest_contentful_paint.h index c20ced0..1c4b5e7 100644 --- a/third_party/blink/renderer/core/timing/largest_contentful_paint.h +++ b/third_party/blink/renderer/core/timing/largest_contentful_paint.h
@@ -27,7 +27,6 @@ const AtomicString& id, const String& url, Element* element, - uint32_t navigation_id, DOMWindow* source); ~LargestContentfulPaint() override;
diff --git a/third_party/blink/renderer/core/timing/layout_shift.cc b/third_party/blink/renderer/core/timing/layout_shift.cc index 847789d..b71b43c 100644 --- a/third_party/blink/renderer/core/timing/layout_shift.cc +++ b/third_party/blink/renderer/core/timing/layout_shift.cc
@@ -16,11 +16,9 @@ bool input_detected, double input_timestamp, AttributionList sources, - uint32_t navigation_id, DOMWindow* source) { return MakeGarbageCollected<LayoutShift>(start_time, value, input_detected, - input_timestamp, sources, - navigation_id, source); + input_timestamp, sources, source); } LayoutShift::LayoutShift(double start_time, @@ -28,13 +26,8 @@ bool input_detected, double input_timestamp, AttributionList sources, - uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(g_empty_atom, - start_time, - start_time, - navigation_id, - source), + : PerformanceEntry(g_empty_atom, start_time, start_time, source), value_(value), had_recent_input_(input_detected), most_recent_input_timestamp_(input_timestamp),
diff --git a/third_party/blink/renderer/core/timing/layout_shift.h b/third_party/blink/renderer/core/timing/layout_shift.h index 6476499..2bcb710 100644 --- a/third_party/blink/renderer/core/timing/layout_shift.h +++ b/third_party/blink/renderer/core/timing/layout_shift.h
@@ -31,7 +31,6 @@ bool input_detected, double input_timestamp, AttributionList sources, - uint32_t navigation_id, DOMWindow* source); explicit LayoutShift(double start_time, @@ -39,7 +38,6 @@ bool input_detected, double input_timestamp, AttributionList sources, - uint32_t navigation_id, DOMWindow* source); ~LayoutShift() override;
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc index a301e9a..b2ade8b 100644 --- a/third_party/blink/renderer/core/timing/performance.cc +++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -163,19 +163,72 @@ entries[rightIndex] = tmp; } +inline bool CheckName(const PerformanceEntry* entry, + const AtomicString& maybe_name) { + // If we're not filtering by name, then any entry matches. + if (!maybe_name) { + return true; + } + return entry->name() == maybe_name; +} + } // namespace PerformanceEntryVector MergePerformanceEntryVectors( const PerformanceEntryVector& first_entry_vector, - const PerformanceEntryVector& second_entry_vector) { + const PerformanceEntryVector& second_entry_vector, + const AtomicString& maybe_name) { PerformanceEntryVector merged_entries; merged_entries.reserve(first_entry_vector.size() + second_entry_vector.size()); - std::merge(first_entry_vector.begin(), first_entry_vector.end(), - second_entry_vector.begin(), second_entry_vector.end(), - std::back_inserter(merged_entries), - PerformanceEntry::StartTimeCompareLessThan); + auto* first_it = first_entry_vector.begin(); + auto* first_end = first_entry_vector.end(); + auto* second_it = second_entry_vector.begin(); + auto* second_end = second_entry_vector.end(); + + // Advance the second iterator past any entries with disallowed names. + while (second_it != second_end && !CheckName(*second_it, maybe_name)) { + ++second_it; + } + + auto PushBackSecondIteratorAndAdvance = [&]() { + DCHECK(CheckName(*second_it, maybe_name)); + merged_entries.push_back(*second_it); + ++second_it; + while (second_it != second_end && !CheckName(*second_it, maybe_name)) { + ++second_it; + } + }; + + // What follows is based roughly on a reference implementation of std::merge, + // except that after copying a value from the second iterator, it must also + // advance the second iterator past any entries with disallowed names. + + while (first_it != first_end) { + // If the second iterator has ended, just copy the rest of the contents + // from the first iterator. + if (second_it == second_end) { + std::copy(first_it, first_end, std::back_inserter(merged_entries)); + break; + } + + // Add an entry to the result vector from either the first or second + // iterator, whichever has an earlier time. The first iterator wins ties. + if (PerformanceEntry::StartTimeCompareLessThan(*second_it, *first_it)) { + PushBackSecondIteratorAndAdvance(); + } else { + DCHECK(CheckName(*first_it, maybe_name)); + merged_entries.push_back(*first_it); + ++first_it; + } + } + + // If there are still entries in the second iterator after the first iterator + // has ended, copy all remaining entries that have allowed names. + while (second_it != second_end) { + PushBackSecondIteratorAndAdvance(); + } return merged_entries; } @@ -281,11 +334,13 @@ } } -PerformanceEntryVector Performance::GetEntriesForCurrentFrame() { +PerformanceEntryVector Performance::GetEntriesForCurrentFrame( + const AtomicString& maybe_name) { PerformanceEntryVector entries; - entries = MergePerformanceEntryVectors(entries, resource_timing_buffer_); - if (first_input_timing_) { + entries = MergePerformanceEntryVectors(entries, resource_timing_buffer_, + maybe_name); + if (first_input_timing_ && CheckName(first_input_timing_, maybe_name)) { InsertEntryIntoSortedBuffer(entries, *first_input_timing_, kDoNotRecordSwaps); } @@ -294,24 +349,36 @@ } // This extra checking is needed when WorkerPerformance // calls this method. - if (navigation_timing_) { + if (navigation_timing_ && CheckName(navigation_timing_, maybe_name)) { InsertEntryIntoSortedBuffer(entries, *navigation_timing_, kDoNotRecordSwaps); } if (user_timing_) { - entries = MergePerformanceEntryVectors(entries, user_timing_->GetMarks()); - entries = - MergePerformanceEntryVectors(entries, user_timing_->GetMeasures()); + if (maybe_name) { + // UserTiming already stores lists of marks and measures by name, so + // requesting them directly is much more efficient than getting the full + // lists of marks and measures and then filtering during the merge. + entries = MergePerformanceEntryVectors( + entries, user_timing_->GetMarks(maybe_name), g_null_atom); + entries = MergePerformanceEntryVectors( + entries, user_timing_->GetMeasures(maybe_name), g_null_atom); + } else { + entries = MergePerformanceEntryVectors(entries, user_timing_->GetMarks(), + g_null_atom); + entries = MergePerformanceEntryVectors( + entries, user_timing_->GetMeasures(), g_null_atom); + } } if (paint_entries_timing_.size()) { - entries = MergePerformanceEntryVectors(entries, paint_entries_timing_); + entries = MergePerformanceEntryVectors(entries, paint_entries_timing_, + maybe_name); } if (RuntimeEnabledFeatures::NavigationIdEnabled(GetExecutionContext())) { entries = MergePerformanceEntryVectors( - entries, back_forward_cache_restoration_buffer_); + entries, back_forward_cache_restoration_buffer_, maybe_name); } if (RuntimeEnabledFeatures::SoftNavigationHeuristicsEnabled( @@ -319,7 +386,8 @@ soft_navigation_buffer_.size()) { UseCounter::Count(GetExecutionContext(), WebFeature::kSoftNavigationHeuristics); - entries = MergePerformanceEntryVectors(entries, soft_navigation_buffer_); + entries = MergePerformanceEntryVectors(entries, soft_navigation_buffer_, + maybe_name); } return entries; @@ -345,7 +413,8 @@ } PerformanceEntryVector Performance::GetEntriesByTypeForCurrentFrame( - const AtomicString& entry_type) { + const AtomicString& entry_type, + const AtomicString& maybe_name) { PerformanceEntry::EntryType type = PerformanceEntry::ToEntryTypeEnum(entry_type); if (!PerformanceEntry::IsValidTimelineEntryType(type)) { @@ -358,23 +427,33 @@ } return empty_entries; } - return getEntriesByTypeInternal(type); + return getEntriesByTypeInternal(type, maybe_name); } PerformanceEntryVector Performance::getEntriesByTypeInternal( - PerformanceEntry::EntryType type) { + PerformanceEntry::EntryType type, + const AtomicString& maybe_name) { + // This vector may be used by any cases below which require local storage. + // Cases which refer to pre-existing vectors may simply set `entries` instead. + PerformanceEntryVector entries_storage; + + const PerformanceEntryVector* entries = &entries_storage; + bool already_filtered_by_name = false; switch (type) { case PerformanceEntry::kResource: UseCounter::Count(GetExecutionContext(), WebFeature::kResourceTiming); - return resource_timing_buffer_; + entries = &resource_timing_buffer_; + break; case PerformanceEntry::kElement: - return element_timing_buffer_; + entries = &element_timing_buffer_; + break; case PerformanceEntry::kEvent: UseCounter::Count(GetExecutionContext(), WebFeature::kEventTimingExplicitlyRequested); - return event_timing_buffer_; + entries = &event_timing_buffer_; + break; case PerformanceEntry::kFirstInput: UseCounter::Count(GetExecutionContext(), @@ -382,7 +461,7 @@ UseCounter::Count(GetExecutionContext(), WebFeature::kEventTimingFirstInputExplicitlyRequested); if (first_input_timing_) - return {first_input_timing_}; + entries_storage = {first_input_timing_}; break; case PerformanceEntry::kNavigation: @@ -390,45 +469,62 @@ if (!navigation_timing_) navigation_timing_ = CreateNavigationTimingInstance(); if (navigation_timing_) - return {navigation_timing_}; + entries_storage = {navigation_timing_}; break; case PerformanceEntry::kMark: - if (user_timing_) - return user_timing_->GetMarks(); + if (user_timing_) { + if (maybe_name) { + entries_storage = user_timing_->GetMarks(maybe_name); + already_filtered_by_name = true; + } else { + entries_storage = user_timing_->GetMarks(); + } + } break; case PerformanceEntry::kMeasure: - if (user_timing_) - return user_timing_->GetMeasures(); + if (user_timing_) { + if (maybe_name) { + entries_storage = user_timing_->GetMeasures(maybe_name); + already_filtered_by_name = true; + } else { + entries_storage = user_timing_->GetMeasures(); + } + } break; case PerformanceEntry::kPaint: { UseCounter::Count(GetExecutionContext(), WebFeature::kPaintTimingRequested); - return paint_entries_timing_; + entries = &paint_entries_timing_; + break; } case PerformanceEntry::kLongTask: - return longtask_buffer_; + entries = &longtask_buffer_; + break; // TaskAttribution entries are only associated to longtask entries. case PerformanceEntry::kTaskAttribution: break; case PerformanceEntry::kLayoutShift: - return layout_shift_buffer_; + entries = &layout_shift_buffer_; + break; case PerformanceEntry::kLargestContentfulPaint: - return largest_contentful_paint_buffer_; + entries = &largest_contentful_paint_buffer_; + break; case PerformanceEntry::kVisibilityState: - return visibility_state_buffer_; + entries = &visibility_state_buffer_; + break; case PerformanceEntry::kBackForwardCacheRestoration: if (RuntimeEnabledFeatures::NavigationIdEnabled(GetExecutionContext())) - return back_forward_cache_restoration_buffer_; + entries = &back_forward_cache_restoration_buffer_; break; case PerformanceEntry::kSoftNavigation: @@ -436,7 +532,7 @@ GetExecutionContext())) { UseCounter::Count(GetExecutionContext(), WebFeature::kSoftNavigationHeuristics); - return soft_navigation_buffer_; + entries = &soft_navigation_buffer_; } break; @@ -444,7 +540,18 @@ break; } - return {}; + DCHECK_NE(entries, nullptr); + if (!maybe_name || already_filtered_by_name) { + return *entries; + } + + PerformanceEntryVector filtered_entries; + std::copy_if(entries->begin(), entries->end(), + std::back_inserter(filtered_entries), + [&](const PerformanceEntry* entry) { + return entry->name() == maybe_name; + }); + return filtered_entries; } PerformanceEntryVector Performance::getEntriesByName( @@ -453,32 +560,26 @@ const AtomicString& entry_type, bool include_frames) { PerformanceEntryVector entries; - PerformanceEntryVector all_entries; // Get sorted entry list based on provided input. if (include_frames && RuntimeEnabledFeatures::CrossFramePerformanceTimelineEnabled()) { - all_entries = GetEntriesWithChildFrames(script_state, entry_type); + entries = GetEntriesWithChildFrames(script_state, entry_type, name); } else { if (entry_type.IsNull()) { - all_entries = GetEntriesForCurrentFrame(); + entries = GetEntriesForCurrentFrame(name); } else { - all_entries = GetEntriesByTypeForCurrentFrame(entry_type); + entries = GetEntriesByTypeForCurrentFrame(entry_type, name); } } - // Filter all entries by name. - for (const auto& entry : all_entries) { - if (entry->name() == name) - entries.push_back(entry); - } - return entries; } PerformanceEntryVector Performance::GetEntriesWithChildFrames( ScriptState* script_state, - const AtomicString& entry_type) { + const AtomicString& maybe_type, + const AtomicString& maybe_name) { PerformanceEntryVector entries; LocalDOMWindow* window = LocalDOMWindow::From(script_state); @@ -513,15 +614,16 @@ WindowPerformance* window_performance = DOMWindowPerformance::performance(*current_window); - // Get the performance entries based on entry_type input. Since the root + // Get the performance entries based on maybe_type input. Since the root // frame can script the current frame, its okay to expose the current // frame's performance entries to the root. PerformanceEntryVector current_entries; - if (entry_type.IsNull()) { - current_entries = window_performance->GetEntriesForCurrentFrame(); - } else { + if (maybe_type.IsNull()) { current_entries = - window_performance->GetEntriesByTypeForCurrentFrame(entry_type); + window_performance->GetEntriesForCurrentFrame(maybe_name); + } else { + current_entries = window_performance->GetEntriesByTypeForCurrentFrame( + maybe_type, maybe_name); } entries.AppendVector(current_entries); @@ -653,7 +755,7 @@ ExecutionContext* context) { auto* entry = MakeGarbageCollected<PerformanceResourceTiming>( *info, time_origin_, cross_origin_isolated_capability_, initiator_type, - context, DynamicTo<LocalDOMWindow>(context)); + DynamicTo<LocalDOMWindow>(context)); NotifyObserversOfEntry(*entry); // https://w3c.github.io/resource-timing/#dfn-add-a-performanceresourcetiming-entry if (CanAddResourceTimingEntry() && @@ -795,7 +897,6 @@ base::TimeTicks start_time) { PerformanceEntry* entry = MakeGarbageCollected<PerformancePaintTiming>( type, MonotonicTimeToDOMHighResTimeStamp(start_time), - PerformanceEntry::GetNavigationId(GetExecutionContext()), DynamicTo<LocalDOMWindow>(GetExecutionContext())); DCHECK((type == PerformancePaintTiming::PaintType::kFirstPaint) || (type == PerformancePaintTiming::PaintType::kFirstContentfulPaint)); @@ -830,7 +931,6 @@ static_cast<int>(MonotonicTimeToDOMHighResTimeStamp(end_time) - dom_high_res_start_time), name, container_type, container_src, container_id, container_name, - PerformanceEntry::GetNavigationId(execution_context), DynamicTo<LocalDOMWindow>(execution_context)); if (longtask_buffer_.size() < kDefaultLongTaskBufferSize) { InsertEntryIntoSortedBuffer(longtask_buffer_, *entry, kRecordSwaps); @@ -854,7 +954,6 @@ MonotonicTimeToDOMHighResTimeStamp(start_time), MonotonicTimeToDOMHighResTimeStamp(pageshow_start_time), MonotonicTimeToDOMHighResTimeStamp(pageshow_end_time), - PerformanceEntry::GetNavigationId(GetExecutionContext()), DynamicTo<LocalDOMWindow>(GetExecutionContext())); if (back_forward_cache_restoration_buffer_.size() < back_forward_cache_restoration_buffer_size_limit_) {
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h index 849d027..6685b6d5 100644 --- a/third_party/blink/renderer/core/timing/performance.h +++ b/third_party/blink/renderer/core/timing/performance.h
@@ -88,10 +88,14 @@ using PerformanceEntryVector = HeapVector<Member<PerformanceEntry>>; using PerformanceEntryDeque = HeapDeque<Member<PerformanceEntry>>; -// Merge two sorted PerformanceEntryVectors in linear time. +// Merge two sorted PerformanceEntryVectors in linear time. If a non-null name +// is provided, then items in second_entry_vector will be included in the result +// only if their names match the given name. It is expected (and DCHECKed) that +// first_entry_vector has already been filtered by name. CORE_EXPORT PerformanceEntryVector MergePerformanceEntryVectors(const PerformanceEntryVector& first_entry_vector, - const PerformanceEntryVector& second_entry_vector); + const PerformanceEntryVector& second_entry_vector, + const AtomicString& maybe_name); class CORE_EXPORT Performance : public EventTargetWithInlineData { DEFINE_WRAPPERTYPEINFO(); @@ -351,22 +355,27 @@ void CopySecondaryBuffer(); PerformanceEntryVector getEntriesByTypeInternal( - PerformanceEntry::EntryType type); + PerformanceEntry::EntryType type, + const AtomicString& maybe_name = g_null_atom); void MeasureMemoryExperimentTimerFired(TimerBase*); - // Get performance entries of the current frame. - PerformanceEntryVector GetEntriesForCurrentFrame(); + // Get performance entries of the current frame, with an optional name filter. + PerformanceEntryVector GetEntriesForCurrentFrame( + const AtomicString& maybe_name = g_null_atom); - // Get performance entries of the current frame by type. + // Get performance entries of the current frame by type, with an optional name + // filter. PerformanceEntryVector GetEntriesByTypeForCurrentFrame( - const AtomicString& entry_type); + const AtomicString& entry_type, + const AtomicString& maybe_name = g_null_atom); // Get performance entries of nested same-origin iframes, with an optional - // type. + // type and optional name filter. PerformanceEntryVector GetEntriesWithChildFrames( ScriptState* script_state, - const AtomicString& entry_type = g_null_atom); + const AtomicString& maybe_type = g_null_atom, + const AtomicString& maybe_name = g_null_atom); protected: Performance(base::TimeTicks time_origin,
diff --git a/third_party/blink/renderer/core/timing/performance_element_timing.cc b/third_party/blink/renderer/core/timing/performance_element_timing.cc index 6e527f2..89c79d0 100644 --- a/third_party/blink/renderer/core/timing/performance_element_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_element_timing.cc
@@ -23,7 +23,6 @@ int naturalHeight, const AtomicString& id, Element* element, - uint32_t navigation_id, DOMWindow* source) { // It is possible to 'paint' images which have naturalWidth or naturalHeight // equal to 0. @@ -33,8 +32,7 @@ double start_time = render_time != 0.0 ? render_time : load_time; return MakeGarbageCollected<PerformanceElementTiming>( name, start_time, url, intersection_rect, render_time, load_time, - identifier, naturalWidth, naturalHeight, id, element, navigation_id, - source); + identifier, naturalWidth, naturalHeight, id, element, source); } PerformanceElementTiming::PerformanceElementTiming( @@ -49,9 +47,8 @@ int naturalHeight, const AtomicString& id, Element* element, - uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(name, start_time, start_time, navigation_id, source), + : PerformanceEntry(name, start_time, start_time, source), element_(element), intersection_rect_(DOMRectReadOnly::FromRectF(intersection_rect)), render_time_(render_time),
diff --git a/third_party/blink/renderer/core/timing/performance_element_timing.h b/third_party/blink/renderer/core/timing/performance_element_timing.h index 3be35a42..86274fb 100644 --- a/third_party/blink/renderer/core/timing/performance_element_timing.h +++ b/third_party/blink/renderer/core/timing/performance_element_timing.h
@@ -32,7 +32,6 @@ int naturalHeight, const AtomicString& id, Element*, - uint32_t navigation_id, DOMWindow* source); PerformanceElementTiming(const AtomicString& name, DOMHighResTimeStamp start_time, @@ -45,7 +44,6 @@ int naturalHeight, const AtomicString& id, Element*, - uint32_t navigation_id, DOMWindow* source); ~PerformanceElementTiming() override;
diff --git a/third_party/blink/renderer/core/timing/performance_entry.cc b/third_party/blink/renderer/core/timing/performance_entry.cc index 52a9592..d07f951 100644 --- a/third_party/blink/renderer/core/timing/performance_entry.cc +++ b/third_party/blink/renderer/core/timing/performance_entry.cc
@@ -48,25 +48,27 @@ PerformanceEntry::PerformanceEntry(const AtomicString& name, double start_time, double finish_time, - uint32_t navigation_id, DOMWindow* source) : duration_(finish_time - start_time), name_(name), start_time_(start_time), index_(index_seq.GetNext()), - navigation_id_(navigation_id), + navigation_id_(DynamicTo<LocalDOMWindow>(source) + ? DynamicTo<LocalDOMWindow>(source)->GetNavigationId() + : kNavigationIdDefaultValue), source_(source) {} PerformanceEntry::PerformanceEntry(double duration, const AtomicString& name, double start_time, - uint32_t navigation_id, DOMWindow* source) : duration_(duration), name_(name), start_time_(start_time), index_(index_seq.GetNext()), - navigation_id_(navigation_id), + navigation_id_(DynamicTo<LocalDOMWindow>(source) + ? DynamicTo<LocalDOMWindow>(source)->GetNavigationId() + : kNavigationIdDefaultValue), source_(source) { DCHECK_GE(duration_, 0.0); } @@ -152,15 +154,6 @@ return local_dom_window->GetNavigationId(); } -// static -uint32_t PerformanceEntry::GetNavigationId(ExecutionContext* context) { - const auto* local_dom_window = DynamicTo<LocalDOMWindow>(context); - if (!local_dom_window) - return kNavigationIdDefaultValue; - - return local_dom_window->GetNavigationId(); -} - void PerformanceEntry::Trace(Visitor* visitor) const { visitor->Trace(source_); ScriptWrappable::Trace(visitor);
diff --git a/third_party/blink/renderer/core/timing/performance_entry.h b/third_party/blink/renderer/core/timing/performance_entry.h index 93695e7..0a68205 100644 --- a/third_party/blink/renderer/core/timing/performance_entry.h +++ b/third_party/blink/renderer/core/timing/performance_entry.h
@@ -45,7 +45,6 @@ class ScriptState; class ScriptValue; class V8ObjectBuilder; -class ExecutionContext; using PerformanceEntryType = unsigned; using PerformanceEntryTypeMask = unsigned; @@ -124,7 +123,6 @@ } static uint32_t GetNavigationId(ScriptState* script_state); - static uint32_t GetNavigationId(ExecutionContext* context); // PerformanceMark/Measure override this and it returns Mojo structure pointer // which has all members of PerformanceMark/Measure. Common data members are @@ -139,12 +137,10 @@ PerformanceEntry(const AtomicString& name, double start_time, double finish_time, - uint32_t navigation_id, DOMWindow* source); PerformanceEntry(double duration, const AtomicString& name, double start_time, - uint32_t navigation_id, DOMWindow* source); virtual void BuildJSONValue(V8ObjectBuilder&) const;
diff --git a/third_party/blink/renderer/core/timing/performance_entry_test.cc b/third_party/blink/renderer/core/timing/performance_entry_test.cc index 68c808b..c03b3f9 100644 --- a/third_party/blink/renderer/core/timing/performance_entry_test.cc +++ b/third_party/blink/renderer/core/timing/performance_entry_test.cc
@@ -18,6 +18,6 @@ EXPECT_EQ(1u, PerformanceEntry::GetNavigationId(scope.GetScriptState())); scope.GetFrame().DomWindow()->IncrementNavigationId(); - EXPECT_EQ(2u, PerformanceEntry::GetNavigationId(scope.GetExecutionContext())); + EXPECT_EQ(2u, PerformanceEntry::GetNavigationId(scope.GetScriptState())); } } // namespace blink
diff --git a/third_party/blink/renderer/core/timing/performance_event_timing.cc b/third_party/blink/renderer/core/timing/performance_event_timing.cc index 24259bb..5ede7823 100644 --- a/third_party/blink/renderer/core/timing/performance_event_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_event_timing.cc
@@ -22,14 +22,13 @@ DOMHighResTimeStamp processing_end, bool cancelable, Node* target, - uint32_t navigation_id, DOMWindow* source) { // TODO(npm): enable this DCHECK once https://crbug.com/852846 is fixed. // DCHECK_LE(start_time, processing_start); DCHECK_LE(processing_start, processing_end); return MakeGarbageCollected<PerformanceEventTiming>( event_type, performance_entry_names::kEvent, start_time, processing_start, - processing_end, cancelable, target, navigation_id, source); + processing_end, cancelable, target, source); } // static @@ -39,8 +38,7 @@ MakeGarbageCollected<PerformanceEventTiming>( entry->name(), performance_entry_names::kFirstInput, entry->startTime(), entry->processingStart(), entry->processingEnd(), - entry->cancelable(), entry->target(), entry->navigationId(), - entry->source()); + entry->cancelable(), entry->target(), entry->source()); first_input->SetDuration(entry->duration()); return first_input; } @@ -53,9 +51,8 @@ DOMHighResTimeStamp processing_end, bool cancelable, Node* target, - uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(event_type, start_time, 0.0, navigation_id, source), + : PerformanceEntry(event_type, start_time, 0.0, source), entry_type_(entry_type), processing_start_(processing_start), processing_end_(processing_end),
diff --git a/third_party/blink/renderer/core/timing/performance_event_timing.h b/third_party/blink/renderer/core/timing/performance_event_timing.h index 84b44e0e..2328331 100644 --- a/third_party/blink/renderer/core/timing/performance_event_timing.h +++ b/third_party/blink/renderer/core/timing/performance_event_timing.h
@@ -24,7 +24,6 @@ DOMHighResTimeStamp processing_end, bool cancelable, Node* target, - uint32_t navigation_id, DOMWindow* source); static PerformanceEventTiming* CreateFirstInputTiming( @@ -37,7 +36,6 @@ DOMHighResTimeStamp processing_end, bool cancelable, Node* target, - uint32_t navigation_id, DOMWindow* source); ~PerformanceEventTiming() override;
diff --git a/third_party/blink/renderer/core/timing/performance_long_task_timing.cc b/third_party/blink/renderer/core/timing/performance_long_task_timing.cc index 929be42f..610ce61 100644 --- a/third_party/blink/renderer/core/timing/performance_long_task_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_long_task_timing.cc
@@ -20,12 +20,10 @@ const AtomicString& culprit_src, const AtomicString& culprit_id, const AtomicString& culprit_name, - const uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(duration, name, start_time, navigation_id, source) { + : PerformanceEntry(duration, name, start_time, source) { auto* attribution_entry = MakeGarbageCollected<TaskAttributionTiming>( - "unknown", culprit_type, culprit_src, culprit_id, culprit_name, - navigation_id, source); + "unknown", culprit_type, culprit_src, culprit_id, culprit_name, source); attribution_.push_back(*attribution_entry); }
diff --git a/third_party/blink/renderer/core/timing/performance_long_task_timing.h b/third_party/blink/renderer/core/timing/performance_long_task_timing.h index 85318575..e595a05 100644 --- a/third_party/blink/renderer/core/timing/performance_long_task_timing.h +++ b/third_party/blink/renderer/core/timing/performance_long_task_timing.h
@@ -31,7 +31,6 @@ const AtomicString& culprit_src, const AtomicString& culprit_id, const AtomicString& culprit_name, - const uint32_t navigation_id, DOMWindow* source); ~PerformanceLongTaskTiming() override;
diff --git a/third_party/blink/renderer/core/timing/performance_mark.cc b/third_party/blink/renderer/core/timing/performance_mark.cc index 7e1372a..070883be 100644 --- a/third_party/blink/renderer/core/timing/performance_mark.cc +++ b/third_party/blink/renderer/core/timing/performance_mark.cc
@@ -23,9 +23,8 @@ base::TimeTicks unsafe_time_for_traces, scoped_refptr<SerializedScriptValue> serialized_detail, ExceptionState& exception_state, - uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(name, start_time, start_time, navigation_id, source), + : PerformanceEntry(name, start_time, start_time, source), serialized_detail_(std::move(serialized_detail)), unsafe_time_for_traces_(unsafe_time_for_traces) {} @@ -91,10 +90,9 @@ if (exception_state.HadException()) return nullptr; - uint32_t navigation_id = PerformanceEntry::GetNavigationId(script_state); return MakeGarbageCollected<PerformanceMark>( mark_name, start, unsafe_start_for_traces, std::move(serialized_detail), - exception_state, navigation_id, LocalDOMWindow::From(script_state)); + exception_state, LocalDOMWindow::From(script_state)); } const AtomicString& PerformanceMark::entryType() const {
diff --git a/third_party/blink/renderer/core/timing/performance_mark.h b/third_party/blink/renderer/core/timing/performance_mark.h index d8dd8be..593ad429 100644 --- a/third_party/blink/renderer/core/timing/performance_mark.h +++ b/third_party/blink/renderer/core/timing/performance_mark.h
@@ -62,7 +62,6 @@ base::TimeTicks unsafe_time_for_traces, scoped_refptr<SerializedScriptValue>, ExceptionState& exception_state, - uint32_t navigation_count, DOMWindow* source); ~PerformanceMark() override = default;
diff --git a/third_party/blink/renderer/core/timing/performance_mark_test.cc b/third_party/blink/renderer/core/timing/performance_mark_test.cc index ddbd2352..3fcfeac 100644 --- a/third_party/blink/renderer/core/timing/performance_mark_test.cc +++ b/third_party/blink/renderer/core/timing/performance_mark_test.cc
@@ -47,7 +47,7 @@ PerformanceMark* pm = MakeGarbageCollected<PerformanceMark>( "mark-name", 0, base::TimeTicks(), SerializedScriptValue::NullValue(), - exception_state, 1, LocalDOMWindow::From(script_state)); + exception_state, LocalDOMWindow::From(script_state)); ASSERT_EQ(pm->entryType(), performance_entry_names::kMark); ASSERT_EQ(pm->EntryTypeEnum(), PerformanceEntry::EntryType::kMark); @@ -66,7 +66,7 @@ SerializedScriptValue::Create(String("some-payload")); PerformanceMark* pm = MakeGarbageCollected<PerformanceMark>( - "mark-name", 0, base::TimeTicks(), payload_string, exception_state, 0, + "mark-name", 0, base::TimeTicks(), payload_string, exception_state, LocalDOMWindow::From(script_state)); ASSERT_EQ(pm->entryType(), performance_entry_names::kMark); ASSERT_EQ(pm->EntryTypeEnum(), PerformanceEntry::EntryType::kMark); @@ -82,13 +82,11 @@ ScriptState* script_state = scope.GetScriptState(); const AtomicString expected_name = "mark-name"; - const uint32_t expected_navigation_count = 2; const double expected_start_time = 0; const double expected_duration = 0; const AtomicString expected_entry_type = "mark"; PerformanceMark pm(expected_name, expected_start_time, base::TimeTicks(), SerializedScriptValue::NullValue(), exception_state, - expected_navigation_count, LocalDOMWindow::From(script_state)); ScriptValue json_object = pm.toJSONForBinding(script_state); @@ -111,8 +109,6 @@ parsed_json->GetDict().FindDouble("startTime").value()); EXPECT_EQ(expected_duration, parsed_json->GetDict().FindDouble("duration").value()); - EXPECT_EQ(expected_navigation_count, - (uint32_t)parsed_json->GetDict().FindInt("navigationId").value()); EXPECT_EQ(5ul, parsed_json->GetDict().size()); }
diff --git a/third_party/blink/renderer/core/timing/performance_measure.cc b/third_party/blink/renderer/core/timing/performance_measure.cc index d98397a4..c46f498 100644 --- a/third_party/blink/renderer/core/timing/performance_measure.cc +++ b/third_party/blink/renderer/core/timing/performance_measure.cc
@@ -21,11 +21,7 @@ scoped_refptr<SerializedScriptValue> serialized_detail, ExceptionState& exception_state, DOMWindow* source) - : PerformanceEntry(name, - start_time, - end_time, - PerformanceEntry::GetNavigationId(script_state), - source), + : PerformanceEntry(name, start_time, end_time, source), serialized_detail_(serialized_detail) {} // static
diff --git a/third_party/blink/renderer/core/timing/performance_observer_test.cc b/third_party/blink/renderer/core/timing/performance_observer_test.cc index a829916..65bbe052 100644 --- a/third_party/blink/renderer/core/timing/performance_observer_test.cc +++ b/third_party/blink/renderer/core/timing/performance_observer_test.cc
@@ -78,9 +78,9 @@ EXPECT_EQ(0, NumPerformanceEntries()); // add a layout-shift to performance so getEntries() returns it - auto* entry = LayoutShift::Create( - 0.0, 1234, true, 5678, LayoutShift::AttributionList(), - /*navigation_id=*/1, LocalDOMWindow::From(scope.GetScriptState())); + auto* entry = + LayoutShift::Create(0.0, 1234, true, 5678, LayoutShift::AttributionList(), + LocalDOMWindow::From(scope.GetScriptState())); base_->AddLayoutShiftBuffer(*entry); // call observe with the buffered flag
diff --git a/third_party/blink/renderer/core/timing/performance_paint_timing.cc b/third_party/blink/renderer/core/timing/performance_paint_timing.cc index 3c75040..bbf98e9 100644 --- a/third_party/blink/renderer/core/timing/performance_paint_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_paint_timing.cc
@@ -32,12 +32,10 @@ PerformancePaintTiming::PerformancePaintTiming(PaintType type, double start_time, - uint32_t navigation_id, DOMWindow* source) : PerformanceEntry(FromPaintTypeToString(type), start_time, start_time, - navigation_id, source) {} PerformancePaintTiming::~PerformancePaintTiming() = default;
diff --git a/third_party/blink/renderer/core/timing/performance_paint_timing.h b/third_party/blink/renderer/core/timing/performance_paint_timing.h index c640163..5599f25 100644 --- a/third_party/blink/renderer/core/timing/performance_paint_timing.h +++ b/third_party/blink/renderer/core/timing/performance_paint_timing.h
@@ -16,10 +16,7 @@ public: enum class PaintType { kFirstPaint, kFirstContentfulPaint }; - PerformancePaintTiming(PaintType, - double start_time, - uint32_t navigation_id, - DOMWindow* source); + PerformancePaintTiming(PaintType, double start_time, DOMWindow* source); ~PerformancePaintTiming() override; const AtomicString& entryType() const override;
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing.cc b/third_party/blink/renderer/core/timing/performance_resource_timing.cc index ce3b0a4..5d40325 100644 --- a/third_party/blink/renderer/core/timing/performance_resource_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_resource_timing.cc
@@ -107,7 +107,6 @@ base::TimeTicks time_origin, bool cross_origin_isolated_capability, const AtomicString& initiator_type, - ExecutionContext* context, LocalDOMWindow* source) : PerformanceEntry(AtomicString(info.name), Performance::MonotonicTimeToDOMHighResTimeStamp( @@ -120,7 +119,6 @@ info.response_end, info.allow_negative_values, cross_origin_isolated_capability), - PerformanceEntry::GetNavigationId(context), source), initiator_type_(initiator_type.empty() ? fetch_initiator_type_names::kOther @@ -131,7 +129,6 @@ resource_load_timing_(ResourceLoadTiming::FromMojo(info.timing.get())), server_timing_( PerformanceServerTiming::FromParsedServerTiming(info.server_timing)) { - DCHECK(context); } // This constructor is for PerformanceNavigationTiming. @@ -150,7 +147,6 @@ : g_empty_atom, 0.0, 0.0, - kNavigationIdDefaultValue, &source_window), initiator_type_(initiator_type), time_origin_(time_origin),
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing.h b/third_party/blink/renderer/core/timing/performance_resource_timing.h index ba2a25f6..680d23b 100644 --- a/third_party/blink/renderer/core/timing/performance_resource_timing.h +++ b/third_party/blink/renderer/core/timing/performance_resource_timing.h
@@ -59,7 +59,6 @@ base::TimeTicks time_origin, bool cross_origin_isolated_capability, const AtomicString& initiator_type, - ExecutionContext* context, LocalDOMWindow* source); ~PerformanceResourceTiming() override;
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing_test.cc b/third_party/blink/renderer/core/timing/performance_resource_timing_test.cc index bab768d..b4127c0 100644 --- a/third_party/blink/renderer/core/timing/performance_resource_timing_test.cc +++ b/third_party/blink/renderer/core/timing/performance_resource_timing_test.cc
@@ -47,9 +47,7 @@ dummy_page_holder->GetDocument() .GetExecutionContext() ->CrossOriginIsolatedCapability(), - /*initiator_type=*/"", - dummy_page_holder->GetDocument().GetExecutionContext(), - LocalDOMWindow::From(GetScriptState())); + /*initiator_type=*/"", LocalDOMWindow::From(GetScriptState())); } Persistent<ScriptState> script_state_;
diff --git a/third_party/blink/renderer/core/timing/performance_test.cc b/third_party/blink/renderer/core/timing/performance_test.cc index b415620..bc54df0f0 100644 --- a/third_party/blink/renderer/core/timing/performance_test.cc +++ b/third_party/blink/renderer/core/timing/performance_test.cc
@@ -236,7 +236,7 @@ PerformanceEntryVector test_buffer_; PerformanceEventTiming* test_entry = PerformanceEventTiming::Create( - "event", 0.0, 0.0, 0.0, false, nullptr, 0, + "event", 0.0, 0.0, 0.0, false, nullptr, LocalDOMWindow::From(scope.GetScriptState())); base_->InsertEntryIntoSortedBuffer(test_buffer_, *test_entry, @@ -259,13 +259,13 @@ for (int i = 0; i < 3; i++) { double tmp = 1.0; PerformanceEventTiming* entry = PerformanceEventTiming::Create( - "event", tmp * i, 0.0, 0.0, false, nullptr, 0, + "event", tmp * i, 0.0, 0.0, false, nullptr, LocalDOMWindow::From(scope.GetScriptState())); test_buffer_.push_back(*entry); } PerformanceEventTiming* test_entry = PerformanceEventTiming::Create( - "event", 1.0, 0.0, 0.0, false, nullptr, 0, + "event", 1.0, 0.0, 0.0, false, nullptr, LocalDOMWindow::From(scope.GetScriptState())); // Create copy of the test_buffer_. @@ -292,13 +292,13 @@ for (int i = 0; i < 3; i++) { double tmp = 1.0; PerformanceEventTiming* entry = PerformanceEventTiming::Create( - "event", tmp * i, 0.0, 0.0, false, nullptr, 0, + "event", tmp * i, 0.0, 0.0, false, nullptr, LocalDOMWindow::From(scope.GetScriptState())); test_buffer_.push_back(*entry); } PerformanceEventTiming* test_entry = PerformanceEventTiming::Create( - "event", 0.0, 0.0, 0.0, false, nullptr, 0, + "event", 0.0, 0.0, 0.0, false, nullptr, LocalDOMWindow::From(scope.GetScriptState())); // Create copy of the test_buffer_. @@ -326,7 +326,7 @@ for (int i = 0; i < 6; i += 2) { double tmp = 1.0; PerformanceEventTiming* entry = PerformanceEventTiming::Create( - "event", tmp * i, 0.0, 0.0, false, nullptr, 0, + "event", tmp * i, 0.0, 0.0, false, nullptr, LocalDOMWindow::From(scope.GetScriptState())); first_vector.push_back(*entry); test_vector.push_back(*entry); @@ -335,15 +335,17 @@ for (int i = 1; i < 6; i += 2) { double tmp = 1.0; PerformanceEventTiming* entry = PerformanceEventTiming::Create( - "event", tmp * i, 0.0, 0.0, false, nullptr, 0, + "event", tmp * i, 0.0, 0.0, false, nullptr, LocalDOMWindow::From(scope.GetScriptState())); second_vector.push_back(*entry); test_vector.push_back(*entry); } PerformanceEntryVector all_entries; - all_entries = MergePerformanceEntryVectors(all_entries, first_vector); - all_entries = MergePerformanceEntryVectors(all_entries, second_vector); + all_entries = + MergePerformanceEntryVectors(all_entries, first_vector, g_null_atom); + all_entries = + MergePerformanceEntryVectors(all_entries, second_vector, g_null_atom); std::sort(test_vector.begin(), test_vector.end(), PerformanceEntry::StartTimeCompareLessThan);
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_entry.cc b/third_party/blink/renderer/core/timing/soft_navigation_entry.cc index 06c47c65..fbe30f50 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_entry.cc +++ b/third_party/blink/renderer/core/timing/soft_navigation_entry.cc
@@ -11,9 +11,8 @@ SoftNavigationEntry::SoftNavigationEntry(AtomicString name, double start_time, - uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(name, start_time, start_time, navigation_id, source) {} + : PerformanceEntry(name, start_time, start_time, source) {} SoftNavigationEntry::~SoftNavigationEntry() = default;
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_entry.h b/third_party/blink/renderer/core/timing/soft_navigation_entry.h index 4472ba0..f783856 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_entry.h +++ b/third_party/blink/renderer/core/timing/soft_navigation_entry.h
@@ -14,10 +14,7 @@ DEFINE_WRAPPERTYPEINFO(); public: - SoftNavigationEntry(AtomicString name, - double start_time, - uint32_t navigation_id, - DOMWindow* source); + SoftNavigationEntry(AtomicString name, double start_time, DOMWindow* source); ~SoftNavigationEntry() override; const AtomicString& entryType() const override;
diff --git a/third_party/blink/renderer/core/timing/task_attribution_timing.cc b/third_party/blink/renderer/core/timing/task_attribution_timing.cc index cf46dc7..9e9d53e 100644 --- a/third_party/blink/renderer/core/timing/task_attribution_timing.cc +++ b/third_party/blink/renderer/core/timing/task_attribution_timing.cc
@@ -15,9 +15,8 @@ const AtomicString& container_src, const AtomicString& container_id, const AtomicString& container_name, - const uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(name, 0.0, 0.0, navigation_id, source), + : PerformanceEntry(name, 0.0, 0.0, source), container_type_(container_type), container_src_(container_src), container_id_(container_id),
diff --git a/third_party/blink/renderer/core/timing/task_attribution_timing.h b/third_party/blink/renderer/core/timing/task_attribution_timing.h index c1a07ad..8f8af34 100644 --- a/third_party/blink/renderer/core/timing/task_attribution_timing.h +++ b/third_party/blink/renderer/core/timing/task_attribution_timing.h
@@ -31,7 +31,6 @@ const AtomicString& container_src, const AtomicString& container_id, const AtomicString& container_name, - const uint32_t navigation_id, DOMWindow* source); ~TaskAttributionTiming() override;
diff --git a/third_party/blink/renderer/core/timing/visibility_state_entry.cc b/third_party/blink/renderer/core/timing/visibility_state_entry.cc index 6722d6d..b63d474 100644 --- a/third_party/blink/renderer/core/timing/visibility_state_entry.cc +++ b/third_party/blink/renderer/core/timing/visibility_state_entry.cc
@@ -11,9 +11,8 @@ VisibilityStateEntry::VisibilityStateEntry(AtomicString name, double start_time, - uint32_t navigation_id, DOMWindow* source) - : PerformanceEntry(name, start_time, start_time, navigation_id, source) {} + : PerformanceEntry(name, start_time, start_time, source) {} VisibilityStateEntry::~VisibilityStateEntry() = default;
diff --git a/third_party/blink/renderer/core/timing/visibility_state_entry.h b/third_party/blink/renderer/core/timing/visibility_state_entry.h index ead3b39..e6e1853b 100644 --- a/third_party/blink/renderer/core/timing/visibility_state_entry.h +++ b/third_party/blink/renderer/core/timing/visibility_state_entry.h
@@ -14,10 +14,7 @@ DEFINE_WRAPPERTYPEINFO(); public: - VisibilityStateEntry(AtomicString name, - double start_time, - uint32_t navigation_id, - DOMWindow* source); + VisibilityStateEntry(AtomicString name, double start_time, DOMWindow* source); ~VisibilityStateEntry() override; const AtomicString& entryType() const override;
diff --git a/third_party/blink/renderer/core/timing/window_performance.cc b/third_party/blink/renderer/core/timing/window_performance.cc index 077df80..a1eef32 100644 --- a/third_party/blink/renderer/core/timing/window_performance.cc +++ b/third_party/blink/renderer/core/timing/window_performance.cc
@@ -421,7 +421,6 @@ MonotonicTimeToDOMHighResTimeStamp(processing_start), MonotonicTimeToDOMHighResTimeStamp(processing_end), event.cancelable(), event.target() ? event.target()->ToNode() : nullptr, - PerformanceEntry::GetNavigationId(GetExecutionContext()), DomWindow()); // TODO(haoliuk): Add WPT for Event Timing. // See crbug.com/1320878. absl::optional<int> key_code; @@ -631,7 +630,7 @@ name, url, rect, MonotonicTimeToDOMHighResTimeStamp(start_time), MonotonicTimeToDOMHighResTimeStamp(load_time), identifier, intrinsic_size.width(), intrinsic_size.height(), id, element, - PerformanceEntry::GetNavigationId(GetExecutionContext()), DomWindow()); + DomWindow()); TRACE_EVENT2("loading", "PerformanceElementTiming", "data", entry->ToTracedValue(), "frame", ToTraceValue(DomWindow()->GetFrame())); @@ -670,7 +669,6 @@ VisibilityStateEntry* entry = MakeGarbageCollected<VisibilityStateEntry>( PageHiddenStateString(!is_visible), MonotonicTimeToDOMHighResTimeStamp(timestamp), - PerformanceEntry::GetNavigationId(GetExecutionContext()), DomWindow()); // Todo(haoliuk): Add WPT for // VisibilityStateEntry. See // crbug.com/1320878. @@ -688,8 +686,7 @@ return; } SoftNavigationEntry* entry = MakeGarbageCollected<SoftNavigationEntry>( - name, MonotonicTimeToDOMHighResTimeStamp(timestamp), - PerformanceEntry::GetNavigationId(GetExecutionContext()), DomWindow()); + name, MonotonicTimeToDOMHighResTimeStamp(timestamp), DomWindow()); if (HasObserverFor(PerformanceEntry::kSoftNavigation)) { UseCounter::Count(GetExecutionContext(), @@ -737,8 +734,7 @@ // TODO(yoav): Should we modify start to represent the animated frame? auto* entry = MakeGarbageCollected<LargestContentfulPaint>( start_timestamp, render_timestamp, paint_size, load_timestamp, - first_animated_frame_timestamp, id, url, element, - PerformanceEntry::GetNavigationId(GetExecutionContext()), DomWindow()); + first_animated_frame_timestamp, id, url, element, DomWindow()); if (HasObserverFor(PerformanceEntry::kLargestContentfulPaint)) NotifyObserversOfEntry(*entry); AddLargestContentfulPaint(entry);
diff --git a/third_party/blink/renderer/core/timing/window_performance_test.cc b/third_party/blink/renderer/core/timing/window_performance_test.cc index 2ff96bc5..d3af86a 100644 --- a/third_party/blink/renderer/core/timing/window_performance_test.cc +++ b/third_party/blink/renderer/core/timing/window_performance_test.cc
@@ -134,7 +134,7 @@ PerformanceEventTiming* CreatePerformanceEventTiming( const AtomicString& name) { return PerformanceEventTiming::Create( - name, 0.0, 0.0, 0.0, false, nullptr, 1, + name, 0.0, 0.0, 0.0, false, nullptr, LocalDOMWindow::From(GetScriptState())); }
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.h b/third_party/blink/renderer/core/workers/worker_global_scope.h index 1bdcef95..c110086 100644 --- a/third_party/blink/renderer/core/workers/worker_global_scope.h +++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -52,7 +52,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/code_cache_host.h" #include "third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.h" #include "third_party/blink/renderer/platform/wtf/casting.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "v8/include/v8-inspector.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn index d3d911a2..7fd413d 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -612,6 +612,7 @@ "webaudio/stereo_panner_node_test.cc", "webdatabase/dom_window_web_database_test.cc", "webdatabase/quota_tracker_test.cc", + "webrtc/webrtc_audio_device_impl_test.cc", "webshare/navigator_share_test.cc", "websockets/dom_websocket_test.cc", "websockets/mock_websocket_channel.cc",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h index 5639fe7..e4ad0584 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -56,7 +56,7 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc b/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc index d9e3934..361d343 100644 --- a/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc +++ b/third_party/blink/renderer/modules/accessibility/inspector_accessibility_agent.cc
@@ -237,11 +237,11 @@ AddHasPopupProperty(node_data.GetHasPopup(), properties); - const int heading_level = node_data.GetIntAttribute( + const int hierarchical_level = node_data.GetIntAttribute( ax::mojom::blink::IntAttribute::kHierarchicalLevel); - if (heading_level > 0) { - properties.emplace_back( - CreateProperty(AXPropertyNameEnum::Level, CreateValue(heading_level))); + if (hierarchical_level > 0) { + properties.emplace_back(CreateProperty(AXPropertyNameEnum::Level, + CreateValue(hierarchical_level))); } if (RoleAllowsMultiselectable(role)) {
diff --git a/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc b/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc index 28523ad3..ca4aed3 100644 --- a/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc +++ b/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc
@@ -57,7 +57,6 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include "v8/include/v8-primitive.h"
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h index e064ad57..ade4caae 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
@@ -15,7 +15,7 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/buckets/storage_bucket.h b/third_party/blink/renderer/modules/buckets/storage_bucket.h index ee0c3dc..2ac5b49 100644 --- a/third_party/blink/renderer/modules/buckets/storage_bucket.h +++ b/third_party/blink/renderer/modules/buckets/storage_bucket.h
@@ -17,7 +17,7 @@ #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/core/execution_context/navigator_base.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h index 0ad5729b..d746c84 100644 --- a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h +++ b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.h
@@ -12,7 +12,7 @@ #include "third_party/blink/renderer/core/inspector/inspector_base_agent.h" #include "third_party/blink/renderer/core/inspector/protocol/cache_storage.h" #include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/compute_pressure/DIR_METADATA b/third_party/blink/renderer/modules/compute_pressure/DIR_METADATA index d2b9158..2bcea0be 100644 --- a/third_party/blink/renderer/modules/compute_pressure/DIR_METADATA +++ b/third_party/blink/renderer/modules/compute_pressure/DIR_METADATA
@@ -1 +1 @@ -mixins: "//content/browser/compute_pressure/COMMON_METADATA" +mixins: "//services/device/compute_pressure/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/compute_pressure/OWNERS b/third_party/blink/renderer/modules/compute_pressure/OWNERS index cccf8e5..89fd6fb 100644 --- a/third_party/blink/renderer/modules/compute_pressure/OWNERS +++ b/third_party/blink/renderer/modules/compute_pressure/OWNERS
@@ -1,4 +1,4 @@ -file://content/browser/compute_pressure/OWNERS +file://services/device/compute_pressure/OWNERS beaufort.francois@gmail.com
diff --git a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_manager.cc b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_manager.cc index 2d7e888..fa13666b 100644 --- a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_manager.cc +++ b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_manager.cc
@@ -73,7 +73,7 @@ PressureObserverManager::PressureObserverManager(LocalDOMWindow& window) : ExecutionContextLifecycleStateObserver(&window), Supplement<LocalDOMWindow>(window), - pressure_service_(GetSupplementable()->GetExecutionContext()), + pressure_manager_(GetSupplementable()->GetExecutionContext()), receiver_(this, GetSupplementable()->GetExecutionContext()) { UpdateStateIfNeeded(); } @@ -91,9 +91,9 @@ // Not connected to the browser process yet. Make the binding. scoped_refptr<base::SingleThreadTaskRunner> task_runner = GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI); - pressure_service_->BindObserver( + pressure_manager_->AddClient( receiver_.BindNewPipeAndPassRemote(std::move(task_runner)), - WTF::BindOnce(&PressureObserverManager::DidBindObserver, + WTF::BindOnce(&PressureObserverManager::DidAddClient, WrapWeakPersistent(this), source)); receiver_.set_disconnect_handler(WTF::BindOnce( &PressureObserverManager::Reset, WrapWeakPersistent(this))); @@ -134,7 +134,7 @@ // when frozen or send a disconnect event. } -void PressureObserverManager::OnUpdate( +void PressureObserverManager::OnPressureUpdated( device::mojom::blink::PressureUpdatePtr update) { if (!PassesPrivacyTest()) return; @@ -166,7 +166,7 @@ for (const auto& observer_set : observers_) { visitor->Trace(observer_set); } - visitor->Trace(pressure_service_); + visitor->Trace(pressure_manager_); visitor->Trace(receiver_); ExecutionContextLifecycleStateObserver::Trace(visitor); Supplement<LocalDOMWindow>::Trace(visitor); @@ -175,14 +175,15 @@ void PressureObserverManager::EnsureServiceConnection() { DCHECK(GetExecutionContext()); - if (pressure_service_.is_bound()) + if (pressure_manager_.is_bound()) { return; + } auto task_runner = GetExecutionContext()->GetTaskRunner(TaskType::kUserInteraction); GetExecutionContext()->GetBrowserInterfaceBroker().GetInterface( - pressure_service_.BindNewPipeAndPassReceiver(task_runner)); - pressure_service_.set_disconnect_handler( + pressure_manager_.BindNewPipeAndPassReceiver(task_runner)); + pressure_manager_.set_disconnect_handler( WTF::BindOnce(&PressureObserverManager::OnServiceConnectionError, WrapWeakPersistent(this))); } @@ -241,31 +242,31 @@ void PressureObserverManager::Reset() { state_ = State::kUninitialized; receiver_.reset(); - pressure_service_.reset(); + pressure_manager_.reset(); for (auto& observer_set : observers_) { observer_set.clear(); } } -void PressureObserverManager::DidBindObserver( +void PressureObserverManager::DidAddClient( V8PressureSource::Enum source, - mojom::blink::PressureStatus status) { + device::mojom::blink::PressureStatus status) { DCHECK_EQ(state_, State::kInitializing); DCHECK(receiver_.is_bound()); - DCHECK(pressure_service_.is_bound()); + DCHECK(pressure_manager_.is_bound()); // Take a snapshot so as to safely iterate. HeapVector<Member<blink::PressureObserver>> observers( observers_[ToSourceIndex(source)]); switch (status) { - case mojom::blink::PressureStatus::kOk: { + case device::mojom::blink::PressureStatus::kOk: { state_ = State::kInitialized; for (const auto& observer : observers) { observer->OnBindingSucceeded(source); } break; } - case mojom::blink::PressureStatus::kNotSupported: { + case device::mojom::blink::PressureStatus::kNotSupported: { // TODO(crbug.com/1342184): Consider other sources. // For now, "cpu" is the only source. Reset();
diff --git a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_manager.h b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_manager.h index a0e52089..41fb177 100644 --- a/third_party/blink/renderer/modules/compute_pressure/pressure_observer_manager.h +++ b/third_party/blink/renderer/modules/compute_pressure/pressure_observer_manager.h
@@ -5,7 +5,8 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_COMPUTE_PRESSURE_PRESSURE_OBSERVER_MANAGER_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_COMPUTE_PRESSURE_PRESSURE_OBSERVER_MANAGER_H_ -#include "third_party/blink/public/mojom/compute_pressure/pressure_service.mojom-blink.h" +#include "services/device/public/mojom/pressure_manager.mojom-blink.h" +#include "services/device/public/mojom/pressure_update.mojom-blink.h" #include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_pressure_source.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h" @@ -20,11 +21,15 @@ namespace blink { +// This class implements the "device::mojom::blink::PressureClient" +// interface to receive "device::mojom::blink::PressureUpdate" from +// "device::PressureManagerImpl" and broadcasts the information to active +// PressureObservers. class MODULES_EXPORT PressureObserverManager final : public GarbageCollected<PressureObserverManager>, public ExecutionContextLifecycleStateObserver, public Supplement<LocalDOMWindow>, - public mojom::blink::PressureObserver { + public device::mojom::blink::PressureClient { public: static const char kSupplementName[]; @@ -44,18 +49,18 @@ void ContextDestroyed() override; void ContextLifecycleStateChanged(mojom::blink::FrameLifecycleState) override; - // mojom::blink::PressureObserver implementation. - void OnUpdate(device::mojom::blink::PressureUpdatePtr) override; + // device::mojom::blink::PressureClient implementation. + void OnPressureUpdated(device::mojom::blink::PressureUpdatePtr) override; // GarbageCollected implementation. void Trace(Visitor*) const override; private: // kUninitialized: receiver_ is not bound and - // pressure_service_->BindObserver() must be called. - // kInitializing: pressure_service_->BindObserver() has been called, - // but DidBindObserver() has not been called yet. - // kInitialized: DidBindObserver() was invoked and succeeded. + // pressure_manager_->AddClient() must be called. + // kInitializing: pressure_manager_->AddClient() has been called, + // but DidAddClient() has not been called yet. + // kInitialized: DidAddClient() was invoked and succeeded. enum class State { kUninitialized, kInitializing, kInitialized }; void EnsureServiceConnection(); @@ -63,21 +68,23 @@ // Verifies if the data should be delivered according to privacy status. bool PassesPrivacyTest() const; - // Called when `pressure_service_` is disconnected. + // Called when `pressure_manager_` is disconnected. void OnServiceConnectionError(); // Called when `receiver_` is disconnected. void Reset(); - void DidBindObserver(V8PressureSource::Enum, mojom::blink::PressureStatus); + void DidAddClient(V8PressureSource::Enum, + device::mojom::blink::PressureStatus); constexpr static size_t kPressureSourceSize = V8PressureSource::kEnumSize; // Connection to the browser-side implementation. - HeapMojoRemote<mojom::blink::PressureService> pressure_service_; + HeapMojoRemote<device::mojom::blink::PressureManager> pressure_manager_; // Routes PressureObserver mojo messages to this instance. - HeapMojoReceiver<mojom::blink::PressureObserver, PressureObserverManager> + HeapMojoReceiver<device::mojom::blink::PressureClient, + PressureObserverManager> receiver_; State state_ = State::kUninitialized;
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.h b/third_party/blink/renderer/modules/cookie_store/cookie_store.h index e71630a..3102d32 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.h +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.h
@@ -17,7 +17,7 @@ #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/modules/direct_sockets/udp_readable_stream_wrapper_unittest.cc b/third_party/blink/renderer/modules/direct_sockets/udp_readable_stream_wrapper_unittest.cc index 787bd82..7f6cc2ad 100644 --- a/third_party/blink/renderer/modules/direct_sockets/udp_readable_stream_wrapper_unittest.cc +++ b/third_party/blink/renderer/modules/direct_sockets/udp_readable_stream_wrapper_unittest.cc
@@ -27,7 +27,7 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_uchar.h" #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
diff --git a/third_party/blink/renderer/modules/direct_sockets/udp_writable_stream_wrapper_unittest.cc b/third_party/blink/renderer/modules/direct_sockets/udp_writable_stream_wrapper_unittest.cc index 2e311c1..204af1f7 100644 --- a/third_party/blink/renderer/modules/direct_sockets/udp_writable_stream_wrapper_unittest.cc +++ b/third_party/blink/renderer/modules/direct_sockets/udp_writable_stream_wrapper_unittest.cc
@@ -28,7 +28,7 @@ #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/googletest/src/googlemock/include/gmock/gmock-matchers.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/font_access/font_access.h b/third_party/blink/renderer/modules/font_access/font_access.h index 036c0d1f..51b3612 100644 --- a/third_party/blink/renderer/modules/font_access/font_access.h +++ b/third_party/blink/renderer/modules/font_access/font_access.h
@@ -13,7 +13,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/supplementable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture.cc b/third_party/blink/renderer/modules/imagecapture/image_capture.cc index 6e272e0..15a0bc4 100644 --- a/third_party/blink/renderer/modules/imagecapture/image_capture.cc +++ b/third_party/blink/renderer/modules/imagecapture/image_capture.cc
@@ -368,7 +368,7 @@ } service_->SetOptions( - stream_track_->Component()->Source()->Id(), std::move(settings), + SourceId(), std::move(settings), WTF::BindOnce(&ImageCapture::OnMojoSetOptions, WrapPersistent(this), WrapPersistent(resolver), trigger_take_photo)); return promise; @@ -794,7 +794,7 @@ service_requests_.insert(resolver); service_->SetOptions( - stream_track_->Component()->Source()->Id(), std::move(settings), + SourceId(), std::move(settings), WTF::BindOnce(&ImageCapture::OnMojoSetOptions, WrapPersistent(this), WrapPersistent(resolver), false /* trigger_take_photo */)); } @@ -852,7 +852,7 @@ } service_->SetOptions( - stream_track_->Component()->Source()->Id(), std::move(settings), + SourceId(), std::move(settings), WTF::BindOnce(&ImageCapture::OnSetPanTiltZoomSettingsFromTrack, WrapPersistent(this), std::move(initialized_callback))); } @@ -861,7 +861,7 @@ base::OnceClosure done_callback, bool result) { service_->GetPhotoState( - stream_track_->Component()->Source()->Id(), + SourceId(), WTF::BindOnce(&ImageCapture::UpdateMediaTrackCapabilities, WrapPersistent(this), std::move(done_callback))); } @@ -918,7 +918,7 @@ // Launch a retrieval of the current photo state, which arrive asynchronously // to avoid blocking the main UI thread. service_->GetPhotoState( - stream_track_->Component()->Source()->Id(), + SourceId(), WTF::BindOnce(&ImageCapture::SetPanTiltZoomSettingsFromTrack, WrapPersistent(this), std::move(initialized_callback))); @@ -963,12 +963,8 @@ } service_requests_.insert(resolver); - // m_streamTrack->component()->source()->id() is the renderer "name" of the - // camera; - // TODO(mcasas) consider sending the security origin as well: - // scriptState->getExecutionContext()->getSecurityOrigin()->toString() service_->GetPhotoState( - stream_track_->Component()->Source()->Id(), + SourceId(), WTF::BindOnce(&ImageCapture::OnMojoGetPhotoState, WrapPersistent(this), WrapPersistent(resolver), std::move(resolver_cb), false /* trigger_take_photo */)); @@ -1025,7 +1021,7 @@ if (trigger_take_photo) { service_->TakePhoto( - stream_track_->Component()->Source()->Id(), + SourceId(), WTF::BindOnce(&ImageCapture::OnMojoTakePhoto, WrapPersistent(this), WrapPersistent(resolver))); return; @@ -1055,10 +1051,9 @@ // Retrieve the current device status after setting the options. service_->GetPhotoState( - stream_track_->Component()->Source()->Id(), - WTF::BindOnce(&ImageCapture::OnMojoGetPhotoState, WrapPersistent(this), - WrapPersistent(resolver), std::move(resolver_cb), - trigger_take_photo)); + SourceId(), WTF::BindOnce(&ImageCapture::OnMojoGetPhotoState, + WrapPersistent(this), WrapPersistent(resolver), + std::move(resolver_cb), trigger_take_photo)); } void ImageCapture::OnMojoTakePhoto(ScriptPromiseResolver* resolver, @@ -1243,6 +1238,10 @@ return DomWindow() ? DomWindow()->document()->IsPageVisible() : false; } +const String& ImageCapture::SourceId() const { + return stream_track_->Component()->Source()->Id(); +} + ImageCapture* ImageCapture::Clone() const { ImageCapture* clone = MakeGarbageCollected<ImageCapture>( GetExecutionContext(), stream_track_, HasPanTiltZoomPermissionGranted(),
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture.h b/third_party/blink/renderer/modules/imagecapture/image_capture.h index 62a1c32..4e2acaa 100644 --- a/third_party/blink/renderer/modules/imagecapture/image_capture.h +++ b/third_party/blink/renderer/modules/imagecapture/image_capture.h
@@ -136,6 +136,8 @@ // Returns true if page is visible. Otherwise returns false. bool IsPageVisible(); + const String& SourceId() const; + Member<MediaStreamTrack> stream_track_; std::unique_ptr<ImageCaptureFrameGrabber> frame_grabber_; HeapMojoRemote<media::mojom::blink::ImageCapture> service_;
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_factory.cc b/third_party/blink/renderer/modules/indexeddb/idb_factory.cc index f3cbdef..5e81ed4ac 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_factory.cc +++ b/third_party/blink/renderer/modules/indexeddb/idb_factory.cc
@@ -64,7 +64,7 @@ #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_factory.h b/third_party/blink/renderer/modules/indexeddb/idb_factory.h index 41124d5..8b39d46 100644 --- a/third_party/blink/renderer/modules/indexeddb/idb_factory.h +++ b/third_party/blink/renderer/modules/indexeddb/idb_factory.h
@@ -42,7 +42,7 @@ #include "third_party/blink/renderer/modules/indexeddb/idb_open_db_request.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/media/audio/audio_device_factory.cc b/third_party/blink/renderer/modules/media/audio/audio_device_factory.cc index ee06276..9ec915f 100644 --- a/third_party/blink/renderer/modules/media/audio/audio_device_factory.cc +++ b/third_party/blink/renderer/modules/media/audio/audio_device_factory.cc
@@ -159,7 +159,7 @@ media::OutputDeviceInfo AudioDeviceFactory::GetOutputDeviceInfo( const blink::LocalFrameToken& frame_token, - const media::AudioSinkParameters& params) { + const std::string& device_id) { DCHECK(IsMainThread()) << __func__ << "() is called on a wrong thread."; constexpr base::TimeDelta kDeleteTimeout = base::Milliseconds(5000); @@ -175,8 +175,12 @@ blink::WebAudioDeviceSourceType::kNone), kDeleteTimeout); } - return sink_cache_->GetSinkInfo(frame_token, params.session_id, - params.device_id); + + // Passing a base::UnguessableToken() as a session ID is fine here, as we can + // identify entirely off of |device_id|. + // TODO(tguilbert): remove the use of session ID from AudioRendererSinkCache. + return sink_cache_->GetSinkInfo(frame_token, base::UnguessableToken(), + device_id); } scoped_refptr<media::AudioRendererSink>
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc index b1fffb5..7e68941 100644 --- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc +++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
@@ -1452,9 +1452,6 @@ ExecutionContext* execution_context = pending_cb->resolver->GetExecutionContext(); - DCHECK(UseGpuFactoriesForPowerEfficient(execution_context, - pending_cb->key_system_access)); - // Frame may become detached in the time it takes us to get callback for // NotifyDecoderSupportKnown. In this case, report false as a means of clean // shutdown. @@ -1463,6 +1460,9 @@ return; } + DCHECK(UseGpuFactoriesForPowerEfficient(execution_context, + pending_cb->key_system_access)); + media::GpuVideoAcceleratorFactories* gpu_factories = Platform::Current()->GetGpuFactories(); if (!gpu_factories) {
diff --git a/third_party/blink/renderer/modules/mediasession/media_session.h b/third_party/blink/renderer/modules/mediasession/media_session.h index d5005d0..c2bf6190 100644 --- a/third_party/blink/renderer/modules/mediasession/media_session.h +++ b/third_party/blink/renderer/modules/mediasession/media_session.h
@@ -14,7 +14,7 @@ #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" #include "third_party/blink/renderer/platform/supplementable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace base {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc b/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc index 86085d3..4d52a81 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc +++ b/third_party/blink/renderer/modules/mediastream/user_media_client_test.cc
@@ -50,7 +50,7 @@ #include "third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h" #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h" #include "third_party/blink/renderer/platform/wtf/functional.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "ui/display/screen_info.h"
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc index 6c10b0a..f4382eb 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
@@ -17,6 +17,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_pool_2d_options.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/modules/ml/ml.h" #include "third_party/blink/renderer/modules/ml/ml_context.h" @@ -397,6 +398,58 @@ return xnn_status_success; } +struct XnnPadding2D { + uint32_t top; + uint32_t bottom; + uint32_t left; + uint32_t right; +}; + +// Helper to get padding sizes for XNNPACK convolution 2d or pooling 2d Nodes. +template <typename OptionsType> +XnnPadding2D GetXnnPadding2D(const OptionsType* options, + uint32_t input_height, + uint32_t input_width, + uint32_t filter_height, + uint32_t filter_width, + uint32_t stride_height, + uint32_t stride_width, + uint32_t dilation_height, + uint32_t dilation_width) { + XnnPadding2D xnn_padding; + switch (options->autoPad().AsEnum()) { + case V8MLAutoPad::Enum::kExplicit: { + // Set the XNNPACK padding from WebNN explicit padding that is in + // [beginning_height, ending_height, beginning_width, ending_width], + // default to 0. + const Vector<uint32_t> default_pads({0, 0, 0, 0}); + xnn_padding.top = options->getPaddingOr(default_pads)[0]; + xnn_padding.bottom = options->getPaddingOr(default_pads)[1]; + xnn_padding.left = options->getPaddingOr(default_pads)[2]; + xnn_padding.right = options->getPaddingOr(default_pads)[3]; + break; + } + case V8MLAutoPad::Enum::kSameUpper: + case V8MLAutoPad::Enum::kSameLower: { + // Calculate the XNNPACK padding based on WebNN auto padding mode and + // sizes. + auto padding_sizes_height = MLGraphBuilder::CalculatePaddingForAutoPad( + options->autoPad().AsEnum(), input_height, filter_height, + stride_height, dilation_height); + DCHECK(padding_sizes_height); + xnn_padding.top = padding_sizes_height.value().begin; + xnn_padding.bottom = padding_sizes_height.value().end; + auto padding_sizes_width = MLGraphBuilder::CalculatePaddingForAutoPad( + options->autoPad().AsEnum(), input_width, filter_width, stride_width, + dilation_width); + xnn_padding.left = padding_sizes_width.value().begin; + xnn_padding.right = padding_sizes_width.value().end; + break; + } + } + return xnn_padding; +} + xnn_status DefineXnnNodeForConv2d(xnn_subgraph_t subgraph, const MLOperator* conv2d, const OperandValueIdMap& operand_value_id_map, @@ -489,28 +542,9 @@ } // Set or calculate padding sizes of XNNPACK conv2d. - uint32_t pad_top, pad_bottom, pad_left, pad_right; - if (options->autoPad().AsEnum() == V8MLAutoPad::Enum::kExplicit) { - // WebNN padding sizes are in [beginning_height, ending_height, - // beginning_width, ending_width], default to 0. - const Vector<uint32_t> default_pads({0, 0, 0, 0}); - pad_top = options->getPaddingOr(default_pads)[0]; - pad_bottom = options->getPaddingOr(default_pads)[1]; - pad_left = options->getPaddingOr(default_pads)[2]; - pad_right = options->getPaddingOr(default_pads)[3]; - } else { - auto padding_sizes_height = MLGraphBuilder::CalculatePaddingForAutoPad( - options->autoPad().AsEnum(), input_height, filter_height, stride_height, - dilation_height); - DCHECK(padding_sizes_height); - pad_top = padding_sizes_height.value().begin; - pad_bottom = padding_sizes_height.value().end; - auto padding_sizes_width = MLGraphBuilder::CalculatePaddingForAutoPad( - options->autoPad().AsEnum(), input_width, filter_width, stride_width, - dilation_width); - pad_left = padding_sizes_width.value().begin; - pad_right = padding_sizes_width.value().end; - } + const auto padding = GetXnnPadding2D( + options, input_height, input_width, filter_height, filter_width, + stride_height, stride_width, dilation_height, dilation_width); // Set the minimum and maximum output values for XNNPACK conv2d based on the // fused activation function. If no fused activation function is set, there @@ -541,17 +575,18 @@ if (depthwise) { const uint32_t depth_multiplier = 1; XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_depthwise_convolution_2d( - subgraph, pad_top, pad_right, pad_bottom, pad_left, filter_height, - filter_width, stride_height, stride_width, dilation_height, - dilation_width, depth_multiplier, input_channels, output_range.min, - output_range.max, input_id, filter_id, bias_id, output_id, flags)); - } else { - XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_convolution_2d( - subgraph, pad_top, pad_right, pad_bottom, pad_left, filter_height, - filter_width, stride_height, stride_width, dilation_height, - dilation_width, groups, group_input_channels, group_output_channels, + subgraph, padding.top, padding.right, padding.bottom, padding.left, + filter_height, filter_width, stride_height, stride_width, + dilation_height, dilation_width, depth_multiplier, input_channels, output_range.min, output_range.max, input_id, filter_id, bias_id, output_id, flags)); + } else { + XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_convolution_2d( + subgraph, padding.top, padding.right, padding.bottom, padding.left, + filter_height, filter_width, stride_height, stride_width, + dilation_height, dilation_width, groups, group_input_channels, + group_output_channels, output_range.min, output_range.max, input_id, + filter_id, bias_id, output_id, flags)); } return xnn_status_success; } @@ -607,6 +642,103 @@ return xnn_status_success; } +xnn_status DefineXnnNodeForPool2d(xnn_subgraph_t subgraph, + const MLOperator* pool2d, + const OperandValueIdMap& operand_value_id_map, + String& error_message) { + const uint32_t input_id = + GetOperatorInputValueId(pool2d, operand_value_id_map); + const uint32_t output_id = + GetOperatorOutputValueId(pool2d, operand_value_id_map); + + // Set strides of XNNPACK pooling 2d Node, default to 1. + const MLPool2dOptions* options = + static_cast<const MLPool2dOptions*>(pool2d->Options()); + const Vector<uint32_t> default_strides({1, 1}); + const uint32_t stride_height = options->getStridesOr(default_strides)[0]; + const uint32_t stride_width = options->getStridesOr(default_strides)[1]; + + // Set dilations of XNNPACK pooling 2d Node, default to 1. + const Vector<uint32_t> default_dilations({1, 1}); + const uint32_t dilation_height = + options->getDilationsOr(default_dilations)[0]; + const uint32_t dilation_width = options->getDilationsOr(default_dilations)[1]; + + // Set window sizes of XNNPACK pooling 2d Node. + uint32_t input_height, input_width; + uint32_t filter_height, filter_width; + bool global_pooling = false; + switch (options->layout().AsEnum()) { + case V8MLInputOperandLayout::Enum::kNhwc: { + const auto* input = pool2d->Inputs()[0].Get(); + DCHECK(input); + input_height = input->Dimensions()[1]; + input_width = input->Dimensions()[2]; + if (options->hasWindowDimensions()) { + filter_height = options->windowDimensions()[0]; + filter_width = options->windowDimensions()[1]; + } else { + // According to WebNN pool2d spec: + // https://www.w3.org/TR/webnn/#api-mlgraphbuilder-pool2d, if the window + // dimensions are not present, the window dimensions are assumed to be + // the height and width dimensions of the input shape that could be + // mapped to the global pooling operation. + filter_height = input_height; + filter_width = input_width; + global_pooling = true; + } + break; + } + case V8MLInputOperandLayout::Enum::kNchw: { + // TODO(crbug.com/1273291): support nchw input layout by transposing the + // input tensor. + error_message = "The nchw input layout is not supported."; + return xnn_status_unsupported_parameter; + } + } + + // Set or calculate padding sizes of XNNPACK pooling 2d Node. + const auto padding = GetXnnPadding2D( + options, input_height, input_width, filter_height, filter_width, + stride_height, stride_width, dilation_height, dilation_width); + + // Define XNNPACK average or max pooling 2d Node for the Subgraph object. + const float output_min = -std::numeric_limits<float>::infinity(); + const float output_max = +std::numeric_limits<float>::infinity(); + const uint32_t flags = 0; + switch (pool2d->Kind()) { + case MLOperator::OperatorKind::kAveragePool2d: { + if (dilation_height != 1 || dilation_width != 1) { + error_message = "averagePool2d doesn't support dilations."; + return xnn_status_unsupported_parameter; + } + if (global_pooling) { + XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE( + xnn_define_global_average_pooling_2d( + subgraph, output_min, output_max, input_id, output_id, flags)); + } else { + XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_average_pooling_2d( + subgraph, padding.top, padding.right, padding.bottom, padding.left, + filter_height, filter_width, stride_height, stride_width, + output_min, output_max, input_id, output_id, flags)); + } + break; + } + case MLOperator::OperatorKind::kMaxPool2d: { + XNN_CHECK_STATUS_AND_SET_ERROR_MESSAGE(xnn_define_max_pooling_2d( + subgraph, padding.top, padding.right, padding.bottom, padding.left, + filter_height, filter_width, stride_height, stride_width, + dilation_height, dilation_width, output_min, output_max, input_id, + output_id, flags)); + break; + } + default: + // Only average and max pool2d are supported by this method. + NOTREACHED(); + } + return xnn_status_success; +} + xnn_status DefineXnnNodeForRelu(xnn_subgraph_t subgraph, const MLOperator* relu, const OperandValueIdMap& operand_value_id_map, @@ -651,6 +783,13 @@ subgraph, ml_operator, operand_value_id_map, error_message)); break; } + // Define XNNPACK Node for pool2d operators. + case MLOperator::OperatorKind::kAveragePool2d: + case MLOperator::OperatorKind::kMaxPool2d: { + XNN_CHECK_STATUS(DefineXnnNodeForPool2d( + subgraph, ml_operator, operand_value_id_map, error_message)); + break; + } case MLOperator::OperatorKind::kRelu: XNN_CHECK_STATUS(DefineXnnNodeForRelu( subgraph, ml_operator, operand_value_id_map, error_message));
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack_test.cc index 17c8cf7..281f2e4 100644 --- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack_test.cc +++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack_test.cc
@@ -14,6 +14,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_dom_exception.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_pool_2d_options.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/modules/ml/ml.h" @@ -1028,6 +1029,80 @@ } } +template <typename T> +struct Pool2dTester { + MLGraphXnnpackTest* helper; + Pool2dKind kind; + OperandInfo<T> input; + Vector<T> expected; + + void Test(V8TestingScope& scope, + MLPool2dOptions* options = MLPool2dOptions::Create()) { + auto* builder = CreateMLGraphBuilder(scope); + auto* input_operand = + BuildInput(scope, builder, "input", input.dimensions, input.type); + auto* output_operand = + BuildPool2d(scope, builder, kind, input_operand, options); + auto [graph, build_exception] = + helper->BuildGraph(scope, builder, {{"output", output_operand}}); + EXPECT_NE(graph, nullptr); + + auto input_buffer = + CreateArrayBufferViewForOperand(input_operand, input.values); + auto output_buffer = CreateArrayBufferViewForOperand(output_operand); + auto* compute_exception = helper->ComputeGraph( + scope, graph, {{"input", input_buffer}}, {{"output", output_buffer}}); + EXPECT_EQ(compute_exception, nullptr); + Vector<float> results = GetArrayBufferViewValues<T>(output_buffer); + EXPECT_EQ(results, expected); + } +}; + +TEST_P(MLGraphXnnpackTest, Pool2dTest) { + V8TestingScope scope; + { + // Test averagePool2d operator for nhwc input layout. + auto* options = MLPool2dOptions::Create(); + options->setLayout(V8MLInputOperandLayout::Enum::kNhwc); + options->setWindowDimensions({3, 3}); + Pool2dTester<float>{ + .kind = Pool2dKind::kAverage, + .input = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {1, 4, 4, 1}, + .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, + 11.0, 12.0, 13.0, 14.0, 15.0, 16.0}}, + .expected = {6.0, 7.0, 10.0, 11.0}} + .Test(scope, options); + } + { + // Test global averagePool2d operator for nhwc input layout. + auto* options = MLPool2dOptions::Create(); + options->setLayout(V8MLInputOperandLayout::Enum::kNhwc); + Pool2dTester<float>{ + .kind = Pool2dKind::kAverage, + .input = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {1, 4, 4, 1}, + .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, + 11.0, 12.0, 13.0, 14.0, 15.0, 16.0}}, + .expected = {8.5}} + .Test(scope, options); + } + { + // Test maxPool2d operator for nhwc input layout. + auto* options = MLPool2dOptions::Create(); + options->setLayout(V8MLInputOperandLayout::Enum::kNhwc); + options->setWindowDimensions({3, 3}); + Pool2dTester<float>{ + .kind = Pool2dKind::kMax, + .input = {.type = V8MLOperandType::Enum::kFloat32, + .dimensions = {1, 4, 4, 1}, + .values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, + 11.0, 12.0, 13.0, 14.0, 15.0, 16.0}}, + .expected = {11.0, 12.0, 15.0, 16.0}} + .Test(scope, options); + } +} + // TODO(crbug.com/1273291): Test the async execution mode once the // MLGraphXnnpack implements it. INSTANTIATE_TEST_SUITE_P(All,
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy.h b/third_party/blink/renderer/modules/nfc/nfc_proxy.h index 6756a2e..b7aa3ae 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_proxy.h +++ b/third_party/blink/renderer/modules/nfc/nfc_proxy.h
@@ -14,7 +14,7 @@ #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" #include "third_party/blink/renderer/platform/supplementable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h b/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h index 9585b7d..71b4dcd9 100644 --- a/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h +++ b/third_party/blink/renderer/modules/payments/goods/digital_goods_service.h
@@ -11,7 +11,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/forward.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h b/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h index 07e0cf7..cb8d40e5 100644 --- a/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h +++ b/third_party/blink/renderer/modules/payments/goods/dom_window_digital_goods.h
@@ -10,7 +10,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/platform/heap/visitor.h" #include "third_party/blink/renderer/platform/supplementable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h index 0381449..dc37d98 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h
@@ -18,7 +18,7 @@ #include "third_party/blink/renderer/platform/heap/prefinalizer.h" #include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h" #include "third_party/blink/renderer/platform/supplementable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/webrtc/api/peer_connection_interface.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h index dd91c3b..bedc7b0 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h
@@ -21,7 +21,7 @@ #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_transceiver_platform.h" #include "third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h" #include "third_party/blink/renderer/platform/supplementable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/webrtc/api/peer_connection_interface.h"
diff --git a/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc b/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc index cfbc49c9..01342fa 100644 --- a/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/webrtc_audio_renderer_test.cc
@@ -11,10 +11,13 @@ #include "base/cfi_buildflags.h" #include "base/functional/bind.h" #include "base/run_loop.h" +#include "base/time/time.h" #include "build/build_config.h" #include "media/audio/audio_sink_parameters.h" #include "media/audio/audio_source_parameters.h" +#include "media/base/audio_bus.h" #include "media/base/audio_capturer_source.h" +#include "media/base/audio_glitch_info.h" #include "media/base/mock_audio_renderer_sink.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -36,6 +39,7 @@ #include "third_party/webrtc/api/media_stream_interface.h" using testing::_; +using testing::AnyNumber; using testing::DoAll; using testing::InvokeWithoutArgs; using testing::Return; @@ -50,16 +54,22 @@ const char kDefaultOutputDeviceId[] = ""; const char kOtherOutputDeviceId[] = "other-output-device"; const char kInvalidOutputDeviceId[] = "invalid-device"; +const media::AudioParameters kAudioParameters( + media::AudioParameters::AUDIO_PCM_LOW_LATENCY, + media::ChannelLayoutConfig::Stereo(), + kHardwareSampleRate, + kHardwareBufferSize); class MockAudioRendererSource : public blink::WebRtcAudioRendererSource { public: - MockAudioRendererSource() {} - ~MockAudioRendererSource() override {} - MOCK_METHOD4(RenderData, + MockAudioRendererSource() = default; + ~MockAudioRendererSource() override = default; + MOCK_METHOD5(RenderData, void(media::AudioBus* audio_bus, int sample_rate, base::TimeDelta audio_delay, - base::TimeDelta* current_time)); + base::TimeDelta* current_time, + const media::AudioGlitchInfo& glitch_info)); MOCK_METHOD1(RemoveAudioRenderer, void(blink::WebRtcAudioRenderer* renderer)); MOCK_METHOD0(AudioRendererThreadStopped, void()); MOCK_METHOD1(SetOutputDeviceForAec, void(const String&)); @@ -88,9 +98,7 @@ params.device_id == kInvalidOutputDeviceId ? media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL : media::OUTPUT_DEVICE_STATUS_OK, - media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, - media::ChannelLayoutConfig::Stereo(), - kHardwareSampleRate, kHardwareBufferSize)); + kAudioParameters); if (params.device_id != kInvalidOutputDeviceId) { EXPECT_CALL(*mock_sink_.get(), Start()); @@ -202,6 +210,10 @@ return audio_device_factory_platform_->mock_sink(); } + media::AudioRendererSink::RenderCallback* render_callback() { + return mock_sink()->callback(); + } + void TearDown() override { base::RunLoop().RunUntilIdle(); renderer_proxy_ = nullptr; @@ -296,6 +308,31 @@ renderer_proxy_->Stop(); } +TEST_F(WebRtcAudioRendererTest, Render) { + SetupRenderer(kDefaultOutputDeviceId); + EXPECT_EQ(kDefaultOutputDeviceId, + mock_sink()->GetOutputDeviceInfo().device_id()); + renderer_proxy_->Start(); + + auto dest = media::AudioBus::Create(kAudioParameters); + media::AudioGlitchInfo glitch_info{}; + auto audio_delay = base::Seconds(1); + + EXPECT_CALL(*mock_sink(), CurrentThreadIsRenderingThread()) + .WillRepeatedly(Return(true)); + // We cannot place any specific expectations on the calls to RenderData, + // because they vary depending on whether or not the fifo is used, which in + // turn varies depending on the platform. + EXPECT_CALL(*source_, RenderData(_, kAudioParameters.sample_rate(), _, _, _)) + .Times(AnyNumber()); + render_callback()->Render(audio_delay, base::TimeTicks(), glitch_info, + dest.get()); + + EXPECT_CALL(*mock_sink(), Stop()); + EXPECT_CALL(*source_.get(), RemoveAudioRenderer(renderer_.get())); + renderer_proxy_->Stop(); +} + TEST_F(WebRtcAudioRendererTest, NonDefaultDevice) { SetupRenderer(kDefaultOutputDeviceId); EXPECT_EQ(kDefaultOutputDeviceId,
diff --git a/third_party/blink/renderer/modules/presentation/presentation_connection.cc b/third_party/blink/renderer/modules/presentation/presentation_connection.cc index 9c49388..718f3c7 100644 --- a/third_party/blink/renderer/modules/presentation/presentation_connection.cc +++ b/third_party/blink/renderer/modules/presentation/presentation_connection.cc
@@ -288,14 +288,16 @@ void ControllerPresentationConnection::CloseInternal() { auto& service = controller_->GetPresentationService(); - if (service) + if (service.is_bound()) { service->CloseConnection(url_, id_); + } } void ControllerPresentationConnection::TerminateInternal() { auto& service = controller_->GetPresentationService(); - if (service) + if (service.is_bound()) { service->Terminate(url_, id_); + } } // static
diff --git a/third_party/blink/renderer/modules/presentation/presentation_controller.cc b/third_party/blink/renderer/modules/presentation/presentation_controller.cc index 9d151d91..c967b63 100644 --- a/third_party/blink/renderer/modules/presentation/presentation_controller.cc +++ b/third_party/blink/renderer/modules/presentation/presentation_controller.cc
@@ -17,6 +17,7 @@ PresentationController::PresentationController(LocalDOMWindow& window) : Supplement<LocalDOMWindow>(window), + presentation_service_remote_(&window), presentation_controller_receiver_(this, &window) {} PresentationController::~PresentationController() = default; @@ -44,6 +45,7 @@ } void PresentationController::Trace(Visitor* visitor) const { + visitor->Trace(presentation_service_remote_); visitor->Trace(presentation_controller_receiver_); visitor->Trace(presentation_); visitor->Trace(connections_); @@ -139,9 +141,9 @@ return nullptr; } -mojo::Remote<mojom::blink::PresentationService>& +HeapMojoRemote<mojom::blink::PresentationService>& PresentationController::GetPresentationService() { - if (!presentation_service_remote_ && GetSupplementable()) { + if (!presentation_service_remote_.is_bound() && GetSupplementable()) { scoped_refptr<base::SingleThreadTaskRunner> task_runner = GetSupplementable()->GetTaskRunner(TaskType::kPresentation); GetSupplementable()->GetBrowserInterfaceBroker().GetInterface(
diff --git a/third_party/blink/renderer/modules/presentation/presentation_controller.h b/third_party/blink/renderer/modules/presentation/presentation_controller.h index 46b1d4b..e0f74285 100644 --- a/third_party/blink/renderer/modules/presentation/presentation_controller.h +++ b/third_party/blink/renderer/modules/presentation/presentation_controller.h
@@ -5,7 +5,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_CONTROLLER_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PRESENTATION_PRESENTATION_CONTROLLER_H_ -#include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/presentation/presentation.mojom-blink.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/platform/web_url.h" @@ -16,9 +15,10 @@ #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" +#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" #include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink { @@ -67,7 +67,7 @@ // Returns a reference to the PresentationService remote, requesting the // remote service if needed. May return an invalid remote if the associated // Document is detached. - mojo::Remote<mojom::blink::PresentationService>& GetPresentationService(); + HeapMojoRemote<mojom::blink::PresentationService>& GetPresentationService(); // Returns the PresentationAvailabilityState owned by |this|, creating it if // needed. Always non-null. @@ -105,8 +105,8 @@ HeapHashSet<WeakMember<ControllerPresentationConnection>> connections_; // Holder of the Mojo connection to the PresentationService remote. - GC_PLUGIN_IGNORE("https://crbug.com/1381979") - mojo::Remote<mojom::blink::PresentationService> presentation_service_remote_; + HeapMojoRemote<mojom::blink::PresentationService> + presentation_service_remote_; // Lazily-initialized binding for mojom::blink::PresentationController. Sent // to |presentation_service_|'s implementation.
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc index 0b451bf..da7cdf1 100644 --- a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc +++ b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
@@ -32,7 +32,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "v8/include/v8.h" using blink::mojom::ServiceWorkerResponseError;
diff --git a/third_party/blink/renderer/modules/storage/storage_namespace.cc b/third_party/blink/renderer/modules/storage/storage_namespace.cc index 0276e52..838c3f6 100644 --- a/third_party/blink/renderer/modules/storage/storage_namespace.cc +++ b/third_party/blink/renderer/modules/storage/storage_namespace.cc
@@ -84,7 +84,10 @@ CacheMetrics metric = CacheMetrics::kMiss; scoped_refptr<CachedStorageArea> result; - auto cache_it = cached_areas_.find(&local_dom_window->GetStorageKey()); + const BlinkStorageKey& storage_key = + IsSessionStorage() ? local_dom_window->GetSessionStorageKey() + : local_dom_window->GetStorageKey(); + auto cache_it = cached_areas_.find(&storage_key); if (cache_it != cached_areas_.end()) { metric = cache_it->value->HasOneRef() ? CacheMetrics::kHit : CacheMetrics::kUnused; @@ -104,10 +107,9 @@ result = base::MakeRefCounted<CachedStorageArea>( IsSessionStorage() ? CachedStorageArea::AreaType::kSessionStorage : CachedStorageArea::AreaType::kLocalStorage, - local_dom_window->GetStorageKey(), local_dom_window, this, + storage_key, local_dom_window, this, /*is_session_storage_for_prerendering=*/false, std::move(storage_area)); - cached_areas_.insert(std::make_unique<const BlinkStorageKey>( - local_dom_window->GetStorageKey()), + cached_areas_.insert(std::make_unique<const BlinkStorageKey>(storage_key), result); return result; } @@ -119,7 +121,9 @@ return base::MakeRefCounted<CachedStorageArea>( IsSessionStorage() ? CachedStorageArea::AreaType::kSessionStorage : CachedStorageArea::AreaType::kLocalStorage, - local_dom_window->GetStorageKey(), local_dom_window, this, + IsSessionStorage() ? local_dom_window->GetSessionStorageKey() + : local_dom_window->GetStorageKey(), + local_dom_window, this, /*is_session_storage_for_prerendering=*/true, std::move(storage_area)); } @@ -222,8 +226,9 @@ mojo::PendingReceiver<mojom::blink::StorageArea> receiver) { if (IsSessionStorage()) { controller_->dom_storage()->BindSessionStorageArea( - local_dom_window.GetStorageKey(), local_dom_window.GetLocalFrameToken(), - namespace_id_, std::move(receiver)); + local_dom_window.GetSessionStorageKey(), + local_dom_window.GetLocalFrameToken(), namespace_id_, + std::move(receiver)); } else { controller_->dom_storage()->OpenLocalStorage( local_dom_window.GetStorageKey(), local_dom_window.GetLocalFrameToken(),
diff --git a/third_party/blink/renderer/modules/webcodecs/DEPS b/third_party/blink/renderer/modules/webcodecs/DEPS index 339324a..5eb560ca 100644 --- a/third_party/blink/renderer/modules/webcodecs/DEPS +++ b/third_party/blink/renderer/modules/webcodecs/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+base/containers/flat_map.h", "+base/functional/bind.h", "+base/strings/string_util.h", "+base/test",
diff --git a/third_party/blink/renderer/modules/webcodecs/codec_logger.h b/third_party/blink/renderer/modules/webcodecs/codec_logger.h index 5810218..dfc901f 100644 --- a/third_party/blink/renderer/modules/webcodecs/codec_logger.h +++ b/third_party/blink/renderer/modules/webcodecs/codec_logger.h
@@ -14,6 +14,7 @@ #include "base/sequence_checker.h" #include "media/base/media_log.h" #include "media/base/media_util.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -83,10 +84,15 @@ // instance of |CodecLogger|. if (parent_media_log_) { parent_media_log_->Stop(); - // This task runner may be destroyed without running tasks, so don't use - // DeleteSoon() which can leak the log. See https://crbug.com/1376851. - task_runner_->PostTask(FROM_HERE, base::DoNothingWithBoundArgs( - std::move(parent_media_log_))); + if (base::FeatureList::IsEnabled( + features::kUseBlinkSchedulerTaskRunnerWithCustomDeleter)) { + task_runner_->DeleteSoon(FROM_HERE, std::move(parent_media_log_)); + } else { + // This task runner may be destroyed without running tasks, so don't use + // DeleteSoon() which can leak the log. See https://crbug.com/1376851. + task_runner_->PostTask(FROM_HERE, base::DoNothingWithBoundArgs( + std::move(parent_media_log_))); + } } }
diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc index ef22f2b..011a447 100644 --- a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc +++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
@@ -18,6 +18,7 @@ #include "media/base/decoder_status.h" #include "media/media_buildflags.h" #include "media/video/gpu_video_accelerator_factories.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" @@ -530,11 +531,15 @@ // Clear decoding and JS-visible queue state. Use PostTask() to avoid deleting // decoder_ when its callback (e.g. OnDecodeDone()) may be below us in the // stack. - // - // NOTE: This task runner may be destroyed without running tasks, so don't use - // DeleteSoon() which can leak the codec. See https://crbug.com/1376851. - main_thread_task_runner_->PostTask( - FROM_HERE, base::DoNothingWithBoundArgs(std::move(decoder_))); + if (base::FeatureList::IsEnabled( + features::kUseBlinkSchedulerTaskRunnerWithCustomDeleter)) { + main_thread_task_runner_->DeleteSoon(FROM_HERE, std::move(decoder_)); + } else { + // NOTE: This task runner may be destroyed without running tasks, so don't + // use DeleteSoon() which can leak the codec. See https://crbug.com/1376851. + main_thread_task_runner_->PostTask( + FROM_HERE, base::DoNothingWithBoundArgs(std::move(decoder_))); + } if (pending_request_) { // This request was added as part of calling ResetAlgorithm above. However,
diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc index 2a5de4ab..671758b6 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc +++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
@@ -14,6 +14,7 @@ #include "base/metrics/histogram_functions.h" #include "base/trace_event/common/trace_event_common.h" #include "base/trace_event/trace_event.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/bindings/core/v8/script_function.h" @@ -232,11 +233,15 @@ // |media_encoder_|. If we delete it now, this thread might come back up // the call stack and continue executing code belonging to deleted // |media_encoder_|. - // - // NOTE: This task runner may be destroyed without running tasks, so don't - // use DeleteSoon() which can leak the codec. See https://crbug.com/1376851. - callback_runner_->PostTask( - FROM_HERE, base::DoNothingWithBoundArgs(std::move(media_encoder_))); + if (base::FeatureList::IsEnabled( + features::kUseBlinkSchedulerTaskRunnerWithCustomDeleter)) { + callback_runner_->DeleteSoon(FROM_HERE, std::move(media_encoder_)); + } else { + // NOTE: This task runner may be destroyed without running tasks, so don't + // use DeleteSoon() which can leak the codec. See https://crbug.com/1376851. + callback_runner_->PostTask( + FROM_HERE, base::DoNothingWithBoundArgs(std::move(media_encoder_))); + } // This codec isn't holding on to any resources, and doesn't need to be // reclaimed.
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder.cc b/third_party/blink/renderer/modules/webcodecs/video_decoder.cc index de8fd6c..d0f43094 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_decoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_decoder.cc
@@ -519,8 +519,7 @@ VideoDecoder::VideoDecoder(ScriptState* script_state, const VideoDecoderInit* init, ExceptionState& exception_state) - : DecoderTemplate<VideoDecoderTraits>(script_state, init, exception_state), - chunk_metadata_(128) { + : DecoderTemplate<VideoDecoderTraits>(script_state, init, exception_state) { UseCounter::Count(ExecutionContext::From(script_state), WebFeature::kWebCodecs); } @@ -618,8 +617,8 @@ } } - chunk_metadata_.Put(chunk.buffer()->timestamp(), - ChunkMetadata{chunk.buffer()->duration()}); + chunk_metadata_[chunk.buffer()->timestamp()] = + ChunkMetadata{chunk.buffer()->duration()}; return decoder_buffer; } @@ -627,7 +626,7 @@ media::DecoderStatus::Or<VideoDecoder::OutputType*> VideoDecoder::MakeOutput( scoped_refptr<MediaOutputType> output, ExecutionContext* context) { - const auto it = chunk_metadata_.Get(output->timestamp()); + const auto it = chunk_metadata_.find(output->timestamp()); if (it != chunk_metadata_.end()) { const auto duration = it->second.duration; if (!duration.is_zero() && duration != media::kNoTimestamp) { @@ -638,8 +637,11 @@ wrapped_output->metadata().frame_duration = duration; output = wrapped_output; } - } + // We erase from the beginning onward to our target frame since frames + // should be returned in presentation order. + chunk_metadata_.erase(chunk_metadata_.begin(), it + 1); + } return MakeGarbageCollected<OutputType>(std::move(output), context); }
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder.h b/third_party/blink/renderer/modules/webcodecs/video_decoder.h index 376b6ae3..1796bd8 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_decoder.h +++ b/third_party/blink/renderer/modules/webcodecs/video_decoder.h
@@ -8,7 +8,7 @@ #include <stdint.h> #include <memory> -#include "base/containers/lru_cache.h" +#include "base/containers/flat_map.h" #include "base/time/time.h" #include "media/base/media_types.h" #include "media/base/status.h" @@ -140,7 +140,7 @@ struct ChunkMetadata { base::TimeDelta duration; }; - base::LRUCache<base::TimeDelta, ChunkMetadata> chunk_metadata_; + base::flat_map<base::TimeDelta, ChunkMetadata> chunk_metadata_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc index b8d8171..7be22fc 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -37,6 +37,7 @@ #include "media/video/offloading_video_encoder.h" #include "media/video/video_encode_accelerator_adapter.h" #include "media/video/video_encoder_fallback.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-blink.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" @@ -557,8 +558,7 @@ const VideoEncoderInit* init, ExceptionState& exception_state) : Base(script_state, init, exception_state), - max_active_encodes_(ComputeMaxActiveEncodes()), - frame_metadata_(128) { + max_active_encodes_(ComputeMaxActiveEncodes()) { UseCounter::Count(ExecutionContext::From(script_state), WebFeature::kWebCodecs); } @@ -875,8 +875,8 @@ MakeUnwrappingCrossThreadHandle(request))); if (frame->metadata().frame_duration) { - frame_metadata_.Put(frame->timestamp(), - FrameMetadata{*frame->metadata().frame_duration}); + frame_metadata_[frame->timestamp()] = + FrameMetadata{*frame->metadata().frame_duration}; } // Currently underlying encoders can't handle frame backed by textures, @@ -1094,11 +1094,19 @@ buffer->set_is_key_frame(output.key_frame); // Get duration from |frame_metadata_|. - const auto it = frame_metadata_.Get(output.timestamp); + const auto it = frame_metadata_.find(output.timestamp); if (it != frame_metadata_.end()) { const auto duration = it->second.duration; - if (!duration.is_zero() && duration != media::kNoTimestamp) + if (!duration.is_zero() && duration != media::kNoTimestamp) { buffer->set_duration(duration); + } + + // While encoding happens in presentation order, outputs may be out of order + // for some codec configurations. The maximum number of reordered outputs is + // 16, so we can clear everything before that. + if (it - frame_metadata_.begin() > 16) { + frame_metadata_.erase(frame_metadata_.begin(), it + 1); + } } auto* chunk = MakeGarbageCollected<EncodedVideoChunk>(std::move(buffer)); @@ -1205,10 +1213,15 @@ media::EncoderStatus status) { support->setSupported(status.is_ok()); resolver->Resolve(support); - // This task runner may be destroyed without running tasks, so don't use - // DeleteSoon() which can leak the codec. See https://crbug.com/1376851. - runner->PostTask(FROM_HERE, - base::DoNothingWithBoundArgs(std::move(encoder))); + if (base::FeatureList::IsEnabled( + features::kUseBlinkSchedulerTaskRunnerWithCustomDeleter)) { + runner->DeleteSoon(FROM_HERE, std::move(encoder)); + } else { + // This task runner may be destroyed without running tasks, so don't use + // DeleteSoon() which can leak the codec. See https://crbug.com/1376851. + runner->PostTask(FROM_HERE, + base::DoNothingWithBoundArgs(std::move(encoder))); + } }; auto* context = ExecutionContext::From(script_state);
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.h b/third_party/blink/renderer/modules/webcodecs/video_encoder.h index 3f54a1ad..ace1aa4 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_encoder.h +++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
@@ -7,7 +7,7 @@ #include <memory> -#include "base/containers/lru_cache.h" +#include "base/containers/flat_map.h" #include "base/time/time.h" #include "media/base/video_codecs.h" #include "media/base/video_color_space.h" @@ -155,7 +155,7 @@ struct FrameMetadata { base::TimeDelta duration; }; - base::LRUCache<base::TimeDelta, FrameMetadata> frame_metadata_; + base::flat_map<base::TimeDelta, FrameMetadata> frame_metadata_; // The color space corresponding to the last emitted output. Used to update // emitted VideoDecoderConfig when necessary.
diff --git a/third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc b/third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc index a4672a6..6c2b88a7 100644 --- a/third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc +++ b/third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc
@@ -77,7 +77,7 @@ framebuffer_binding->SetAttachmentForBoundFramebuffer( target, attachment, textarget, texture, level, base_view_index, num_views); - scoped.Context()->ApplyStencilTest(); + scoped.Context()->ApplyDepthAndStencilTest(); } bool OVRMultiview2::Supported(WebGLRenderingContextBase* context) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc index 531810c..b6950f6 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -546,7 +546,7 @@ } framebuffer_binding->SetAttachmentForBoundFramebuffer( target, attachment, textarget, texture, level, layer, 0); - ApplyStencilTest(); + ApplyDepthAndStencilTest(); } ScriptValue WebGL2RenderingContextBase::getInternalformatParameter( @@ -1087,7 +1087,7 @@ } RenderbufferStorageImpl(target, samples, internalformat, width, height, function_name); - ApplyStencilTest(); + ApplyDepthAndStencilTest(); } void WebGL2RenderingContextBase::ResetUnpackParameters() {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc index f1ba374..8ffeabd 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
@@ -184,9 +184,11 @@ WebGLFramebuffer::WebGLAttachment::WebGLAttachment() = default; WebGLFramebuffer* WebGLFramebuffer::CreateOpaque(WebGLRenderingContextBase* ctx, + bool has_depth, bool has_stencil) { WebGLFramebuffer* const fb = MakeGarbageCollected<WebGLFramebuffer>(ctx, true); + fb->SetOpaqueHasDepth(has_depth); fb->SetOpaqueHasStencil(has_stencil); return fb; } @@ -368,6 +370,18 @@ return GL_FRAMEBUFFER_UNSUPPORTED; } +bool WebGLFramebuffer::HasDepthBuffer() const { + if (opaque_) { + return opaque_has_depth_; + } else { + WebGLAttachment* attachment = GetAttachment(GL_DEPTH_ATTACHMENT); + if (!attachment) { + attachment = GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT); + } + return attachment && attachment->Valid(); + } +} + bool WebGLFramebuffer::HasStencilBuffer() const { if (opaque_) { return opaque_has_stencil_;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h index a2673fe..534b4593 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h +++ b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h
@@ -76,6 +76,7 @@ // the browser and not inspectable or alterable via Javascript. This is // primarily used by the VRWebGLLayer interface. static WebGLFramebuffer* CreateOpaque(WebGLRenderingContextBase*, + bool has_depth, bool has_stencil); GLuint Object() const { return object_; } @@ -106,6 +107,7 @@ void SetHasEverBeenBound() { has_ever_been_bound_ = true; } + bool HasDepthBuffer() const; bool HasStencilBuffer() const; bool HaveContentsChanged() { return contents_changed_; } @@ -113,6 +115,7 @@ bool Opaque() const { return opaque_; } void MarkOpaqueBufferComplete(bool complete) { opaque_complete_ = complete; } + void SetOpaqueHasDepth(bool has_depth) { opaque_has_depth_ = has_depth; } void SetOpaqueHasStencil(bool has_stencil) { opaque_has_stencil_ = has_stencil; } @@ -168,6 +171,7 @@ bool web_gl1_depth_stencil_consistent_; bool contents_changed_ = false; const bool opaque_; + bool opaque_has_depth_ = false; bool opaque_has_stencil_ = false; bool opaque_complete_ = false;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 7bde2e81..8e2d6a6 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1232,6 +1232,7 @@ framebuffer_binding_ = nullptr; renderbuffer_binding_ = nullptr; depth_mask_ = true; + depth_enabled_ = false; stencil_enabled_ = false; stencil_mask_ = 0xFFFFFFFF; stencil_mask_back_ = 0xFFFFFFFF; @@ -2828,7 +2829,12 @@ return; if (cap == GL_STENCIL_TEST) { stencil_enabled_ = false; - ApplyStencilTest(); + ApplyDepthAndStencilTest(); + return; + } + if (cap == GL_DEPTH_TEST) { + depth_enabled_ = false; + ApplyDepthAndStencilTest(); return; } if (cap == GL_SCISSOR_TEST) @@ -2983,7 +2989,12 @@ return; if (cap == GL_STENCIL_TEST) { stencil_enabled_ = true; - ApplyStencilTest(); + ApplyDepthAndStencilTest(); + return; + } + if (cap == GL_DEPTH_TEST) { + depth_enabled_ = true; + ApplyDepthAndStencilTest(); return; } if (cap == GL_SCISSOR_TEST) @@ -3055,7 +3066,7 @@ } framebuffer_binding->SetAttachmentForBoundFramebuffer(target, attachment, buffer); - ApplyStencilTest(); + ApplyDepthAndStencilTest(); } void WebGLRenderingContextBase::framebufferTexture2D(GLenum target, @@ -3087,7 +3098,7 @@ } framebuffer_binding->SetAttachmentForBoundFramebuffer( target, attachment, textarget, texture, level, 0, 0); - ApplyStencilTest(); + ApplyDepthAndStencilTest(); } void WebGLRenderingContextBase::frontFace(GLenum mode) { @@ -3587,7 +3598,7 @@ case GL_DEPTH_RANGE: return GetWebGLFloatArrayParameter(script_state, pname); case GL_DEPTH_TEST: - return GetBooleanParameter(script_state, pname); + return WebGLAny(script_state, depth_enabled_); case GL_DEPTH_WRITEMASK: return GetBooleanParameter(script_state, pname); case GL_DITHER: @@ -4514,8 +4525,12 @@ GLboolean WebGLRenderingContextBase::isEnabled(GLenum cap) { if (isContextLost() || !ValidateCapability("isEnabled", cap)) return 0; - if (cap == GL_STENCIL_TEST) + if (cap == GL_DEPTH_TEST) { + return depth_enabled_; + } + if (cap == GL_STENCIL_TEST) { return stencil_enabled_; + } return ContextGL()->IsEnabled(cap); } @@ -4967,7 +4982,7 @@ return; RenderbufferStorageImpl(target, 0, internalformat, width, height, function_name); - ApplyStencilTest(); + ApplyDepthAndStencilTest(); } void WebGLRenderingContextBase::sampleCoverage(GLfloat value, @@ -8758,15 +8773,20 @@ NotifyWebGLWarning(); } -void WebGLRenderingContextBase::ApplyStencilTest() { +void WebGLRenderingContextBase::ApplyDepthAndStencilTest() { bool have_stencil_buffer = false; + bool have_depth_buffer = false; if (framebuffer_binding_) { + have_depth_buffer = framebuffer_binding_->HasDepthBuffer(); have_stencil_buffer = framebuffer_binding_->HasStencilBuffer(); } else { + have_depth_buffer = !isContextLost() && CreationAttributes().depth && + GetDrawingBuffer()->HasDepthBuffer(); have_stencil_buffer = !isContextLost() && CreationAttributes().stencil && GetDrawingBuffer()->HasStencilBuffer(); } + EnableOrDisable(GL_DEPTH_TEST, depth_enabled_ && have_depth_buffer); EnableOrDisable(GL_STENCIL_TEST, stencil_enabled_ && have_stencil_buffer); } @@ -8824,7 +8844,7 @@ if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) { framebuffer_binding_ = buffer; - ApplyStencilTest(); + ApplyDepthAndStencilTest(); } if (!buffer) { // Instead of binding fb 0, bind the drawing buffer.
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h index 702dc807..fce3445 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -963,6 +963,7 @@ GLboolean color_mask_[4]; GLboolean depth_mask_; + bool depth_enabled_; bool stencil_enabled_; GLuint stencil_mask_, stencil_mask_back_; GLint stencil_func_ref_, @@ -1825,9 +1826,10 @@ String EnsureNotNull(const String&) const; - // Enable or disable stencil test based on user setting and - // whether the current FBO has a stencil buffer. - void ApplyStencilTest(); + // Enable or disable the depth and stencil test based on the user's + // setting and whether the current FBO has a depth and stencil + // buffer. + void ApplyDepthAndStencilTest(); // Helper for enabling or disabling a capability. void EnableOrDisable(GLenum capability, bool enable);
diff --git a/third_party/blink/renderer/modules/webrtc/DEPS b/third_party/blink/renderer/modules/webrtc/DEPS index 378ca4f..3f359076 100644 --- a/third_party/blink/renderer/modules/webrtc/DEPS +++ b/third_party/blink/renderer/modules/webrtc/DEPS
@@ -5,6 +5,7 @@ "+media/base/audio_bus.h", "+media/base/audio_capturer_source.h", "+media/base/audio_decoder.h", + "+media/base/audio_glitch_info.h", "+media/base/audio_power_monitor.h", "+media/base/audio_latency.h", "+media/base/audio_parameters.h",
diff --git a/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc b/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc index 366039d..78194f06 100644 --- a/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc +++ b/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.cc
@@ -11,6 +11,7 @@ #include "base/trace_event/trace_event.h" #include "media/base/audio_bus.h" #include "media/base/audio_parameters.h" +#include "media/base/audio_timestamp_helper.h" #include "media/base/sample_rates.h" #include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h" #include "third_party/blink/renderer/modules/mediastream/processed_local_audio_source.h" @@ -50,14 +51,24 @@ DCHECK(!initialized_) << "Terminate must have been called."; } -void WebRtcAudioDeviceImpl::RenderData(media::AudioBus* audio_bus, - int sample_rate, - base::TimeDelta audio_delay, - base::TimeDelta* current_time) { +void WebRtcAudioDeviceImpl::RenderData( + media::AudioBus* audio_bus, + int sample_rate, + base::TimeDelta audio_delay, + base::TimeDelta* current_time, + const media::AudioGlitchInfo& glitch_info) { TRACE_EVENT2("audio", "WebRtcAudioDeviceImpl::RenderData", "sample_rate", sample_rate, "audio_delay_ms", audio_delay.InMilliseconds()); { base::AutoLock auto_lock(lock_); + cumulative_glitch_info_ += glitch_info; + total_samples_count_ += audio_bus->frames(); + // |total_playout_delay_| refers to the sum of playout delays for all + // samples, so we add the delay multiplied by the number of samples. See + // https://w3c.github.io/webrtc-stats/#dom-rtcaudioplayoutstats-totalplayoutdelay + total_playout_delay_ += audio_delay * audio_bus->frames(); + total_samples_duration_ += media::AudioTimestampHelper::FramesToTime( + audio_bus->frames(), sample_rate); #if DCHECK_IS_ON() DCHECK(!renderer_ || renderer_->CurrentThreadIsRenderingThread()); if (!audio_renderer_thread_checker_.CalledOnValidThread()) { @@ -387,6 +398,19 @@ playout_sinks_.remove(sink); } +absl::optional<webrtc::AudioDeviceModule::Stats> +WebRtcAudioDeviceImpl::GetStats() const { + base::AutoLock auto_lock(lock_); + return absl::optional<webrtc::AudioDeviceModule::Stats>( + webrtc::AudioDeviceModule::Stats{ + .synthesized_samples_duration_s = + cumulative_glitch_info_.duration.InSecondsF(), + .synthesized_samples_events = cumulative_glitch_info_.count, + .total_samples_duration_s = total_samples_duration_.InSecondsF(), + .total_playout_delay_s = total_playout_delay_.InSecondsF(), + .total_samples_count = total_samples_count_}); +} + base::UnguessableToken WebRtcAudioDeviceImpl::GetAuthorizedDeviceSessionIdForAudioRenderer() { DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
diff --git a/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h b/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h index b68f80d..9452dde 100644 --- a/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h +++ b/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h
@@ -15,6 +15,7 @@ #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "base/unguessable_token.h" +#include "media/base/audio_glitch_info.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webrtc/webrtc_audio_device_not_impl.h" #include "third_party/blink/renderer/platform/webrtc/webrtc_source.h" @@ -120,7 +121,8 @@ void RenderData(media::AudioBus* audio_bus, int sample_rate, base::TimeDelta audio_delay, - base::TimeDelta* current_time) override; + base::TimeDelta* current_time, + const media::AudioGlitchInfo& glitch_info) override; // Called on the main render thread. void RemoveAudioRenderer(blink::WebRtcAudioRenderer* renderer) override; @@ -131,6 +133,8 @@ void AddPlayoutSink(blink::WebRtcPlayoutDataSource::Sink* sink) override; void RemovePlayoutSink(blink::WebRtcPlayoutDataSource::Sink* sink) override; + absl::optional<webrtc::AudioDeviceModule::Stats> GetStats() const override; + private: using CapturerList = std::list<ProcessedLocalAudioSource*>; using PlayoutDataSinkList = std::list<blink::WebRtcPlayoutDataSource::Sink*>; @@ -180,6 +184,13 @@ // The output device used for echo cancellation String output_device_id_for_aec_; + + // Corresponds to RTCAudioPlayoutStats as defined in + // https://w3c.github.io/webrtc-stats/#playoutstats-dict* + media::AudioGlitchInfo cumulative_glitch_info_ GUARDED_BY(lock_); + base::TimeDelta total_samples_duration_ GUARDED_BY(lock_); + base::TimeDelta total_playout_delay_ GUARDED_BY(lock_); + uint64_t total_samples_count_ GUARDED_BY(lock_) = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl_test.cc b/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl_test.cc new file mode 100644 index 0000000..ed7d12c8 --- /dev/null +++ b/third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl_test.cc
@@ -0,0 +1,124 @@ +// Copyright 2023 The Chromium Authors +// 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/modules/webrtc/webrtc_audio_device_impl.h" + +#include <memory> + +#include "base/time/time.h" +#include "media/base/audio_bus.h" +#include "media/base/audio_glitch_info.h" +#include "media/base/audio_parameters.h" +#include "media/base/audio_timestamp_helper.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/webrtc/webrtc_source.h" +#include "third_party/webrtc/rtc_base/ref_counted_object.h" + +namespace blink { + +namespace { + +class MockAudioTransport : public webrtc::AudioTransport { + public: + MockAudioTransport() = default; + + MockAudioTransport(const MockAudioTransport&) = delete; + MockAudioTransport& operator=(const MockAudioTransport&) = delete; + + MOCK_METHOD10(RecordedDataIsAvailable, + int32_t(const void* audioSamples, + size_t nSamples, + size_t nBytesPerSample, + size_t nChannels, + uint32_t samplesPerSec, + uint32_t totalDelayMS, + int32_t clockDrift, + uint32_t currentMicLevel, + bool keyPressed, + uint32_t& newMicLevel)); + + MOCK_METHOD8(NeedMorePlayData, + int32_t(size_t nSamples, + size_t nBytesPerSample, + size_t nChannels, + uint32_t samplesPerSec, + void* audioSamples, + size_t& nSamplesOut, + int64_t* elapsed_time_ms, + int64_t* ntp_time_ms)); + + MOCK_METHOD7(PullRenderData, + void(int bits_per_sample, + int sample_rate, + size_t number_of_channels, + size_t number_of_frames, + void* audio_data, + int64_t* elapsed_time_ms, + int64_t* ntp_time_ms)); +}; + +const int kHardwareSampleRate = 44100; +const int kHardwareBufferSize = 512; + +const media::AudioParameters kAudioParameters = + media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, + media::ChannelLayoutConfig::Stereo(), + kHardwareSampleRate, + kHardwareBufferSize); + +} // namespace + +class WebRtcAudioDeviceImplTest : public testing::Test { + public: + WebRtcAudioDeviceImplTest() + : audio_device_( + new rtc::RefCountedObject<blink::WebRtcAudioDeviceImpl>()), + audio_transport_(new MockAudioTransport()) { + audio_device_module()->Init(); + audio_device_module()->RegisterAudioCallback(audio_transport_.get()); + } + + ~WebRtcAudioDeviceImplTest() override { audio_device_module()->Terminate(); } + + protected: + webrtc::AudioDeviceModule* audio_device_module() { + return static_cast<webrtc::AudioDeviceModule*>(audio_device_.get()); + } + + scoped_refptr<blink::WebRtcAudioDeviceImpl> audio_device_; + std::unique_ptr<MockAudioTransport> audio_transport_; +}; + +// Verify that stats are accumulated during calls to RenderData and are +// available through GetStats(). +TEST_F(WebRtcAudioDeviceImplTest, GetStats) { + auto audio_bus = media::AudioBus::Create(kAudioParameters); + int sample_rate = kAudioParameters.sample_rate(); + auto audio_delay = base::Seconds(1); + base::TimeDelta current_time; + media::AudioGlitchInfo glitch_info; + glitch_info.duration = base::Seconds(2); + glitch_info.count = 3; + + for (int i = 0; i < 10; i++) { + webrtc::AudioDeviceModule::Stats stats = *audio_device_->GetStats(); + EXPECT_EQ(stats.synthesized_samples_duration_s, + (base::Seconds(2) * i).InSecondsF()); + EXPECT_EQ(stats.synthesized_samples_events, 3ull * i); + EXPECT_EQ(stats.total_samples_count, + static_cast<uint64_t>(audio_bus->frames() * i)); + EXPECT_EQ(stats.total_playout_delay_s, + (audio_bus->frames() * i * base::Seconds(1)).InSecondsF()); + EXPECT_EQ(stats.total_samples_duration_s, + (media::AudioTimestampHelper::FramesToTime(audio_bus->frames(), + sample_rate) * + i) + .InSecondsF()); + audio_device_->RenderData(audio_bus.get(), sample_rate, audio_delay, + ¤t_time, glitch_info); + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc index d792707..1b216e4 100644 --- a/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc +++ b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.cc
@@ -618,6 +618,7 @@ return 0; audio_delay_ = delay; + glitch_info_accumulator_.Add(glitch_info); // Pull the data we will deliver. if (audio_fifo_) @@ -673,7 +674,7 @@ // We need to keep render data for the |source_| regardless of |state_|, // otherwise the data will be buffered up inside |source_|. source_->RenderData(audio_bus, sink_params_.sample_rate(), output_delay, - ¤t_time_); + ¤t_time_, glitch_info_accumulator_.GetAndReset()); // Avoid filling up the audio bus if we are not playing; instead // return here and ensure that the returned value in Render() is 0.
diff --git a/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.h b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.h index 45b0541d..c05e581 100644 --- a/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.h +++ b/third_party/blink/renderer/modules/webrtc/webrtc_audio_renderer.h
@@ -22,6 +22,7 @@ #include "base/time/time.h" #include "base/unguessable_token.h" #include "media/base/audio_decoder.h" +#include "media/base/audio_glitch_info.h" #include "media/base/audio_power_monitor.h" #include "media/base/audio_pull_fifo.h" #include "media/base/audio_renderer_sink.h" @@ -389,6 +390,9 @@ std::unique_ptr<media::SpeechRecognitionClient> speech_recognition_client_; TranscribeAudioCallback transcribe_audio_callback_; + // Accessed only on the rendering thread. + media::AudioGlitchInfo::Accumulator glitch_info_accumulator_; + base::WeakPtrFactory<WebRtcAudioRenderer> weak_factory_{this}; };
diff --git a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h index a12e234..70ac972 100644 --- a/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h +++ b/third_party/blink/renderer/modules/websockets/websocket_channel_impl.h
@@ -58,7 +58,7 @@ #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/deque.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.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"
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc index cbdea55..c12557d3 100644 --- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc +++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
@@ -127,8 +127,8 @@ gfx::ToFlooredSize(gfx::ScaleSize(framebuffers_size, framebuffer_scale)); // Create an opaque WebGL Framebuffer - WebGLFramebuffer* framebuffer = - WebGLFramebuffer::CreateOpaque(webgl_context, want_stencil_buffer); + WebGLFramebuffer* framebuffer = WebGLFramebuffer::CreateOpaque( + webgl_context, want_depth_buffer, want_stencil_buffer); scoped_refptr<XRWebGLDrawingBuffer> drawing_buffer = XRWebGLDrawingBuffer::Create(webgl_context->GetDrawingBuffer(),
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 5b82a79..f4559b5 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1496,7 +1496,6 @@ "weborigin/scheme_registry.h", "weborigin/security_origin.cc", "weborigin/security_origin.h", - "weborigin/security_origin_hash.h", "weborigin/security_policy.cc", "weborigin/security_policy.h", "webrtc/convert_to_webrtc_video_frame_buffer.cc",
diff --git a/third_party/blink/renderer/platform/fonts/font_cache_key.h b/third_party/blink/renderer/platform/fonts/font_cache_key.h index 9a7be88..2d8a95d 100644 --- a/third_party/blink/renderer/platform/fonts/font_cache_key.h +++ b/third_party/blink/renderer/platform/fonts/font_cache_key.h
@@ -62,7 +62,8 @@ scoped_refptr<FontVariationSettings> variation_settings, scoped_refptr<FontPalette> palette, scoped_refptr<FontVariantAlternates> font_variant_alternates, - bool is_unique_match) + bool is_unique_match, + bool is_generic_family) : creation_params_(creation_params), font_size_(font_size * kFontSizePrecisionMultiplier), options_(options), @@ -70,7 +71,8 @@ variation_settings_(std::move(variation_settings)), palette_(palette), font_variant_alternates_(font_variant_alternates), - is_unique_match_(is_unique_match) {} + is_unique_match_(is_unique_match), + is_generic_family_(is_generic_family) {} FontCacheKey(WTF::HashTableDeletedValueType) : font_size_(std::numeric_limits<unsigned>::max()), @@ -84,7 +86,7 @@ unsigned GetHash() const { // Convert from float with 3 digit precision before hashing. unsigned device_scale_factor_hash = device_scale_factor_ * 1000; - unsigned hash_codes[8] = { + unsigned hash_codes[9] = { creation_params_.GetHash(), font_size_, options_, @@ -95,7 +97,8 @@ (variation_settings_ ? variation_settings_->GetHash() : 0), palette_ ? palette_->GetHash() : 0, font_variant_alternates_ ? font_variant_alternates_->GetHash() : 0, - is_unique_match_ + is_unique_match_, + is_generic_family_ }; return StringHasher::HashMemory<sizeof(hash_codes)>(hash_codes); } @@ -117,7 +120,8 @@ variation_settings_equal && palette_equal && base::ValuesEquivalent(font_variant_alternates_, other.font_variant_alternates_) && - is_unique_match_ == other.is_unique_match_; + is_unique_match_ == other.is_unique_match_ && + is_generic_family_ == other.is_generic_family_; } bool operator!=(const FontCacheKey& other) const { return !(*this == other); } @@ -150,6 +154,7 @@ scoped_refptr<FontPalette> palette_; scoped_refptr<FontVariantAlternates> font_variant_alternates_; bool is_unique_match_ = false; + bool is_generic_family_ = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font_cache_test.cc b/third_party/blink/renderer/platform/fonts/font_cache_test.cc index bee99633..9f8be91 100644 --- a/third_party/blink/renderer/platform/fonts/font_cache_test.cc +++ b/third_party/blink/renderer/platform/fonts/font_cache_test.cc
@@ -172,7 +172,8 @@ /* variation_settings */ nullptr, /* palette */ nullptr, /* variant_alternates */ nullptr, - /* is_unique_match */ false); + /* is_unique_match */ false, + /* is_generic_family */ false); FontCacheKey key2 = key1; EXPECT_EQ(key1.GetHash(), key2.GetHash()); EXPECT_EQ(key1, key2);
diff --git a/third_party/blink/renderer/platform/fonts/font_description.cc b/third_party/blink/renderer/platform/fonts/font_description.cc index 2c3f254..85ff9929 100644 --- a/third_party/blink/renderer/platform/fonts/font_description.cc +++ b/third_party/blink/renderer/platform/fonts/font_description.cc
@@ -265,7 +265,8 @@ FontCacheKey FontDescription::CacheKey( const FontFaceCreationParams& creation_params, - bool is_unique_match) const { + bool is_unique_match, + bool is_generic_family) const { unsigned options = static_cast<unsigned>(fields_.font_optical_sizing_) << 7 | // bit 8 static_cast<unsigned>(fields_.synthetic_italic_) << 6 | // bit 7 @@ -283,7 +284,7 @@ options | font_selection_request_.GetHash() << 9, device_scale_factor_for_key, variation_settings_, font_palette_, font_variant_alternates_, - is_unique_match); + is_unique_match, is_generic_family); #if BUILDFLAG(IS_ANDROID) if (const LayoutLocale* locale = Locale()) { if (FontCache::GetLocaleSpecificFamilyName(creation_params.Family()))
diff --git a/third_party/blink/renderer/platform/fonts/font_description.h b/third_party/blink/renderer/platform/fonts/font_description.h index e1b3581..cd39d13b 100644 --- a/third_party/blink/renderer/platform/fonts/font_description.h +++ b/third_party/blink/renderer/platform/fonts/font_description.h
@@ -338,7 +338,8 @@ float EffectiveFontSize() const; // Returns either the computedSize or the computedPixelSize FontCacheKey CacheKey(const FontFaceCreationParams&, - bool is_unique_match) const; + bool is_unique_match, + bool is_generic_family) const; void SetFamily(const FontFamily& family) { family_list_ = family; } void SetComputedSize(float s) { computed_size_ = ClampTo<float>(s); }
diff --git a/third_party/blink/renderer/platform/fonts/font_description_test.cc b/third_party/blink/renderer/platform/fonts/font_description_test.cc index b71ecaa..8a0cf2c 100644 --- a/third_party/blink/renderer/platform/fonts/font_description_test.cc +++ b/third_party/blink/renderer/platform/fonts/font_description_test.cc
@@ -85,8 +85,8 @@ ASSERT_EQ(a, b); FontFaceCreationParams test_creation_params; - FontCacheKey cache_key_a = a.CacheKey(test_creation_params, false); - FontCacheKey cache_key_b = b.CacheKey(test_creation_params, false); + FontCacheKey cache_key_a = a.CacheKey(test_creation_params, false, false); + FontCacheKey cache_key_b = b.CacheKey(test_creation_params, false, false); ASSERT_EQ(cache_key_a, cache_key_b); } @@ -112,8 +112,8 @@ FontFaceCreationParams test_creation_params; - FontCacheKey cache_key_a = a.CacheKey(test_creation_params, false); - FontCacheKey cache_key_b = b.CacheKey(test_creation_params, false); + FontCacheKey cache_key_a = a.CacheKey(test_creation_params, false, false); + FontCacheKey cache_key_b = b.CacheKey(test_creation_params, false, false); ASSERT_NE(cache_key_a, cache_key_b); @@ -131,8 +131,10 @@ ASSERT_NE(a, b); - FontCacheKey second_cache_key_a = a.CacheKey(test_creation_params, false); - FontCacheKey second_cache_key_b = b.CacheKey(test_creation_params, false); + FontCacheKey second_cache_key_a = + a.CacheKey(test_creation_params, false, false); + FontCacheKey second_cache_key_b = + b.CacheKey(test_creation_params, false, false); ASSERT_NE(second_cache_key_a, second_cache_key_b); } @@ -156,8 +158,8 @@ FontFaceCreationParams test_creation_params; - FontCacheKey cache_key_a = a.CacheKey(test_creation_params, false); - FontCacheKey cache_key_b = b.CacheKey(test_creation_params, false); + FontCacheKey cache_key_a = a.CacheKey(test_creation_params, false, false); + FontCacheKey cache_key_b = b.CacheKey(test_creation_params, false, false); ASSERT_NE(cache_key_a, cache_key_b); } @@ -182,8 +184,8 @@ ASSERT_NE(a, b); FontFaceCreationParams test_creation_params; - FontCacheKey key_a = a.CacheKey(test_creation_params, false); - FontCacheKey key_b = b.CacheKey(test_creation_params, false); + FontCacheKey key_a = a.CacheKey(test_creation_params, false, false); + FontCacheKey key_b = b.CacheKey(test_creation_params, false, false); ASSERT_NE(key_a, key_b); }
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_list.cc b/third_party/blink/renderer/platform/fonts/font_fallback_list.cc index 8a22237..59c3334 100644 --- a/third_party/blink/renderer/platform/fonts/font_fallback_list.cc +++ b/third_party/blink/renderer/platform/fonts/font_fallback_list.cc
@@ -228,7 +228,9 @@ } if (result) { bool is_unique_match = false; - key.Add(font_description.CacheKey(params, is_unique_match)); + bool is_generic_family = current_family->FamilyIsGeneric(); + key.Add(font_description.CacheKey(params, is_unique_match, + is_generic_family)); auto* font_data = DynamicTo<SimpleFontData>(result.get()); if (!font_data && !result->IsCustomFont()) FontCache::Get().ReleaseFontData(font_data);
diff --git a/third_party/blink/renderer/platform/fonts/font_platform_data_cache.cc b/third_party/blink/renderer/platform/fonts/font_platform_data_cache.cc index fae5547..2781d9d 100644 --- a/third_party/blink/renderer/platform/fonts/font_platform_data_cache.cc +++ b/third_party/blink/renderer/platform/fonts/font_platform_data_cache.cc
@@ -65,8 +65,9 @@ AlternateFontName alternate_font_name) { const bool is_unique_match = alternate_font_name == AlternateFontName::kLocalUniqueFace; - FontCacheKey key = - font_description.CacheKey(creation_params, is_unique_match); + const bool is_generic_family = false; + FontCacheKey key = font_description.CacheKey(creation_params, is_unique_match, + is_generic_family); DCHECK(!key.IsHashTableDeletedValue()); if (no_size_in_key_) {
diff --git a/third_party/blink/renderer/platform/heap/self_keep_alive.h b/third_party/blink/renderer/platform/heap/self_keep_alive.h index d56ac12..dc0e631 100644 --- a/third_party/blink/renderer/platform/heap/self_keep_alive.h +++ b/third_party/blink/renderer/platform/heap/self_keep_alive.h
@@ -8,7 +8,7 @@ #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/loader/fetch/preload_key.h b/third_party/blink/renderer/platform/loader/fetch/preload_key.h index ac0adad..8d0e638 100644 --- a/third_party/blink/renderer/platform/loader/fetch/preload_key.h +++ b/third_party/blink/renderer/platform/loader/fetch/preload_key.h
@@ -42,25 +42,9 @@ template <> struct HashTraits<blink::PreloadKey> - : public SimpleClassHashTraits<blink::PreloadKey> { - static unsigned GetHash(const blink::PreloadKey& key) { - return WTF::GetHash(key.url); - } - static constexpr bool kSafeToCompareToEmptyOrDeleted = - HashTraits<blink::KURL>::kSafeToCompareToEmptyOrDeleted; - - // This doesn't delegate to KURL because the `type` field of PreloadKey() is - // not zero. - static constexpr bool kEmptyValueIsZero = false; - - static bool IsDeletedValue(const blink::PreloadKey& value) { - return HashTraits<blink::KURL>::IsDeletedValue(value.url); - } - - static void ConstructDeletedValue(blink::PreloadKey& slot) { - HashTraits<blink::KURL>::ConstructDeletedValue(slot.url); - } -}; + : TwoFieldsHashTraits<blink::PreloadKey, + &blink::PreloadKey::url, + &blink::PreloadKey::type> {}; } // namespace WTF
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h index 5bd0801..1b42e3ec 100644 --- a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h +++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.h
@@ -24,7 +24,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/response_body_loader_client.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/shared_buffer.h" #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
diff --git a/third_party/blink/renderer/platform/mojo/mojo_binding_context.h b/third_party/blink/renderer/platform/mojo/mojo_binding_context.h index 5e7fdd4..0ac3341 100644 --- a/third_party/blink/renderer/platform/mojo/mojo_binding_context.h +++ b/third_party/blink/renderer/platform/mojo/mojo_binding_context.h
@@ -12,7 +12,7 @@ #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/supplementable.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace base { class SingleThreadTaskRunner;
diff --git a/third_party/blink/renderer/platform/network/blink_schemeful_site.h b/third_party/blink/renderer/platform/network/blink_schemeful_site.h index bc3d887fd..67707d19 100644 --- a/third_party/blink/renderer/platform/network/blink_schemeful_site.h +++ b/third_party/blink/renderer/platform/network/blink_schemeful_site.h
@@ -10,7 +10,6 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -119,34 +118,8 @@ template <> struct HashTraits<blink::BlinkSchemefulSite> - : SimpleClassHashTraits<blink::BlinkSchemefulSite> { - static unsigned GetHash(const blink::BlinkSchemefulSite& schemeful_site) { - return blink::SecurityOriginHashTraits::GetHash( - schemeful_site.site_as_origin_); - } - - static bool Equal(const blink::BlinkSchemefulSite& a, - const blink::BlinkSchemefulSite& b) { - return blink::SecurityOriginHashTraits::Equal(a.site_as_origin_, - b.site_as_origin_); - } - - static constexpr bool kSafeToCompareToEmptyOrDeleted = false; - - static bool IsEmptyValue(const blink::BlinkSchemefulSite& value) { - return !value.site_as_origin_; - } - - static bool IsDeletedValue(const blink::BlinkSchemefulSite& value) { - return HashTraits<scoped_refptr<const blink::SecurityOrigin>>:: - IsDeletedValue(value.site_as_origin_); - } - - static void ConstructDeletedValue(blink::BlinkSchemefulSite& slot) { - HashTraits<scoped_refptr<const blink::SecurityOrigin>>:: - ConstructDeletedValue(slot.site_as_origin_); - } -}; + : OneFieldHashTraits<blink::BlinkSchemefulSite, + &blink::BlinkSchemefulSite::site_as_origin_> {}; } // namespace WTF
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 34a899e4..ddd5bc3 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -634,7 +634,8 @@ }, { name: "CSSBaselineSource", - status: "experimental", + status: "stable", + base_feature: "CSSBaselineSource", }, { // Support CSS Values Level 4 calc simplification and serialization
diff --git a/third_party/blink/renderer/platform/scheduler/common/blink_scheduler_single_thread_task_runner.cc b/third_party/blink/renderer/platform/scheduler/common/blink_scheduler_single_thread_task_runner.cc index f0cf97e..dd4f5459 100644 --- a/third_party/blink/renderer/platform/scheduler/common/blink_scheduler_single_thread_task_runner.cc +++ b/third_party/blink/renderer/platform/scheduler/common/blink_scheduler_single_thread_task_runner.cc
@@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "base/debug/dump_without_crashing.h" #include "base/location.h" #include "base/memory/scoped_refptr.h" #include "base/task/single_thread_task_runner.h" @@ -64,9 +65,10 @@ Delete(); } else { // The deleter task couldn't be posted to the intended thread, so the only - // safe thing to do is leak the object. - // TODO(crbug.com/1376851): Add a CHECK, DumpWithoutCrashing, or trace - // event to determine if leaks still occur. + // safe thing to do is leak the object. As leaks of this type should not + // be permitted, flush out any places where this happens so they can be + // fixed. + base::debug::DumpWithoutCrashing(); } }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h index 9de12b1..be4de7d 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h
@@ -14,7 +14,7 @@ #include "third_party/blink/renderer/platform/heap/prefinalizer.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace base { class SingleThreadTaskRunner;
diff --git a/third_party/blink/renderer/platform/storage/blink_storage_key.cc b/third_party/blink/renderer/platform/storage/blink_storage_key.cc index 4203fb59..cfec393 100644 --- a/third_party/blink/renderer/platform/storage/blink_storage_key.cc +++ b/third_party/blink/renderer/platform/storage/blink_storage_key.cc
@@ -41,12 +41,21 @@ ? top_level_site : BlinkSchemefulSite(origin)), top_level_site_if_third_party_enabled_(top_level_site), - nonce_(nonce ? absl::make_optional(*nonce) : absl::nullopt), + nonce_(base::OptionalFromPtr(nonce)), ancestor_chain_bit_(StorageKey::IsThirdPartyStoragePartitioningEnabled() ? ancestor_chain_bit : mojom::blink::AncestorChainBit::kSameSite), ancestor_chain_bit_if_third_party_enabled_(ancestor_chain_bit) { DCHECK(origin_); + // If we're setting a `nonce`, the `top_level_site` must be the same as + // the `origin` and the `ancestor_chain_bit` must be kSameSite. We don't + // serialize those pieces of information so have to check to prevent + // mistaken reliance on what is supposed to be an invariant. + if (nonce) { + DCHECK(!nonce->is_empty()); + DCHECK(top_level_site == BlinkSchemefulSite(origin)); + DCHECK_EQ(ancestor_chain_bit, mojom::blink::AncestorChainBit::kSameSite); + } } // static
diff --git a/third_party/blink/renderer/platform/storage/blink_storage_key_hash.h b/third_party/blink/renderer/platform/storage/blink_storage_key_hash.h index 7e1c3e0..14bf6fb 100644 --- a/third_party/blink/renderer/platform/storage/blink_storage_key_hash.h +++ b/third_party/blink/renderer/platform/storage/blink_storage_key_hash.h
@@ -8,7 +8,6 @@ #include "build/build_config.h" #include "third_party/blink/renderer/platform/storage/blink_storage_key.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h" namespace blink { @@ -18,7 +17,7 @@ absl::optional<base::UnguessableToken> nonce = storage_key->GetNonce(); size_t nonce_hash = nonce ? base::UnguessableTokenHash()(*nonce) : 0; unsigned hash_codes[] = { - SecurityOriginHashTraits::GetHash(storage_key->GetSecurityOrigin()), + WTF::GetHash(storage_key->GetSecurityOrigin()), WTF::GetHash(storage_key->GetTopLevelSite()), static_cast<unsigned>(storage_key->GetAncestorChainBit()), #if ARCH_CPU_32_BITS
diff --git a/third_party/blink/renderer/platform/storage/blink_storage_key_test.cc b/third_party/blink/renderer/platform/storage/blink_storage_key_test.cc index 6bd6000..5411d278 100644 --- a/third_party/blink/renderer/platform/storage/blink_storage_key_test.cc +++ b/third_party/blink/renderer/platform/storage/blink_storage_key_test.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/platform/storage/blink_storage_key.h" #include "base/memory/scoped_refptr.h" +#include "base/test/gtest_util.h" #include "base/test/scoped_feature_list.h" #include "base/unguessable_token.h" #include "net/base/features.h" @@ -237,4 +238,43 @@ } } +TEST(BlinkStorageKeyTest, NonceRequiresMatchingOriginSiteAndSameSite) { + scoped_refptr<const SecurityOrigin> origin = + SecurityOrigin::CreateFromString("https://foo.com"); + const BlinkSchemefulSite site(origin); + const BlinkSchemefulSite opaque_site; + const BlinkSchemefulSite other_site( + SecurityOrigin::CreateFromString("https://notfoo.com")); + base::UnguessableToken nonce = base::UnguessableToken::Create(); + + for (const bool toggle : {false, true}) { + base::test::ScopedFeatureList scope_feature_list; + scope_feature_list.InitWithFeatureState( + net::features::kThirdPartyStoragePartitioning, toggle); + + // A nonce key with a matching origin/site that's SameSite works. + (void)BlinkStorageKey(origin, site, &nonce, + mojom::blink::AncestorChainBit::kSameSite); + + // A nonce key with a non-matching origin/site that's SameSite fails. + EXPECT_DCHECK_DEATH( + BlinkStorageKey(origin, opaque_site, &nonce, + mojom::blink::AncestorChainBit::kSameSite)); + EXPECT_DCHECK_DEATH(BlinkStorageKey( + origin, other_site, &nonce, mojom::blink::AncestorChainBit::kSameSite)); + + // A nonce key with a matching origin/site that's CrossSite fails. + EXPECT_DCHECK_DEATH(BlinkStorageKey( + origin, site, &nonce, mojom::blink::AncestorChainBit::kCrossSite)); + + // A nonce key with a non-matching origin/site that's CrossSite fails. + EXPECT_DCHECK_DEATH( + BlinkStorageKey(origin, opaque_site, &nonce, + mojom::blink::AncestorChainBit::kCrossSite)); + EXPECT_DCHECK_DEATH( + BlinkStorageKey(origin, other_site, &nonce, + mojom::blink::AncestorChainBit::kCrossSite)); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/weborigin/kurl_hash.h b/third_party/blink/renderer/platform/weborigin/kurl_hash.h index bec443e..cf53198 100644 --- a/third_party/blink/renderer/platform/weborigin/kurl_hash.h +++ b/third_party/blink/renderer/platform/weborigin/kurl_hash.h
@@ -37,26 +37,8 @@ // HashMap<KURL,..., KURLHash> cause a null-pointer dereference when passed null // KURLs. template <> -struct HashTraits<blink::KURL> : SimpleClassHashTraits<blink::KURL> { - static unsigned GetHash(const blink::KURL& key) { - return WTF::GetHash(key.GetString()); - } - - static bool Equal(const blink::KURL& a, const blink::KURL& b) { - return HashTraits<String>::Equal(a.GetString(), b.GetString()); - } - - static constexpr bool kSafeToCompareToEmptyOrDeleted = - HashTraits<String>::kSafeToCompareToEmptyOrDeleted; - - static bool IsDeletedValue(const blink::KURL& value) { - return HashTraits<String>::IsDeletedValue(value.GetString()); - } - - static void ConstructDeletedValue(blink::KURL& slot) { - HashTraits<String>::ConstructDeletedValue(slot.string_); - } -}; +struct HashTraits<blink::KURL> + : OneFieldHashTraits<blink::KURL, &blink::KURL::string_> {}; } // namespace WTF
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.h b/third_party/blink/renderer/platform/weborigin/security_origin.h index 30aca31..9108bf57 100644 --- a/third_party/blink/renderer/platform/weborigin/security_origin.h +++ b/third_party/blink/renderer/platform/weborigin/security_origin.h
@@ -36,6 +36,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/hash_traits.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "url/origin.h" @@ -382,7 +383,7 @@ private: // Various serialisation and test routines that need direct nonce access. friend struct mojo::UrlOriginAdapter; - friend struct SecurityOriginHashTraits; + friend struct WTF::HashTraits<scoped_refptr<const SecurityOrigin>>; friend class SecurityOriginTest; // For calling GetNonceForSerialization(). @@ -453,4 +454,60 @@ } // namespace blink +namespace WTF { + +// The default HashTraits of SecurityOrigin implements the "same origin" +// equality relation between two origins. As such it ignores the domain that +// might or might not be set on the origin. If you need "same origin-domain" +// equality you'll need to define a custom hash traits type using a different +// hash function. +template <> +struct HashTraits<scoped_refptr<const blink::SecurityOrigin>> + : GenericHashTraits<scoped_refptr<const blink::SecurityOrigin>> { + static unsigned GetHash(const blink::SecurityOrigin* origin) { + const base::UnguessableToken* nonce = origin->GetNonceForSerialization(); + size_t nonce_hash = nonce ? base::UnguessableTokenHash()(*nonce) : 0; + + unsigned hash_codes[] = { + origin->Protocol().Impl() ? origin->Protocol().Impl()->GetHash() : 0, + origin->Host().Impl() ? origin->Host().Impl()->GetHash() : 0, + origin->Port(), +#if ARCH_CPU_32_BITS + nonce_hash, +#elif ARCH_CPU_64_BITS + static_cast<unsigned>(nonce_hash), + static_cast<unsigned>(nonce_hash >> 32), +#else +#error "Unknown bits" +#endif + }; + return StringHasher::HashMemory<sizeof(hash_codes)>(hash_codes); + } + static unsigned GetHash( + const scoped_refptr<const blink::SecurityOrigin>& origin) { + return GetHash(origin.get()); + } + + static bool Equal(const blink::SecurityOrigin* a, + const blink::SecurityOrigin* b) { + return a->IsSameOriginWith(b); + } + static bool Equal(const blink::SecurityOrigin* a, + const scoped_refptr<const blink::SecurityOrigin>& b) { + return Equal(a, b.get()); + } + static bool Equal(const scoped_refptr<const blink::SecurityOrigin>& a, + const blink::SecurityOrigin* b) { + return Equal(a.get(), b); + } + static bool Equal(const scoped_refptr<const blink::SecurityOrigin>& a, + const scoped_refptr<const blink::SecurityOrigin>& b) { + return Equal(a.get(), b.get()); + } + + static constexpr bool kSafeToCompareToEmptyOrDeleted = false; +}; + +} // namespace WTF + #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_SECURITY_ORIGIN_H_
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin_hash.h b/third_party/blink/renderer/platform/weborigin/security_origin_hash.h deleted file mode 100644 index 510b3ae..0000000 --- a/third_party/blink/renderer/platform/weborigin/security_origin_hash.h +++ /dev/null
@@ -1,91 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_SECURITY_ORIGIN_HASH_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_SECURITY_ORIGIN_HASH_H_ - -#include "base/memory/scoped_refptr.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/wtf/hash_traits.h" - -namespace blink { - -// This Hash implements the "same origin" equality relation between two origins. -// As such it ignores the domain that might or might not be set on the origin. -// If you need "same origin-domain" equality you'll need to use a different hash -// function. -struct SecurityOriginHashTraits - : GenericHashTraits<scoped_refptr<const SecurityOrigin>> { - static unsigned GetHash(const SecurityOrigin* origin) { - const base::UnguessableToken* nonce = origin->GetNonceForSerialization(); - size_t nonce_hash = nonce ? base::UnguessableTokenHash()(*nonce) : 0; - - unsigned hash_codes[] = { - origin->Protocol().Impl() ? origin->Protocol().Impl()->GetHash() : 0, - origin->Host().Impl() ? origin->Host().Impl()->GetHash() : 0, - origin->Port(), -#if ARCH_CPU_32_BITS - nonce_hash, -#elif ARCH_CPU_64_BITS - static_cast<unsigned>(nonce_hash), - static_cast<unsigned>(nonce_hash >> 32), -#else -#error "Unknown bits" -#endif - }; - return StringHasher::HashMemory<sizeof(hash_codes)>(hash_codes); - } - static unsigned GetHash(const scoped_refptr<const SecurityOrigin>& origin) { - return GetHash(origin.get()); - } - - static bool Equal(const SecurityOrigin* a, const SecurityOrigin* b) { - if (!a || !b) - return a == b; - - return a->IsSameOriginWith(b); - } - static bool Equal(const SecurityOrigin* a, - const scoped_refptr<const SecurityOrigin>& b) { - return Equal(a, b.get()); - } - static bool Equal(const scoped_refptr<const SecurityOrigin>& a, - const SecurityOrigin* b) { - return Equal(a.get(), b); - } - static bool Equal(const scoped_refptr<const SecurityOrigin>& a, - const scoped_refptr<const SecurityOrigin>& b) { - return Equal(a.get(), b.get()); - } - - static constexpr bool kSafeToCompareToEmptyOrDeleted = false; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WEBORIGIN_SECURITY_ORIGIN_HASH_H_
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc index 67e18463..a41db08 100644 --- a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc +++ b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
@@ -44,7 +44,7 @@ #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin_hash.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/string_builder.h" #include "third_party/blink/renderer/platform/wtf/text/string_operators.h" @@ -719,9 +719,9 @@ scoped_refptr<const SecurityOrigin> copied = origin->IsolatedCopy(); EXPECT_TRUE(origin->CanAccess(copied.get())); EXPECT_TRUE(origin->IsSameOriginWith(copied.get())); - EXPECT_EQ(SecurityOriginHashTraits::GetHash(origin), - SecurityOriginHashTraits::GetHash(copied)); - EXPECT_TRUE(SecurityOriginHashTraits::Equal(origin, copied)); + EXPECT_EQ(WTF::GetHash(origin), WTF::GetHash(copied)); + EXPECT_TRUE( + HashTraits<scoped_refptr<const SecurityOrigin>>::Equal(origin, copied)); } TEST_F(SecurityOriginTest, EdgeCases) {
diff --git a/third_party/blink/renderer/platform/webrtc/webrtc_source.h b/third_party/blink/renderer/platform/webrtc/webrtc_source.h index 58e0f54..3c2deae 100644 --- a/third_party/blink/renderer/platform/webrtc/webrtc_source.h +++ b/third_party/blink/renderer/platform/webrtc/webrtc_source.h
@@ -14,6 +14,7 @@ namespace media { class AudioBus; +struct AudioGlitchInfo; } namespace blink { @@ -29,7 +30,8 @@ virtual void RenderData(media::AudioBus* audio_bus, int sample_rate, base::TimeDelta audio_delay, - base::TimeDelta* current_time) = 0; + base::TimeDelta* current_time, + const media::AudioGlitchInfo& glitch_info) = 0; // Callback to notify the client that the renderer is going away. virtual void RemoveAudioRenderer(WebRtcAudioRenderer* renderer) = 0;
diff --git a/third_party/blink/renderer/platform/wtf/BUILD.gn b/third_party/blink/renderer/platform/wtf/BUILD.gn index a4a3470..b4329d5 100644 --- a/third_party/blink/renderer/platform/wtf/BUILD.gn +++ b/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -73,7 +73,7 @@ "dynamic_annotations.h", "forward.h", "functional.h", - "gc_plugin_ignore.h", + "gc_plugin.h", "get_ptr.h", "hash_counted_set.h", "hash_functions.h",
diff --git a/third_party/blink/renderer/platform/wtf/gc_plugin.h b/third_party/blink/renderer/platform/wtf/gc_plugin.h new file mode 100644 index 0000000..f275c3ca --- /dev/null +++ b/third_party/blink/renderer/platform/wtf/gc_plugin.h
@@ -0,0 +1,25 @@ +// Copyright 2021 The Chromium Authors +// 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_WTF_GC_PLUGIN_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_GC_PLUGIN_H_ + +// GC_PLUGIN_IGNORE is used to make the Blink GC plugin ignore a particular +// class or field when checking for proper usage. When using GC_PLUGIN_IGNORE a +// reason must be provided as an argument. In most cases this will be a bug id +// where the bug describes what needs to happen to remove the GC_PLUGIN_IGNORE +// again. +#if defined(__clang__) +#define GC_PLUGIN_IGNORE(reason) \ + __attribute__((annotate("blink_gc_plugin_ignore"))) +#else // !defined(__clang__) +#define GC_PLUGIN_IGNORE(reason) +#endif // !defined(__clang__) + +// GC_SAFE_FIELD is used to make the Blink GC plugin ignore a particular field. +// This must only be used when we can ensure that the pattern it is marking is +// safe despite the exception thrown by the plugin. +#define GC_SAFE_FIELD(reason) GC_PLUGIN_IGNORE(reason) + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_GC_PLUGIN_H_
diff --git a/third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h b/third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h deleted file mode 100644 index 0639a87..0000000 --- a/third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2021 The Chromium Authors -// 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_WTF_GC_PLUGIN_IGNORE_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_GC_PLUGIN_IGNORE_H_ - -// GC_PLUGIN_IGNORE is used to make the Blink GC plugin ignore a particular -// class or field when checking for proper usage. When using GC_PLUGIN_IGNORE a -// reason must be provided as an argument. In most cases this will be a bug id -// where the bug describes what needs to happen to remove the GC_PLUGIN_IGNORE -// again. -#if defined(__clang__) -#define GC_PLUGIN_IGNORE(reason) \ - __attribute__((annotate("blink_gc_plugin_ignore"))) -#else // !defined(__clang__) -#define GC_PLUGIN_IGNORE(reason) -#endif // !defined(__clang__) - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_GC_PLUGIN_IGNORE_H_
diff --git a/third_party/blink/renderer/platform/wtf/hash_traits.h b/third_party/blink/renderer/platform/wtf/hash_traits.h index 4ddd363..de3a34a 100644 --- a/third_party/blink/renderer/platform/wtf/hash_traits.h +++ b/third_party/blink/renderer/platform/wtf/hash_traits.h
@@ -469,24 +469,67 @@ IsHashTraitsDeletedValue<Traits, T>(value); } -namespace internal { - -template <template <typename, typename> typename T, - typename FirstTraits, - typename SecondTraits, - auto first_field, - auto second_field> -struct PairHashTraitsBase - : GenericHashTraits<T<typename FirstTraits::TraitType, - typename SecondTraits::TraitType>> { - using TraitType = - T<typename FirstTraits::TraitType, typename SecondTraits::TraitType>; - - static unsigned GetHash(const TraitType& p) { - return HashInts(FirstTraits::GetHash(p.first), - SecondTraits::GetHash(p.second)); +// A HashTraits type for T to delegate all HashTraits API to a field. +template <typename T, + auto T::*field, + typename FieldTraits = HashTraits< + std::remove_reference_t<decltype(std::declval<T>().*field)>>> +struct OneFieldHashTraits : GenericHashTraits<T> { + using TraitType = T; + static unsigned GetHash(const T& p) { return FieldTraits::GetHash(p.*field); } + static bool Equal(const T& a, const T& b) { + return FieldTraits::Equal(a.*field, b.*field); } - static bool Equal(const TraitType& a, const TraitType& b) { + static constexpr bool kSafeToCompareToEmptyOrDeleted = + FieldTraits::kSafeToCompareToEmptyOrDeleted; + + static constexpr bool kEmptyValueIsZero = FieldTraits::kEmptyValueIsZero; + static T EmptyValue() { return T(FieldTraits::EmptyValue()); } + + static bool IsEmptyValue(const T& value) { + return IsHashTraitsEmptyValue<FieldTraits>(value.*field); + } + + static void ConstructDeletedValue(T& slot) { + ConstructHashTraitsDeletedValue<FieldTraits>(slot.*field); + } + static bool IsDeletedValue(const T& value) { + return IsHashTraitsDeletedValue<FieldTraits>(value.*field); + } + + static constexpr unsigned kMinimumTableSize = FieldTraits::kMinimumTableSize; + + template <typename U = void> + struct IsTraceableInCollection { + static const bool value = IsTraceableInCollectionTrait<FieldTraits>::value; + }; + + template <typename U = void> + struct NeedsToForbidGCOnMove { + static const bool value = + FieldTraits::template NeedsToForbidGCOnMove<>::value; + }; + + static constexpr bool kCanTraceConcurrently = + FieldTraits::kCanTraceConcurrently; +}; + +// A HashTraits type for T to delegate all HashTraits API to two fields. +template < + typename T, + auto T::*first_field, + auto T::*second_field, + typename FirstTraits = HashTraits< + std::remove_reference_t<decltype(std::declval<T>().*first_field)>>, + typename SecondTraits = HashTraits< + std::remove_reference_t<decltype(std::declval<T>().*second_field)>>> +struct TwoFieldsHashTraits : OneFieldHashTraits<T, first_field, FirstTraits> { + using TraitType = T; + static unsigned GetHash(const T& p) { + return HashInts(FirstTraits::GetHash(p.*first_field), + SecondTraits::GetHash(p.*second_field)); + } + static bool Equal(const T& a, const T& b) { return FirstTraits::Equal(a.*first_field, b.*first_field) && SecondTraits::Equal(a.*second_field, b.*second_field); } @@ -496,8 +539,8 @@ static constexpr bool kEmptyValueIsZero = FirstTraits::kEmptyValueIsZero && SecondTraits::kEmptyValueIsZero; - static TraitType EmptyValue() { - return TraitType(FirstTraits::EmptyValue(), SecondTraits::EmptyValue()); + static T EmptyValue() { + return T(FirstTraits::EmptyValue(), SecondTraits::EmptyValue()); } static bool IsEmptyValue(const TraitType& value) { @@ -505,14 +548,8 @@ IsHashTraitsEmptyValue<SecondTraits>(value.*second_field); } - static constexpr unsigned kMinimumTableSize = FirstTraits::kMinimumTableSize; - - static void ConstructDeletedValue(TraitType& slot) { - ConstructHashTraitsDeletedValue<FirstTraits>(slot.*first_field); - } - static bool IsDeletedValue(const TraitType& value) { - return IsHashTraitsDeletedValue<FirstTraits>(value.*first_field); - } + // ConstructDeletedValue(), IsDeletedValue(), kMinimumTableSize delegate to + // the first field, inherited from OneFieldHashTraits. template <typename U = void> struct IsTraceableInCollection { @@ -537,17 +574,15 @@ !IsTraceable<typename SecondTraits::TraitType>::value); }; -} // namespace internal - template <typename FirstTraitsArg, typename SecondTraitsArg, typename P = std::pair<typename FirstTraitsArg::TraitType, typename SecondTraitsArg::TraitType>> -struct PairHashTraits : internal::PairHashTraitsBase<std::pair, - FirstTraitsArg, - SecondTraitsArg, - &P::first, - &P::second> { +struct PairHashTraits : TwoFieldsHashTraits<P, + &P::first, + &P::second, + FirstTraitsArg, + SecondTraitsArg> { using TraitType = P; using FirstTraits = FirstTraitsArg; using SecondTraits = SecondTraitsArg; @@ -583,11 +618,8 @@ typename ValueTraitsArg, typename P = KeyValuePair<typename KeyTraitsArg::TraitType, typename ValueTraitsArg::TraitType>> -struct KeyValuePairHashTraits : internal::PairHashTraitsBase<KeyValuePair, - KeyTraitsArg, - ValueTraitsArg, - &P::key, - &P::value> { +struct KeyValuePairHashTraits + : TwoFieldsHashTraits<P, &P::key, &P::value, KeyTraitsArg, ValueTraitsArg> { using TraitType = P; using KeyTraits = KeyTraitsArg; using ValueTraits = ValueTraitsArg; @@ -612,7 +644,9 @@ using WTF::HashTraits; using WTF::IntHashTraits; using WTF::IntWithZeroKeyHashTraits; +using WTF::OneFieldHashTraits; using WTF::PairHashTraits; using WTF::SimpleClassHashTraits; +using WTF::TwoFieldsHashTraits; #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_HASH_TRAITS_H_
diff --git a/third_party/blink/renderer/platform/wtf/pod_interval.h b/third_party/blink/renderer/platform/wtf/pod_interval.h index a8b79f5..0ba0816 100644 --- a/third_party/blink/renderer/platform/wtf/pod_interval.h +++ b/third_party/blink/renderer/platform/wtf/pod_interval.h
@@ -31,7 +31,7 @@ #endif #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" -#include "third_party/blink/renderer/platform/wtf/gc_plugin_ignore.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" namespace WTF {
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index a557739..31fdf25f 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -1145,7 +1145,7 @@ # The modules listed above need access to the following GL drawing and # display-related types. 'allowed': [ - 'base::LRUCache', + 'base::flat_map', 'gl::GpuPreference', 'gpu::SHARED_IMAGE_USAGE_.+', 'gpu::gles2::GLES2Interface',
diff --git a/third_party/blink/web_tests/FlagExpectations/highdpi b/third_party/blink/web_tests/FlagExpectations/highdpi index 97477e8e..3797111 100644 --- a/third_party/blink/web_tests/FlagExpectations/highdpi +++ b/third_party/blink/web_tests/FlagExpectations/highdpi
@@ -453,6 +453,8 @@ crbug.com/1310040 virtual/gpu-rasterization-disable-yuv/images/yuv-decode-eligible/color-profile-layer.html [ Failure Pass ] +crbug.com/1318592 external/wpt/resource-timing/object-not-found-after-TAO-cross-origin-redirect.html [ Failure Pass ] + crbug.com/1324618 external/wpt/css/css-images/object-view-box-fit-fill* [ Pass ] # crbug.com/1339051: some ref tests generate output with minor differences.
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests index 5ed4a17..65bc272 100644 --- a/third_party/blink/web_tests/SlowTests +++ b/third_party/blink/web_tests/SlowTests
@@ -1350,3 +1350,5 @@ crbug.com/1372747 [ Win ] http/tests/uri/css-href.php [ Slow ] crbug.com/1376679 [ Mac12 ] virtual/threaded/external/wpt/scroll-animations/css/scroll-timeline-dynamic.tentative.html [ Slow ] + +crbug.com/1366717 http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack.js [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index ea2ba282..01e7068b 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2266,8 +2266,6 @@ crbug.com/538717 http/tests/permissions/chromium/test-request-multiple-worker.html [ Failure Pass Timeout ] crbug.com/538717 http/tests/permissions/chromium/test-request-multiple-sharedworker.html [ Failure Pass Timeout ] -crbug.com/548765 http/tests/devtools/console-fetch-logging.js [ Failure Pass ] - crbug.com/399951 http/tests/mime/javascript-mimetype-usecounters.html [ Failure Pass ] crbug.com/663847 fast/events/context-no-deselect.html [ Failure Pass ] @@ -3033,8 +3031,10 @@ crbug.com/626703 [ Mac12-arm64 ] wpt_internal/webxr/ar/iframe-oopif.sub.https.html [ Failure Timeout ] crbug.com/626703 [ Mac12 ] external/wpt/html/cross-origin-opener-policy/resource-popup.https.html [ Timeout ] crbug.com/626703 external/wpt/webcodecs/videoFrame-serialization.crossAgentCluster.html [ Timeout ] -crbug.com/626703 [ Debug Mac12 ] external/wpt/url/a-element.html?exclude=(file|javascript|mailto) [ Crash Failure ] -crbug.com/1404285 [ Mac ] virtual/compute-pressure/external/wpt/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.html [ Crash Failure ] +crbug.com/626703 [ Linux ] external/wpt/resource-timing/response-status-code.html [ Skip Timeout ] +crbug.com/626703 [ Win ] external/wpt/resource-timing/response-status-code.html [ Skip Timeout ] +crbug.com/626703 virtual/plz-dedicated-worker/external/wpt/resource-timing/response-status-code.html [ Skip Timeout ] +crbug.com/626703 [ Mac11 ] external/wpt/resource-timing/response-status-code.html [ Skip Timeout ] crbug.com/626703 [ Win11 ] wpt_internal/geolocation-api/watchPosition-page-visibility.https.html [ Timeout ] crbug.com/626703 [ Win10.20h2 ] external/wpt/web-animations/idlharness.window.html [ Crash Failure ] crbug.com/626703 [ Mac11 ] external/wpt/performance-timeline/tentative/include-frames-from-child-cross-origin-grandchild.sub.html [ Timeout ] @@ -4408,7 +4408,6 @@ # Swiftshader issue. crbug.com/1048149 external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-innerwidth.html [ Crash Timeout ] -crbug.com/1048149 external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-screeny.html [ Crash Timeout ] crbug.com/1048149 external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-width.html [ Crash Timeout ] # SwANGLE issues @@ -5329,7 +5328,7 @@ crbug.com/1249176 [ Mac12-arm64 ] external/wpt/html/canvas/element/manual/drawing-images-to-the-canvas/image-orientation/drawImage-from-blob.tentative.html [ Failure ] crbug.com/1249176 [ Mac11-arm64 ] external/wpt/largest-contentful-paint/image-src-change.html [ Failure ] crbug.com/1249176 [ Mac11-arm64 ] http/tests/images/document-policy-oversized-images-forced-layout.php [ Failure ] -crbug.com/1249176 [ Mac11-arm64 ] transforms/transformed-document-element.html [ Failure ] +crbug.com/1249176 [ Mac ] transforms/transformed-document-element.html [ Failure ] crbug.com/1249176 [ Mac11-arm64 ] virtual/threaded/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Failure ] crbug.com/1249176 [ Mac12-arm64 ] virtual/threaded/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Failure Pass ] crbug.com/1249176 [ Mac11-arm64 ] webaudio/codec-tests/webm/webm-decode.html [ Failure ] @@ -6263,9 +6262,6 @@ # Sheriff 2022-09-09 crbug.com/1361956 [ Linux ] fast/dom/Element/scrollTop-scrollLeft-body.html [ Pass Timeout ] -# Investigate timeouts on bots -crbug.com/1366717 http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack.js [ Failure Pass ] - crbug.com/1367113 fast/dom/shadow/event-path-load.html [ Crash Failure Pass Timeout ] crbug.com/1367113 http/tests/security/cors-check-for-cached-image.html [ Crash Failure Pass Timeout ] crbug.com/1367113 paint/images/animated-gif-last-frame-crash.html [ Crash Failure Pass Timeout ] @@ -6917,6 +6913,7 @@ # fast/dom/Element/scrollTop-scrollLeft-body.html previously also linked with crbug.com/1249176 crbug.com/1361956 [ Mac12 ] fast/dom/Element/scrollTop-scrollLeft-body.html [ Failure Pass Timeout ] crbug.com/1354433 [ Win ] external/wpt/html/browsers/the-window-object/window-properties.https.html [ Failure Pass ] +crbug.com/1404252 [ Mac11-arm64 Release ] external/wpt/resource-timing/response-status-code.html [ Failure Pass ] # Sheriff 2023-01-11 crbug.com/1406380 [ Win ] external/wpt/infrastructure/server/webtransport-h3.https.sub.any.worker.html [ Failure Pass ] @@ -6944,3 +6941,10 @@ crbug.com/1408919 [ Mac ] virtual/text-antialias/capitalize-boundaries.html [ Failure Pass ] crbug.com/1408967 [ Fuchsia ] fast/block/float/float-in-float-painting.html [ Failure Pass ] crbug.com/1408967 [ Fuchsia ] fast/layers/opacity-transforms.html [ Failure Pass ] + +# Sheriff 2023-01-23 +crbug.com/1409463 external/wpt/html/browsers/the-window-object/open-close/open-features-non-integer-screeny.html [ Failure Pass Crash Timeout ] + +# Sheriff 2023-01-24 +crbug.com/1409804 [ Mac ] fast/backgrounds/repeat/negative-offset-repeat-transformed.html [ Failure ] +crbug.com/1409804 [ Mac ] fast/borders/border-image-rotate-transform.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index fb94bd7..af6de60 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -967,6 +967,10 @@ "wpt_internal/storage/quota/partitioned-webkitTemporaryStorage-usage-details.tentative.sub.html", "wpt_internal/storage/quota/partitioned-webkitPersistentStorage-quota-usage-details.tentative.sub.html", "wpt_internal/storage/quota/partitioned-webkitStorageInfo-temporary-quota-usage-details.tentative.sub.html", + "wpt_internal/webstorage/storage-deprecation-trial-disabled-local.sub.https.html", + "wpt_internal/webstorage/storage-deprecation-trial-disabled-session.sub.https.html", + "wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https.html", + "wpt_internal/webstorage/storage-deprecation-trial-enabled-session.sub.https.html", "external/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html", "external/wpt/storage/partitioned-estimate-usage-details-caches.tentative.https.sub.html", "external/wpt/storage/partitioned-estimate-usage-details-indexeddb.tentative.https.sub.html", @@ -1343,6 +1347,18 @@ "expires": "Jul 1, 2023" }, { + "prefix": "shared-storage-fenced-frame-mparch-reportevent-limit", + "platforms": ["Linux", "Mac", "Win"], + "bases": [ + "wpt_internal/shared_storage_reportevent_limit/" + ], + "exclusive_tests": [ + "wpt_internal/shared_storage_reportevent_limit/" + ], + "args": ["--enable-features=SharedStorageAPI,FencedFrames:implementation_type/mparch,PrivacySandboxAdsAPIsOverride,SharedStorageReportEventLimit"], + "expires": "Jul 1, 2023" + }, + { "prefix": "shared-storage-fenced-frame-mparch-selecturl-limit", "platforms": ["Linux", "Mac", "Win"], "bases": [ @@ -1376,7 +1392,7 @@ "wpt_internal/fenced_frame", "http/tests/inspector-protocol/fenced-frame" ], - "args": ["--enable-features=FencedFrames:implementation_type/mparch,PrivacySandboxAdsAPIsOverride,SharedStorageAPI,NoncedPartitionedCookies,Fledge,InterestGroupStorage,AdInterestGroupAPI,AllowURNsInIframes,BiddingAndScoringDebugReportingAPI", + "args": ["--enable-features=FencedFrames:implementation_type/mparch,PrivacySandboxAdsAPIsOverride,SharedStorageAPI,NoncedPartitionedCookies,Fledge,InterestGroupStorage,AdInterestGroupAPI,AllowURNsInIframes,BiddingAndScoringDebugReportingAPI,ComputePressure", "--enable-blink-features=FencedFramesAPIChanges"], "expires": "Jul 1, 2023" }, @@ -1732,5 +1748,14 @@ "exclusive_tests": "ALL", "args": ["--enable-features=ExtendScriptResourceLifetime"], "expires": "Jul 1, 2023" + }, + { + "prefix": "webcodecs-without-task-runner-with-custom-deleter", + "platforms": ["Linux", "Mac", "Win"], + "bases": [ + "external/wpt/webcodecs" + ], + "args": ["--disable-features=UseBlinkSchedulerTaskRunnerWithCustomDeleter"], + "expires": "Jul 1, 2023" } ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations index 862b9f6..b12b48d 100644 --- a/third_party/blink/web_tests/WebGPUExpectations +++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -11,6 +11,7 @@ crbug.com/1231599 wpt_internal/webgpu/000_run_me_first.https.html [ Skip ] # Mac doesn't support rgba8unorm for the swapchain format (yet) +crbug.com/1298618 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html [ Skip ] crbug.com/1298618 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_complex_rgba8unorm_copy.https.html [ Skip ] crbug.com/1298618 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_complex_rgba8unorm_draw.https.html [ Skip ] crbug.com/1298618 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_copy.https.html [ Skip ] @@ -39,3 +40,8 @@ crbug.com/1405639 wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html [ Failure ] crbug.com/1405639 wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html [ Failure ] crbug.com/1405639 wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html [ Failure ] + +# Linux/Nvidia times out for colorspace tests +crbug.com/1409154 [ Linux ] wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_bgra8unorm.https.html [ Skip ] +crbug.com/1409154 [ Linux ] wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html [ Skip ] +crbug.com/1409154 [ Linux ] wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html [ Skip ]
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 d4708f5..0734fa8 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
@@ -83691,6 +83691,19 @@ {} ] ], + "block-in-inline-004.html": [ + "338f4ad52ccb87ba5e164efda3a60cac82e9c82f", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "block-max-height-001.html": [ "acb4316d13eee6d791e8c27e5e1b8ab2be03e0ac", [ @@ -122844,6 +122857,19 @@ {} ] ], + "hiragana-katakana-kerning.html": [ + "9d72378581a0e5d96b0611c9bcd9228721030e64", + [ + null, + [ + [ + "/css/css-fonts/hiragana-katakana-kerning-notref.html", + "!=" + ] + ], + {} + ] + ], "line-gap-override.html": [ "487fb2ea59d91cc57715a44e33198fc6223c1d68", [ @@ -262850,16 +262876,6 @@ } }, "support": { - ".cache": { - "gitignore2.json": [ - "daa62d6d0d934d1e59e5ca8eb5dcb709cef13182", - [] - ], - "mtime.json": [ - "200ec7bb8d676a173280f8f612a32a48a4a175b9", - [] - ] - }, ".gitignore": [ "d93e645d547894b50149d3726de2654957b6e06f", [] @@ -278910,10 +278926,6 @@ "7c7430e8fba093d1284c8d9dcc30868df592c69a", [] ], - "CSSAnimation-effect.tentative-expected.txt": [ - "aa98c773694103c8dc59882bf72c6474ab3a75f0", - [] - ], "CSSAnimation-effect.tentative.html.ini": [ "7f6aa9adec5c3839653859f5fbd2cdc966f456ab", [] @@ -278931,7 +278943,7 @@ [] ], "KeyframeEffect-getKeyframes.tentative-expected.txt": [ - "51b5c2105d9bfe0f76db2922d623a60312a38ac0", + "e7d3535d47b4cd21aea7cd243531b5ec5482f67f", [] ], "KeyframeEffect-getKeyframes.tentative.html.ini": [ @@ -279003,22 +279015,6 @@ [] ], "parsing": { - "animation-composition-computed.tentative-expected.txt": [ - "44d81d1bb976a15e39e2e7db734efc3c6ebeeac8", - [] - ], - "animation-composition-computed.tentative.html.ini": [ - "05eb67ba3c000f95c107fb26d393b432c45bc401", - [] - ], - "animation-composition-valid.tentative-expected.txt": [ - "0f58883c97448d970d76b822f26f36efe3f14489", - [] - ], - "animation-composition-valid.tentative.html.ini": [ - "749e6bae389b9279875f7c1df551566ada9c36ea", - [] - ], "animation-computed-expected.txt": [ "7cf62fe5bbfce3752012ad4adfe7773b7ce127ce", [] @@ -291946,6 +291942,10 @@ "eff564952cf02d3ed0aae91f17615c5bcccc1b81", [] ], + "hiragana-katakana-kerning-notref.html": [ + "89d41d42252b0998174bd77f47fbaca12984f2bd", + [] + ], "idlharness-expected.txt": [ "8f0bdf05f436428fb3493a5200d0e64c7cbc28fb", [] @@ -292187,6 +292187,10 @@ "0f28caf21e6fde2660c251471f528e4ed21b82a3", [] ], + "NotoSansJP-kana_test-subset.otf": [ + "9be3823c3e4ab297f8ef2652fdfa47b710761cc8", + [] + ], "ahem-ex-250.otf": [ "186240b91c247a6f1c329d04d32cbe039a03967f", [] @@ -310682,7 +310686,7 @@ ], "parsing": { "marker-supported-properties-expected.txt": [ - "042120083ba2a2893a41b89056940590459bb8f1", + "20bd48882d836ca57b9a1070b7f69c0637ca4494", [] ], "marker-supported-properties-in-animation-expected.txt": [ @@ -310694,7 +310698,7 @@ [] ], "marker-supported-properties.html.ini": [ - "db2d9ceafe3a6cb762903215b95dccf6ae8b7c5d", + "255a365b845a7941453f6ffc9d1223a8e62097e2", [] ] }, @@ -393406,7 +393410,7 @@ [] ], "RTCRtpParameters-encodings-expected.txt": [ - "e849fa74b33545e79894cc64b9604ace49fa5c32", + "b0b528e4136e5c13924f0cbb0f502fe08e4263e5", [] ], "RTCRtpParameters-encodings.html.ini": [ @@ -393611,7 +393615,7 @@ [] ], "setParameters-encodings.https-expected.txt": [ - "04ed2bc75f47b7ab8a47912a3a3d68f35102a985", + "8b89cfda8cbb8c67b08660afaa23a1e8d7e0802c", [] ], "setParameters-encodings.https.html.ini": [ @@ -393835,10 +393839,6 @@ "7ba755bdbd8739f98bcb0ca97dccd77bc30c678f", [] ], - "RTCRtpParameters-maxFramerate-expected.txt": [ - "71a5976c5ef3e2d911e2a28e42cb7b3a909cb65d", - [] - ], "RTCRtpParameters-maxFramerate.html.ini": [ "beab43ef5d4e6a672727d375bb8e235daf325718", [] @@ -435387,7 +435387,7 @@ ] ], "KeyframeEffect-getKeyframes.tentative.html": [ - "a716745c8431520a7fef856178a9f44b3007bd3e", + "4547cae0d202d85720f6f961e06047874acfb61b", [ null, {} @@ -459182,7 +459182,7 @@ }, "declared": { "append.tentative.html": [ - "ced6e81aaad39031adb68e87e7f2b20babaccb58", + "2ff92b22c21d6c7547ebce63de93543f9e4acdd3", [ null, {} @@ -600842,6 +600842,15 @@ {} ] ], + "prefetch-traverse-reload.sub.html": [ + "3f1312ed1222ad78b9f752e190f75e3275929c60", + [ + null, + { + "timeout": "long" + } + ] + ], "redirect-url.https.html": [ "07db405dc3f6ef961605ce14ee7e01eda9ac8408", [
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/back-forward-cache-open-transaction.window.js b/third_party/blink/web_tests/external/wpt/IndexedDB/back-forward-cache-open-transaction.window.js index 41d70d5..e9511d38 100644 --- a/third_party/blink/web_tests/external/wpt/IndexedDB/back-forward-cache-open-transaction.window.js +++ b/third_party/blink/web_tests/external/wpt/IndexedDB/back-forward-cache-open-transaction.window.js
@@ -14,21 +14,26 @@ /*config=*/ null, /*options=*/ {features: 'noopener'}); await rc1.executeScript(() => { - // Create an IndexedDB database and the object store named `store` as the - // test scope for the transaction later on. - const db = indexedDB.open(/*name=*/ 'test_idb', /*version=*/ 1); - db.onupgradeneeded = () => { - db.result.createObjectStore('store'); - }; - addEventListener('pagehide', () => { - let transaction = db.result.transaction(['store'], 'readwrite'); - let store = transaction.objectStore('store'); - store.put("key", "value"); + return new Promise(resolve => { + // Create an IndexedDB database and the object store named `store` as the + // test scope for the transaction later on. + const db = indexedDB.open(/*name=*/ 'test_idb', /*version=*/ 1); + db.onupgradeneeded = () => { + db.result.createObjectStore('store'); + addEventListener('pagehide', () => { + let transaction = db.result.transaction(['store'], 'readwrite'); + let store = transaction.objectStore('store'); + store.put('key', 'value'); - // Queue a request to close the connection, while keeping the transaction - // open, so that the BFCache eligibility will be determined solely by the - // pending transaction. - db.result.close(); + // Queue a request to close the connection, while keeping the transaction + // open, so that the BFCache eligibility will be determined solely by the + // pending transaction. + db.result.close(); + }); + // Only resolve the promise when the connection is established + // and the `pagehide` event listener is added. + resolve(); + }; }); });
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/animation-composition-keyframes.html b/third_party/blink/web_tests/external/wpt/css/css-animations/animation-composition-keyframes.html new file mode 100644 index 0000000..86a27a2b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-animations/animation-composition-keyframes.html
@@ -0,0 +1,113 @@ +<!doctype html> +<meta charset=utf-8> +<title>animation-composition test in keyframes</title> +<link rel="help" href="https://w3c.github.io/csswg-drafts/css-animations-2/#animation-composition"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src="support/testcommon.js"></script> +<style> + @keyframes anim { + from { + animation-composition: add; + filter: blur(10px); + width: 100px; + } + 50% { + animation-composition: accumulate; + filter: blur(15px); + width: 228px; + } + to { + animation-composition: replace; + filter: blur(50px); + width: 1337px; + } + } + + .anim-target { + animation: anim 1s; + animation-fill-mode: forwards; + animation-timing-function: linear; + filter: blur(5px); + width: 50px; + } + + .replace { + animation-composition: replace; + } + + .add { + animation-composition: add; + } + + .accumulate { + animation-composition: accumulate; + } +</style> +<div id="log"></div> +<script> + function run_test_case(element, property, composite_type, timing_value_map) { + element.classList.add(composite_type); + const anim = element.getAnimations()[0]; + for (const [time, value] of Object.entries(timing_value_map)) { + anim.currentTime = time; + const property_value = getComputedStyle(element).getPropertyValue(property); + assert_equals(property_value, value, "at time " + time); + } + element.classList.remove(composite_type); + } + + const test_cases = [ + ["filter", { + "replace": { + 0: "blur(5px) blur(10px)", + 250: "blur(12.5px) blur(5px)", + 500: "blur(20px)", + 1000: "blur(50px)" + }, + "add": { + 0: "blur(5px) blur(10px)", + 250: "blur(12.5px) blur(5px)", + 500: "blur(20px)", + 1000: "blur(50px)" + }, + "accumulate": { + 0: "blur(5px) blur(10px)", + 250: "blur(12.5px) blur(5px)", + 500: "blur(20px)", + 1000: "blur(50px)" + } + }], + ["width", { + "replace": { + 0: "150px", + 250: "214px", + 500: "278px", + 1000: "1337px" + }, + "add": { + 0: "150px", + 250: "214px", + 500: "278px", + 1000: "1337px" + }, + "accumulate": { + 0: "150px", + 250: "214px", + 500: "278px", + 1000: "1337px" + } + }] + ] + + for (const test_case of test_cases) { + const property = test_case[0]; + const test_data = test_case[1]; + for (const [composite_type, expected_values] of Object.entries(test_data)) { + test(t => { + let elem = addDiv(t, {"class": "anim-target"}); + run_test_case(elem, property, composite_type, expected_values); + }, "animation-composition: " + composite_type + " of property " + property); + } + } +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/animation-composition.html b/third_party/blink/web_tests/external/wpt/css/css-animations/animation-composition.html new file mode 100644 index 0000000..48e757c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-animations/animation-composition.html
@@ -0,0 +1,110 @@ +<!doctype html> +<meta charset=utf-8> +<title>animation-composition test</title> +<link rel="help" href="https://w3c.github.io/csswg-drafts/css-animations-2/#animation-composition"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src="support/testcommon.js"></script> +<style> + @keyframes anim { + from { + filter: blur(10px); + width: 100px; + } + 50% { + filter: blur(15px); + width: 228px; + } + to { + filter: blur(20px); + width: 1337px; + } + } + + .anim-target { + animation: anim 1s; + animation-fill-mode: forwards; + animation-timing-function: linear; + filter: blur(5px); + width: 50px; + } + + .replace { + animation-composition: replace; + } + + .add { + animation-composition: add; + } + + .accumulate { + animation-composition: accumulate; + } +</style> +<div id="log"></div> +<script> + function run_test_case(element, property, composite_type, timing_value_map) { + element.classList.add(composite_type); + const anim = element.getAnimations()[0]; + for (const [time, value] of Object.entries(timing_value_map)) { + anim.currentTime = time; + const property_value = getComputedStyle(element).getPropertyValue(property); + assert_equals(property_value, value, "at time " + time); + } + element.classList.remove(composite_type); + } + + const test_cases = [ + ["filter", { + "replace": { + 0: "blur(10px)", + 250: "blur(12.5px)", + 500: "blur(15px)", + 1000: "blur(20px)" + }, + "add": { + 0: "blur(5px) blur(10px)", + 250: "blur(5px) blur(12.5px)", + 500: "blur(5px) blur(15px)", + 1000: "blur(5px) blur(20px)" + }, + "accumulate": { + 0: "blur(15px)", + 250: "blur(17.5px)", + 500: "blur(20px)", + 1000: "blur(25px)" + } + }], + ["width", { + "replace": { + 0: "100px", + 250: "164px", + 500: "228px", + 1000: "1337px" + }, + "add": { + 0: "150px", + 250: "214px", + 500: "278px", + 1000: "1387px" + }, + "accumulate": { + 0: "150px", + 250: "214px", + 500: "278px", + 1000: "1387px" + } + }] + ] + + for (const test_case of test_cases) { + const property = test_case[0]; + const test_data = test_case[1]; + for (const [composite_type, expected_values] of Object.entries(test_data)) { + test(t => { + let elem = addDiv(t, {"class": "anim-target"}); + run_test_case(elem, property, composite_type, expected_values); + }, "animation-composition: " + composite_type + " of property " + property); + } + } +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-invalid-color-mix-function.html b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-invalid-color-mix-function.html index df36aab6..40299644 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-invalid-color-mix-function.html +++ b/third_party/blink/web_tests/external/wpt/css/css-color/parsing/color-invalid-color-mix-function.html
@@ -42,6 +42,7 @@ test_invalid_value(`color`, `color-mix(in hwb, hwb(120deg 10% 20%) hwb(30deg 30% 40%))`); // Missing comma between colors. test_invalid_value(`color`, `color-mix(hwb(120deg 10% 20%), hwb(30deg 30% 40%), in hwb)`); // Interpolation method not at the beginning. test_invalid_value(`color`, `color-mix(hwb(120deg 10% 20%), hwb(30deg 30% 40%))`); // Missing interpolation method. + test_invalid_value(`color`, `color-mix(in srgb, red, blue blue)`); // Too many parameters. for (const colorSpace of [ "lch", "oklch" ]) { test_invalid_value(`color`, `color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg) -10%, ${colorSpace}(50% 60 70deg))`); // Percentages less than 0 are not valid.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/generic-family-keywords-003-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-fonts/generic-family-keywords-003-expected.txt new file mode 100644 index 0000000..893a21f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/generic-family-keywords-003-expected.txt
@@ -0,0 +1,16 @@ +This is a testharness.js-based test. +PASS @font-face matching for quoted and unquoted serif (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted sans-serif (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted cursive (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted fantasy (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted monospace (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted system-ui (drawing text in a canvas) +FAIL @font-face matching for quoted and unquoted emoji (drawing text in a canvas) assert_equals: unquoted emoji does not match @font-face rule expected 25 but got 125 +PASS @font-face matching for quoted and unquoted math (drawing text in a canvas) +FAIL @font-face matching for quoted and unquoted fangsong (drawing text in a canvas) assert_equals: unquoted fangsong does not match @font-face rule expected 25 but got 125 +FAIL @font-face matching for quoted and unquoted ui-serif (drawing text in a canvas) assert_equals: unquoted ui-serif does not match @font-face rule expected 25 but got 125 +FAIL @font-face matching for quoted and unquoted ui-sans-serif (drawing text in a canvas) assert_equals: unquoted ui-sans-serif does not match @font-face rule expected 25 but got 125 +FAIL @font-face matching for quoted and unquoted ui-monospace (drawing text in a canvas) assert_equals: unquoted ui-monospace does not match @font-face rule expected 25 but got 125 +FAIL @font-face matching for quoted and unquoted ui-rounded (drawing text in a canvas) assert_equals: unquoted ui-rounded does not match @font-face rule expected 25 but got 125 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/generic-family-keywords-003.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/generic-family-keywords-003.html new file mode 100644 index 0000000..c787b59f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/generic-family-keywords-003.html
@@ -0,0 +1,53 @@ +<!DOCTYPE html> +<title>Test quotes vs. no-quotes matchings of generic font family keywords in a CanvasRenderingContext2D</title> +<link rel="help" href="https://drafts.csswg.org/css-fonts-4/#family-name-syntax"> +<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/css-fonts/support/font-family-keywords.js"></script> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css"/> +<body> +<canvas id="canvas" width="400" height="150"></canvas> +<script> + setup({ explicit_done: true }); + window.addEventListener("load", () => { document.fonts.ready.then(runTests); }); + function runTests() { + const measured_text = "|||||"; + const canvas = document.getElementById("canvas"); + const ctx = canvas.getContext("2d"); + ctx.font = `25px Ahem`; + let ahem_expected_width = ctx.measureText(measured_text).width; + + kGenericFontFamilyKeywords.forEach(keyword => { + test(() => { + ctx.font = `25px ${keyword}`; + let expected_width = ctx.measureText(measured_text).width; + + // Insert the @font-face rules for quoted and unquoted keywords. + document.documentElement.insertAdjacentHTML('beforeend', ` +<style> +@font-face { + font-family: ${keyword}; + src: local(Ahem), url('/fonts/Ahem.ttf'); +} +</style> +<style> +@font-face { + font-family: "${keyword}"; + src: local(Ahem), url('/fonts/Ahem.ttf'); +} +</style>`); + + ctx.font = `25px ${keyword}`; + let unquoted_width = ctx.measureText(measured_text).width; + assert_equals(unquoted_width, expected_width, `unquoted ${keyword} does not match @font-face rule`); + + ctx.font = `25px "${keyword}"`; + let quoted_width = ctx.measureText(measured_text).width; + assert_equals(quoted_width, ahem_expected_width, `quoted ${keyword} matches @font-face rule`); + }, `@font-face matching for quoted and unquoted ${keyword} (drawing text in a canvas)`); + }); + done(); + } +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/hiragana-katakana-kerning-notref.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/hiragana-katakana-kerning-notref.html new file mode 100644 index 0000000..89d41d4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/hiragana-katakana-kerning-notref.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8" /> + <title>CSS Reference: Hiragana/Katakana kerning</title> + <style> + @font-face { + font-family: "Noto Sans JP"; + src: url(resources/NotoSansJP-kana_test-subset.otf); + } + + p { + position: absolute; + top: 0; + left: 0; + + font-size: 6em; + font-family: "Noto Sans JP"; + font-feature-settings: "palt" on; + font-kerning: none; + + margin: 1em; + } + + .no-kerning-red { + color: red; + } + + .no-kerning-green { + color: green; + mix-blend-mode: multiply; + } + </style> + </head> + <body> + <span> + RED or GREEN text is visible if kerning is applying correctly, with only + BLACK otherwise: + </span> + <p class="no-kerning-red">すペ</p> + <p class="no-kerning-green">すペ</p> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/hiragana-katakana-kerning.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/hiragana-katakana-kerning.html new file mode 100644 index 0000000..9d723785 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/hiragana-katakana-kerning.html
@@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8" /> + <title>CSS Test: Hiragana/Katakana kerning</title> + <link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com"> + <!-- Based on testcase by Harry Dalton, see https://bugzilla.mozilla.org/show_bug.cgi?id=1811471; + check that kerning works between hiragana and katakana, because both map to the same + OpenType script behavior. --> + <link rel="mismatch" href="hiragana-katakana-kerning-notref.html"> + <link rel="help" href="https://learn.microsoft.com/en-us/typography/opentype/spec/scripttags"> + <style> + @font-face { + font-family: "Noto Sans JP"; + src: url(resources/NotoSansJP-kana_test-subset.otf); + } + + p { + position: absolute; + top: 0; + left: 0; + + font-size: 6em; + font-family: "Noto Sans JP"; + font-feature-settings: "palt" on; + + margin: 1em; + } + + .with-kerning { + font-kerning: normal; + color: red; + } + + .no-kerning { + font-kerning: none; + color: green; + mix-blend-mode: multiply; + } + </style> + </head> + <body> + <span> + RED or GREEN text is visible if kerning is applying correctly, with only + BLACK otherwise: + </span> + <p class="with-kerning">すペ</p> + <p class="no-kerning">すペ</p> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/resources/NotoSansJP-kana_test-subset.otf b/third_party/blink/web_tests/external/wpt/css/css-fonts/resources/NotoSansJP-kana_test-subset.otf new file mode 100644 index 0000000..9be3823c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/resources/NotoSansJP-kana_test-subset.otf Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-001.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-001.html index cd27731..171c53f 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-001.html
@@ -2,11 +2,11 @@ <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> <link rel="help" href="https://drafts.csswg.org/css-multicol-1"> <link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export"> -<meta name="assert" content="The multicol container here has no baseline, since we're only supposed to look for a baseline in the first column, which has no lines at all."> +<meta name="assert" content="Look for the highest baseline of all the columns."> <link rel="match" href="baseline-001-ref.html"> <p>There should be a green square below.</p> <div style="display:flex; align-items:baseline;"> - <div style="width:50px; height:100px; background:green;"></div> + <div style="width:50px; height:100px; background:green;"><br></div> <div style="columns:2; height:100px; column-fill:auto;"> <div style="width:50px; height:100px; background:green;"></div> <br>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-002-ref.html index 6de99d0..dc6562c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-002-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-002-ref.html
@@ -1,7 +1,4 @@ <!DOCTYPE html> <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> -<p>The word "PASS" should be seen below, with letters baseline aligned.</p> -<div style="line-height:2em;"> - <br> - PASS -</div> +<p>There should be a green square below.</p> +<div style="width:100px; height:100px; background:green"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-002.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-002.html index 127ecd5..b1e660b 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-002.html +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-002.html
@@ -3,13 +3,15 @@ <link rel="help" href="https://drafts.csswg.org/css-multicol-1"> <link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export"> <link rel="match" href="baseline-002-ref.html"> -<meta name="assert" content="Make sure that baseline propagation doesn't take place before column balancing is finished."> -<p>The word "PASS" should be seen below, with letters baseline aligned.</p> -<div style="display:flex; align-items:baseline;"> - PA - <div style="columns:3; orphans:1; widows:1; line-height:2em;"> +<meta name="assert" content="The first-baseline is propagated from the secound column, as it is the highest."> +<p>There should be a green square below.</p> +<div style="display:flex; align-items:baseline; line-height:2em;"> + <div style="background:green; width:50px; height:100px;"> + <br> + </div> + <div style="background:green; columns:3; orphans:1; widows:1; width:50px; height:100px;"> <div style="break-inside:avoid; height:2em;"></div> - SS<br> + <br> <br> <br> </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-007.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-007.html index be886e9..95f18fe 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-007.html +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/baseline-007.html
@@ -2,12 +2,14 @@ <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> <link rel="help" href="https://drafts.csswg.org/css-multicol-1"> <link rel="help" href="https://drafts.csswg.org/css-align/#baseline-export"> -<meta name="assert" content="The first column has no baseline. The column after the spanner does have one, but we're not supposed to look beyond the first column (and any spanners)."> <link rel="match" href="baseline-007-ref.html"> <p>There should be a green square below.</p> -<div style="display:flex; align-items:baseline;"> - <div style="width:50px; height:100px; background:green;"></div> - <div style="columns:3; width:50px; line-height:40px; background:green;"> +<div style="display:flex; align-items:baseline; line-height:40px;"> + <div style="width:50px; background:green;"> + <div style="height:60px;"></div> + <br> + </div> + <div style="columns:3; width:50px; background:green;"> <div style="height:90px;"></div> <div style="column-span:all; height:30px;"></div> <br>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/spanner-in-overflowed-clipped-container.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/spanner-in-overflowed-clipped-container.html new file mode 100644 index 0000000..d38c7b6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/spanner-in-overflowed-clipped-container.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1377576"> +<div style="columns:2;"> + <div style="overflow:clip; height:15px;"> + <div style="height:20px;"></div> + <div style="column-span:all;"></div> + <div></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/resources/include-frames-subframe.html b/third_party/blink/web_tests/external/wpt/performance-timeline/resources/include-frames-subframe.html new file mode 100644 index 0000000..b74b1175 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/resources/include-frames-subframe.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> + +<head> +</head> +<!-- + This html is embedded as a sub-frame in include-frames-originA-B-A.html, + include-frames-originA-B-B.html and include-frames-originA-A-A.html. Once embedded, + this would take a url parameter named origin which is the origin of the child frame + this html is to load in step 3 listed below. + It does, + 1, waits for load. + 2, creates a single mark performance entry. + 3, creates and loads a child frame, and waits for it to load. + 4. posts a message to its parent with the combined number of performance entries + in both this frame and the child (if readable). +--> + +<body> + <script> + (async () => { + // Wait for load. + await new Promise(resolve => window.addEventListener("load", resolve)); + + // Mark. + performance.mark("entry-name"); + + // Create and load an iframe and wait for load. + await new Promise(resolve => { + const childFrame = document.createElement('iframe'); + + childFrame.addEventListener('load', async () => { + const entries = performance.getEntries(true); + + // Report number of performance entries to the parent. + window.parent.postMessage(entries.length, "*"); + + resolve(); + }) + childFrame.src = (new URL(document.location)).searchParams.get('origin') + + '/performance-timeline/resources/child-frame.html'; + + document.body.appendChild(childFrame); + } + ); + })(); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/resources/parent-frame-with-cross-origin-child.sub.html b/third_party/blink/web_tests/external/wpt/performance-timeline/resources/parent-frame-with-cross-origin-child.sub.html deleted file mode 100644 index a4917451..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/resources/parent-frame-with-cross-origin-child.sub.html +++ /dev/null
@@ -1,18 +0,0 @@ -<!DOCTYPE html> -<head></head> -<body></body> -<script> - // Create child frame that is cross-origin with its parent. - const childFrame = document.createElement('iframe') - childFrame.src = "http://{{hosts[][]}}:{{ports[http][0]}}/performance-timeline/resources/child-frame.html" - document.body.appendChild(childFrame) - - performance.mark("entry-name") - const loadPromise = new Promise(resolve => window.addEventListener("load", resolve)) - - childFrame.addEventListener('load', async () => { - await loadPromise - const entries = performance.getEntries(true) - window.parent.postMessage(entries.length, "*") - }) -</script>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/resources/parent-frame-with-same-origin-child.html b/third_party/blink/web_tests/external/wpt/performance-timeline/resources/parent-frame-with-same-origin-child.html deleted file mode 100644 index 813c2a7..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/resources/parent-frame-with-same-origin-child.html +++ /dev/null
@@ -1,18 +0,0 @@ -<!DOCTYPE html> -<head></head> -<body></body> -<script> - // Create child frame that is same-origin with its parent. - const childFrame = document.createElement('iframe') - childFrame.src = "child-frame.html" - document.body.appendChild(childFrame) - - performance.mark("entry-name") - const loadPromise = new Promise(resolve => window.addEventListener("load", resolve)); - - childFrame.addEventListener('load', async () => { - await loadPromise; - const entries = performance.getEntries(true) - window.parent.postMessage(entries.length, "*") - }) -</script>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-from-child-cross-origin-grandchild.sub.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-from-child-cross-origin-grandchild.sub.html deleted file mode 100644 index 1886f04..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-from-child-cross-origin-grandchild.sub.html +++ /dev/null
@@ -1,32 +0,0 @@ -<!DOCTYPE html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -</body> -<script> -promise_test(() => { - return new Promise(resolve => { - performance.clearResourceTimings() - - // Create child iframe with an embedded frame that is same-origin with its parent but cross-origin with the current frame. - const crossOriginChildFrame = document.createElement('iframe') - crossOriginChildFrame.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/performance-timeline/resources/parent-frame-with-same-origin-child.html" - document.body.appendChild(crossOriginChildFrame) - - // Listen for postMessage() from child frame. - window.addEventListener("message", e => { - // 0 entries for parent, 4 for child, 2 for grandchild. - assert_equals(e.data, 6) - - const entries = performance.getEntries(true) - - // 3 entries for parent, 0 for child, 0 for grandchild. - assert_equals(entries.length, 3) - - resolve() - }) - }) -}, "GetEntries of a Cross-Origin child frame with one Cross-Origin grandchild frame") -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-from-child-same-origin-grandchild.sub.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-from-child-same-origin-grandchild.sub.html deleted file mode 100644 index 16142ca..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-from-child-same-origin-grandchild.sub.html +++ /dev/null
@@ -1,32 +0,0 @@ -<!DOCTYPE html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -</body> -<script> -promise_test(() => { - return new Promise(resolve => { - performance.clearResourceTimings() - - // Create child iframe with an embedded frame that is cross-origin with its parent but same-origin with the current frame. - const crossOriginChildFrame = document.createElement('iframe') - crossOriginChildFrame.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/performance-timeline/resources/parent-frame-with-cross-origin-child.sub.html" - document.body.appendChild(crossOriginChildFrame) - - // Listen for postMessage() from child frame. - window.addEventListener("message", e => { - // 0 entries for parent, 4 for child, 0 for grandchild. - assert_equals(e.data, 4) - - const entries = performance.getEntries(true) - - // 3 entries for parent, 0 for child, 2 for grandchild. - assert_equals(entries.length, 5) - - resolve() - }) - }) -}, "GetEntries of a Cross-Origin child frame with one Same-Origin grandchild frame") -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-cross-origin-child-one-same-origin-grandchild.sub.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-cross-origin-child-one-same-origin-grandchild.sub.html deleted file mode 100644 index 8aa5df77..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-cross-origin-child-one-same-origin-grandchild.sub.html +++ /dev/null
@@ -1,37 +0,0 @@ -<!DOCTYPE html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -</body> -<script> -promise_test(() => { - return new Promise(resolve => { - performance.clearResourceTimings() - - // Create child iframe with an embedded frame that is cross-origin with its parent, but same-origin with the current frame. - const crossOriginChildFrame = document.createElement('iframe') - crossOriginChildFrame.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/performance-timeline/resources/parent-frame-with-cross-origin-child.sub.html" - document.body.appendChild(crossOriginChildFrame) - - // Listen for postMessage() from grandchild frame. - window.addEventListener("message", () => { - const entries = performance.getEntries(true) - const navigationEntries = performance.getEntriesByType("navigation", true) - const markedEntries = performance.getEntriesByName("entry-name", undefined, true) - - // 3 entries for parent, 0 for child, 2 for grandchild. - assert_equals(entries.length, 5) - - // 1 entry for parent, 1 for grandchild. - assert_equals(navigationEntries.length, 2) - - // 1 entry for grandchild. - assert_equals(markedEntries.length, 1) - - resolve() - }) - }) -}, "GetEntries of a parent Frame with one Cross-Origin child and one Same-Origin grandchild") -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-remote-child.sub.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-remote-child.sub.html deleted file mode 100644 index 61e7a1f6..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-remote-child.sub.html +++ /dev/null
@@ -1,36 +0,0 @@ -<!DOCTYPE html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -</body> -<script> -promise_test(() => { - return new Promise(resolve => { - performance.clearResourceTimings() - - // Create Remote child iframe. - const childFrame = document.createElement('iframe') - childFrame.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/resources/child-frame.html" - document.body.appendChild(childFrame) - - childFrame.addEventListener("load", () => { - const entries = performance.getEntries(true) - const navigationEntries = performance.getEntriesByType("navigation", true) - const markedEntries = performance.getEntriesByName("entry-name", undefined, true) - - // 3 entries for parent, 0 for child. - assert_equals(entries.length, 3) - - // 1 entry for parent. - assert_equals(navigationEntries.length, 1) - - // 0 entries. - assert_equals(markedEntries.length, 0) - - resolve() - }) - }) -}, "GetEntries of a parent Frame with one Cross-Origin child") -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child-one-cross-origin-child.sub.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child-one-cross-origin-child.sub.html deleted file mode 100644 index b20bde9..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child-one-cross-origin-child.sub.html +++ /dev/null
@@ -1,56 +0,0 @@ -<!DOCTYPE html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -</body> -<script> -promise_test(() => { - return new Promise(resolve => { - performance.clearResourceTimings() - - let sameOriginFrameLoaded = false - let crossOriginFrameLoaded = false - - // Create first child iframe. - const sameOriginChildFrame = document.createElement('iframe') - sameOriginChildFrame.src = "../resources/child-frame.html" - document.body.appendChild(sameOriginChildFrame) - - sameOriginChildFrame.addEventListener("load", () => { - sameOriginFrameLoaded = true - if (crossOriginFrameLoaded) - verifyPerformanceEntries() - }) - - // Create second child iframe. - const crossOriginChildFrame = document.createElement('iframe') - crossOriginChildFrame.src = "http://{{hosts[][www]}}:{{ports[http][0]}}/resources/child-frame.html" - document.body.appendChild(crossOriginChildFrame) - - crossOriginChildFrame.addEventListener("load", () => { - crossOriginFrameLoaded = true - if (sameOriginFrameLoaded) - verifyPerformanceEntries() - }) - - function verifyPerformanceEntries() { - const entries = performance.getEntries(true) - const navigationEntries = performance.getEntriesByType("navigation", true) - const markedEntries = performance.getEntriesByName("entry-name", undefined, true) - - // 4 entries for parent, 2 for local child, 0 for remote child. - assert_equals(entries.length, 6) - - // 1 entry for parent, 1 for local child. - assert_equals(navigationEntries.length, 2) - - // 1 entry for local child. - assert_equals(markedEntries.length, 1) - - resolve() - } - }) -}, "GetEntries of a parent Frame with one Cross-Origin child and one Same-Origin child") -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child-one-same-origin-grandchild.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child-one-same-origin-grandchild.html deleted file mode 100644 index 10ccea3..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child-one-same-origin-grandchild.html +++ /dev/null
@@ -1,37 +0,0 @@ -<!DOCTYPE html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -</body> -<script> -promise_test(() => { - return new Promise(resolve => { - performance.clearResourceTimings() - - // Create child iframe with an embedded frame that is cross-origin with its parent, but same-origin with the current frame. - const childFrame = document.createElement('iframe') - childFrame.src = "../resources/parent-frame-with-cross-origin-child.sub.html" - document.body.appendChild(childFrame) - - // Listen for postMessage() from grandchild frame. - window.addEventListener("message", () => { - const entries = performance.getEntries(true) - const navigationEntries = performance.getEntriesByType("navigation", true) - const markedEntries = performance.getEntriesByName("entry-name", undefined, true) - - // 4 entries for parent, 3 for child, 2 for grandchild. - assert_equals(entries.length, 9) - - // 1 entry for parent, 1 for child, 1 for grandchild. - assert_equals(navigationEntries.length, 3) - - // 1 entry for child, 1 for grandchild. - assert_equals(markedEntries.length, 2) - - resolve() - }) - }) -}, "GetEntries of a parent Frame with one Same-Origin child and one Same-Origin grandchild") -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child.html deleted file mode 100644 index 73dc417..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-one-same-origin-child.html +++ /dev/null
@@ -1,37 +0,0 @@ -<!DOCTYPE html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -</body> -<script> -promise_test(() => { - return new Promise(resolve => { - performance.clearResourceTimings() - - // Create child iframe. - const childFrame = document.createElement('iframe') - childFrame.src = "../resources/child-frame.html" - document.body.appendChild(childFrame) - - // On-load event handler to assert size of entries. - childFrame.addEventListener("load", () => { - const entries = performance.getEntries(true) - const navigationEntries = performance.getEntriesByType("navigation", true) - const markedEntries = performance.getEntriesByName("entry-name", undefined, true) - - // 3 entries for parent, 2 for child. - assert_equals(entries.length, 5) - - // 1 entry for parent, 1 for child. - assert_equals(navigationEntries.length, 2) - - // 1 entry for child. - assert_equals(markedEntries.length, 1) - - resolve() - }) - }) -}, "GetEntries of a parent Frame with one Same-Origin child"); -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-A-A.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-A-A.html new file mode 100644 index 0000000..0cdcd581 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-A-A.html
@@ -0,0 +1,54 @@ +<!DOCTYPE html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src=/common/get-host-info.sub.js></script> +</head> + +<body> + <script> + const loadChildFrame = () => { + return new Promise(resolve => { + + const childFrame = document.createElement('iframe'); + + window.addEventListener("message", (e) => { + resolve(e.data) + }); + + childFrame.src = "../resources/include-frames-subframe.html?origin=" + get_host_info().ORIGIN; + + document.body.appendChild(childFrame); + }); + } + + promise_test(async () => { + performance.clearResourceTimings(); + + // Load a child frame. The child frame upon loading would load a child frame of its own. + childFrameEntrySize = await loadChildFrame(); + + // Verify the number of performance entries in the child frame. + assert_equals(childFrameEntrySize, 6, 'Child Frame should have 6 entries.'); + + const entries = performance.getEntries(true); + + const navigationEntries = performance.getEntriesByType('navigation', true); + + const markedEntries = performance.getEntriesByName('entry-name', undefined, true); + + + // 3 entries for parent, 4 for child, 2 for grandchild. + assert_equals(entries.length, 9, 'Total entries should be 9.'); + + // 1 entry for parent, 1 for child, 1 for grandchild. + assert_equals(navigationEntries.length, 3, 'Navigation entries should be 3.'); + + // 1 entry for child, 1 for grandchild. + assert_equals(markedEntries.length, 2, 'Mark entries should be 2.'); + + }, 'GetEntries of a document of origin A, its child frame of origin B and \ + its grandchild frame of origin A.'); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-A.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-A.html new file mode 100644 index 0000000..bb4ee9e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-A.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> +<script> + const loadSameOriginChildFrame = () => { + return new Promise(resolve => { + + const childFrame = document.createElement('iframe'); + + childFrame.addEventListener("load", () => { + resolve(); + }); + + childFrame.src = "../resources/child-frame.html"; + + document.body.appendChild(childFrame); + }); + } + + promise_test(async () => { + performance.clearResourceTimings(); + + // Load a child frame. + await loadSameOriginChildFrame(); + + const entries = performance.getEntries(true); + + const navigationEntries = performance.getEntriesByType('navigation', true); + + const markedEntries = performance.getEntriesByName('entry-name', undefined, true); + + // 3 entries for parent, 2 for child. + assert_equals(entries.length, 5, 'Total entries should be 5.'); + + // 1 entry for parent, 1 for child. + assert_equals(navigationEntries.length, 2, 'Navigation entries should be 2.'); + + // 1 entry for child. + assert_equals(markedEntries.length, 1, 'Mark entries should be 1.'); + }, 'GetEntries of a document of origin A and its child frame of origin A.'); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-AA.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-AA.html new file mode 100644 index 0000000..e4c742a0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-AA.html
@@ -0,0 +1,55 @@ + +<!DOCTYPE html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> +<script> + const verifyPerformanceEntries = () => { + const entries = performance.getEntries(true); + + const navigationEntries = performance.getEntriesByType( 'navigation', true); + + const markedEntries = performance.getEntriesByName('entry-name', undefined, true ); + + // 4 entries for parent, 2 for each child + assert_equals(entries.length, 8,'Total entries should be 8.'); + + // 1 entry for parent, 1 for each child. + assert_equals(navigationEntries.length, 3, 'Navigation entries should be 3.'); + + // 1 entry for each child. + assert_equals(markedEntries.length, 2, 'Mark entries should be 2.'); + } + + const loadChildFrame = () => { + return new Promise(resolve => { + + const childFrame = document.createElement('iframe'); + + childFrame.addEventListener("load", () => { + resolve(); + }); + + childFrame.src = "../resources/child-frame.html"; + + document.body.appendChild(childFrame); + }); + } + + promise_test(async () => { + performance.clearResourceTimings(); + + // Load first child iframe. + const promise1 = loadChildFrame(); + + // Load second child iframe. + const promise2 = loadChildFrame(); + + return Promise.all([promise1, promise2]).then(verifyPerformanceEntries); + }, 'GetEntries of a document of origin A and its two child frames both of origin A.'); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-AB.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-AB.html new file mode 100644 index 0000000..cbd27a03 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-AB.html
@@ -0,0 +1,55 @@ +<!DOCTYPE html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src=/common/get-host-info.sub.js></script> +</head> + +<body> + <script> + const loadChildFrame = (src) => { + return new Promise(resolve => { + const childFrame = document.createElement('iframe'); + + childFrame.addEventListener("load", () => { + resolve(); + }); + + childFrame.src = src; + + document.body.appendChild(childFrame); + }); + } + + const verifyPerformanceEntries = () => { + const entries = performance.getEntries(true); + + const navigationEntries = performance.getEntriesByType('navigation', true); + + const markedEntries = performance.getEntriesByName('entry-name', undefined, true); + + // 4 entries for parent, 2 for local child, 0 for remote child. + assert_equals(entries.length, 6, 'Total entries should 6.'); + + // 1 entry for parent, 1 for local child. + assert_equals(navigationEntries.length, 2, 'Navigation entries should be 2.'); + + // 1 entry for local child. + assert_equals(markedEntries.length, 1, 'Mark entries should be 1.'); + } + + promise_test(() => { + performance.clearResourceTimings(); + + // Load first child iframe. + sameOriginPromise = loadChildFrame('../resources/child-frame.html'); + + // Create second child iframe. + crossOriginPromise = loadChildFrame( + get_host_info().HTTP_REMOTE_ORIGIN + '/resources/child-frame.html'); + + return Promise.all([sameOriginPromise, crossOriginPromise]).then(verifyPerformanceEntries); + }, 'GetEntries of a document of origin A and its two child frames of origin A and B respectively.'); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B-A.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B-A.html new file mode 100644 index 0000000..5e46bc2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B-A.html
@@ -0,0 +1,57 @@ +<!DOCTYPE html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src=/common/get-host-info.sub.js></script> + +</head> + +<body> + <script> + const loadChildFrame = () => { + return new Promise(resolve => { + + const crossOriginChildFrame = document.createElement('iframe'); + + // Wait for child frame to report number of performance entries. + window.addEventListener("message", (e) => { + resolve(e.data); + }); + + crossOriginChildFrame.src = get_host_info().REMOTE_ORIGIN + + '/performance-timeline/resources/include-frames-subframe.html?origin=' + get_host_info().ORIGIN; + + document.body.appendChild(crossOriginChildFrame); + }); + } + + promise_test(async () => { + + performance.clearResourceTimings(); + + // Load a child frame. The child frame upon loading would load a child frame of its own. + childFrameEntrySize = await loadChildFrame(); + + // Verify the number of performance entries in the child frame. + assert_equals(childFrameEntrySize, 4, 'Child frame entries should be 4.'); + + const entries = performance.getEntries(true); + + const navigationEntries = performance.getEntriesByType( + 'navigation', true); + + const markedEntries = performance.getEntriesByName('entry-name', undefined, true); + + // 3 entries for parent, 0 for child, 2 for grandchild. + assert_equals(entries.length, 5, 'Total entries should be 5.'); + + // 1 entry for parent, 1 for grandchild. + assert_equals(navigationEntries.length, 2, 'Navigation entries should be 2.'); + + // 1 entry for grandchild. + assert_equals(markedEntries.length, 1, 'Mark entries should be 1.'); + }, 'GetEntries of a document of origin A, its child frame of origin B and \ + its grandchild frame of origin A.'); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B-B.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B-B.html new file mode 100644 index 0000000..a1c8515 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B-B.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src=/common/get-host-info.sub.js></script> + +</head> + +<body> + <script> + const loadChildFrame = () => { + return new Promise(resolve => { + + const crossOriginChildFrame = document.createElement('iframe'); + + crossOriginChildFrame.src = get_host_info().REMOTE_ORIGIN + + "/performance-timeline/resources/include-frames-subframe.html?origin=" + get_host_info().REMOTE_ORIGIN; + + document.body.appendChild(crossOriginChildFrame) + + window.addEventListener("message", e => { + resolve(e.data); + }); + }); + } + + promise_test(async () => { + performance.clearResourceTimings(); + + // Load a child frame. The child frame upon loading would load a child frame of its own. + childFrameEntrySize = await loadChildFrame(); + + // Verify the number of performance entries in the child frame. + // 4 for child, 2 for grandchild. + assert_equals(childFrameEntrySize, 6, 'Child frame entries should be 6.'); + + const entries = performance.getEntries(true); + + // 3 entries for parent, 0 for child, 0 for grandchild. + assert_equals(entries.length, 3, 'Total entries should be 3.'); + }, 'GetEntries of a document of origin A, its child frame of origin B and \ + its grandchild frame of origin B.'); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B.html new file mode 100644 index 0000000..0373c82 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-originA-B.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src=/common/get-host-info.sub.js></script> + +</head> + +<body> + <script> + const loadCrossOriginChildFrame = () => { + return new Promise((resolve, reject) => { + + const childFrame = document.createElement('iframe'); + + childFrame.addEventListener("load", resolve); + + childFrame.src = + get_host_info().HTTP_REMOTE_ORIGIN + '/performance_timeline/resources/child-frame.html'; + + document.body.appendChild(childFrame); + }) + } + + promise_test(async () => { + performance.clearResourceTimings(); + + await loadCrossOriginChildFrame(); + + const entries = performance.getEntries(true); + + const navigationEntries = performance.getEntriesByType("navigation", true); + + const markedEntries = performance.getEntriesByName('entry-name', undefined, true); + + // 3 entries for parent, 0 for child. + assert_equals(entries.length, 3, 'Total entries should be 3.'); + + // 1 entry for parent. + assert_equals(navigationEntries.length, 1, 'Navigation entries should 1.'); + + // 0 entries. + assert_equals(markedEntries.length, 0, 'Mark entries should 0.'); + }, 'GetEntries of a parent Frame of origin A and its child frame of origin B'); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-two-local-children.html b/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-two-local-children.html deleted file mode 100644 index 01d4844..0000000 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/tentative/include-frames-two-local-children.html +++ /dev/null
@@ -1,56 +0,0 @@ -<!DOCTYPE html> -<head> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -</head> -<body> -</body> -<script> -promise_test(() => { - return new Promise(resolve => { - performance.clearResourceTimings() - - let childFrameOneLoaded = false - let childFrameTwoLoaded = false - - // Create first child iframe. - const childFrameOne = document.createElement('iframe') - childFrameOne.src = "../resources/child-frame.html" - document.body.appendChild(childFrameOne) - - childFrameOne.addEventListener("load", () => { - childFrameOneLoaded = true - if (childFrameTwoLoaded) - verifyPerformanceEntries() - }) - - // Create second child iframe. - const childFrameTwo = document.createElement('iframe') - childFrameTwo.src = "../resources/child-frame.html" - document.body.appendChild(childFrameTwo) - - childFrameTwo.addEventListener("load", () => { - childFrameTwoLoaded = true - if (childFrameOneLoaded) - verifyPerformanceEntries() - }) - - function verifyPerformanceEntries() { - const entries = performance.getEntries(true) - const navigationEntries = performance.getEntriesByType("navigation", true) - const markedEntries = performance.getEntriesByName("entry-name", undefined, true) - - // 4 entries for parent, 2 for each child - assert_equals(entries.length, 8) - - // 1 entry for parent, 1 for each child. - assert_equals(navigationEntries.length, 3) - - // 1 entry for each child. - assert_equals(markedEntries.length, 2) - - resolve() - } - }) -}, "GetEntries of a parent Frame with two Same-Origin children") -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/mock-pressure-service.js b/third_party/blink/web_tests/external/wpt/resources/chromium/mock-pressure-service.js index 19eb1e9..91efe529 100644 --- a/third_party/blink/web_tests/external/wpt/resources/chromium/mock-pressure-service.js +++ b/third_party/blink/web_tests/external/wpt/resources/chromium/mock-pressure-service.js
@@ -1,11 +1,11 @@ +import {PressureManager, PressureManagerReceiver, PressureStatus} from '/gen/services/device/public/mojom/pressure_manager.mojom.m.js' import {PressureFactor, PressureState} from '/gen/services/device/public/mojom/pressure_update.mojom.m.js' -import {PressureService, PressureServiceReceiver, PressureStatus} from '/gen/third_party/blink/public/mojom/compute_pressure/pressure_service.mojom.m.js' class MockPressureService { constructor() { - this.receiver_ = new PressureServiceReceiver(this); + this.receiver_ = new PressureManagerReceiver(this); this.interceptor_ = - new MojoInterfaceInterceptor(PressureService.$interfaceName); + new MojoInterfaceInterceptor(PressureManager.$interfaceName); this.interceptor_.oninterfacerequest = e => { this.receiver_.$.bindHandle(e.handle); }; @@ -47,7 +47,7 @@ this.updatesDelivered_ = 0; } - async bindObserver(observer) { + async addClient(observer) { if (this.observer_ !== null) throw new Error('BindObserver() has already been called'); @@ -89,7 +89,7 @@ this.pressureUpdate_.timestamp = { internalValue: BigInt((new Date().getTime() + epochDeltaInMs) * 1000) }; - this.observer_.onUpdate(this.pressureUpdate_); + this.observer_.onPressureUpdated(this.pressureUpdate_); this.updatesDelivered_++; }, timeout); }
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/helpers.js b/third_party/blink/web_tests/external/wpt/storage-access-api/helpers.js index 99ba792..337a92c 100644 --- a/third_party/blink/web_tests/external/wpt/storage-access-api/helpers.js +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/helpers.js
@@ -132,3 +132,14 @@ function FrameInitiatedReload(frame) { return PostMessageAndAwait({ command: "reload" }, frame.contentWindow, ReloadPromise(frame)); } + +// Tries to set storage access policy, ignoring any errors. +async function MaybeSetStorageAccess(origin, embedding_origin, value) { + try { + await test_driver.set_storage_access(origin, embedding_origin, value); + } catch (e) { + // Ignore, can be unimplemented if the platform blocks cross-site cookies + // by default. If this failed without default blocking we'll notice it later + // in the test. + } +}
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe-navigation.sub.https.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe-navigation.sub.https.window.js index 5081bb4..958b609 100644 --- a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe-navigation.sub.https.window.js +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe-navigation.sub.https.window.js
@@ -6,19 +6,10 @@ (async function() { // This is on the www subdomain, so it's cross-origin from the current document. - const wwwHost = "https://{{domains[www]}}:{{ports[https][0]}}"; - - // Set up storage access rules - try { - await test_driver.set_storage_access(wwwHost + "/", "*", "blocked"); - } catch (e) { - // Ignore, can be unimplemented if the platform blocks cross-site cookies - // by default. If this failed without default blocking we'll notice it later - // in the test. - } + const wwwAlt = "https://{{hosts[alt][www]}}:{{ports[https][0]}}"; promise_test(async (t) => { - const responder_html = `${wwwHost}/storage-access-api/resources/script-with-cookie-header.py?script=embedded_responder.js`; + const responder_html = `${wwwAlt}/storage-access-api/resources/script-with-cookie-header.py?script=embedded_responder.js`; const frame = await CreateFrame(responder_html); t.add_cleanup(async () => { @@ -27,8 +18,13 @@ }); await SetPermissionInFrame(frame, [{ name: 'storage-access' }, 'granted']); - await fetch(`${wwwHost}/cookies/resources/set.py?cookie=monster;Secure;SameSite=None;Path=/`, - { mode: "no-cors", credentials: "include" }); + await fetch(`${wwwAlt}/cookies/resources/set.py?cookie=monster;Secure;SameSite=None;Path=/`, + { mode: "no-cors", credentials: "include" }).then((resp) => resp.text()); + + await MaybeSetStorageAccess(wwwAlt + "/", "*", "blocked"); + t.add_cleanup(async () => { + await MaybeSetStorageAccess(wwwAlt + "/", "*", "allowed"); + }); assert_false(await FrameHasStorageAccess(frame), "frame initially does not have storage access."); assert_false(cookieStringHasCookie("cookie", "monster", await GetJSCookiesFromFrame(frame)), "frame cannot access cookies via JS.");
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe.sub.https.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe.sub.https.window.js index 38e3fd6..2367afd00 100644 --- a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe.sub.https.window.js +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-iframe.sub.https.window.js
@@ -4,15 +4,6 @@ 'use strict'; (async function() { - // Set up storage access rules - try { - await test_driver.set_storage_access("https://{{domains[www]}}:{{ports[https][0]}}/", "*", "blocked"); - } catch (e) { - // Ignore, can be unimplemented if the platform blocks cross-site cookies - // by default. If this failed without default blocking we'll notice it later - // in the test. - } - // Create a test with a single-child cross-origin iframe. RunTestsInIFrame('https://{{domains[www]}}:{{ports[https][0]}}/storage-access-api/resources/requestStorageAccess-iframe.https.html?testCase=cross-origin-frame&rootdocument=false'); })();
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-sibling-iframes.sub.https.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-sibling-iframes.sub.https.window.js index 75ea907..8da905ae 100644 --- a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-sibling-iframes.sub.https.window.js +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-cross-origin-sibling-iframes.sub.https.window.js
@@ -6,19 +6,10 @@ (async function() { // This is on the www subdomain, so it's cross-origin from the current document. - const wwwHost = "https://{{domains[www]}}:{{ports[https][0]}}"; - - // Set up storage access rules - try { - await test_driver.set_storage_access(wwwHost + "/", "*", "blocked"); - } catch (e) { - // Ignore, can be unimplemented if the platform blocks cross-site cookies - // by default. If this failed without default blocking we'll notice it later - // in the test. - } + const wwwAlt = "https://{{hosts[alt][www]}}:{{ports[https][0]}}"; promise_test(async (t) => { - const responder_html = `${wwwHost}/storage-access-api/resources/script-with-cookie-header.py?script=embedded_responder.js`; + const responder_html = `${wwwAlt}/storage-access-api/resources/script-with-cookie-header.py?script=embedded_responder.js`; const [frame1, frame2] = await Promise.all([ CreateFrame(responder_html), CreateFrame(responder_html), @@ -30,8 +21,13 @@ }); await SetPermissionInFrame(frame1, [{ name: 'storage-access' }, 'granted']); - await fetch(`${wwwHost}/cookies/resources/set.py?cookie=monster;Secure;SameSite=None;Path=/`, - { mode: "no-cors", credentials: "include" }); + await fetch(`${wwwAlt}/cookies/resources/set.py?cookie=monster;Secure;SameSite=None;Path=/`, + { mode: "no-cors", credentials: "include" }).then((resp) => resp.text()); + + await MaybeSetStorageAccess(wwwAlt + "/", "*", "blocked"); + t.add_cleanup(async () => { + await MaybeSetStorageAccess(wwwAlt + "/", "*", "allowed"); + }); assert_false(await FrameHasStorageAccess(frame1), "frame1 should not have storage access initially."); assert_false(await FrameHasStorageAccess(frame2), "frame2 should not have storage access initially.");
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-origin-iframe.sub.https.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-origin-iframe.sub.https.window.js index bdc5429e..e79148b4c 100644 --- a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-origin-iframe.sub.https.window.js +++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess-nested-cross-origin-iframe.sub.https.window.js
@@ -4,15 +4,6 @@ 'use strict'; (async function() { - // Set up storage access rules - try { - await test_driver.set_storage_access("https://{{domains[www]}}:{{ports[https][0]}}/", "*", "blocked"); - } catch (e) { - // Ignore, can be unimplemented if the platform blocks cross-site cookies - // by default. If this failed without default blocking we'll notice it later - // in the test. - } - // Validate the nested-iframe scenario where the cross-origin frame // containing the tests is not the first child. RunTestsInNestedIFrame('https://{{domains[www]}}:{{ports[https][0]}}/storage-access-api/resources/requestStorageAccess-iframe.https.html?testCase=nested-cross-origin-frame&rootdocument=false');
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/rtp-stats-creation-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-stats/rtp-stats-creation-expected.txt index e0e519a..cc8d410 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-stats/rtp-stats-creation-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/rtp-stats-creation-expected.txt
@@ -3,5 +3,6 @@ FAIL No RTCRtpStreamStats exist when only local description is set assert_equals: no rtp stats with only local description expected 0 but got 2 FAIL No RTCOutboundRtpStreamStats exist until packets have been sent assert_true: no outbound rtp stats before packets sent expected true got false FAIL No RTCInboundRtpStreamStats exist until packets have been received assert_true: no inbound rtp stats before packets received expected true got false +PASS RTCAudioPlayoutStats should be present Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/rtp-stats-creation.html b/third_party/blink/web_tests/external/wpt/webrtc-stats/rtp-stats-creation.html index 3141bc08..c12f266 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-stats/rtp-stats-creation.html +++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/rtp-stats-creation.html
@@ -82,4 +82,26 @@ await new Promise(r => test.step_timeout(r, 100)); } }, "No RTCInboundRtpStreamStats exist until packets have been received"); + +promise_test(async (test) => { + const localPc = createPeerConnectionWithCleanup(test); + const remotePc = createPeerConnectionWithCleanup(test); + + localPc.addTrack(...await createTrackAndStreamWithCleanup(test, "audio")); + exchangeIceCandidates(localPc, remotePc); + await exchangeOfferAnswer(localPc, remotePc); + const start = performance.now(); + while (true) { + const report = await remotePc.getStats(); + const audioPlayout = + [...report.values()].filter(({type}) => type == "audio-playout"); + if (audioPlayout.length == 1) { + break; + } + if (performance.now() > start + 5000) { + assert_unreached("Audio playout stats should become available"); + } + await new Promise(r => test.step_timeout(r, 100)); + } +}, "RTCAudioPlayoutStats should be present"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats.https-expected.txt index fe1bbcf..369a0a7 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/supported-stats.https-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 248 tests; 231 PASS, 17 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 248 tests; 232 PASS, 16 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS getStats succeeds PASS Validating stats PASS codec's payloadType @@ -56,7 +56,7 @@ PASS inbound-rtp's totalSamplesDuration PASS inbound-rtp's framesReceived PASS inbound-rtp's decoderImplementation -FAIL inbound-rtp's playoutId assert_true: Is playoutId present expected true got false +PASS inbound-rtp's playoutId PASS inbound-rtp's powerEfficientDecoder PASS inbound-rtp's framesAssembledFromMultiplePackets PASS inbound-rtp's totalAssemblyTime
diff --git a/third_party/blink/web_tests/http/tests/devtools/console-fetch-logging-expected.txt b/third_party/blink/web_tests/http/tests/devtools/console-fetch-logging-expected.txt deleted file mode 100644 index 2027d18c..0000000 --- a/third_party/blink/web_tests/http/tests/devtools/console-fetch-logging-expected.txt +++ /dev/null
@@ -1,91 +0,0 @@ -Tests that fetch logging works when XMLHttpRequest Logging is Enabled and doesn't show logs when it is Disabled. - -Making requests with monitoring ENABLED -console-fetch-logging.js:13 sending a GET request to resources/xhr-exists.html -console-fetch-logging.js:13 sending a GET request to resources/xhr-does-not-exist.html -VM:58 Fetch finished loading: GET "http://127.0.0.1:8000/devtools/resources/xhr-exists.html". -makeFetch @ VM:58 -requestHelper @ console-fetch-logging.js:20 -step1 @ console-fetch-logging.js:33 -makeRequests @ console-fetch-logging.js:27 -(anonymous) @ VM:1 -VM:58 GET http://127.0.0.1:8000/devtools/resources/xhr-does-not-exist.html 404 (Not Found) -makeFetch @ VM:58 -requestHelper @ console-fetch-logging.js:20 -step2 @ console-fetch-logging.js:39 -setTimeout (async) -delayCallback @ console-fetch-logging.js:18 -Promise.then (async) -requestHelper @ console-fetch-logging.js:20 -step1 @ console-fetch-logging.js:33 -makeRequests @ console-fetch-logging.js:27 -(anonymous) @ VM:1 -console-fetch-logging.js:13 sending a POST request to resources/post-target.cgi -VM:58 Fetch failed loading: GET "http://127.0.0.1:8000/devtools/resources/xhr-does-not-exist.html". -makeFetch @ VM:58 -requestHelper @ console-fetch-logging.js:20 -step2 @ console-fetch-logging.js:39 -setTimeout (async) -delayCallback @ console-fetch-logging.js:18 -Promise.then (async) -requestHelper @ console-fetch-logging.js:20 -step1 @ console-fetch-logging.js:33 -makeRequests @ console-fetch-logging.js:27 -(anonymous) @ VM:1 -VM:58 Fetch finished loading: POST "http://127.0.0.1:8000/devtools/resources/post-target.cgi". -makeFetch @ VM:58 -requestHelper @ console-fetch-logging.js:20 -step3 @ console-fetch-logging.js:45 -setTimeout (async) -delayCallback @ console-fetch-logging.js:18 -Promise.then (async) -requestHelper @ console-fetch-logging.js:20 -step2 @ console-fetch-logging.js:39 -setTimeout (async) -delayCallback @ console-fetch-logging.js:18 -Promise.then (async) -requestHelper @ console-fetch-logging.js:20 -step1 @ console-fetch-logging.js:33 -makeRequests @ console-fetch-logging.js:27 -(anonymous) @ VM:1 -console-fetch-logging.js:13 sending a GET request to http://localhost:8000/devtools/resources/xhr-exists.html -inspected-page.html:1 Failed to load http://localhost:8000/devtools/resources/xhr-exists.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. -VM:58 Fetch finished loading: GET "http://localhost:8000/devtools/resources/xhr-exists.html". -makeFetch @ VM:58 -requestHelper @ console-fetch-logging.js:20 -step4 @ console-fetch-logging.js:51 -setTimeout (async) -delayCallback @ console-fetch-logging.js:18 -Promise.then (async) -requestHelper @ console-fetch-logging.js:20 -step3 @ console-fetch-logging.js:45 -setTimeout (async) -delayCallback @ console-fetch-logging.js:18 -Promise.then (async) -requestHelper @ console-fetch-logging.js:20 -step2 @ console-fetch-logging.js:39 -setTimeout (async) -delayCallback @ console-fetch-logging.js:18 -Promise.then (async) -requestHelper @ console-fetch-logging.js:20 -step1 @ console-fetch-logging.js:33 -makeRequests @ console-fetch-logging.js:27 -(anonymous) @ VM:1 -Making requests with monitoring DISABLED -console-fetch-logging.js:13 sending a GET request to resources/xhr-exists.html -console-fetch-logging.js:13 sending a GET request to resources/xhr-does-not-exist.html -VM:58 GET http://127.0.0.1:8000/devtools/resources/xhr-does-not-exist.html 404 (Not Found) -makeFetch @ VM:58 -requestHelper @ console-fetch-logging.js:20 -step2 @ console-fetch-logging.js:39 -setTimeout (async) -delayCallback @ console-fetch-logging.js:18 -Promise.then (async) -requestHelper @ console-fetch-logging.js:20 -step1 @ console-fetch-logging.js:33 -makeRequests @ console-fetch-logging.js:27 -(anonymous) @ VM:1 -console-fetch-logging.js:13 sending a POST request to resources/post-target.cgi -console-fetch-logging.js:13 sending a GET request to http://localhost:8000/devtools/resources/xhr-exists.html -inspected-page.html:1 Failed to load http://localhost:8000/devtools/resources/xhr-exists.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. -
diff --git a/third_party/blink/web_tests/http/tests/devtools/console-fetch-logging.js b/third_party/blink/web_tests/http/tests/devtools/console-fetch-logging.js deleted file mode 100644 index 588ba2e..0000000 --- a/third_party/blink/web_tests/http/tests/devtools/console-fetch-logging.js +++ /dev/null
@@ -1,70 +0,0 @@ -// Copyright 2017 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -(async function() { - TestRunner.addResult( - `Tests that fetch logging works when XMLHttpRequest Logging is Enabled and doesn't show logs when it is Disabled.\n`); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner'); - await TestRunner.loadTestModule('network_test_runner'); - await TestRunner.evaluateInPagePromise(` - function requestHelper(method, url, callback) - { - console.log("sending a " + method + " request to " + url); - // Delay invoking callback to let didFinishLoading() a chance to fire and log - // console message. - function delayCallback() - { - setTimeout(callback, 0); - } - makeFetch(url, {method: method}).then(delayCallback); - } - - function makeRequests() - { - var callback; - var promise = new Promise((fulfill) => callback = fulfill); - step1(); - return promise; - - function step1() - { - // Page that exists. - requestHelper("GET", "resources/xhr-exists.html", step2); - } - - function step2() - { - // Page that doesn't exist. - requestHelper("GET", "resources/xhr-does-not-exist.html", step3); - } - - function step3() - { - // POST to a page. - requestHelper("POST", "resources/post-target.cgi", step4); - } - - function step4() - { - // (Failed) cross-origin request - requestHelper("GET", "http://localhost:8000/devtools/resources/xhr-exists.html", callback); - } - } - `); - - TestRunner.addResult('Making requests with monitoring ENABLED'); - Common.settingForTest('monitoringXHREnabled').set(true); - await TestRunner.callFunctionInPageAsync('makeRequests'); - await ConsoleTestRunner.waitForPendingViewportUpdates(); - await ConsoleTestRunner.dumpConsoleMessages(); - Console.ConsoleView.clearConsole(); - - TestRunner.addResult('Making requests with monitoring DISABLED'); - Common.settingForTest('monitoringXHREnabled').set(false); - await TestRunner.callFunctionInPageAsync('makeRequests'); - await ConsoleTestRunner.waitForPendingViewportUpdates(); - await ConsoleTestRunner.dumpConsoleMessages(); - - TestRunner.completeTest(); -})();
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack-expected.txt index edd201a..34e5f6a 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack-expected.txt +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack-expected.txt
@@ -1,27 +1,25 @@ Tests that tracking and untracking IndexedDB for storage key works Open database, object store and set value -[ - [0] : { - method : Storage.indexedDBListUpdated - params : { - origin : http://127.0.0.1:8000 - storageKey : http://127.0.0.1:8000/ - } - sessionId : <string> +{ + method : Storage.indexedDBListUpdated + params : { + origin : http://127.0.0.1:8000 + storageKey : http://127.0.0.1:8000/ } - [1] : { - method : Storage.indexedDBContentUpdated - params : { - databaseName : test-database - objectStoreName : test-store - origin : http://127.0.0.1:8000 - storageKey : http://127.0.0.1:8000/ - } - sessionId : <string> + sessionId : <string> +} +Title{ + method : Storage.indexedDBContentUpdated + params : { + databaseName : <string> + objectStoreName : test-store + origin : http://127.0.0.1:8000 + storageKey : http://127.0.0.1:8000/ } - [2] : key-value pair added successfully -] + sessionId : <string> +} +key-value pair added successfully Untrack IndexedDB for storage key
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack.js b/third_party/blink/web_tests/http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack.js index e883923..bd0edaea 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack.js +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/storage/indexed-db-storage-key-track-untrack.js
@@ -1,47 +1,25 @@ (async function(testRunner) { + const before = Date.now(); const {dp, session} = await testRunner.startBlank( `Tests that tracking and untracking IndexedDB for storage key works\n`); - await dp.Page.enable(); - const protocolMessages = []; - const originalDispatchMessage = DevToolsAPI.dispatchMessage; - const originalSendCommand = DevToolsAPI._sendCommand; - DevToolsAPI.dispatchMessage = (message) => { - protocolMessages.push(message); - originalDispatchMessage(message); - }; - DevToolsAPI._sendCommand = (sessionId, method, params) => { - protocolMessages.push({sessionId, method, params}); - return originalSendCommand(sessionId, method, params); - } - window.onerror = (msg) => testRunner.log('onerror: ' + msg); - window.onunhandledrejection = (e) => testRunner.log('onunhandledrejection: ' + e.reason); - let errorForLog = new Error(); - setTimeout(() => { - testRunner.log(protocolMessages); - testRunner.die('Timeout', errorForLog); - }, 5000); - const frameId = (await dp.Page.getResourceTree()).result.frameTree.frame.id; - errorForLog = new Error(); const storageKey = (await dp.Storage.getStorageKeyForFrame({ frameId: frameId })).result.storageKey; - errorForLog = new Error(); await dp.Storage.trackIndexedDBForStorageKey({storageKey}); - errorForLog = new Error(); const listUpdatedPromise = dp.Storage.onceIndexedDBListUpdated( message => {return `indexedDB list updated for storage key ${ message.params.storageKey}`}); const contentUpdatedPromise = dp.Storage.onceIndexedDBContentUpdated( message => {return `indexedDB content updated for ${message.params}`}); - testRunner.log(`Open database, object store and set value`); + const id = Math.random(); // Create database, objectStore and add a key-value pair. const valuePromise = session.evaluateAsync(` new Promise(async resolve => { - const request = window.indexedDB.open("test-database"); + const request = window.indexedDB.open("test-database${id}"); request.onerror = (event) => { resolve('failed to create a database'); }; @@ -54,14 +32,15 @@ }) `); - testRunner.log(await Promise.all( - [listUpdatedPromise, contentUpdatedPromise, valuePromise])); - errorForLog = new Error(); + const [listUpdatedEvent, contentUpdatedEvent, value] = await Promise.all( + [listUpdatedPromise, contentUpdatedPromise, valuePromise]); + testRunner.log(listUpdatedEvent); + testRunner.log(contentUpdatedEvent, "Title", ['databaseName', 'sessionId']); + testRunner.log(value); testRunner.log('\nUntrack IndexedDB for storage key'); await dp.Storage.untrackIndexedDBForStorageKey({storageKey}); - errorForLog = new Error(); dp.Storage.onIndexedDBListUpdated(message => {message.params.storageKey}); dp.Storage.onIndexedDBContentUpdated(message => {message.params}); @@ -70,7 +49,7 @@ // Open database, objectStore and add another value. const oneMoreValue = await session.evaluateAsync(` new Promise(async resolve => { - const openreq = window.indexedDB.open("test-database"); + const openreq = window.indexedDB.open("test-database${id}"); openreq.onerror = (event) => { resolve("not able to open database"); } @@ -82,13 +61,22 @@ }; }) `); - errorForLog = new Error(); testRunner.log(oneMoreValue); - // Clean up - await dp.IndexedDB.deleteDatabase({storageKey, databaseName: "test-database"}); - errorForLog = new Error(); + // Clean up + try { + await session.evaluateAsync(` + new Promise(async (resolve, reject) => { + const req = window.indexedDB.deleteDatabase("test-database${id}"); + req.onsuccess = resolve; + req.onerror = reject; + }); + `); + } catch (e) { + testRunner.log(e); + } finally { + testRunner.completeTest(); + } - testRunner.completeTest(); })
diff --git a/third_party/blink/web_tests/paint/tables/huge-table-composited-scroll-collapsed-borders.html b/third_party/blink/web_tests/paint/tables/huge-table-composited-scroll-collapsed-borders.html index 383268f..95dbe8f8 100644 --- a/third_party/blink/web_tests/paint/tables/huge-table-composited-scroll-collapsed-borders.html +++ b/third_party/blink/web_tests/paint/tables/huge-table-composited-scroll-collapsed-borders.html
@@ -43,6 +43,10 @@ </div> <script src="../../resources/run-after-layout-and-paint.js"></script> <script> +// Under-invalidation checking for this test is slow. +if (window.internals) { + internals.runtimeFlags.paintUnderInvalidationCheckingEnabled = false; +} runAfterLayoutAndPaint(function() { container.scrollTop = 10000; container.scrollLeft = 10000;
diff --git a/third_party/blink/web_tests/paint/tables/huge-table-composited-scroll.html b/third_party/blink/web_tests/paint/tables/huge-table-composited-scroll.html index ddbd37f..790eb27 100644 --- a/third_party/blink/web_tests/paint/tables/huge-table-composited-scroll.html +++ b/third_party/blink/web_tests/paint/tables/huge-table-composited-scroll.html
@@ -39,6 +39,10 @@ </div> <script src="../../resources/run-after-layout-and-paint.js"></script> <script> +// Under-invalidation checking for this test is slow. +if (window.internals) { + internals.runtimeFlags.paintUnderInvalidationCheckingEnabled = false; +} runAfterLayoutAndPaint(function() { container.scrollTop = 9000; container.scrollLeft = 9000;
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-fonts/generic-family-keywords-003-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-fonts/generic-family-keywords-003-expected.txt new file mode 100644 index 0000000..f8955cb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-fonts/generic-family-keywords-003-expected.txt
@@ -0,0 +1,16 @@ +This is a testharness.js-based test. +PASS @font-face matching for quoted and unquoted serif (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted sans-serif (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted cursive (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted fantasy (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted monospace (drawing text in a canvas) +PASS @font-face matching for quoted and unquoted system-ui (drawing text in a canvas) +FAIL @font-face matching for quoted and unquoted emoji (drawing text in a canvas) assert_equals: unquoted emoji does not match @font-face rule expected 25.0244140625 but got 125 +PASS @font-face matching for quoted and unquoted math (drawing text in a canvas) +FAIL @font-face matching for quoted and unquoted fangsong (drawing text in a canvas) assert_equals: unquoted fangsong does not match @font-face rule expected 25.0244140625 but got 125 +FAIL @font-face matching for quoted and unquoted ui-serif (drawing text in a canvas) assert_equals: unquoted ui-serif does not match @font-face rule expected 25.0244140625 but got 125 +FAIL @font-face matching for quoted and unquoted ui-sans-serif (drawing text in a canvas) assert_equals: unquoted ui-sans-serif does not match @font-face rule expected 25.0244140625 but got 125 +FAIL @font-face matching for quoted and unquoted ui-monospace (drawing text in a canvas) assert_equals: unquoted ui-monospace does not match @font-face rule expected 25.0244140625 but got 125 +FAIL @font-face matching for quoted and unquoted ui-rounded (drawing text in a canvas) assert_equals: unquoted ui-rounded does not match @font-face rule expected 25.0244140625 but got 125 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/shared-storage-fenced-frame-mparch-reportevent-limit/README.md b/third_party/blink/web_tests/virtual/shared-storage-fenced-frame-mparch-reportevent-limit/README.md new file mode 100644 index 0000000..7e7b002 --- /dev/null +++ b/third_party/blink/web_tests/virtual/shared-storage-fenced-frame-mparch-reportevent-limit/README.md
@@ -0,0 +1,8 @@ +# Shared Storage with reportEvent Limit + +The tests are run with the flag --enable-features=SharedStorageAPI,FencedFrames:implementation\_type/mparch,PrivacySandboxAdsAPIsOverride,SharedStorageReportEventLimit + +You can run these tests by targeting the following directory: +`virtual/shared-storage-fenced-frame-mparch-reportevent-limit/wpt_internal/shared_storage_reportevent_limit. + +See crbug.com/1218540 and crbug.com/1405261. \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/shared-storage-fenced-frame-mparch-reportevent-limit/wpt_internal/shared_storage_reportevent_limit/README.md b/third_party/blink/web_tests/virtual/shared-storage-fenced-frame-mparch-reportevent-limit/wpt_internal/shared_storage_reportevent_limit/README.md new file mode 100644 index 0000000..7e7b002 --- /dev/null +++ b/third_party/blink/web_tests/virtual/shared-storage-fenced-frame-mparch-reportevent-limit/wpt_internal/shared_storage_reportevent_limit/README.md
@@ -0,0 +1,8 @@ +# Shared Storage with reportEvent Limit + +The tests are run with the flag --enable-features=SharedStorageAPI,FencedFrames:implementation\_type/mparch,PrivacySandboxAdsAPIsOverride,SharedStorageReportEventLimit + +You can run these tests by targeting the following directory: +`virtual/shared-storage-fenced-frame-mparch-reportevent-limit/wpt_internal/shared_storage_reportevent_limit. + +See crbug.com/1218540 and crbug.com/1405261. \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt index c610558..cf93bbe 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
@@ -39,6 +39,7 @@ backgroundSize basePalette baselineShift +baselineSource blockSize border borderBlock
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt index 628623eb..ed92a22 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt
@@ -82,6 +82,7 @@ background-repeat-y background-size baseline-shift + baseline-source block-size border-block-end-color border-block-end-style
diff --git a/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/README.txt b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/README.txt new file mode 100644 index 0000000..6d7c1c6 --- /dev/null +++ b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/README.txt
@@ -0,0 +1,6 @@ +This suite runs the following tests with ThirdPartyStoragePartitioning disabled: + +- storage-deprecation-trial-disabled-local.sub.https.html +- storage-deprecation-trial-disabled-session.sub.https.html +- storage-deprecation-trial-enabled-local.sub.https.html +- storage-deprecation-trial-enabled-session.sub.https.html
diff --git a/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-disabled-local.sub.https-expected.txt b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-disabled-local.sub.https-expected.txt new file mode 100644 index 0000000..e9c4714 --- /dev/null +++ b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-disabled-local.sub.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL Test for Local Storage with DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning disabled assert_true: IDs pulled from same-origin partitioned frames should be different. expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-disabled-session.sub.https-expected.txt b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-disabled-session.sub.https-expected.txt new file mode 100644 index 0000000..3d6fb41 --- /dev/null +++ b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-disabled-session.sub.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL Test for Session Storage with DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning disabled assert_true: IDs pulled from same-origin partitioned frames should be different. expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https-expected.txt b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https-expected.txt new file mode 100644 index 0000000..6abe184d --- /dev/null +++ b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL Test for Local Storage with DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning enabled assert_true: IDs pulled from same-origin partitioned frames should be different. expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/webcodecs-without-task-runner-with-custom-deleter/README.md b/third_party/blink/web_tests/virtual/webcodecs-without-task-runner-with-custom-deleter/README.md new file mode 100644 index 0000000..c0456ec --- /dev/null +++ b/third_party/blink/web_tests/virtual/webcodecs-without-task-runner-with-custom-deleter/README.md
@@ -0,0 +1,3 @@ +This suite runs external/wpt/webcodecs tests with +UseBlinkSchedulerTaskRunnerWithCustomDeleter disabled to test the original code +paths with the killswich.
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/compute-pressure.https.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/compute-pressure.https.html new file mode 100644 index 0000000..81091af --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/compute-pressure.https.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>Verify that Compute Pressure API from a fenced frame is blocked</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="resources/utils.js"></script> + +<body> +<script> +promise_test(async () => { + const frame = attachFencedFrameContext({ + headers: [["Permissions-Policy", "compute-pressure=*"]] + }); + const result = await frame.execute(async () => { + try { + const observer = new PressureObserver(() => {}); + await observer.observe('cpu'); + return 'observation succeeded'; + } catch (e) { + if (e.name == 'NotAllowedError' && + e.message.includes(`Access to the feature "compute pressure" is ` + + "disallowed by permissions policy.")) { + return 'observation failed'; + } else { + return `observation failed with unknown error - ${e.name}: ${e.message}`; + } + } + }); + assert_equals(result, 'observation failed', + 'PressureObserver.observe() fails in a fenced frame.'); +}, 'PressureObserver.observe() fails in a fenced frame.'); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage/resources/report.py b/third_party/blink/web_tests/wpt_internal/shared_storage/resources/report.py new file mode 100644 index 0000000..7d0fa36 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage/resources/report.py
@@ -0,0 +1,25 @@ +def main(request, response): + + # `token` should be a unique UUID request parameter for the duration of this + # request. It will get stored in the server stash and will be used later in + # a query request. + # `query` should be a request parameter indicating the request would like + # to know how many times the server has seen the request (with the + # same token). + token = request.GET.first(b"token", None) + is_query = request.GET.first(b"query", None) is not None + with request.server.stash.lock: + value = request.server.stash.take(token) + count = 0 + if value is not None: + count = int(value) + if is_query: + request.server.stash.put(token, count) + else: + count += 1 + request.server.stash.put(token, count) + + headers = [] + if is_query: + headers = [(b"Count", count)] + return (200, headers, b"")
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage/select-url-report-event.https.html b/third_party/blink/web_tests/wpt_internal/shared_storage/select-url-report-event.https.html index 85779f7..5174c4e 100644 --- a/third_party/blink/web_tests/wpt_internal/shared_storage/select-url-report-event.https.html +++ b/third_party/blink/web_tests/wpt_internal/shared_storage/select-url-report-event.https.html
@@ -9,6 +9,23 @@ <script> 'use strict'; +// Poll the server for the test result. +async function waitForReportCount(id) { + const url = `resources/report.py?query&token=${id}`; + for (let i = 0; i < 30; ++i) { + const response = await fetch(url); + let count = response.headers.get("Count"); + + if (!count || count === '0') { + await new Promise(resolve => step_timeout(resolve, 100)); + continue; + } + + return parseInt(count); + } + assert_true(false, 'timeout'); +} + promise_test(async () => { const ancestor_key = token(); let url0 = generateURL("resources/sender0.html", [ancestor_key]); @@ -16,12 +33,14 @@ await sharedStorage.worklet.addModule("resources/simple-module.js"); + const report_id = token(); + const reportURL = `resources/report.py?token=${report_id}`; let uuid0 = await sharedStorage.selectURL( "test-url-selection-operation", [ {url: url0, reportingMetadata: { - 'click': "resources/receiver0.html", + 'click': reportURL, 'mouse interaction': "resources/receiver1.html" } }, {url: url1} @@ -30,6 +49,9 @@ attachFencedFrame(uuid0, 'opaque-ads'); const result0 = await nextValueFromServer(ancestor_key); assert_equals(result0, "sender0_reported"); + + const reportCount = await waitForReportCount(report_id); + assert_equals(reportCount, 1, `Num reports received: ${reportCount}`); }, 'selectURL() with reportEvent()'); </script>
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit-with-nested.https.html b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit-with-nested.https.html new file mode 100644 index 0000000..9c70fa06 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit-with-nested.https.html
@@ -0,0 +1,63 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="../fenced_frame/resources/utils.js"></script> +<title>Test fence.reportEvent limit for Shared Storage with nested fenced frames</title> + +<body> +<script> +// Poll the server for the test result. +async function waitForReportCount(reportID) { + const url = `../shared_storage/resources/report.py?query&token=${reportID}`; + for (let i = 0; i < 100; ++i) { + const response = await fetch(url); + let count = response.headers.get("Count"); + + if (!count || count === '0') { + await new Promise(resolve => step_timeout(resolve, 100)); + continue; + } + + return parseInt(count); + } + assert_true(false, 'timeout'); +} + +promise_test(async () => { + const frameToken = token(); + const reportID = token(); + const reportURL = `../shared_storage/resources/report.py?token=${reportID}`; + let url0 = generateURL("resources/report-event-limit-with-nested-inner.https.html", + [frameToken, reportID]); + let url1 = generateURL("../shared_storage/resources/frame0.html", + [frameToken, reportID]); + let url2 = generateURL("../shared_storage/resources/frame1.html", + [frameToken, reportID]); + let url3 = generateURL("../shared_storage/resources/frame2.html", + [frameToken, reportID]); + + await sharedStorage.worklet.addModule("../shared_storage/resources/simple-module.js"); + + for (let i = 0; i < 3; ++i) { + let urn = await sharedStorage.selectURL( + "test-url-selection-operation", [{url: url0}, {url: url1}, {url: url2}, + {url: url3}], + {data: {'mockResult': 0}}); + + // Create nested fenced frames. A report will be sent, if allowed. + attachFencedFrame(urn, 'opaque-ads'); + + // Wait for the nested fenced frame to complete its tasks. + await nextValueFromServer(frameToken); + } + + // Wait for the report count. + const reportCount = await waitForReportCount(reportID); + + // Only the first 2 reports will be sent. The third will be blocked due to + // insufficient budget. + assert_equals(reportCount, 2, `Num reports received: ${reportCount}`); +}, "window.fence.reportEvent"); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit.https.html b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit.https.html new file mode 100644 index 0000000..282628e --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/report-event-limit.https.html
@@ -0,0 +1,60 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="../fenced_frame/resources/utils.js"></script> +<title>Test fence.reportEvent limit for Shared Storage</title> + +<body> +<script> +// Poll the server for the test result. +async function waitForReportCount(reportID) { + const url = `../shared_storage/resources/report.py?query&token=${reportID}`; + for (let i = 0; i < 30; ++i) { + const response = await fetch(url); + let count = response.headers.get("Count"); + + if (!count || count === '0') { + await new Promise(resolve => step_timeout(resolve, 100)); + continue; + } + + return parseInt(count); + } + assert_true(false, 'timeout'); +} + +promise_test(async () => { + const frameToken = token(); + const reportID = token(); + const reportURL = `../shared_storage/resources/report.py?token=${reportID}`; + const reportingMetadata = {'click': reportURL}; + let url0 = generateURL("resources/report-event-limit-inner.https.html", [frameToken]); + let url1 = generateURL("../shared_storage/resources/frame0.html", [frameToken]); + let url2 = generateURL("../shared_storage/resources/frame1.html", [frameToken]); + let url3 = generateURL("../shared_storage/resources/frame2.html", [frameToken]); + + await sharedStorage.worklet.addModule("../shared_storage/resources/simple-module.js"); + + for (let i = 0; i < 5; ++i) { + let urn = await sharedStorage.selectURL( + "test-url-selection-operation", [{url: url0, reportingMetadata}, + {url: url1}, {url: url2}, {url: url3}], + {data: {'mockResult': 0}}); + + // Create a fenced frame. A report will be sent, if allowed. + attachFencedFrame(urn, 'opaque-ads'); + + // Wait for the fenced frame to complete its tasks. + await nextValueFromServer(frameToken); + } + + // Wait for the report count. + const reportCount = await waitForReportCount(reportID); + + // Only the first 4 reports will be sent. The fifth will be blocked due to + // insufficient budget. + assert_equals(reportCount, 4, `Num reports received: ${reportCount}`); +}, "window.fence.reportEvent"); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-inner.https.html b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-inner.https.html new file mode 100644 index 0000000..cf883278 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-inner.https.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="../../fenced_frame/resources/utils.js"></script> +<title>Fenced frame content to test fence.reportEvent limit for Shared Storage</title> + +<body> +<script> + + // Get the token for communication with the parent. + const [frameToken] = parseKeylist(); + + window.fence.reportEvent({ + eventType: 'click', + eventData: "user clicked", + destination: ['shared-storage-select-url'] + }); + + // Tell the parent that the fenced frame code has succeeded. + writeValueToServer(frameToken, ""); + +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-inner.https.html.headers b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-inner.https.html.headers new file mode 100644 index 0000000..1b63235 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-inner.https.html.headers
@@ -0,0 +1 @@ +Supports-Loading-Mode: fenced-frame
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner-inner.https.html b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner-inner.https.html new file mode 100644 index 0000000..91b6fe1 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner-inner.https.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="../../fenced_frame/resources/utils.js"></script> +<title>Inner fenced frame content to test fence.reportEvent limit for Shared Storage with nested fenced frames</title> + +<body> +<script> + // Get the token for communication with the parent. + const [frameToken] = parseKeylist(); + + window.fence.reportEvent({ + eventType: 'click', + eventData: "user clicked", + destination: ['shared-storage-select-url'] + }); + + // Tell the parent that the fenced frame code has succeeded. + writeValueToServer(frameToken, ""); + +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner-inner.https.html.headers b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner-inner.https.html.headers new file mode 100644 index 0000000..1b63235 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner-inner.https.html.headers
@@ -0,0 +1 @@ +Supports-Loading-Mode: fenced-frame
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner.https.html b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner.https.html new file mode 100644 index 0000000..adf3ea4 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner.https.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="../../fenced_frame/resources/utils.js"></script> +<title>Outer fenced frame content to test fence.reportEvent limit for Shared Storage with nested fenced frames</title> + +<body> +<script> + // Get the token for communication with the parent. + const [frameToken, reportID] = parseKeylist(); + + async function createNestedFrame(frameToken, reportID) { + const reportURL = `../../shared_storage/resources/report.py?token=${reportID}`; + const reportingMetadata = {'click': reportURL}; + let url0 = generateURL("report-event-limit-with-nested-inner-inner.https.html", + [frameToken]); + let url1 = generateURL("../shared_storage/resources/frame0.html", + [frameToken]); + let url2 = generateURL("../shared_storage/resources/frame1.html", + [frameToken]); + let url3 = generateURL("../shared_storage/resources/frame2.html", + [frameToken]); + + await sharedStorage.worklet.addModule("../../shared_storage/resources/simple-module.js"); + + let urn = await sharedStorage.selectURL( + "test-url-selection-operation", [{url: url0, reportingMetadata}, + {url: url1}, {url: url2}, + {url: url3}], + {data: {'mockResult': 0}}); + + // Create a nested fenced frame. A report will be sent, if allowed. + attachFencedFrame(urn, 'opaque-ads'); + } + + createNestedFrame(frameToken, reportID); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner.https.html.headers b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner.https.html.headers new file mode 100644 index 0000000..1b63235 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/shared_storage_reportevent_limit/resources/report-event-limit-with-nested-inner.https.html.headers
@@ -0,0 +1 @@ +Supports-Loading-Mode: fenced-frame
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_bgra8unorm.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_bgra8unorm.https.html new file mode 100644 index 0000000..c29e904 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_bgra8unorm.https.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html class="reftest-wait"> + <base href="/gen/third_party/webgpu-cts/src/webgpu/web_platform/reftests/" /> + <title>WebGPU canvas_colorspace_bgra8unorm</title> + <meta charset="utf-8" /> + <style> + canvas { + width: 128px; + height: 128px; + margin-right: 5px; + image-rendering: pixelated; + image-rendering: crisp-edges; + } + </style> + <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> + <meta name="assert" content="WebGPU bgra8norm canvas with colorSpace set should be rendered correctly" /> + <link rel="match" href="./ref/canvas_colorspace-ref.html" /> + <script type="module"> + import { runColorSpaceTest } from './canvas_colorspace.html.js'; + runColorSpaceTest('bgra8unorm'); + </script> + <body></body> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html new file mode 100644 index 0000000..2b868d6 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html class="reftest-wait"> + <base href="/gen/third_party/webgpu-cts/src/webgpu/web_platform/reftests/" /> + <title>WebGPU canvas_colorspace_rgba16float</title> + <meta charset="utf-8" /> + <style> + canvas { + width: 128px; + height: 128px; + margin-right: 5px; + image-rendering: pixelated; + image-rendering: crisp-edges; + } + </style> + <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> + <meta name="assert" content="WebGPU rgba16float canvas with colorSpace set should be rendered correctly" /> + <link rel="match" href="./ref/canvas_colorspace-ref.html" /> + <meta name=fuzzy content="maxDifference=1;totalPixels=8192"> + <script type="module"> + import { runColorSpaceTest } from './canvas_colorspace.html.js'; + runColorSpaceTest('rgba16float'); + </script> + <body></body> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html new file mode 100644 index 0000000..33fb6dc --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html class="reftest-wait"> + <base href="/gen/third_party/webgpu-cts/src/webgpu/web_platform/reftests/" /> + <title>WebGPU canvas_colorspace_rgba8unorm</title> + <meta charset="utf-8" /> + <style> + canvas { + width: 128px; + height: 128px; + margin-right: 5px; + image-rendering: pixelated; + image-rendering: crisp-edges; + } + </style> + <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> + <meta name="assert" content="WebGPU rgba8unorm canvas with colorSpace set should be rendered correctly" /> + <link rel="match" href="./ref/canvas_colorspace-ref.html" /> + <script type="module"> + import { runColorSpaceTest } from './canvas_colorspace.html.js'; + runColorSpaceTest('rgba8unorm'); + </script> + <body></body> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/ref/canvas_colorspace-ref.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/ref/canvas_colorspace-ref.html new file mode 100644 index 0000000..f64c5b8 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/ref/canvas_colorspace-ref.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + <base href="/gen/third_party/webgpu-cts/src/webgpu/web_platform/reftests/ref/" /> + <title>WebGPU canvas_colorspace (ref)</title> + <meta charset="utf-8" /> + <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> + <style> + canvas { + width: 128px; + height: 128px; + margin-right: 5px; + image-rendering: pixelated; + image-rendering: crisp-edges; + } + </style> + <body></body> + <script type="module" src="canvas_colorspace-ref.html.js"></script> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe-iframe.html b/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe-iframe.html new file mode 100644 index 0000000..8a3996c --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe-iframe.html
@@ -0,0 +1,17 @@ +<!doctype html> +<meta charset="utf-8"> +<script type="module"> +import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js"; + +// Step 5 (wpt_internal/webstorage/storage-deprecation-trial-{enabled|disabled}-{local|session}.sub.https.html) +const useSessionStorage = (new URLSearchParams(window.location.search)).has("session"); +const userID = getOrCreateID(useSessionStorage); +clearID(useSessionStorage); + +// Step 6 (wpt_internal/webstorage/storage-deprecation-trial-{enabled|disabled}-{local|session}.sub.https.html) +const payload = { + message: "UserID", + userID: userID, +} +window.top.postMessage(payload, window.top.origin); +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html b/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html new file mode 100644 index 0000000..717048f0 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html
@@ -0,0 +1,11 @@ +<!doctype html> +<meta charset="utf-8"> +<body> +<script> +// Step 4 (wpt_internal/webstorage/storage-deprecation-trial-{enabled|disabled}-{local|session}.sub.https.html) +const useSessionStorage = (new URLSearchParams(window.location.search)).has("session"); +const iframe = document.createElement("iframe"); +iframe.src = "https://{{host}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe-iframe.html" + (useSessionStorage ? "?session" : ""); +document.body.appendChild(iframe); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js b/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js new file mode 100644 index 0000000..32d64716 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js
@@ -0,0 +1,21 @@ +const STORAGE_KEY = "UserID"; + +export function getOrCreateID(useSessionStorage) { + if(typeof useSessionStorage !== "boolean") { + throw new Error("`useSessionStorage` should be a boolean"); + } + const storage = useSessionStorage ? sessionStorage : localStorage; + if (!storage.getItem(STORAGE_KEY)) { + const newID = +new Date() + "-" + Math.random(); + storage.setItem(STORAGE_KEY, newID); + } + return storage.getItem(STORAGE_KEY); +} + +export function clearID(useSessionStorage) { + if(typeof useSessionStorage !== "boolean") { + throw new Error("`useSessionStorage` should be a boolean"); + } + const storage = useSessionStorage ? sessionStorage : localStorage; + storage.clear(); +}
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-disabled-local.sub.https.html b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-disabled-local.sub.https.html new file mode 100644 index 0000000..84256fb --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-disabled-local.sub.https.html
@@ -0,0 +1,41 @@ +<!doctype html> +<meta charset=utf-8> +<title>Local Storage: deprecation trial</title> +<meta name=help href="https://privacycg.github.io/storage-partitioning/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script type="module"> +import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js"; +// Here's the set-up for this test: +// Step 1 (top-frame) Create an ID in storage. +// Step 2 (top-frame) Set up listener for "UserID" message. +// Step 3 (top-frame) Embed an iframe that's cross-origin with top-frame. +// Step 4 (sub-frame) Embed an iframe that's same-origin with top-frame. +// Step 5 (sub-sub-frame) Get or create an ID in storage and cleanup. +// Step 6 (sub-sub-frame) Send "UserID" message to top-frame. +// Step 7 (top-frame) Compare IDs recieved and cleanup. + +async_test(t => { + // Step 1 + const userID = getOrCreateID(/*useSessionStorage=*/false); + + // Step 2 + window.addEventListener("message", t.step_func(e => { + // Step 7 + if (e.data.message === "UserID") { + t.step(() => { + assert_true(e.data.userID !== userID, "IDs pulled from same-origin partitioned frames should be different.") + }); + clearID(/*useSessionStorage=*/false); + t.done(); + }; + })); + + // Step 3 + let iframe = document.createElement("iframe"); + iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html"; + document.body.appendChild(iframe); +}, "Test for Local Storage with DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning disabled"); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-disabled-session.sub.https.html b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-disabled-session.sub.https.html new file mode 100644 index 0000000..555369a --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-disabled-session.sub.https.html
@@ -0,0 +1,41 @@ +<!doctype html> +<meta charset=utf-8> +<title>Session Storage: deprecation trial</title> +<meta name=help href="https://privacycg.github.io/storage-partitioning/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script type="module"> +import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js"; +// Here's the set-up for this test: +// Step 1 (top-frame) Create an ID in storage. +// Step 2 (top-frame) Set up listener for "UserID" message. +// Step 3 (top-frame) Embed an iframe that's cross-origin with top-frame. +// Step 4 (sub-frame) Embed an iframe that's same-origin with top-frame. +// Step 5 (sub-sub-frame) Get or create an ID in storage and cleanup. +// Step 6 (sub-sub-frame) Send "UserID" message to top-frame. +// Step 7 (top-frame) Compare IDs recieved and cleanup. + +async_test(t => { + // Step 1 + const userID = getOrCreateID(/*useSessionStorage=*/true); + + // Step 2 + window.addEventListener("message", t.step_func(e => { + // Step 7 + if (e.data.message === "UserID") { + t.step(() => { + assert_true(e.data.userID !== userID, "IDs pulled from same-origin partitioned frames should be different.") + }); + clearID(/*useSessionStorage=*/true); + t.done(); + }; + })); + + // Step 3 + let iframe = document.createElement("iframe"); + iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html?session"; + document.body.appendChild(iframe); +}, "Test for Session Storage with DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning disabled"); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https.html b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https.html new file mode 100644 index 0000000..953e057 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https.html
@@ -0,0 +1,44 @@ +<!doctype html> +<meta charset=utf-8> +<title>Local Storage: deprecation trial</title> +<meta name=help href="https://privacycg.github.io/storage-partitioning/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script type="module"> +import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js"; +// Generate token in headers file with the command: +// generate_token.py https://web-platform.test:8444 DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning --expire-timestamp=2000000000 +// +// Here's the set-up for this test: +// Step 1 (top-frame) Create an ID in storage. +// Step 2 (top-frame) Set up listener for "UserID" message. +// Step 3 (top-frame) Embed an iframe that's cross-origin with top-frame. +// Step 4 (sub-frame) Embed an iframe that's same-origin with top-frame. +// Step 5 (sub-sub-frame) Get or create an ID in storage and cleanup. +// Step 6 (sub-sub-frame) Send "UserID" message to top-frame. +// Step 7 (top-frame) Compare IDs recieved and cleanup. + +async_test(t => { + // Step 1 + const userID = getOrCreateID(/*useSessionStorage=*/false); + + // Step 2 + window.addEventListener("message", t.step_func(e => { + // Step 7 + if (e.data.message === "UserID") { + t.step(() => { + assert_true(e.data.userID !== userID, "IDs pulled from same-origin partitioned frames should be different.") + }); + clearID(/*useSessionStorage=*/false); + t.done(); + }; + })); + + // Step 3 + let iframe = document.createElement("iframe"); + iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html"; + document.body.appendChild(iframe); +}, "Test for Local Storage with DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning enabled"); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https.html.headers b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https.html.headers new file mode 100644 index 0000000..a34fcc2 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-local.sub.https.html.headers
@@ -0,0 +1 @@ +Origin-Trial: A51FTBtilIEH2x17+d60rreZqDr/Z6Wz/VIfEHVNXX1Pe64Hav9CvephRV9TLYfeZWc+EMYb0HzRN6C29RG/CwIAAACUeyJvcmlnaW4iOiAiaHR0cHM6Ly93ZWItcGxhdGZvcm0udGVzdDo4NDQ0IiwgImZlYXR1cmUiOiAiRGlzYWJsZVRoaXJkUGFydHlTZXNzaW9uU3RvcmFnZVBhcnRpdGlvbmluZ0FmdGVyR2VuZXJhbFBhcnRpdGlvbmluZyIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-session.sub.https.html b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-session.sub.https.html new file mode 100644 index 0000000..0d89d76b --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-session.sub.https.html
@@ -0,0 +1,44 @@ +<!doctype html> +<meta charset=utf-8> +<title>Session Storage: deprecation trial</title> +<meta name=help href="https://privacycg.github.io/storage-partitioning/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script type="module"> +import { getOrCreateID, clearID } from "/wpt_internal/webstorage/resources/storage-deprecation-trial-utils.js"; +// Generate token in headers file with the command: +// generate_token.py https://web-platform.test:8444 DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning --expire-timestamp=2000000000 +// +// Here's the set-up for this test: +// Step 1 (top-frame) Create an ID in storage. +// Step 2 (top-frame) Set up listener for "UserID" message. +// Step 3 (top-frame) Embed an iframe that's cross-origin with top-frame. +// Step 4 (sub-frame) Embed an iframe that's same-origin with top-frame. +// Step 5 (sub-sub-frame) Get or create an ID in storage and cleanup. +// Step 6 (sub-sub-frame) Send "UserID" message to top-frame. +// Step 7 (top-frame) Compare IDs recieved and cleanup. + +async_test(t => { + // Step 1 + const userID = getOrCreateID(/*useSessionStorage=*/true); + + // Step 2 + window.addEventListener("message", t.step_func(e => { + // Step 7 + if (e.data.message === "UserID") { + t.step(() => { + assert_true(e.data.userID === userID, "IDs pulled from same-origin un-partitioned frames shouldn't be different.") + }); + clearID(/*useSessionStorage=*/true); + t.done(); + }; + })); + + // Step 3 + let iframe = document.createElement("iframe"); + iframe.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/wpt_internal/webstorage/resources/storage-deprecation-trial-iframe.sub.html?session"; + document.body.appendChild(iframe); +}, "Test for Session Storage with DisableThirdPartySessionStoragePartitioningAfterGeneralPartitioning enabled"); +</script> +</body>
diff --git a/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-session.sub.https.html.headers b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-session.sub.https.html.headers new file mode 100644 index 0000000..a34fcc2 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webstorage/storage-deprecation-trial-enabled-session.sub.https.html.headers
@@ -0,0 +1 @@ +Origin-Trial: A51FTBtilIEH2x17+d60rreZqDr/Z6Wz/VIfEHVNXX1Pe64Hav9CvephRV9TLYfeZWc+EMYb0HzRN6C29RG/CwIAAACUeyJvcmlnaW4iOiAiaHR0cHM6Ly93ZWItcGxhdGZvcm0udGVzdDo4NDQ0IiwgImZlYXR1cmUiOiAiRGlzYWJsZVRoaXJkUGFydHlTZXNzaW9uU3RvcmFnZVBhcnRpdGlvbmluZ0FmdGVyR2VuZXJhbFBhcnRpdGlvbmluZyIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js index 3f8be04..5c4b768 100644 --- a/third_party/closure_compiler/externs/file_manager_private.js +++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -294,6 +294,7 @@ QUEUED: 'queued', SCANNING: 'scanning', IN_PROGRESS: 'in_progress', + PAUSED: 'paused', SUCCESS: 'success', ERROR: 'error', NEED_PASSWORD: 'need_password',
diff --git a/third_party/kotlinc/3pp/fetch.py b/third_party/kotlinc/3pp/fetch.py index 19844899..47518ba 100755 --- a/third_party/kotlinc/3pp/fetch.py +++ b/third_party/kotlinc/3pp/fetch.py
@@ -4,25 +4,58 @@ # found in the LICENSE file. import argparse +import hashlib import json import os +import pathlib +import urllib.request -_FILE_URL = 'https://github.com/JetBrains/kotlin/releases/download/v{0}/kotlin-compiler-{0}.zip' -_FILE_NAME = 'kotlinc.zip' -_VERSION = '1.7.21' -_PATCH_VERSION = '-cr1' +# Releases can be found: https://github.com/JetBrains/kotlin/releases/ +_LATEST_URL = 'https://api.github.com/repos/JetBrains/kotlin/releases/latest' + + +def get_latest_release(): + """Returns data of the latest release.""" + return json.load(urllib.request.urlopen(_LATEST_URL)) def do_latest(): - print(_VERSION + _PATCH_VERSION) + # Make the version change every time this file changes. + md5 = hashlib.md5() + md5.update(pathlib.Path(__file__).read_bytes()) + file_hash = md5.hexdigest()[:10] + release = get_latest_release() + print('{}.{}'.format(release['name'], file_hash)) -def get_download_url(version): - if version.endswith(_PATCH_VERSION): - version = version[:-len(_PATCH_VERSION)] +def get_download_url(original_version): + release = get_latest_release() + latest_release_name = release['name'] + version_release_name = original_version.rsplit('.', 1)[0] + assert latest_release_name == version_release_name, ( + f'The latest release name is {latest_release_name} but the one given ' + f'via the version parameter is {version_release_name}.') + + # version without file hash. + version = release['name'] + release_url = None + file_name = None + for asset in release['assets']: + name = asset['name'] + if 'kotlin-compiler-' in name and name.endswith('.zip'): + if release_url is not None: + raise Exception( + 'Multiple valid assets found: \n{}\n{}\n'.format( + release_url, asset['browser_download_url'])) + file_name = name + release_url = asset['browser_download_url'] + + if release_url is None: + raise Exception(f'kotlin-compiler asset not found for {version}.') + partial_manifest = { - 'url': [_FILE_URL.format(version)], - 'name': [_FILE_NAME], + 'url': [release_url], + 'name': [file_name], 'ext': '.zip', } print(json.dumps(partial_manifest))
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium index a0fb072..1e23b6a 100644 --- a/third_party/libaom/README.chromium +++ b/third_party/libaom/README.chromium
@@ -2,8 +2,8 @@ Short Name: libaom URL: https://aomedia.googlesource.com/aom/ Version: 0 -Date: Thursday January 19 2023 -Revision: 5115747345e7de18fdbafc333e078604f39ba932 +Date: Friday January 20 2023 +Revision: 9c915757e556d5df75400a6b847c37f06a71a426 CPEPrefix: cpe:/a:aomedia:aomedia:3.5.0 License: BSD License File: source/libaom/LICENSE
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h index 0587f7f9..a458966 100644 --- a/third_party/libaom/source/config/config/aom_version.h +++ b/third_party/libaom/source/config/config/aom_version.h
@@ -12,8 +12,8 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 5 #define VERSION_PATCH 0 -#define VERSION_EXTRA "693-g511574734" +#define VERSION_EXTRA "698-g9c915757e" #define VERSION_PACKED \ ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH)) -#define VERSION_STRING_NOSP "3.5.0-693-g511574734" -#define VERSION_STRING " 3.5.0-693-g511574734" +#define VERSION_STRING_NOSP "3.5.0-698-g9c915757e" +#define VERSION_STRING " 3.5.0-698-g9c915757e"
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium index 8a0c2fa..723f790 100644 --- a/third_party/libvpx/README.chromium +++ b/third_party/libvpx/README.chromium
@@ -1,8 +1,8 @@ Name: libvpx URL: https://chromium.googlesource.com/webm/libvpx Version: 0 -Date: Tuesday November 15 2022 -Revision: 605350bd5b68ac47f595d60cc8ef346588e773c0 +Date: Friday January 20 2023 +Revision: b7c22b3a9584d7d9c0a7b9b37a52bc595113b398 CPEPrefix: cpe:/a:webmproject:libvpx:1.12.0 License: BSD License File: source/libvpx/LICENSE
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h index 83cc5525..4dffd6b0ba 100644 --- a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
@@ -3006,7 +3006,13 @@ int height, const uint16_t* ref, int ref_stride); -#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_c +void vpx_highbd_comp_avg_pred_sse2(uint16_t* comp_pred, + const uint16_t* pred, + int width, + int height, + const uint16_t* ref, + int ref_stride); +#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_sse2 void vpx_highbd_convolve8_c(const uint16_t* src, ptrdiff_t src_stride, @@ -5155,7 +5161,24 @@ const uint8_t* pred8_ptr, ptrdiff_t pred_stride, int bd); -#define vpx_highbd_subtract_block vpx_highbd_subtract_block_c +void vpx_highbd_subtract_block_avx2(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); +RTCD_EXTERN void (*vpx_highbd_subtract_block)(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); void vpx_highbd_tm_predictor_16x16_c(uint16_t* dst, ptrdiff_t stride, @@ -7961,6 +7984,9 @@ vpx_highbd_satd = vpx_highbd_satd_c; if (flags & HAS_AVX2) vpx_highbd_satd = vpx_highbd_satd_avx2; + vpx_highbd_subtract_block = vpx_highbd_subtract_block_c; + if (flags & HAS_AVX2) + vpx_highbd_subtract_block = vpx_highbd_subtract_block_avx2; vpx_idct32x32_135_add = vpx_idct32x32_135_add_sse2; if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h index 8924989..190dc124 100644 --- a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
@@ -3011,7 +3011,13 @@ int height, const uint16_t* ref, int ref_stride); -#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_c +void vpx_highbd_comp_avg_pred_sse2(uint16_t* comp_pred, + const uint16_t* pred, + int width, + int height, + const uint16_t* ref, + int ref_stride); +#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_sse2 void vpx_highbd_convolve8_c(const uint16_t* src, ptrdiff_t src_stride, @@ -5232,7 +5238,24 @@ const uint8_t* pred8_ptr, ptrdiff_t pred_stride, int bd); -#define vpx_highbd_subtract_block vpx_highbd_subtract_block_c +void vpx_highbd_subtract_block_avx2(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); +RTCD_EXTERN void (*vpx_highbd_subtract_block)(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); void vpx_highbd_tm_predictor_16x16_c(uint16_t* dst, ptrdiff_t stride, @@ -8041,6 +8064,9 @@ vpx_highbd_satd = vpx_highbd_satd_c; if (flags & HAS_AVX2) vpx_highbd_satd = vpx_highbd_satd_avx2; + vpx_highbd_subtract_block = vpx_highbd_subtract_block_c; + if (flags & HAS_AVX2) + vpx_highbd_subtract_block = vpx_highbd_subtract_block_avx2; vpx_idct32x32_135_add = vpx_idct32x32_135_add_sse2; if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h index 83cc5525..4dffd6b0ba 100644 --- a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
@@ -3006,7 +3006,13 @@ int height, const uint16_t* ref, int ref_stride); -#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_c +void vpx_highbd_comp_avg_pred_sse2(uint16_t* comp_pred, + const uint16_t* pred, + int width, + int height, + const uint16_t* ref, + int ref_stride); +#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_sse2 void vpx_highbd_convolve8_c(const uint16_t* src, ptrdiff_t src_stride, @@ -5155,7 +5161,24 @@ const uint8_t* pred8_ptr, ptrdiff_t pred_stride, int bd); -#define vpx_highbd_subtract_block vpx_highbd_subtract_block_c +void vpx_highbd_subtract_block_avx2(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); +RTCD_EXTERN void (*vpx_highbd_subtract_block)(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); void vpx_highbd_tm_predictor_16x16_c(uint16_t* dst, ptrdiff_t stride, @@ -7961,6 +7984,9 @@ vpx_highbd_satd = vpx_highbd_satd_c; if (flags & HAS_AVX2) vpx_highbd_satd = vpx_highbd_satd_avx2; + vpx_highbd_subtract_block = vpx_highbd_subtract_block_c; + if (flags & HAS_AVX2) + vpx_highbd_subtract_block = vpx_highbd_subtract_block_avx2; vpx_idct32x32_135_add = vpx_idct32x32_135_add_sse2; if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h index 8924989..190dc124 100644 --- a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
@@ -3011,7 +3011,13 @@ int height, const uint16_t* ref, int ref_stride); -#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_c +void vpx_highbd_comp_avg_pred_sse2(uint16_t* comp_pred, + const uint16_t* pred, + int width, + int height, + const uint16_t* ref, + int ref_stride); +#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_sse2 void vpx_highbd_convolve8_c(const uint16_t* src, ptrdiff_t src_stride, @@ -5232,7 +5238,24 @@ const uint8_t* pred8_ptr, ptrdiff_t pred_stride, int bd); -#define vpx_highbd_subtract_block vpx_highbd_subtract_block_c +void vpx_highbd_subtract_block_avx2(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); +RTCD_EXTERN void (*vpx_highbd_subtract_block)(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); void vpx_highbd_tm_predictor_16x16_c(uint16_t* dst, ptrdiff_t stride, @@ -8041,6 +8064,9 @@ vpx_highbd_satd = vpx_highbd_satd_c; if (flags & HAS_AVX2) vpx_highbd_satd = vpx_highbd_satd_avx2; + vpx_highbd_subtract_block = vpx_highbd_subtract_block_c; + if (flags & HAS_AVX2) + vpx_highbd_subtract_block = vpx_highbd_subtract_block_avx2; vpx_idct32x32_135_add = vpx_idct32x32_135_add_sse2; if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h index c08816d..2b5d64a 100644 --- a/third_party/libvpx/source/config/vpx_version.h +++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,8 +2,8 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 12 #define VERSION_PATCH 0 -#define VERSION_EXTRA "226-g605350bd5" +#define VERSION_EXTRA "256-gb7c22b3a9" #define VERSION_PACKED \ ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH)) -#define VERSION_STRING_NOSP "v1.12.0-226-g605350bd5" -#define VERSION_STRING " v1.12.0-226-g605350bd5" +#define VERSION_STRING_NOSP "v1.12.0-256-gb7c22b3a9" +#define VERSION_STRING " v1.12.0-256-gb7c22b3a9"
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h index 83cc5525..4dffd6b0ba 100644 --- a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
@@ -3006,7 +3006,13 @@ int height, const uint16_t* ref, int ref_stride); -#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_c +void vpx_highbd_comp_avg_pred_sse2(uint16_t* comp_pred, + const uint16_t* pred, + int width, + int height, + const uint16_t* ref, + int ref_stride); +#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_sse2 void vpx_highbd_convolve8_c(const uint16_t* src, ptrdiff_t src_stride, @@ -5155,7 +5161,24 @@ const uint8_t* pred8_ptr, ptrdiff_t pred_stride, int bd); -#define vpx_highbd_subtract_block vpx_highbd_subtract_block_c +void vpx_highbd_subtract_block_avx2(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); +RTCD_EXTERN void (*vpx_highbd_subtract_block)(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); void vpx_highbd_tm_predictor_16x16_c(uint16_t* dst, ptrdiff_t stride, @@ -7961,6 +7984,9 @@ vpx_highbd_satd = vpx_highbd_satd_c; if (flags & HAS_AVX2) vpx_highbd_satd = vpx_highbd_satd_avx2; + vpx_highbd_subtract_block = vpx_highbd_subtract_block_c; + if (flags & HAS_AVX2) + vpx_highbd_subtract_block = vpx_highbd_subtract_block_avx2; vpx_idct32x32_135_add = vpx_idct32x32_135_add_sse2; if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
diff --git a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h index 8924989..190dc124 100644 --- a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
@@ -3011,7 +3011,13 @@ int height, const uint16_t* ref, int ref_stride); -#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_c +void vpx_highbd_comp_avg_pred_sse2(uint16_t* comp_pred, + const uint16_t* pred, + int width, + int height, + const uint16_t* ref, + int ref_stride); +#define vpx_highbd_comp_avg_pred vpx_highbd_comp_avg_pred_sse2 void vpx_highbd_convolve8_c(const uint16_t* src, ptrdiff_t src_stride, @@ -5232,7 +5238,24 @@ const uint8_t* pred8_ptr, ptrdiff_t pred_stride, int bd); -#define vpx_highbd_subtract_block vpx_highbd_subtract_block_c +void vpx_highbd_subtract_block_avx2(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); +RTCD_EXTERN void (*vpx_highbd_subtract_block)(int rows, + int cols, + int16_t* diff_ptr, + ptrdiff_t diff_stride, + const uint8_t* src8_ptr, + ptrdiff_t src_stride, + const uint8_t* pred8_ptr, + ptrdiff_t pred_stride, + int bd); void vpx_highbd_tm_predictor_16x16_c(uint16_t* dst, ptrdiff_t stride, @@ -8041,6 +8064,9 @@ vpx_highbd_satd = vpx_highbd_satd_c; if (flags & HAS_AVX2) vpx_highbd_satd = vpx_highbd_satd_avx2; + vpx_highbd_subtract_block = vpx_highbd_subtract_block_c; + if (flags & HAS_AVX2) + vpx_highbd_subtract_block = vpx_highbd_subtract_block_avx2; vpx_idct32x32_135_add = vpx_idct32x32_135_add_sse2; if (flags & HAS_SSSE3) vpx_idct32x32_135_add = vpx_idct32x32_135_add_ssse3;
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index 31f32da6..be9157d 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: 43ec97b13bdaf7cb90941a87b0457948d4a0410d +Version: 7f34968b7850b2bd575601bcab8f745220cab8ff License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/re2/BUILD.gn b/third_party/re2/BUILD.gn index fbe4f66..bf901069 100644 --- a/third_party/re2/BUILD.gn +++ b/third_party/re2/BUILD.gn
@@ -10,6 +10,7 @@ static_library("re2") { sources = [ + "src/re2/bitmap256.cc", "src/re2/bitmap256.h", "src/re2/bitstate.cc", "src/re2/compile.cc",
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium index dd93c56..fbbb3673 100644 --- a/third_party/tflite/README.chromium +++ b/third_party/tflite/README.chromium
@@ -1,8 +1,8 @@ Name: TensorFlow Lite Short Name: tflite URL: https://github.com/tensorflow/tensorflow -Version: e6ad9bf9bcd3f33783f4363984f4b24adfd8a469 -Date: 2023/01/17 +Version: ef70dc999eee784e3f505e89c798f8b9cc894e52 +Date: 2023/01/23 License: Apache 2.0 License File: LICENSE Security Critical: Yes
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt index 6c2e89b..d880fd1 100644 --- a/third_party/webgpu-cts/ts_sources.txt +++ b/third_party/webgpu-cts/ts_sources.txt
@@ -462,11 +462,13 @@ src/webgpu/web_platform/external_texture/video.spec.ts src/webgpu/web_platform/reftests/gpu_ref_test.ts src/webgpu/web_platform/reftests/canvas_clear.html.ts +src/webgpu/web_platform/reftests/canvas_colorspace.html.ts src/webgpu/web_platform/reftests/canvas_complex.html.ts src/webgpu/web_platform/reftests/canvas_composite_alpha.html.ts src/webgpu/web_platform/reftests/canvas_image_rendering.html.ts src/webgpu/web_platform/reftests/create-pattern-data-url.ts src/webgpu/web_platform/reftests/resize_observer.html.ts +src/webgpu/web_platform/reftests/ref/canvas_colorspace-ref.html.ts src/webgpu/web_platform/worker/worker.spec.ts src/webgpu/web_platform/worker/worker.ts src/webgpu/web_platform/worker/worker_launcher.ts
diff --git a/tools/android/modularization/convenience/lookup_dep.py b/tools/android/modularization/convenience/lookup_dep.py index c4bfb01..3460eaf5 100755 --- a/tools/android/modularization/convenience/lookup_dep.py +++ b/tools/android/modularization/convenience/lookup_dep.py
@@ -236,10 +236,10 @@ full_class_names = set() - # Read the location of the java_sources_file from the build_config - sources_path = deps_info.get('java_sources_file') + # Read the location of the target_sources_file from the build_config + sources_path = deps_info.get('target_sources_file') if sources_path: - # Read the java_sources_file, indexing the classes found + # Read the target_sources_file, indexing the classes found with open(self._abs_build_output_dir / sources_path) as sources_contents: for source_line in sources_contents: source_path = pathlib.Path(source_line.strip())
diff --git a/tools/binary_size/libsupersize/apkanalyzer.py b/tools/binary_size/libsupersize/apkanalyzer.py index ac4a7cb7..356a8e3 100644 --- a/tools/binary_size/libsupersize/apkanalyzer.py +++ b/tools/binary_size/libsupersize/apkanalyzer.py
@@ -354,6 +354,7 @@ class_deobfuscation_map: Map from obfuscated names to class names. Yields: + string_idx: DEX string index. size: Number of bytes taken by string, including pointer. decoded_string: The decoded string. class_names: List of class names @@ -415,7 +416,7 @@ decoded_string = string_item.data class_idxs = string_idx_to_class_idxs[string_idx] class_names = sorted(LookupDeobfuscatedClassNames(i) for i in class_idxs) - yield size, decoded_string, class_names + yield string_idx, size, decoded_string, class_names logging.info('Deobfuscated %d / %d classes (%d failures)', num_deobfus_names, len(dexfile.class_def_item_list), num_failed_deobfus) @@ -433,12 +434,17 @@ if not dexfile: return [], 0 logging.info('Extractng string symbols from %s', apk_path) + + # Code strings: Strings accessed via class -> method -> code -> string. + # These are extracted into separate symbols ,aliases among referring classes. + fresh_string_idx_set = set(range(len(dexfile.string_data_item_list))) lambda_normalizer = LambdaNormalizer() object_path = str(apk_path) dex_string_data_size = 0 dex_string_symbols = [] string_iter = _GenDexStringsUsedByClasses(dexfile, class_deobfuscation_map) - for size, decoded_string, string_user_class_names in string_iter: + for string_idx, size, decoded_string, string_user_class_names in string_iter: + fresh_string_idx_set.remove(string_idx) dex_string_data_size += size num_aliases = len(string_user_class_names) aliases = [] @@ -458,6 +464,52 @@ aliases.append(sym) assert num_aliases == len(aliases) dex_string_symbols += aliases + + logging.info('Counted %d class -> method -> code strings', + len(dexfile.string_data_item_list) - len(fresh_string_idx_set)) + + # Extract aggregate string symbols for {types, methods, fields, prototypes}. + # Due to significant overlap (coincidental or induced by R8), {method, field} + # string symbols share a common aggregate. Other overlap sare resolved by + # applying the priority: + # code > type > {method, field} > prototype, + # i.e., bytes from code strings are not counted in aggregates; bytes from type + # string aggregate are not counted by {{method, field}, prototype}, etc. + + def _AddAggregateStringSymbol(name, string_idx_set): + nonlocal fresh_string_idx_set + old_count = len(string_idx_set) + string_idx_set &= fresh_string_idx_set + fresh_string_idx_set -= string_idx_set + logging.info('Counted %d %s strings among %d found', len(string_idx_set), + name, old_count) + total_size = 0 + if string_idx_set: + # Each string has +4 for pointer. + size = sum(dexfile.string_data_item_list[string_idx].byte_size + for string_idx in string_idx_set) + 4 * len(string_idx_set) + total_size += size + sym = models.Symbol(models.SECTION_DEX, + size, + full_name=f'** .dex ({name} strings)') + dex_string_symbols.append(sym) + return total_size + + # Type strings. + type_string_idx_set = {i.descriptor_idx for i in dexfile.type_id_item_list} + dex_string_data_size += _AddAggregateStringSymbol('type', type_string_idx_set) + + # Method and field strings. + method_string_idx_set = {i.name_idx for i in dexfile.method_id_item_list} + field_string_idx_set = {i.name_idx for i in dexfile.field_id_item_list} + dex_string_data_size += _AddAggregateStringSymbol( + 'method and field', method_string_idx_set | field_string_idx_set) + + # Prototype strings. + proto_string_idx_set = {i.shorty_idx for i in dexfile.proto_id_item_list} + dex_string_data_size += _AddAggregateStringSymbol('prototype', + proto_string_idx_set) + return dex_string_symbols, dex_string_data_size
diff --git a/tools/binary_size/libsupersize/testdata/ArchiveContainers.golden b/tools/binary_size/libsupersize/testdata/ArchiveContainers.golden index 6e7a96f..85b2dc6 100644 --- a/tools/binary_size/libsupersize/testdata/ArchiveContainers.golden +++ b/tools/binary_size/libsupersize/testdata/ArchiveContainers.golden
@@ -213,7 +213,10 @@ <Container1:>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.Math,object_path=$APK/java/lang/Math,source_path=,flags={},num_aliases=1,component=) <Container1:>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.Object,object_path=$APK/java/lang/Object,source_path=,flags={},num_aliases=1,component=) <Container1:>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.StringBuilder,object_path=$APK/java/lang/StringBuilder,source_path=,flags={},num_aliases=1,component=) -<Container1:>.dex@0(size_without_padding=1260,padding=0,full_name=** .dex (unattributed),object_path=,source_path=,flags={},num_aliases=1,component=) +<Container1:>.dex@0(size_without_padding=146,padding=0,full_name=** .dex (method and field strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<Container1:>.dex@0(size_without_padding=58,padding=0,full_name=** .dex (prototype strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<Container1:>.dex@0(size_without_padding=244,padding=0,full_name=** .dex (type strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<Container1:>.dex@0(size_without_padding=812,padding=0,full_name=** .dex (unattributed),object_path=,source_path=,flags={},num_aliases=1,component=) <Container1:>.dex.method@0(size_without_padding=42,padding=0,full_name=AuxClass#<init>(int),object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=) <Container1:>.dex.method@0(size_without_padding=90,padding=0,full_name=AuxClass#repeatString(java.lang.String): java.lang.String,object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=) <Container1:>.dex.method@0(size_without_padding=62,padding=0,full_name=AuxClass#reverse(int[]): int[],object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Apk.golden b/tools/binary_size/libsupersize/testdata/Archive_Apk.golden index f4a4b09..38ed6df 100644 --- a/tools/binary_size/libsupersize/testdata/Archive_Apk.golden +++ b/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
@@ -169,11 +169,11 @@ * 0 have source paths. Accounts for 0 bytes (0.0%). * 0 have a component assigned. Accounts for 0 bytes (0.0%). * 0 symbols have shared ownership. -Section .dex: has 100.0% of 1446 bytes accounted for from 13 symbols. 0 bytes are unaccounted for. +Section .dex: has 100.0% of 1446 bytes accounted for from 16 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 4 have source paths. Accounts for 67 bytes (4.6%). * 0 have a component assigned. Accounts for 0 bytes (0.0%). -* 1 placeholders exist (symbols that start with **). Accounts for 1260 bytes (87.1%). +* 4 placeholders exist (symbols that start with **). Accounts for 1260 bytes (87.1%). * 0 symbols have shared ownership. Section .dex.method: has 100.0% of 570 bytes accounted for from 14 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) @@ -298,7 +298,10 @@ <test.apk>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.Math,object_path=$APK/java/lang/Math,source_path=,flags={},num_aliases=1,component=) <test.apk>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.Object,object_path=$APK/java/lang/Object,source_path=,flags={},num_aliases=1,component=) <test.apk>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.StringBuilder,object_path=$APK/java/lang/StringBuilder,source_path=,flags={},num_aliases=1,component=) -<test.apk>.dex@0(size_without_padding=1260,padding=0,full_name=** .dex (unattributed),object_path=,source_path=,flags={},num_aliases=1,component=) +<test.apk>.dex@0(size_without_padding=146,padding=0,full_name=** .dex (method and field strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<test.apk>.dex@0(size_without_padding=58,padding=0,full_name=** .dex (prototype strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<test.apk>.dex@0(size_without_padding=244,padding=0,full_name=** .dex (type strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<test.apk>.dex@0(size_without_padding=812,padding=0,full_name=** .dex (unattributed),object_path=,source_path=,flags={},num_aliases=1,component=) <test.apk>.dex.method@0(size_without_padding=42,padding=0,full_name=AuxClass#<init>(int),object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=) <test.apk>.dex.method@0(size_without_padding=90,padding=0,full_name=AuxClass#repeatString(java.lang.String): java.lang.String,object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=) <test.apk>.dex.method@0(size_without_padding=62,padding=0,full_name=AuxClass#reverse(int[]): int[],object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden b/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden index 7bf31041..4c359a91 100644 --- a/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden +++ b/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
@@ -240,11 +240,11 @@ * 0 have source paths. Accounts for 0 bytes (0.0%). * 0 have a component assigned. Accounts for 0 bytes (0.0%). * 0 symbols have shared ownership. -Section .dex: has 100.0% of 1446 bytes accounted for from 13 symbols. 0 bytes are unaccounted for. +Section .dex: has 100.0% of 1446 bytes accounted for from 16 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) * 4 have source paths. Accounts for 67 bytes (4.6%). * 0 have a component assigned. Accounts for 0 bytes (0.0%). -* 1 placeholders exist (symbols that start with **). Accounts for 1260 bytes (87.1%). +* 4 placeholders exist (symbols that start with **). Accounts for 1260 bytes (87.1%). * 0 symbols have shared ownership. Section .dex.method: has 100.0% of 570 bytes accounted for from 14 symbols. 0 bytes are unaccounted for. * Padding accounts for 0 bytes (0.0%) @@ -477,7 +477,10 @@ <Bundle.minimal.apks/base.apk>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.Math,object_path=$APK/java/lang/Math,source_path=,flags={},num_aliases=1,component=) <Bundle.minimal.apks/base.apk>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.Object,object_path=$APK/java/lang/Object,source_path=,flags={},num_aliases=1,component=) <Bundle.minimal.apks/base.apk>.dex@0(size_without_padding=0,padding=0,full_name=java.lang.StringBuilder,object_path=$APK/java/lang/StringBuilder,source_path=,flags={},num_aliases=1,component=) -<Bundle.minimal.apks/base.apk>.dex@0(size_without_padding=1260,padding=0,full_name=** .dex (unattributed),object_path=,source_path=,flags={},num_aliases=1,component=) +<Bundle.minimal.apks/base.apk>.dex@0(size_without_padding=146,padding=0,full_name=** .dex (method and field strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<Bundle.minimal.apks/base.apk>.dex@0(size_without_padding=58,padding=0,full_name=** .dex (prototype strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<Bundle.minimal.apks/base.apk>.dex@0(size_without_padding=244,padding=0,full_name=** .dex (type strings),object_path=,source_path=,flags={},num_aliases=1,component=) +<Bundle.minimal.apks/base.apk>.dex@0(size_without_padding=812,padding=0,full_name=** .dex (unattributed),object_path=,source_path=,flags={},num_aliases=1,component=) <Bundle.minimal.apks/base.apk>.dex.method@0(size_without_padding=42,padding=0,full_name=AuxClass#<init>(int),object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=) <Bundle.minimal.apks/base.apk>.dex.method@0(size_without_padding=90,padding=0,full_name=AuxClass#repeatString(java.lang.String): java.lang.String,object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=) <Bundle.minimal.apks/base.apk>.dex.method@0(size_without_padding=62,padding=0,full_name=AuxClass#reverse(int[]): int[],object_path=$APK/AuxClass,source_path=,flags={},num_aliases=1,component=)
diff --git a/tools/binary_size/libsupersize/viewer/static/start-worker.js b/tools/binary_size/libsupersize/viewer/static/start-worker.js index 2b4bcda2..2cf551e 100644 --- a/tools/binary_size/libsupersize/viewer/static/start-worker.js +++ b/tools/binary_size/libsupersize/viewer/static/start-worker.js
@@ -34,6 +34,12 @@ }); } + /** @public **/ + dispose() { + this._worker.terminate(); + delete this._worker; + } + /** * @param {string} action * @param {any} data @@ -99,6 +105,10 @@ * @return {TreeWorker} */ function restartWorker(onProgressHandler) { + if (window.supersize.worker) { + window.supersize.worker.dispose(); + window.supersize.worker = null; + } const innerWorker = new Worker('tree-worker-wasm.js'); window.supersize.worker = new TreeWorker(innerWorker, onProgressHandler); return window.supersize.worker;
diff --git a/tools/binary_size/libsupersize/viewer/static/tree-ui.js b/tools/binary_size/libsupersize/viewer/static/tree-ui.js index b96e0480..996bc090 100644 --- a/tools/binary_size/libsupersize/viewer/static/tree-ui.js +++ b/tools/binary_size/libsupersize/viewer/static/tree-ui.js
@@ -580,10 +580,15 @@ const loadAnchor = /** @type {HTMLAnchorElement} */ ( document.getElementById('load-anchor')); - beforeAnchor.style.display = beforeUrl ? '' : 'none'; - beforeAnchor.href = beforeUrl; - loadAnchor.style.display = loadUrl ? '' : 'none'; - loadAnchor.href = loadUrl; + const updateAnchor = (anchor, url) => { + anchor.style.display = url ? '' : 'none'; + if (anchor.href && anchor.href.startsWith('blob:')) { + URL.revokeObjectURL(anchor.href); + } + anchor.href = url; + }; + updateAnchor(beforeAnchor, beforeUrl); + updateAnchor(loadAnchor, loadUrl); if (_dataUrlInput.value.includes('.sizediff')) { loadAnchor.title = 'Download .sizediff file'; @@ -688,6 +693,7 @@ const worker = restartWorker(onProgressMessage); _progress.setValue(0.3); const message = await worker.loadAndBuildTree(fileUrl); + URL.revokeObjectURL(fileUrl); processLoadTreeResponse(message); // Clean up afterwards so new files trigger event. input.value = '';
diff --git a/tools/binary_size/libsupersize/viewer/static/tree-worker-wasm.js b/tools/binary_size/libsupersize/viewer/static/tree-worker-wasm.js index 3140d03..b656b051 100644 --- a/tools/binary_size/libsupersize/viewer/static/tree-worker-wasm.js +++ b/tools/binary_size/libsupersize/viewer/static/tree-worker-wasm.js
@@ -253,9 +253,11 @@ const sizeProperties = wasmLoadSizeProperties(); isMultiContainer = sizeProperties.isMultiContainer; if (!isUpload) { + // Revoked in displayOrHideDownloadButton(). loadBlobUrl = URL.createObjectURL(new Blob( [mainSizeBuffer.buffer], {type: 'application/octet-stream'})); if (beforeSizeBuffer) { + // Revoked in displayOrHideDownloadButton(). beforeBlobUrl = URL.createObjectURL(new Blob( [beforeSizeBuffer.buffer], {type: 'application/octet-stream'})); }
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 301c730..5460c3b 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -41,6 +41,10 @@ 'win-chrome': 'official_reclient_x86', 'win64-chrome': 'official_reclient_x64', }, + 'chrome.captured-sites': { + 'linux-autofill-captured-sites-rel': 'release_bot', + 'linux-password-manager-captured-sites-rel': 'release_bot', + }, 'chrome.pgo': { 'android-arm32-pgo': 'official_reclient_android_arm32_pgo', 'android-arm64-pgo': 'official_reclient_android_arm64_pgo', @@ -164,6 +168,7 @@ 'lacros-amd64-generic-rel': 'chromeos_amd64-generic_lacros_rel_reclient', 'lacros-amd64-generic-rel-skylab': 'chromeos_amd64-generic_lacros_rel_skylab_reclient', 'lacros-arm-generic-rel': 'chromeos_arm-generic_lacros_rel_reclient', + 'lacros-arm-generic-rel-skylab': 'chromeos_arm-generic_lacros_rel_skylab_reclient', 'lacros-arm64-generic-rel': 'chromeos_arm64-generic_lacros_rel_reclient', 'lacros-arm64-generic-rel-skylab': 'chromeos_arm64-generic_lacros_rel_skylab_reclient', 'linux-ash-chromium-generator-rel': 'chromeos_with_codecs_release_bot_reclient', @@ -457,6 +462,7 @@ 'mac-perfetto-rel': 'perfetto_release_bot_reclient', 'mac-upload-perfetto': 'release_bot_perfetto_zlib_reclient', 'mac10.15-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient', + 'mac11-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient', 'mac12-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient', 'win-annotator-rel': 'release_bot_reclient', 'win-backuprefptr-x64-fyi-rel': 'release_trybot_backuprefptr_x64_reclient', @@ -891,10 +897,10 @@ 'linux-blink-rel': 'release_bot_blink_minimal_symbols_reclient', 'mac10.13-blink-rel': 'release_bot_blink_minimal_symbols_no_nacl', 'mac10.14-blink-rel': 'release_bot_blink_minimal_symbols_no_nacl', - 'mac10.15-blink-rel': 'release_bot_blink_minimal_symbols_no_nacl', + 'mac10.15-blink-rel': 'release_bot_blink_minimal_symbols_no_nacl_reclient', 'mac11.0-blink-rel': 'release_bot_blink_minimal_symbols_no_nacl', - 'mac11.0.arm64-blink-rel': 'release_bot_blink_arm64_minimal_symbols', - 'mac12.0-blink-rel': 'release_bot_blink_minimal_symbols_no_nacl', + 'mac11.0.arm64-blink-rel': 'release_bot_blink_arm64_minimal_symbols_reclient', + 'mac12.0-blink-rel': 'release_bot_blink_minimal_symbols_no_nacl_reclient', 'mac12.0.arm64-blink-rel': 'release_bot_blink_arm64_minimal_symbols', 'win10.20h2-blink-rel': 'release_bot_blink_x86_minimal_symbols_reclient', 'win11-blink-rel': 'release_bot_blink_x64_minimal_symbols_reclient', @@ -946,6 +952,11 @@ 'win64-chrome-stable': 'official_goma_x64', }, + 'tryserver.chrome.captured-sites': { + 'linux-autofill-captured-sites-rel': 'release_bot', + 'linux-password-manager-captured-sites-rel': 'release_bot', + }, + 'tryserver.chrome.pgo': { 'android-arm32-pgo': 'official_goma_android_arm32_pgo', 'android-arm64-pgo': 'official_goma_android_arm64_pgo', @@ -1246,11 +1257,11 @@ 'ios-fieldtrial-rel': 'ios_simulator_debug_static_bot_xctest_arm64', 'ios-m1-simulator': 'ios_simulator_debug_static_bot_xctest_arm64', 'ios-m1-simulator-cronet': 'ios_cronet_xctest_arm64', - 'ios-simulator': 'ios_simulator_code_coverage_partial_instrumentation_xctest', + 'ios-simulator': 'ios_simulator_code_coverage_partial_instrumentation_xctest_reclient', 'ios-simulator-code-coverage': 'clang_code_coverage_ios_xctest', 'ios-simulator-cr-recipe': 'ios_simulator_debug_static_bot_xctest', 'ios-simulator-cronet': 'ios_cronet_xctest', - 'ios-simulator-full-configs': 'ios_simulator_code_coverage_partial_instrumentation_xctest', + 'ios-simulator-full-configs': 'ios_simulator_code_coverage_partial_instrumentation_xctest_reclient', 'ios-simulator-inverse-fieldtrials-fyi': 'ios_simulator_debug_static_bot_invert_fieldtrials_xctest', 'ios-simulator-multi-window': 'ios_simulator_debug_static_bot_xctest', 'ios-simulator-noncq': 'ios_simulator_debug_static_bot_xctest', @@ -1266,8 +1277,9 @@ 'mac-inverse-fieldtrials-fyi-rel': 'gpu_tests_release_trybot_invert_fieldtrials', 'mac-osxbeta-rel': 'gpu_tests_debug_trybot', 'mac-perfetto-rel': 'perfetto_release_trybot', - 'mac-rel': 'gpu_tests_release_trybot_no_symbols_mac_code_coverage', - 'mac-rel-inverse-fyi': 'gpu_tests_release_trybot_no_symbols_mac_code_coverage', + 'mac-rel': 'gpu_tests_release_trybot_no_symbols_mac_code_coverage_reclient', + 'mac-rel-inverse-fyi': 'gpu_tests_release_trybot_no_symbols_mac_code_coverage_reclient', + 'mac10.15-wpt-content-shell-fyi-rel': 'release_trybot_minimal_symbols_reclient', 'mac11-arm64-rel': 'mac_arm64_gpu_tests_release_trybot_no_symbols_reclient', 'mac12-arm64-rel': 'mac_arm64_gpu_tests_release_trybot_no_symbols', 'mac12-tests': 'release_trybot', @@ -1278,7 +1290,7 @@ 'mac_chromium_11.0_rel_ng': 'release_trybot_reclient', 'mac_chromium_archive_rel_ng': 'release_bot_mac_strip_minimal_symbols', 'mac_chromium_asan_rel_ng': 'asan_dcheck_disable_nacl_release_bot_reclient', - 'mac_chromium_compile_dbg_ng': 'gpu_tests_debug_bot', + 'mac_chromium_compile_dbg_ng': 'gpu_tests_debug_bot_reclient', 'mac_chromium_compile_rel_ng': 'gpu_tests_release_trybot', 'mac_chromium_dbg_ng': 'gpu_tests_debug_bot', 'mac_optional_gpu_tests_rel': 'gpu_fyi_tests_release_trybot_reclient', @@ -1389,12 +1401,12 @@ }, 'tryserver.webrtc': { - 'android_chromium_compile': 'android_release_trybot', - 'linux_chromium_compile': 'release_trybot', - 'linux_chromium_compile_dbg': 'debug_bot', - 'mac_chromium_compile': 'gpu_tests_release_trybot', - 'win_chromium_compile': 'gpu_tests_release_trybot_resource_allowlisting', - 'win_chromium_compile_dbg': 'gpu_tests_debug_bot_x86_no_symbols', + 'android_chromium_compile': 'android_release_trybot_reclient', + 'linux_chromium_compile': 'release_trybot_reclient', + 'linux_chromium_compile_dbg': 'debug_bot_reclient', + 'mac_chromium_compile': 'gpu_tests_release_trybot_reclient', + 'win_chromium_compile': 'gpu_tests_release_trybot_resource_allowlisting_reclient', + 'win_chromium_compile_dbg': 'gpu_tests_debug_bot_x86_no_symbols_reclient', }, }, @@ -2788,8 +2800,8 @@ 'chrome_for_testing', ], - 'gpu_tests_release_trybot_no_symbols_mac_code_coverage': [ - 'gpu_tests', 'release_trybot', 'no_symbols', + 'gpu_tests_release_trybot_no_symbols_mac_code_coverage_reclient': [ + 'gpu_tests', 'release_trybot_reclient', 'no_symbols', 'use_clang_coverage', 'partial_code_coverage_instrumentation' ], @@ -2840,10 +2852,6 @@ 'gpu_tests', 'release_trybot_reclient', ], - 'gpu_tests_release_trybot_resource_allowlisting': [ - 'gpu_tests', 'release_trybot', 'resource_allowlisting', - ], - # TODO(crbug.com/1004523) Delete this once coverage mode is enabled on the # standard Windows trybot and the dedicated coverage trybot is no longer # needed. @@ -2875,6 +2883,10 @@ 'no_goma', 'no_reclient', ], + 'gpu_tests_release_trybot_resource_allowlisting_reclient': [ + 'gpu_tests', 'release_trybot_reclient', 'resource_allowlisting', + ], + 'gpu_tests_release_trybot_x86_reclient': [ 'gpu_tests', 'release_trybot_reclient', 'x86', ], @@ -2945,6 +2957,10 @@ 'use_clang_coverage', 'debug_static_bot', 'x64', 'ios', 'ios_simulator', 'partial_code_coverage_instrumentation', 'xctest', ], + 'ios_simulator_code_coverage_partial_instrumentation_xctest_reclient': [ + 'use_clang_coverage', 'debug_static_bot_reclient', 'x64', 'ios', 'ios_simulator', 'partial_code_coverage_instrumentation', 'xctest', + ], + 'ios_simulator_debug_static_bot_invert_fieldtrials_xctest': [ 'debug_static_bot', 'ios', 'ios_simulator', 'ios_cpu_x64', 'invert_fieldtrials', 'xctest', ], @@ -3425,12 +3441,22 @@ 'release_bot_blink', 'arm64', 'minimal_symbols', ], + 'release_bot_blink_arm64_minimal_symbols_reclient': [ + 'release_bot_blink_reclient', 'arm64', 'minimal_symbols', + ], + 'release_bot_blink_minimal_symbols_no_nacl': [ 'release_bot_blink', 'minimal_symbols', 'disable_nacl', ], + 'release_bot_blink_minimal_symbols_no_nacl_reclient': [ + 'release_bot_blink_reclient', + 'minimal_symbols', + 'disable_nacl', + ], + 'release_bot_blink_minimal_symbols_reclient': [ 'release_bot_blink_reclient', 'minimal_symbols', ],
diff --git a/tools/mb/mb_config_expectations/chrome.captured-sites.json b/tools/mb/mb_config_expectations/chrome.captured-sites.json new file mode 100644 index 0000000..09bc5ead --- /dev/null +++ b/tools/mb/mb_config_expectations/chrome.captured-sites.json
@@ -0,0 +1,18 @@ +{ + "linux-autofill-captured-sites-rel": { + "gn_args": { + "dcheck_always_on": false, + "is_component_build": false, + "is_debug": false, + "use_goma": true + } + }, + "linux-password-manager-captured-sites-rel": { + "gn_args": { + "dcheck_always_on": false, + "is_component_build": false, + "is_debug": false, + "use_goma": true + } + } +} \ No newline at end of file
diff --git a/tools/mb/mb_config_expectations/chromium.chromiumos.json b/tools/mb/mb_config_expectations/chromium.chromiumos.json index 75b1e41..5f6099e 100644 --- a/tools/mb/mb_config_expectations/chromium.chromiumos.json +++ b/tools/mb/mb_config_expectations/chromium.chromiumos.json
@@ -162,6 +162,19 @@ "use_remoteexec": true } }, + "lacros-arm-generic-rel-skylab": { + "args_file": "//build/args/chromeos/arm-generic-crostoolchain.gni", + "gn_args": { + "chromeos_is_browser_only": true, + "dcheck_always_on": false, + "is_chromeos_device": true, + "is_debug": false, + "is_skylab": true, + "ozone_platform_headless": true, + "target_os": "chromeos", + "use_remoteexec": true + } + }, "lacros-arm64-generic-rel": { "args_file": "//build/args/chromeos/arm64-generic-crostoolchain.gni", "gn_args": {
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json index ca521aa..29c1a527d 100644 --- a/tools/mb/mb_config_expectations/chromium.fyi.json +++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -1414,6 +1414,15 @@ "use_remoteexec": true } }, + "mac11-wpt-content-shell-fyi-rel": { + "gn_args": { + "dcheck_always_on": true, + "is_component_build": false, + "is_debug": false, + "symbol_level": 1, + "use_remoteexec": true + } + }, "mac12-wpt-content-shell-fyi-rel": { "gn_args": { "dcheck_always_on": true,
diff --git a/tools/mb/mb_config_expectations/tryserver.blink.json b/tools/mb/mb_config_expectations/tryserver.blink.json index 7463dde..a8d17f4a 100644 --- a/tools/mb/mb_config_expectations/tryserver.blink.json +++ b/tools/mb/mb_config_expectations/tryserver.blink.json
@@ -43,7 +43,7 @@ "is_debug": false, "proprietary_codecs": true, "symbol_level": 1, - "use_goma": true + "use_remoteexec": true } }, "mac11.0-blink-rel": { @@ -67,7 +67,7 @@ "proprietary_codecs": true, "symbol_level": 1, "target_cpu": "arm64", - "use_goma": true + "use_remoteexec": true } }, "mac12.0-blink-rel": { @@ -79,7 +79,7 @@ "is_debug": false, "proprietary_codecs": true, "symbol_level": 1, - "use_goma": true + "use_remoteexec": true } }, "mac12.0.arm64-blink-rel": {
diff --git a/tools/mb/mb_config_expectations/tryserver.chrome.captured-sites.json b/tools/mb/mb_config_expectations/tryserver.chrome.captured-sites.json new file mode 100644 index 0000000..09bc5ead --- /dev/null +++ b/tools/mb/mb_config_expectations/tryserver.chrome.captured-sites.json
@@ -0,0 +1,18 @@ +{ + "linux-autofill-captured-sites-rel": { + "gn_args": { + "dcheck_always_on": false, + "is_component_build": false, + "is_debug": false, + "use_goma": true + } + }, + "linux-password-manager-captured-sites-rel": { + "gn_args": { + "dcheck_always_on": false, + "is_component_build": false, + "is_debug": false, + "use_goma": true + } + } +} \ No newline at end of file
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json index 3103373..99e2d059 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json
@@ -278,7 +278,7 @@ "target_environment": "simulator", "target_os": "ios", "use_clang_coverage": true, - "use_goma": true + "use_remoteexec": true } }, "ios-simulator-code-coverage": { @@ -341,7 +341,7 @@ "target_environment": "simulator", "target_os": "ios", "use_clang_coverage": true, - "use_goma": true + "use_remoteexec": true } }, "ios-simulator-inverse-fieldtrials-fyi": { @@ -535,7 +535,7 @@ "proprietary_codecs": true, "symbol_level": 0, "use_clang_coverage": true, - "use_goma": true + "use_remoteexec": true } }, "mac-rel-inverse-fyi": { @@ -548,7 +548,16 @@ "proprietary_codecs": true, "symbol_level": 0, "use_clang_coverage": true, - "use_goma": true + "use_remoteexec": true + } + }, + "mac10.15-wpt-content-shell-fyi-rel": { + "gn_args": { + "dcheck_always_on": true, + "is_component_build": false, + "is_debug": false, + "symbol_level": 1, + "use_remoteexec": true } }, "mac11-arm64-rel": { @@ -657,7 +666,7 @@ "is_debug": true, "proprietary_codecs": true, "symbol_level": 1, - "use_goma": true + "use_remoteexec": true } }, "mac_chromium_compile_rel_ng": {
diff --git a/tools/mb/mb_config_expectations/tryserver.webrtc.json b/tools/mb/mb_config_expectations/tryserver.webrtc.json index 2f566cfcd..efec9d0 100644 --- a/tools/mb/mb_config_expectations/tryserver.webrtc.json +++ b/tools/mb/mb_config_expectations/tryserver.webrtc.json
@@ -10,7 +10,7 @@ "strip_debug_info": true, "symbol_level": 0, "target_os": "android", - "use_goma": true + "use_remoteexec": true } }, "linux_chromium_compile": { @@ -19,7 +19,7 @@ "is_component_build": false, "is_debug": false, "symbol_level": 0, - "use_goma": true + "use_remoteexec": true } }, "linux_chromium_compile_dbg": { @@ -27,7 +27,7 @@ "is_component_build": true, "is_debug": true, "symbol_level": 1, - "use_goma": true + "use_remoteexec": true } }, "mac_chromium_compile": { @@ -38,7 +38,7 @@ "is_debug": false, "proprietary_codecs": true, "symbol_level": 0, - "use_goma": true + "use_remoteexec": true } }, "win_chromium_compile": { @@ -50,7 +50,7 @@ "is_debug": false, "proprietary_codecs": true, "symbol_level": 0, - "use_goma": true + "use_remoteexec": true } }, "win_chromium_compile_dbg": { @@ -61,7 +61,7 @@ "proprietary_codecs": true, "symbol_level": 0, "target_cpu": "x86", - "use_goma": true + "use_remoteexec": true } } } \ No newline at end of file
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 8ba9568..0c4a506 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -5984,6 +5984,66 @@ <int value="1" label="Suggestion Selected"/> </enum> +<enum name="AutocompleteHtmlFieldMode"> + <int value="0" label="None"/> + <int value="1" label="Billing"/> + <int value="2" label="Shipping"/> +</enum> + +<enum name="AutocompleteHtmlFieldType"> + <int value="0" label="Unspecified"/> + <int value="1" label="Name"/> + <int value="2" label="HonorificPrefix"/> + <int value="3" label="GivenName"/> + <int value="4" label="AdditionalName"/> + <int value="5" label="FamilyName"/> + <int value="6" label="Organization"/> + <int value="7" label="StreetAddress"/> + <int value="8" label="AddressLine1"/> + <int value="9" label="AddressLine2"/> + <int value="10" label="AddressLine3"/> + <int value="11" label="AddressLevel1"/> + <int value="12" label="AddressLevel2"/> + <int value="13" label="AddressLevel3"/> + <int value="14" label="CountryCode"/> + <int value="15" label="CountryName"/> + <int value="16" label="PostalCode"/> + <int value="17" label="FullAddress"/> + <int value="18" label="CreditCardNameFull"/> + <int value="19" label="CreditCardNameFirst"/> + <int value="20" label="CreditCardNameLast"/> + <int value="21" label="CreditCardNumber"/> + <int value="22" label="CreditCardExp"/> + <int value="23" label="CreditCardExpMonth"/> + <int value="24" label="CreditCardExpYear"/> + <int value="25" label="CreditCardVerificationCode"/> + <int value="26" label="CreditCardType"/> + <int value="27" label="Tel"/> + <int value="28" label="TelCountryCode"/> + <int value="29" label="TelNational"/> + <int value="30" label="TelAreaCode"/> + <int value="31" label="TelLocal"/> + <int value="32" label="TelLocalPrefix"/> + <int value="33" label="TelLocalSuffix"/> + <int value="34" label="TelExtension"/> + <int value="35" label="Email"/> + <int value="36" label="BirthdateDay"/> + <int value="37" label="BirthdateMonth"/> + <int value="38" label="BirthdateYear"/> + <int value="39" label="TransactionAmount"/> + <int value="40" label="TransactionCurrency"/> + <int value="41" label="AdditionalNameInitial"/> + <int value="42" label="CreditCardExpDate2DigitYear"/> + <int value="43" label="CreditCardExpDate4DigitYear"/> + <int value="44" label="CreditCardExp2DigitYear"/> + <int value="45" label="CreditCardExp4DigitYear"/> + <int value="46" label="UpiVpa"/> + <int value="47" label="OneTimeCode"/> + <int value="48" label="MerchantPromoCode"/> + <int value="49" label="Iban"/> + <int value="50" label="Unrecognized"/> +</enum> + <enum name="AutoDSEPermissionRevertTransition"> <int value="0" label="NO_DECISION_ASK"/> <int value="1" label="PRESERVE_ALLOW"/> @@ -10631,6 +10691,10 @@ <int value="292" label="MSDH_ON_STREAM_STARTED_DISALLOWED"/> <int value="293" label="RFH_WINDOW_CLOSE_ON_NON_OUTERMOST_FRAME"/> <int value="294" label="RFPH_WINDOW_CLOSE_ON_NON_OUTERMOST_FRAME"/> + <int value="295" label="BIBI_BIND_PRESSURE_MANAGER_FOR_INSECURE_ORIGIN"/> + <int value="296" label="BIBI_BIND_PRESSURE_MANAGER_FOR_FENCED_FRAME"/> + <int value="297" + label="BIBI_BIND_PRESSURE_MANAGER_BLOCKED_BY_PERMISSIONS_POLICY"/> </enum> <enum name="BadMessageReasonExtensions"> @@ -32419,6 +32483,10 @@ <int value="1056" label="KioskTroubleshootingToolsEnabled"/> <int value="1057" label="ForceEnablePepperVideoDecoderDevAPI"/> <int value="1058" label="DomainReliabilityAllowed"/> + <int value="1059" label="ScreensaverEnabled"/> + <int value="1060" label="ScreensaverIdleTimeoutSeconds"/> + <int value="1061" label="ScreensaverImageDisplayIntervalSeconds"/> + <int value="1062" label="ScreensaverImages"/> </enum> <enum name="EnterprisePoliciesSources"> @@ -51732,6 +51800,7 @@ label="AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_DELEGATE_MOBILE"/> <int value="111" label="TAILORED_SECURITY_SERVICE_INFOBAR_DELEGATE"/> <int value="112" label="CHROME_FOR_TESTING_INFOBAR_DELEGATE"/> + <int value="113" label="EXTENSIONS_WEB_AUTH_FLOW_INFOBAR_DELEGATE"/> </enum> <enum name="InfoBarResponse"> @@ -60231,6 +60300,7 @@ <int value="-503601144" label="UserDataSnapshot:disabled"/> <int value="-503430431" label="XRSandbox:enabled"/> <int value="-502004335" label="OobeHidDetectionRevamp:enabled"/> + <int value="-501853726" label="MultiZoneRgbKeyboard:enabled"/> <int value="-499723386" label="EnableFilesAppCopyImage:disabled"/> <int value="-499186481" label="OmniboxGroupSuggestionsBySearchVsUrl:disabled"/> @@ -62020,6 +62090,7 @@ <int value="550387510" label="NTPAssetDownloadSuggestions:disabled"/> <int value="550411207" label="enable-webgpu-developer-features"/> <int value="550741462" label="WebAppBorderless:disabled"/> + <int value="552158955" label="NotificationPermissionBottomSheet:enabled"/> <int value="552317551" label="MediaAppHandlesPdf:disabled"/> <int value="552421509" label="AssistMultiWordExpanded:enabled"/> <int value="553197994" label="FedCmMetricsEndpoint:enabled"/> @@ -63123,6 +63194,7 @@ <int value="1192894768" label="NetworkServiceInProcess2:disabled"/> <int value="1192913630" label="OfflinePagesBackgroundLoading:disabled"/> <int value="1193385506" label="OmniboxLooseMaxLimitOnDedicatedRows:enabled"/> + <int value="1193940165" label="NotificationPermissionBottomSheet:disabled"/> <int value="1194496204" label="NewWallpaperPicker:enabled"/> <int value="1194896796" label="PdfHonorJsContentSettings:disabled"/> <int value="1194964049" label="AutofillFixOfferInIncognito:enabled"/> @@ -63249,6 +63321,7 @@ <int value="1261620998" label="IntentPickerPWAPersistence:disabled"/> <int value="1261713150" label="ChromeHomeOptOutSnackbar:disabled"/> <int value="1262469513" label="GesturePropertiesDBusService:disabled"/> + <int value="1265457230" label="MultiZoneRgbKeyboard:disabled"/> <int value="1265587614" label="AppDiscoveryForOobe:disabled"/> <int value="1265666387" label="DesktopPWAsAppIconShortcutsMenu:disabled"/> <int value="1266156008" label="IdentityDisc:disabled"/> @@ -73131,9 +73204,25 @@ <int value="1" label="Negative: User rejected the dialog"/> <int value="2" label="Dismissed: User dismissed the dialog, either tapped outside of - it or hit the back button"/> - <int value="3" label="Activity was destroyed before user could respond"/> - <int value="4" label="Dialog view no longer attached to window"/> + it or hit the back button [Dialog]"/> + <int value="3" + label="Activity was destroyed before user could respond [Dialog]"/> + <int value="4" label="Dialog view no longer attached to window [Dialog]"/> + <int value="5" + label="Dismissed: Back was pressed on bottom sheet [Bottom Sheet]"/> + <int value="6" + label="Dismissed: Bottom sheet was swiped away [Bottom Sheet]"/> + <int value="7" + label="Dismissed: Bottom sheet scrim was tapped [Bottom Sheet]"/> + <int value="8" label="Failed to open bottom sheet [Bottom Sheet]"/> + <int value="9" + label="Bottom sheet was destroyed before user could respond [Bottom + Sheet]"/> + <int value="10" + label="Dismissed: Bottom sheet closed, reason unknown [Bottom Sheet]"/> + <int value="11" + label="Dismissed: Bottom sheet destroyed before it could be opened + [Bottom Sheet]"/> </enum> <enum name="NotificationSchedulerActionButtonEvent"> @@ -81907,6 +81996,18 @@ <int value="3" label="parse proto failed"/> </enum> +<enum name="PreloadingTriggeringOutcome"> + <int value="0" label="Unspecified"/> + <int value="2" label="Duplicate"/> + <int value="3" label="Running"/> + <int value="4" label="Ready"/> + <int value="5" label="Success"/> + <int value="6" label="Failure"/> + <int value="7" label="TriggeredButOutcomeUnknown"/> + <int value="8" label="TriggeredButUpgradedToPrerender"/> + <int value="9" label="TriggeredButPending"/> +</enum> + <enum name="PreloadPagesState"> <int value="0" label="No preloading"/> <int value="1" label="Standard preloading"/> @@ -84118,6 +84219,11 @@ <int value="1" label="PriorityChanged"/> </enum> +<enum name="PrivacyHubLearnMoreSensor"> + <int value="0" label="Microphone"/> + <int value="1" label="Camera"/> +</enum> + <enum name="PrivacyHubNavigationOrigin"> <int value="0" label="System settings"/> <int value="1" label="Notification"/> @@ -84206,7 +84312,7 @@ <enum name="PrivacySandboxPrivateAggregationHostSendHistogramReportResult"> <int value="0" label="Success"/> <int value="1" label="API disabled in settings"/> - <int value="2" label="Too many contributions"/> + <int value="2" label="Success but truncated due to too many contributions"/> <int value="3" label="Debug key present but debug mode not enabled"/> <int value="4" label="Report request creation failed"/> </enum> @@ -106317,6 +106423,8 @@ <int value="26" label="UpdateTaskFailed"/> <int value="27" label="AppNotInRegistrarAfterCommit"/> <int value="28" label="HaltedBySyncUninstall"/> + <int value="29" label="kInstallURLInvalid"/> + <int value="30" label="kIconDownloadingFailed"/> </enum> <enum name="WebAppInstallSource">
diff --git a/tools/metrics/histograms/histograms_index.txt b/tools/metrics/histograms/histograms_index.txt index bdbf7bed..e6c0f03 100644 --- a/tools/metrics/histograms/histograms_index.txt +++ b/tools/metrics/histograms/histograms_index.txt
@@ -99,6 +99,7 @@ tools/metrics/histograms/metadata/plugin_vm/histograms.xml tools/metrics/histograms/metadata/power/histograms.xml tools/metrics/histograms/metadata/prefetch/histograms.xml +tools/metrics/histograms/metadata/preloading/histograms.xml tools/metrics/histograms/metadata/print/histograms.xml tools/metrics/histograms/metadata/printing/histograms.xml tools/metrics/histograms/metadata/privacy/histograms.xml
diff --git a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS index d38a800..98572cab 100644 --- a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS +++ b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
@@ -290,6 +290,9 @@ spelchat@chromium.org tbansal@chromium.org toyoshim@chromium.org +# preloading +curranmax@chromium.org +spelchat@chromium.org # printing awscreen@chromium.org jimmyxgong@chromium.org
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index e9801d3..f1d2e6a9 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1159,7 +1159,7 @@ </histogram> <histogram name="Ash.CaptureModeController.NumberOfConnectedCameras" - units="connected cameras" expires_after="2023-05-20"> + units="connected cameras" expires_after="2023-07-23"> <owner>conniekxu@chromium.org</owner> <owner>gzadina@google.com</owner> <summary> @@ -1520,7 +1520,7 @@ </histogram> <histogram name="Ash.Desks.BentoBarIsVisible" enum="Boolean" - expires_after="2023-05-19"> + expires_after="2023-07-23"> <owner>minch@chromium.org</owner> <owner>janetmac@chromium.org</owner> <summary> @@ -1735,7 +1735,7 @@ </histogram> <histogram name="Ash.Desks.NumberOfWindowsClosed2" units="units" - expires_after="2023-05-09"> + expires_after="2023-07-23"> <owner>aprilzhou@google.com</owner> <owner>janetmac@chromium.org</owner> <summary> @@ -2246,7 +2246,7 @@ </histogram> <histogram name="Ash.DeviceActiveClient.PreservedFileState" - enum="DeviceActiveClientPreservedFileState" expires_after="2023-05-19"> + enum="DeviceActiveClientPreservedFileState" expires_after="2023-07-23"> <owner>hirthanan@google.com</owner> <owner>chromeos-data-team@google.com</owner> <summary> @@ -2294,7 +2294,7 @@ </histogram> <histogram name="Ash.DeviceActiveClient.SavePreservedFileSuccess" - enum="BooleanSuccess" expires_after="2023-05-19"> + enum="BooleanSuccess" expires_after="2023-07-23"> <owner>hirthanan@google.com</owner> <owner>chromeos-data-team@google.com</owner> <summary> @@ -3087,6 +3087,36 @@ </summary> </histogram> +<histogram name="Ash.MultiDisplay.WindowsMovedAfterRemap.DisplayRotated" + units="Boolean" expires_after="2024-01-20"> + <owner>sammiequon@chromium.org</owner> + <owner>yunchengs@google.com</owner> + <owner>chromeos-wm-corexp@google.com</owner> + <summary> + After a display rotation, the existing app windows will get remapped. A one + minute timer then runs. If any of the app windows are moved or resized by + the user, then this histogram records true. If the timer ends without an app + window being moved or resized, then this histogram records false. Used to + determine if the user is satisfied with the window manager auto remap. + </summary> +</histogram> + +<histogram + name="Ash.MultiDisplay.WindowsMovedAfterRemap.DisplayWorkAreaChanged" + units="Boolean" expires_after="2024-01-20"> + <owner>sammiequon@chromium.org</owner> + <owner>yunchengs@google.com</owner> + <owner>chromeos-wm-corexp@google.com</owner> + <summary> + After a display work area change, the existing app windows will get + remapped. A one minute timer then runs. If any of the app windows are moved + or resized by the user, then this histogram records true. If the timer ends + without an app window being moved or resized, then this histogram records + false. Used to determine if the user is satisfied with the window manager + auto remap. + </summary> +</histogram> + <histogram name="Ash.NavigationWidget.AnimationSmoothness{HotseatTransitionType}" units="%" expires_after="2023-04-20"> @@ -3624,7 +3654,7 @@ </histogram> <histogram name="Ash.Overview.EndAction" enum="OverviewEndAction" - expires_after="2023-05-19"> + expires_after="2023-07-23"> <owner>minch@chromium.org</owner> <owner>janetmac@chromium.org</owner> <summary> @@ -3697,7 +3727,7 @@ </histogram> <histogram name="Ash.Overview.StartAction" enum="OverviewStartAction" - expires_after="2023-05-19"> + expires_after="2023-07-23"> <owner>minch@chromium.org</owner> <owner>janetmac@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/assistant/histograms.xml b/tools/metrics/histograms/metadata/assistant/histograms.xml index 4ad932b2..55ad3db 100644 --- a/tools/metrics/histograms/metadata/assistant/histograms.xml +++ b/tools/metrics/histograms/metadata/assistant/histograms.xml
@@ -53,7 +53,7 @@ </histogram> <histogram name="Assistant.ContextEnabledUserCount" enum="BooleanEnabled" - expires_after="2023-03-21"> + expires_after="2023-07-23"> <owner>updowndota@chromium.org</owner> <owner>xiaohuic@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml index 7438290..be732e8 100644 --- a/tools/metrics/histograms/metadata/autofill/histograms.xml +++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -2960,9 +2960,9 @@ </histogram> <histogram name="Autofill.PopupHidingReason" enum="AutofillPopupHidingReason" - expires_after="2023-03-05"> - <owner>mamir@google.com</owner> + expires_after="2023-09-05"> <owner>koerber@google.com</owner> + <owner>mamir@chromium.org</owner> <summary> This tracks the reasons for which the Autofill popup disappers or cannot be displayed. Recorded everytime an Autofill popup disappears or cannot be @@ -3933,6 +3933,24 @@ </token> </histogram> +<histogram + name="Autofill.TouchToFill.CreditCard.AutofillUsedAfterTouchToFillDismissal" + enum="Boolean" expires_after="2023-06-01"> + <owner>atsvirhckova@google.com</owner> + <owner>izuzic@google.com</owner> + <owner>chrome-autofill-team@google.com</owner> + <summary> + Records whether a user has still used autofill after dismissing the payments + bottom sheet. There is a fallback to still allow the user to autofill the + form after dismissing the bottom sheet, that is to use the keyboard + accessory suggestion. This metric is recorded when submitting the form: true + - if there is at least one autofilled field in the submitted form and the + payments bottom sheet was shown and dismissed by user, false - otherwise. + The metrics is recorded only if the payments bottom sheet was displayed for + the form submitted. + </summary> +</histogram> + <histogram name="Autofill.TouchToFill.CreditCard.NumberOfCardsShown" units="cards" expires_after="2023-06-01"> <owner>atsvirhckova@google.com</owner> @@ -4040,7 +4058,7 @@ </histogram> <histogram name="Autofill.UnmaskPrompt.GetRealPanDuration" units="ms" - expires_after="2023-07-16"> + expires_after="2023-07-23"> <owner>jsaul@google.com</owner> <owner>siyua@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml index 9e48109..8e634cd 100644 --- a/tools/metrics/histograms/metadata/blink/histograms.xml +++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -888,18 +888,6 @@ </summary> </histogram> -<histogram name="Blink.EventPath.CalculateTime" units="microseconds" - expires_after="2023-06-11"> - <owner>dizhangg@chromium.org</owner> - <owner>dom-dev@chromium.org</owner> - <summary> - Time spent creating the event path in the Blink document lifecycle. Records - each time an EventPath gets calculated. - - Note: Not recorded on ~5% of Windows machines with low-resolution clocks. - </summary> -</histogram> - <histogram name="Blink.Experimental.Cookies.CacheLookupResult2" enum="CookieCacheLookupResult" expires_after="2023-07-09"> <owner>carlscab@google.com</owner> @@ -935,7 +923,7 @@ </histogram> <histogram name="Blink.FedCm.CancelReason" enum="FedCmCancelReason" - expires_after="2023-03-12"> + expires_after="2023-07-23"> <owner>pkotwicz@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary> @@ -2671,7 +2659,7 @@ </histogram> <histogram name="Blink.Sms.Receive.CrossDeviceFailure" - enum="WebOTPCrossDeviceFailure" expires_after="2023-05-07"> + enum="WebOTPCrossDeviceFailure" expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary> @@ -2681,7 +2669,7 @@ </histogram> <histogram name="Blink.Sms.Receive.Infobar" enum="WebOTPServiceInfobarAction" - expires_after="2023-03-05"> + expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>goto@chromium.org</owner> <owner>web-identity-eng@google.com</owner> @@ -2712,7 +2700,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeCancel" units="ms" - expires_after="2023-03-05"> + expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>goto@chromium.org</owner> <owner>web-identity-eng@google.com</owner> @@ -2723,7 +2711,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeCancelOnKeyboardDismissal" units="ms" - expires_after="2023-03-05"> + expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>goto@chromium.org</owner> <owner>web-identity-eng@google.com</owner> @@ -2734,7 +2722,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeCancelOnSuccess" units="ms" - expires_after="2023-03-05"> + expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>goto@chromium.org</owner> <owner>web-identity-eng@google.com</owner> @@ -2745,7 +2733,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeContinueOnSuccess" units="ms" - expires_after="2023-03-05"> + expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>goto@chromium.org</owner> <owner>web-identity-eng@google.com</owner> @@ -2756,7 +2744,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeSmsReceive" units="ms" - expires_after="2023-03-05"> + expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>goto@chromium.org</owner> <owner>web-identity-eng@google.com</owner> @@ -2779,7 +2767,7 @@ </histogram> <histogram name="Blink.Sms.Receive.TimeUserCancel" units="ms" - expires_after="2023-03-05"> + expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>goto@chromium.org</owner> <owner>web-identity-eng@google.com</owner> @@ -2791,7 +2779,7 @@ </histogram> <histogram name="Blink.Sms.WebContentsVisibleOnReceive" enum="Boolean" - expires_after="2023-03-05"> + expires_after="2023-07-09"> <owner>yigu@chromium.org</owner> <owner>web-identity-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/bookmarks/histograms.xml b/tools/metrics/histograms/metadata/bookmarks/histograms.xml index 1468800..06c8a042 100644 --- a/tools/metrics/histograms/metadata/bookmarks/histograms.xml +++ b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
@@ -1009,6 +1009,39 @@ </summary> </histogram> +<histogram name="Bookmarks.Utilization.OnProfileLoad.PercentageUsed" + units="Percentage (0-100)" expires_after="2023-07-09"> + <owner>wylieb@chromium.org</owner> + <owner>chrome-collections@google.com</owner> + <component>UI>Browser>Bookmarks</component> + <summary> + The percentage of bookmarks which have been used expressed as 0-100. + Recorded on profile load. + </summary> +</histogram> + +<histogram name="Bookmarks.Utilization.OnProfileLoad.TotalUnused" + units="Bookmarks" expires_after="2023-07-09"> + <owner>wylieb@chromium.org</owner> + <owner>chrome-collections@google.com</owner> + <component>UI>Browser>Bookmarks</component> + <summary> + The total number of bookmarks that haven't been opened. Recorded on profile + load. + </summary> +</histogram> + +<histogram name="Bookmarks.Utilization.OnProfileLoad.TotalUsed" + units="Bookmarks" expires_after="2023-07-09"> + <owner>wylieb@chromium.org</owner> + <owner>chrome-collections@google.com</owner> + <component>UI>Browser>Bookmarks</component> + <summary> + The total number of bookmarks that have been opened. Recorded on profile + load. + </summary> +</histogram> + <histogram name="PowerBookmarks.BookmarkManager.PriceTrackingEnabled" enum="PriceTrackingState" expires_after="2023-10-24"> <owner>wylieb@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/borealis/histograms.xml b/tools/metrics/histograms/metadata/borealis/histograms.xml index c62b737..c7a60b5c 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.Disk.HighestDirtyPagesDaily" units="KiB" - expires_after="2023-10-01"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -33,7 +33,7 @@ </histogram> <histogram name="Borealis.Disk.InodeRatioAtStartup" units="KiB" - expires_after="2023-10-01"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -43,35 +43,35 @@ </histogram> <histogram name="Borealis.Disk.StatefulReadsDaily" units="KiB" - expires_after="2023-07-09"> + expires_after="2023-10-09"> <owner>philpearson@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary>Borealis stateful KiB read per day. Reported daily.</summary> </histogram> <histogram name="Borealis.Disk.StatefulWritesDaily" units="KiB" - expires_after="2023-07-09"> + expires_after="2023-10-09"> <owner>philpearson@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary>Borealis stateful KiB written per day. Reported daily.</summary> </histogram> <histogram name="Borealis.Disk.SwapReadsDaily" units="KiB" - expires_after="2023-07-09"> + expires_after="2023-10-09"> <owner>philpearson@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary>Borealis swap file KiB read per day. Reported daily.</summary> </histogram> <histogram name="Borealis.Disk.SwapWritesDaily" units="KiB" - expires_after="2023-07-09"> + expires_after="2023-10-09"> <owner>philpearson@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary>Borealis swap file KiB written per day. Reported daily.</summary> </histogram> <histogram name="Borealis.Disk.VMUsageToTotalSpacePercentageAtStartup" - units="%" expires_after="2023-10-01"> + units="%" expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -82,7 +82,7 @@ </histogram> <histogram name="Borealis.Disk.VMUsageToTotalUsagePercentageAtStartup" - units="%" expires_after="2023-10-01"> + units="%" expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -93,7 +93,7 @@ </histogram> <histogram name="Borealis.EngagementTime.{Variant}" units="ms" - expires_after="2023-02-01"> + expires_after="2023-10-09"> <owner>lqu@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -118,7 +118,7 @@ </histogram> <histogram name="Borealis.Install.NumAttempts" enum="BooleanAttempted" - expires_after="2023-02-01"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -131,7 +131,7 @@ </histogram> <histogram name="Borealis.Install.OverallTime" units="ms" - expires_after="2023-02-01"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -144,7 +144,7 @@ </histogram> <histogram name="Borealis.Install.Result" enum="BorealisInstallResult" - expires_after="2023-06-11"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -167,7 +167,7 @@ </histogram> <histogram name="Borealis.Shutdown.Attempt" enum="BooleanAttempted" - expires_after="2023-02-01"> + expires_after="2023-10-09"> <owner>lqu@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -177,7 +177,7 @@ </histogram> <histogram name="Borealis.Stability" enum="GuestOsFailureClasses" - expires_after="2023-06-11"> + expires_after="2023-10-09"> <owner>cpelling@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -188,7 +188,7 @@ </histogram> <histogram name="Borealis.Startup.fsckResult" enum="BorealisStartupFsckResult" - expires_after="2023-10-01"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -198,7 +198,7 @@ </histogram> <histogram name="Borealis.Startup.fsckTime" units="ms" - expires_after="2023-10-01"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -208,14 +208,14 @@ </histogram> <histogram name="Borealis.Startup.NumAttempts" enum="BooleanAttempted" - expires_after="2023-06-11"> + expires_after="2023-10-09"> <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="2023-06-11"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary> @@ -225,7 +225,7 @@ </histogram> <histogram name="Borealis.Startup.Result" enum="BorealisStartupResult" - expires_after="2023-06-11"> + expires_after="2023-10-09"> <owner>danielng@google.com</owner> <owner>src/chrome/browser/ash/borealis/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml index 03fa35ce..8ec01d9 100644 --- a/tools/metrics/histograms/metadata/browser/histograms.xml +++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -585,7 +585,7 @@ </histogram> <histogram name="Browser.Tabs.TabSwitchResult2{TabSwitchingType}" - enum="TabSwitchResult" expires_after="2023-01-26"> + enum="TabSwitchResult" expires_after="2024-01-26"> <owner>fdoray@chromium.org</owner> <owner>joenotcharles@google.com</owner> <owner>catan-team@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml index add1976..6eb77b18 100644 --- a/tools/metrics/histograms/metadata/chromeos/histograms.xml +++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1417,7 +1417,7 @@ </histogram> <histogram name="ChromeOS.Intents.LinkCapturingEvent2" - enum="LinkCapturingEvent" expires_after="2023-07-16"> + enum="LinkCapturingEvent" expires_after="2023-07-23"> <owner>vpao@google.com</owner> <owner>chromeos-apps-foundation-team@google.com</owner> <summary> @@ -1481,7 +1481,7 @@ </histogram> <histogram name="ChromeOS.KeyPermissionsManager.Migration" - enum="KeyPermissionsManagerMigrationStatus" expires_after="2023-03-19"> + enum="KeyPermissionsManagerMigrationStatus" expires_after="2023-07-23"> <owner>omorsi@google.com</owner> <owner>pmarko@google.com</owner> <summary> @@ -1553,7 +1553,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.GetPackState.LanguageCode" - enum="LanguagePackLanguageCodes" expires_after="2023-06-04"> + enum="LanguagePackLanguageCodes" expires_after="2023-07-01"> <owner>claudiomagni@chromium.org</owner> <owner>mlcui@google.com</owner> <owner>dvallet@chromium.org</owner> @@ -1564,7 +1564,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.InstallBasePack.FeatureId" - enum="LanguagePackFeatureIds" expires_after="2023-06-04"> + enum="LanguagePackFeatureIds" expires_after="2023-07-01"> <owner>claudiomagni@chromium.org</owner> <owner>mlcui@google.com</owner> <owner>dvallet@chromium.org</owner> @@ -1575,7 +1575,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.InstallComplete.Success" - enum="BooleanSuccess" expires_after="2023-06-04"> + enum="BooleanSuccess" expires_after="2023-07-01"> <owner>claudiomagni@chromium.org</owner> <owner>mlcui@google.com</owner> <owner>dvallet@chromium.org</owner> @@ -1586,7 +1586,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.Mojo.BasePackStateResponse" - enum="LanguagePackMojoPackState" expires_after="2023-01-30"> + enum="LanguagePackMojoPackState" expires_after="2023-07-01"> <owner>mlcui@google.com</owner> <owner>cros-borders-eng@google.com</owner> <summary> @@ -1596,7 +1596,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.Mojo.GetPackInfo.Feature" - enum="LanguagePackMojoFeatureId" expires_after="2023-06-04"> + enum="LanguagePackMojoFeatureId" expires_after="2023-07-01"> <owner>mlcui@google.com</owner> <owner>cros-borders-eng@google.com</owner> <summary> @@ -1606,7 +1606,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.Mojo.InstallBasePack.Feature" - enum="LanguagePackMojoFeatureId" expires_after="2023-01-30"> + enum="LanguagePackMojoFeatureId" expires_after="2023-07-01"> <owner>mlcui@google.com</owner> <owner>cros-borders-eng@google.com</owner> <summary> @@ -1616,7 +1616,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.Mojo.InstallPack.Feature" - enum="LanguagePackMojoFeatureId" expires_after="2023-01-30"> + enum="LanguagePackMojoFeatureId" expires_after="2023-07-01"> <owner>mlcui@google.com</owner> <owner>cros-borders-eng@google.com</owner> <summary> @@ -1626,7 +1626,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.Mojo.PackStateResponse" - enum="LanguagePackMojoPackState" expires_after="2023-06-11"> + enum="LanguagePackMojoPackState" expires_after="2023-07-01"> <owner>mlcui@google.com</owner> <owner>cros-borders-eng@google.com</owner> <summary> @@ -1636,7 +1636,7 @@ </histogram> <histogram name="ChromeOS.LanguagePacks.UninstallComplete.Success" - enum="BooleanSuccess" expires_after="2023-01-30"> + enum="BooleanSuccess" expires_after="2023-07-01"> <owner>claudiomagni@chromium.org</owner> <owner>mlcui@google.com</owner> <owner>dvallet@chromium.org</owner> @@ -1862,6 +1862,22 @@ </summary> </histogram> +<histogram name="ChromeOS.PrivacyHub.LearnMorePage.Opened" + enum="PrivacyHubLearnMoreSensor" expires_after="2024-01-16"> + <owner>cschlosser@chromium.org</owner> + <owner>chromeos-privacyhub@google.com</owner> + <summary> + PrivacyHub is a chrome://os-settings page that allows system wide control of + privacy settings. The Privacy Hub effort adds additional context to already + existing notifications for microphones and cameras in case there is a + physical switch on the device to disable one of these sensors. Prior there + was only the notification message informing the user about the current state + of the system. The notifciations now include a link to a support page where + this is explained in more detail. This histogram records which sensor being + disabled resulted in the notification button being clicked. + </summary> +</histogram> + <histogram name="ChromeOS.PrivacyHub.Opened" enum="PrivacyHubNavigationOrigin" expires_after="2023-09-01"> <owner>zauri@google.com</owner> @@ -2012,7 +2028,7 @@ </histogram> <histogram name="ChromeOS.Secagentd.Policy" enum="SecagentdPolicy" - expires_after="2023-05-18"> + expires_after="2023-07-23"> <owner>aashay@google.com</owner> <owner>cros-enterprise-security@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml index 8771eb3..5c6e385 100644 --- a/tools/metrics/histograms/metadata/content/histograms.xml +++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -861,7 +861,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ActivityLoggingEnabled" enum="Boolean" - expires_after="2023-03-01"> + expires_after="2023-07-23"> <owner>rogerm@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1009,7 +1009,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ContentLifetime.InvalidAge" units="ms" - expires_after="2023-07-02"> + expires_after="2023-07-19"> <owner>birnie@google.com</owner> <owner>feed@chromium.org</owner> <summary> @@ -1020,7 +1020,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ContentLifetime.InvalidAgeIsPresent" - enum="Boolean" expires_after="2023-03-01"> + enum="Boolean" expires_after="2023-07-19"> <owner>birnie@google.com</owner> <owner>feed@chromium.org</owner> <summary> @@ -1032,7 +1032,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ContentLifetime.StaleAge" units="ms" - expires_after="2023-06-18"> + expires_after="2023-07-19"> <owner>birnie@google.com</owner> <owner>feed@chromium.org</owner> <summary> @@ -1043,7 +1043,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ContentLifetime.StaleAgeIsPresent" - enum="Boolean" expires_after="2023-03-01"> + enum="Boolean" expires_after="2023-07-19"> <owner>birnie@google.com</owner> <owner>feed@chromium.org</owner> <summary> @@ -1126,7 +1126,7 @@ <histogram name="ContentSuggestions.Feed.Network.CompressedResponseSizeKB{NetworkRequestType}" - units="KB" expires_after="2023-03-01"> + units="KB" expires_after="2023-07-23"> <owner>carlosk@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1141,7 +1141,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.Network.Duration{NetworkEvent}" - units="ms" expires_after="2023-03-01"> + units="ms" expires_after="2023-07-23"> <owner>sczs@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1171,7 +1171,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.Network.RequestStatusCode" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-03-01"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-07-23"> <owner>carlosk@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1183,7 +1183,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.Network.ResponseSizeKB" units="KB" - expires_after="2023-07-02"> + expires_after="2023-07-23"> <owner>carlosk@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1194,7 +1194,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.Network.ResponseStatus{Type}" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-03-01"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-07-23"> <owner>carlosk@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1205,7 +1205,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.Network.TokenFetchStatus" - enum="GoogleServiceAuthError" expires_after="2023-07-09"> + enum="GoogleServiceAuthError" expires_after="2023-07-23"> <owner>carlosk@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1292,7 +1292,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.RefreshTrigger" - enum="FeedRefreshTrigger" expires_after="2023-03-18"> + enum="FeedRefreshTrigger" expires_after="2023-07-23"> <owner>edchin@google.com</owner> <owner>sczs@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1379,7 +1379,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.SendFeedback" - enum="FeedSendFeedbackType" expires_after="2023-03-01"> + enum="FeedSendFeedbackType" expires_after="2023-07-23"> <owner>carlosk@chromium.org</owner> <owner>petewil@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1398,7 +1398,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.SessionDuration" units="ms" - expires_after="2023-06-25"> + expires_after="2023-07-23"> <owner>edchin@google.com</owner> <owner>sczs@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1436,7 +1436,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.TimeBetweenInteractions" units="ms" - expires_after="2023-06-25"> + expires_after="2023-07-23"> <owner>edchin@google.com</owner> <owner>sczs@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1446,7 +1446,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.TimeBetweenSessions" units="ms" - expires_after="2023-06-25"> + expires_after="2023-07-23"> <owner>edchin@google.com</owner> <owner>sczs@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1458,7 +1458,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.TimeSpentInFeed" units="ms" - expires_after="2023-07-02"> + expires_after="2023-07-23"> <owner>carlosk@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1534,7 +1534,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UploadActionsBatchStatus" - enum="FeedUploadActionsBatchStatus" expires_after="2023-04-30"> + enum="FeedUploadActionsBatchStatus" expires_after="2023-07-23"> <owner>iwells@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1544,7 +1544,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UploadActionsStatus" - enum="FeedUploadActionsStatus" expires_after="2023-07-02"> + enum="FeedUploadActionsStatus" expires_after="2023-07-23"> <owner>iwells@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1556,7 +1556,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UploadVisibilityLog" enum="Boolean" - expires_after="2023-07-09"> + expires_after="2023-07-23"> <owner>freedjm@google.com</owner> <owner>feed@chromium.org</owner> <summary> @@ -1565,7 +1565,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UploadVisibilityLog.{LogType}" - enum="Boolean" expires_after="2023-03-01"> + enum="Boolean" expires_after="2023-07-23"> <owner>freedjm@google.com</owner> <owner>feed@chromium.org</owner> <summary> @@ -1578,7 +1578,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UserActions" enum="FeedUserActionType" - expires_after="2023-07-02"> + expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1589,7 +1589,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UserActions.Commands" - enum="FeedUserCommandType" expires_after="2023-07-16"> + enum="FeedUserCommandType" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>sczs@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1601,7 +1601,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UserJourney.GetMore.FailureDuration" - units="ms" expires_after="2023-07-09"> + units="ms" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1612,7 +1612,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UserJourney.GetMore.SuccessDuration" - units="ms" expires_after="2023-07-09"> + units="ms" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1624,7 +1624,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UserJourney.{Surface}.Failure" - enum="Boolean" expires_after="2023-03-01"> + enum="Boolean" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1639,7 +1639,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UserJourney.{Surface}.SuccessDuration" - units="ms" expires_after="2023-03-01"> + units="ms" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1655,7 +1655,7 @@ <histogram name="ContentSuggestions.Feed.UserJourney.{Surface}.{Status}Duration" - units="ms" expires_after="2023-03-01"> + units="ms" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1678,7 +1678,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.UserSettingsOnStart" - enum="FeedUserSettingsOnStart" expires_after="2023-07-02"> + enum="FeedUserSettingsOnStart" expires_after="2023-07-23"> <owner>carlosk@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1690,7 +1690,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ViewedCardCountAtManualRefresh" - units="count" expires_after="2023-06-04"> + units="count" expires_after="2023-07-23"> <owner>jianli@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1702,7 +1702,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.ViewedCardPercentageAtManualRefresh" - units="%" expires_after="2023-06-04"> + units="%" expires_after="2023-07-23"> <owner>jianli@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1715,7 +1715,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.VisibilityLoggingEnabled" - enum="Boolean" expires_after="2023-07-02"> + enum="Boolean" expires_after="2023-07-23"> <owner>freedjm@google.com</owner> <owner>feed@chromium.org</owner> <summary> @@ -1725,7 +1725,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.VisitDuration" units="ms" - expires_after="2023-07-16"> + expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>freedjm@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1742,7 +1742,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.FollowByIdResult" - enum="WebFeedSubscriptionRequestStatus" expires_after="2023-06-04"> + enum="WebFeedSubscriptionRequestStatus" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1753,7 +1753,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.FollowCount.Engaged" - units="follows" expires_after="2023-07-09"> + units="follows" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1768,7 +1768,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.FollowCount.{Event}" - units="follows" expires_after="2023-03-01"> + units="follows" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1787,7 +1787,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.FollowUriResult" - enum="WebFeedSubscriptionRequestStatus" expires_after="2023-07-02"> + enum="WebFeedSubscriptionRequestStatus" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1813,7 +1813,7 @@ <histogram name="ContentSuggestions.Feed.WebFeed.LoadedCardCount.{ContentOrder}" - units="index" expires_after="2023-03-01"> + units="index" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1829,7 +1829,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.NewFollow.ChangeReason" - enum="WebFeedChangeReason" expires_after="2023-06-04"> + enum="WebFeedChangeReason" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1842,7 +1842,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.NewFollow.IsRecommended" - enum="Boolean" expires_after="2023-07-02"> + enum="Boolean" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1864,7 +1864,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.PostFollowDialog.Show" - enum="WebFeedPostFollowDialogPresentation" expires_after="2023-03-01"> + enum="WebFeedPostFollowDialogPresentation" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1875,7 +1875,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.RefreshContentOrder" - enum="FeedContentOrder" expires_after="2023-03-01"> + enum="FeedContentOrder" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1886,7 +1886,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.RefreshRecommendedFeeds" - enum="WebFeedRefreshStatus" expires_after="2023-03-01"> + enum="WebFeedRefreshStatus" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1897,7 +1897,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.RefreshSubscribedFeeds.{Kind}" - enum="WebFeedRefreshStatus" expires_after="2023-03-01"> + enum="WebFeedRefreshStatus" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1913,7 +1913,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.SortType" enum="FeedSortType" - expires_after="2023-08-15"> + expires_after="2023-07-23"> <owner>adamta@google.com</owner> <owner>sczs@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1921,7 +1921,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.SortTypeWhenEngaged" - enum="FeedSortType" expires_after="2023-08-15"> + enum="FeedSortType" expires_after="2023-07-23"> <owner>adamta@google.com</owner> <owner>sczs@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -1932,7 +1932,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.WebFeed.UnfollowResult" - enum="WebFeedSubscriptionRequestStatus" expires_after="2023-07-09"> + enum="WebFeedSubscriptionRequestStatus" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -1943,7 +1943,7 @@ </histogram> <histogram name="ContentSuggestions.Feed.{PlayType}Video.InitializationError" - enum="FeedVideoInitializationError" expires_after="2023-01-20"> + enum="FeedVideoInitializationError" expires_after="2023-07-23"> <owner>jianli@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -2033,7 +2033,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.FollowCount.Engaged2" - units="follows" expires_after="2023-03-01"> + units="follows" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -2051,7 +2051,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.InfoCard.{Action}" - enum="FeedInfoCardType" expires_after="2023-05-01"> + enum="FeedInfoCardType" expires_after="2023-07-23"> <owner>jianli@chromium.org</owner> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -2090,7 +2090,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.LoadedCardCount" units="index" - expires_after="2023-03-01"> + expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -2108,7 +2108,7 @@ <histogram name="ContentSuggestions.{FeedType}.LoadMoreTrigger.OffsetFromEndOfStream" - units="cards" expires_after="2023-03-01"> + units="cards" expires_after="2023-07-23"> <owner>rogerm@chromium.org</owner> <owner>dewittj@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -2124,7 +2124,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.LoadMoreTrigger.TotalCards" - units="cards" expires_after="2023-03-01"> + units="cards" expires_after="2023-07-23"> <owner>rogerm@chromium.org</owner> <owner>dewittj@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -2141,7 +2141,7 @@ <histogram name="ContentSuggestions.{FeedType}.LoadStreamStatus.BackgroundRefresh" - enum="FeedLoadStreamStatus" expires_after="2023-03-01"> + enum="FeedLoadStreamStatus" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -2159,7 +2159,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.LoadStreamStatus.Initial" - enum="FeedLoadStreamStatus" expires_after="2023-03-01"> + enum="FeedLoadStreamStatus" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -2176,7 +2176,7 @@ <histogram name="ContentSuggestions.{FeedType}.LoadStreamStatus.InitialFromStore" - enum="FeedLoadStreamStatus" expires_after="2023-03-01"> + enum="FeedLoadStreamStatus" expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>carlosk@chromium.org</owner> <owner>feed@chromium.org</owner> @@ -2194,7 +2194,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.LoadStreamStatus.ManualRefresh" - enum="FeedLoadStreamStatus" expires_after="2023-03-01"> + enum="FeedLoadStreamStatus" expires_after="2023-07-23"> <owner>jianli@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -2290,7 +2290,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.ReachedEndOfFeed" units="index" - expires_after="2023-03-01"> + expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -2309,7 +2309,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.SharedStateSizeKB" units="KB" - expires_after="2023-03-01"> + expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary> @@ -2348,7 +2348,7 @@ </histogram> <histogram name="ContentSuggestions.{FeedType}.StreamContentSizeKB" units="KB" - expires_after="2023-03-01"> + expires_after="2023-07-23"> <owner>harringtond@chromium.org</owner> <owner>feed@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml index 0d753d7..2608d1f 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -22,29 +22,6 @@ <histograms> -<histogram name="CustomTab.HadInteractionOnClose.Form" enum="Boolean" - expires_after="2023-06-19"> - <owner>katzz@google.com</owner> - <owner>chrome-connective-tissue@google.com</owner> - <summary> - This histogram records true when the current CCT has seen any form - interactions (e.g. text entry, drop down entry) and false if there have been - no form interactions at the time of closing the CCT. - </summary> -</histogram> - -<histogram name="CustomTab.HadInteractionOnClose.Navigation" enum="Boolean" - expires_after="2023-06-19"> - <owner>katzz@google.com</owner> - <owner>chrome-connective-tissue@google.com</owner> - <summary> - This histogram records true when the current CCT has interactions with the - web contents (e.g. touch, scroll, fling), and the active tab can go back / - forward and false if there have not been web contents interactions or the - tab cannot go back / forward at the time of closing the CCT. - </summary> -</histogram> - <histogram base="true" name="CustomTab.SessionDuration" units="ms" expires_after="2020-10-18"> <owner>ranj@chromium.org</owner> @@ -295,6 +272,43 @@ </summary> </histogram> +<histogram name="CustomTabs.HadInteractionOnClose.Form" enum="Boolean" + expires_after="2023-06-19"> + <owner>katzz@google.com</owner> + <owner>chrome-connective-tissue@google.com</owner> + <summary> + This histogram records true when the current CCT has seen any form + interactions (e.g. text entry, drop down entry) throughout the session and + false if there have been no form interactions at the time of closing the + CCT. If the tab is restored the previous form interactions will be reset. + </summary> +</histogram> + +<histogram name="CustomTabs.HadInteractionOnClose.FormStillActive" + enum="Boolean" expires_after="2023-07-18"> + <owner>katzz@google.com</owner> + <owner>chrome-connective-tissue@google.com</owner> + <summary> + This histogram records true when the current CCT has seen form interaction + (e.g. text entry, drop down entry) on the active page, and false if there + are no interactions in the active form, or if the interaction is reset (e.g. + navigation, form submission) at the time of closing the CCT. + </summary> +</histogram> + +<histogram name="CustomTabs.HadInteractionOnClose.Navigation" enum="Boolean" + expires_after="2023-06-19"> + <owner>katzz@google.com</owner> + <owner>chrome-connective-tissue@google.com</owner> + <summary> + This histogram records true when the current CCT has interactions with the + web contents (e.g. touch, scroll, fling), and the active tab can go back / + forward and false if there have not been web contents interactions or the + tab cannot go back / forward at the time of closing the CCT. If the tab is + restored the previous form interactions will be reset. + </summary> +</histogram> + <histogram name="CustomTabs.ImmersiveModeConfirmationsSettingConfirmed" enum="Boolean" expires_after="2023-05-14"> <obsolete>
diff --git a/tools/metrics/histograms/metadata/download/histograms.xml b/tools/metrics/histograms/metadata/download/histograms.xml index 9abee1ef..3a146c5 100644 --- a/tools/metrics/histograms/metadata/download/histograms.xml +++ b/tools/metrics/histograms/metadata/download/histograms.xml
@@ -1483,7 +1483,7 @@ </histogram> <histogram name="Download.WarningData.AddWarningActionEventOutcome" - enum="DownloadAddWarningActionEventOutcome" expires_after="2023-05-22"> + enum="DownloadAddWarningActionEventOutcome" expires_after="2023-07-23"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/google/histograms.xml b/tools/metrics/histograms/metadata/google/histograms.xml index c5b1cae..ad8e839 100644 --- a/tools/metrics/histograms/metadata/google/histograms.xml +++ b/tools/metrics/histograms/metadata/google/histograms.xml
@@ -30,12 +30,14 @@ </histogram> <histogram name="GoogleUpdate.InstallDetails.UpdateCohort" units="units" - expires_after="2019-06-01"> - <owner>nikunjb@chromium.org</owner> + expires_after="2024-06-01"> + <owner>waffles@chromium.org</owner> <owner>chrome-metrics-team@google.com</owner> + <owner>omaha-team@google.com</owner> <summary> Store the hash of update cohort name as reported by Chrome Updater on - Windows. Recorded at the start of metrics service. + Windows. Recorded at the start of metrics service. Warning: this histogram + was expired from 2019-06-01 to 2023-01-23; data may be missing. </summary> </histogram>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml index 7d1e717..7b055f18 100644 --- a/tools/metrics/histograms/metadata/gpu/histograms.xml +++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -483,7 +483,7 @@ </histogram> <histogram name="GPU.DirectComposition.CompositionMode2.VideoOrCanvas" - enum="DxgiFramePresentationMode" expires_after="2023-05-22"> + enum="DxgiFramePresentationMode" expires_after="2023-07-23"> <owner>sunnyps@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml index 9c47b84..09cde36 100644 --- a/tools/metrics/histograms/metadata/history/histograms.xml +++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -39,6 +39,17 @@ </summary> </histogram> +<histogram name="History.Backend.TransactionBeginError" + enum="SqliteLoggedResultCode" expires_after="2023-10-01"> + <owner>tommycli@chromium.org</owner> + <owner>asully@chromium.org</owner> + <component>UI>Browser>History</component> + <summary> + The exact database error encountered when beginning a transaction, if it + failed. + </summary> +</histogram> + <histogram name="History.Backend.TransactionBeginSuccess" enum="BooleanSuccess" expires_after="2023-10-01"> <owner>tommycli@chromium.org</owner> @@ -50,6 +61,17 @@ </summary> </histogram> +<histogram name="History.Backend.TransactionCommitError" + enum="SqliteLoggedResultCode" expires_after="2023-10-01"> + <owner>tommycli@chromium.org</owner> + <owner>asully@chromium.org</owner> + <component>UI>Browser>History</component> + <summary> + The exact database error encountered when committing a transaction, if it + failed. + </summary> +</histogram> + <histogram name="History.Backend.TransactionCommitSuccess" enum="BooleanSuccess" expires_after="2023-10-01"> <owner>tommycli@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 4ee9d8d..30eecf5 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -2375,7 +2375,7 @@ </histogram> <histogram name="Media.EME.Widevine.HardwareSecure.Support" - enum="BooleanSupported" expires_after="2023-07-16"> + enum="BooleanSupported" expires_after="2023-07-23"> <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -4766,7 +4766,7 @@ </histogram> <histogram name="Media.Video.Capture.Mac.CameraSystemPermission.Startup" - enum="SystemMediaCapturePermission" expires_after="2023-05-14"> + enum="SystemMediaCapturePermission" expires_after="2023-07-23"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -5964,7 +5964,7 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Session.Length.AccessCode" - units="ms" expires_after="2023-05-14"> + units="ms" expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -6053,7 +6053,7 @@ </histogram> <histogram name="MediaRouter.CastStreaming.Start.Success.AccessCodeManualEntry" - enum="MirrorType" expires_after="2023-05-14"> + enum="MirrorType" expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -6308,7 +6308,7 @@ </histogram> <histogram name="MediaRouter.Sink.SelectedType" enum="MediaSinkType" - expires_after="2023-07-16"> + expires_after="2023-07-23"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary> @@ -6402,7 +6402,7 @@ </histogram> <histogram name="MediaRouter.Ui.Device.Count" units="units" - expires_after="2023-07-16"> + expires_after="2023-07-23"> <owner>takumif@chromium.org</owner> <owner>openscreen-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/memory/histograms.xml b/tools/metrics/histograms/metadata/memory/histograms.xml index 1dd171e..d67ee2a 100644 --- a/tools/metrics/histograms/metadata/memory/histograms.xml +++ b/tools/metrics/histograms/metadata/memory/histograms.xml
@@ -2433,7 +2433,7 @@ </histogram> <histogram name="Memory.RenderProcessHost.Count.OriginAgentClusterOverhead" - units="processes" expires_after="2023-04-16"> + units="processes" expires_after="2023-07-23"> <owner>wjmaclean@chromium.org</owner> <owner>alexmos@chromium.org</owner> <owner>creis@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml index 20d48c71..272038f 100644 --- a/tools/metrics/histograms/metadata/net/histograms.xml +++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -570,7 +570,7 @@ </histogram> <histogram name="Net.ConnectionInfo.SubResource" enum="ConnectionInfo" - expires_after="2023-05-11"> + expires_after="2023-07-23"> <owner>dschinazi@chromium.org</owner> <owner>src/net/OWNERS</owner> <summary> @@ -862,7 +862,8 @@ </summary> </histogram> -<histogram name="Net.DNS.DnsHosts.Count" units="count" expires_after="M113"> +<histogram name="Net.DNS.DnsHosts.Count" units="count" + expires_after="2023-07-23"> <owner>horo@chromium.org</owner> <owner>net-dev@chromium.org</owner> <summary> @@ -872,7 +873,7 @@ </histogram> <histogram name="Net.DNS.DnsHosts.EstimateMemoryUsage" units="bytes" - expires_after="M113"> + expires_after="2023-07-23"> <owner>horo@chromium.org</owner> <owner>net-dev@chromium.org</owner> <summary> @@ -881,7 +882,8 @@ </summary> </histogram> -<histogram name="Net.DNS.DnsHosts.FileSize" units="bytes" expires_after="M113"> +<histogram name="Net.DNS.DnsHosts.FileSize" units="bytes" + expires_after="2023-07-23"> <owner>horo@chromium.org</owner> <owner>net-dev@chromium.org</owner> <summary> @@ -1212,7 +1214,7 @@ </histogram> <histogram name="Net.DNS.JobQueueTime.Failure" units="ms" - expires_after="2023-03-19"> + expires_after="2023-07-23"> <owner>dmcardle@chromium.org</owner> <owner>ericorth@chromium.org</owner> <summary> @@ -1532,7 +1534,7 @@ </histogram> <histogram name="Net.DNS.UpgradeConfig.InsecureUpgradeSucceeded" enum="Boolean" - expires_after="2023-04-23"> + expires_after="2023-07-23"> <owner>ericorth@chromium.org</owner> <owner>doh-core@google.com</owner> <summary> @@ -3769,7 +3771,7 @@ </histogram> <histogram name="Net.QuicSession.ReceivedSettings.BlockedStreams" units="units" - expires_after="2023-05-11"> + expires_after="2023-07-23"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary> @@ -3800,7 +3802,7 @@ </histogram> <histogram name="Net.QuicSession.ReceivedSettings.MaxHeaderListSize2" - units="bytes" expires_after="2023-05-11"> + units="bytes" expires_after="2023-07-23"> <owner>dschinazi@chromium.org</owner> <owner>src/net/quic/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml index 24e0dda..0a32e90 100644 --- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml +++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -1937,7 +1937,7 @@ </histogram> <histogram name="NewTabPage.TileTitleClicked" enum="NTPTileTitleSource" - expires_after="2023-04-23"> + expires_after="2023-07-23"> <owner>danielms@google.com</owner> <owner>tiborg@chromium.org</owner> <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml index b2d2e1e..c62714e 100644 --- a/tools/metrics/histograms/metadata/omnibox/histograms.xml +++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -1505,7 +1505,7 @@ </histogram> <histogram name="Omnibox.SelectedPosition" units="position" - expires_after="2023-07-16"> + expires_after="2023-07-23"> <owner>jdonnelly@chromium.org</owner> <owner>mpearson@chromium.org</owner> <owner>chrome-omnibox-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index e549d1f3..774c8f4 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -212,7 +212,7 @@ </variants> <histogram name="AccessCodeCast.Discovery.AddSinkResult.New" - enum="AccessCodeCastAddSinkResult" expires_after="2023-05-14"> + enum="AccessCodeCastAddSinkResult" expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -235,7 +235,7 @@ </histogram> <histogram name="AccessCodeCast.Discovery.CastModeOnSuccess" - enum="AccessCodeCastCastMode" expires_after="2023-05-14"> + enum="AccessCodeCastCastMode" expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -279,7 +279,7 @@ </histogram> <histogram name="AccessCodeCast.Ui.AccessCodeInputTime" units="ms" - expires_after="2023-05-14"> + expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -291,7 +291,7 @@ </histogram> <histogram name="AccessCodeCast.Ui.AccessCodeNotFoundCount" units="instances" - expires_after="2023-03-12"> + expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -303,7 +303,7 @@ </histogram> <histogram name="AccessCodeCast.Ui.CastAttemptLength" units="ms" - expires_after="2023-05-14"> + expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -315,7 +315,7 @@ </histogram> <histogram name="AccessCodeCast.Ui.DialogCloseReason" - enum="AccessCodeCastDialogCloseReason" expires_after="2023-05-14"> + enum="AccessCodeCastDialogCloseReason" expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -325,7 +325,7 @@ </histogram> <histogram name="AccessCodeCast.Ui.DialogLoadTime" units="ms" - expires_after="2023-05-14"> + expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -336,7 +336,7 @@ </histogram> <histogram name="AccessCodeCast.Ui.DialogOpenLocation" - enum="AccessCodeCastDialogOpenLocation" expires_after="2023-05-14"> + enum="AccessCodeCastDialogOpenLocation" expires_after="2023-07-23"> <owner>bzielinski@google.com</owner> <owner>cros-edu-eng@google.com</owner> <summary> @@ -10087,18 +10087,6 @@ </summary> </histogram> -<histogram name="Preloading.AnchorElementPreloader.PreloadingTriggered" - enum="AnchorElementPreloaderType" expires_after="2023-06-04"> - <owner>jacobstanley@google.com</owner> - <owner>spelchat@chromium.org</owner> - <owner>curranmax@chromium.org</owner> - <owner>chrome-brapp-loading@google.com</owner> - <summary> - Logged once for each preconnection request sent to the browser. Associated - with the Source ID of the page triggering the preconnection. - </summary> -</histogram> - <histogram name="Previews.CacheControlNoTransform.BlockedPreview" enum="PreviewsType" expires_after="2021-08-09"> <obsolete>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml index 974fcf7..4c0026ed 100644 --- a/tools/metrics/histograms/metadata/password/histograms.xml +++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -794,7 +794,7 @@ </histogram> <histogram name="PasswordManager.ApplySyncChanges.AddLoginSyncError" - enum="PasswordAddLoginSyncError" expires_after="2023-03-05"> + enum="PasswordAddLoginSyncError" expires_after="2023-09-05"> <owner>mamir@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -805,7 +805,7 @@ </histogram> <histogram name="PasswordManager.ApplySyncChanges.UpdateLoginSyncError" - enum="PasswordUpdateLoginSyncError" expires_after="2023-03-05"> + enum="PasswordUpdateLoginSyncError" expires_after="2023-09-05"> <owner>mamir@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -817,7 +817,7 @@ </histogram> <histogram name="PasswordManager.ApplySyncChangesState" - enum="PasswordApplySyncChangesState" expires_after="2023-03-05"> + enum="PasswordApplySyncChangesState" expires_after="2023-09-05"> <owner>mamir@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -1367,7 +1367,7 @@ </histogram> <histogram name="PasswordManager.DefaultPasswordStoreSet" - enum="PasswordManager.Store" expires_after="2023-04-23"> + enum="PasswordManager.Store" expires_after="2023-07-23"> <owner>mamir@chromium.org</owner> <owner>treib@chromium.org</owner> <summary> @@ -2025,7 +2025,7 @@ </histogram> <histogram name="PasswordManager.MergeSyncData.AddLoginSyncError" - enum="PasswordAddLoginSyncError" expires_after="2023-03-19"> + enum="PasswordAddLoginSyncError" expires_after="2023-07-23"> <owner>mamir@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -2036,7 +2036,7 @@ </histogram> <histogram name="PasswordManager.MergeSyncData.UpdateLoginSyncError" - enum="PasswordUpdateLoginSyncError" expires_after="2023-03-19"> + enum="PasswordUpdateLoginSyncError" expires_after="2023-07-23"> <owner>mamir@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -3152,7 +3152,7 @@ </histogram> <histogram name="PasswordManager.SavingOnUsernameFirstFlow" - enum="SavingOnUsernameFirstFlow" expires_after="2023-03-19"> + enum="SavingOnUsernameFirstFlow" expires_after="2023-07-23"> <owner>kazinova@google.com</owner> <owner>vasilii@chromium.org</owner> <summary> @@ -3362,7 +3362,7 @@ </histogram> <histogram name="PasswordManager.SyncMetadataReadError2" - enum="PasswordSyncMetadataReadError" expires_after="2023-04-23"> + enum="PasswordSyncMetadataReadError" expires_after="2023-07-23"> <owner>mamir@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml index 9eb1f7e..552f5439 100644 --- a/tools/metrics/histograms/metadata/power/histograms.xml +++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -922,7 +922,7 @@ </histogram> <histogram name="Power.BatteryDischargeRate" units="mW" - expires_after="2023-07-16"> + expires_after="2023-07-23"> <owner>puthik@chromium.org</owner> <owner>chromeos-platform-power@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/prefetch/histograms.xml b/tools/metrics/histograms/metadata/prefetch/histograms.xml index 7703fba..e0d54c7 100644 --- a/tools/metrics/histograms/metadata/prefetch/histograms.xml +++ b/tools/metrics/histograms/metadata/prefetch/histograms.xml
@@ -348,7 +348,7 @@ <histogram name="PrefetchProxy.Prefetch.NumExistingEligiblePrefetchWithMatchingURL" - units="count" expires_after="2023-04-25"> + units="count" expires_after="2023-07-23"> <owner>curranmax@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <owner>spelchat@chromium.org</owner> @@ -374,7 +374,7 @@ <histogram name="PrefetchProxy.Prefetch.NumExistingPrefetchWithMatchingURLAndReferrer" - units="count" expires_after="2023-04-25"> + units="count" expires_after="2023-07-23"> <owner>curranmax@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <owner>spelchat@chromium.org</owner> @@ -388,7 +388,7 @@ <histogram name="PrefetchProxy.Prefetch.NumExistingPrefetchWithMatchingURLAndRenderFrameHost" - units="count" expires_after="2023-04-25"> + units="count" expires_after="2023-07-23"> <owner>curranmax@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <owner>spelchat@chromium.org</owner> @@ -405,7 +405,7 @@ <histogram name="PrefetchProxy.Prefetch.NumExistingServablePrefetchWithMatchingURL" - units="count" expires_after="2023-04-25"> + units="count" expires_after="2023-07-23"> <owner>curranmax@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <owner>spelchat@chromium.org</owner> @@ -418,7 +418,7 @@ </histogram> <histogram name="PrefetchProxy.Prefetch.StreamingURLLoaderFinalStatus" - units="PrefetchStreamingURLLoaderStatus" expires_after="2023-04-25"> + units="PrefetchStreamingURLLoaderStatus" expires_after="2023-07-23"> <owner>curranmax@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <owner>spelchat@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/preloading/DIR_METADATA b/tools/metrics/histograms/metadata/preloading/DIR_METADATA new file mode 100644 index 0000000..f0c1039 --- /dev/null +++ b/tools/metrics/histograms/metadata/preloading/DIR_METADATA
@@ -0,0 +1,11 @@ +# Metadata information for this directory. +# +# For more information on DIR_METADATA files, see: +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md +# +# For the schema of this file, see Metadata message: +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto + +monorail { + component: "Internals>Preload" +}
diff --git a/tools/metrics/histograms/metadata/preloading/OWNERS b/tools/metrics/histograms/metadata/preloading/OWNERS new file mode 100644 index 0000000..8a356c6 --- /dev/null +++ b/tools/metrics/histograms/metadata/preloading/OWNERS
@@ -0,0 +1,6 @@ +per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS + +# Prefer sending CLs to the owners listed below. +# Use chromium-metrics-reviews@google.com as a backup. +curranmax@chromium.org +spelchat@chromium.org
diff --git a/tools/metrics/histograms/metadata/preloading/histograms.xml b/tools/metrics/histograms/metadata/preloading/histograms.xml new file mode 100644 index 0000000..c0c194f6 --- /dev/null +++ b/tools/metrics/histograms/metadata/preloading/histograms.xml
@@ -0,0 +1,91 @@ +<!-- +Copyright 2023 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. + +This file is used to generate a comprehensive list of Prefetch histograms +along with a detailed description for each histogram. + +For best practices on writing histogram descriptions, see +https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md + +Please follow the instructions in the OWNERS file in this directory to find a +reviewer. If no OWNERS file exists, please consider signing up at +go/reviewing-metrics (Googlers only), as all subdirectories are expected to +have an OWNERS file. As a last resort you can send the CL to +chromium-metrics-reviews@google.com. +--> + +<histogram-configuration> + +<histograms> + +<variants name="PreloadingPredictor"> + <variant name="DefaultSearchEngine" + summary="When preloading is triggered from the default search engine + suggest service."/> + <variant name="kLinkRel" + summary="When preloading is triggered by the 'rel' keyword embedded in + the link element."/> + <variant name="kUnspecified" summary=""/> + <variant name="kUrlPointerDownOnAnchor" + summary="When preloading is triggered by OnPointerDown."/> + <variant name="kUrlPointerHoverOnAnchor" + summary="When preloading is triggered by OnPointerHover."/> + <variant name="OmniboxDirectURLInput" + summary="When preloading is triggered from the Omnibox DUI."/> + <variant name="OmniboxMousePredictor" + summary="When preloading is triggered from the default search suggest + due to mousedown on a Omnibox Search suggestion."/> + <variant name="OmniboxSearchPredictor" + summary="When preloading is triggered from the default search suggest + due to change in Omnibox selection."/> + <variant name="PointerDownOnAnchor" + summary="When a pointerdown event happens on a HTTP/HTTPS anchor."/> + <variant name="SpeculationRules" + summary="When preloading is triggered by the speculation rules."/> +</variants> + +<variants name="PreloadingType"> + <variant name="NoStatePrefetch" summary=""/> + <variant name="Preconnect" summary=""/> + <variant name="Prefetch" summary=""/> + <variant name="Prerender" summary=""/> + <variant name="Unspecified" summary=""/> +</variants> + +<histogram name="Preloading.AnchorElementPreloader.PreloadingTriggered" + enum="AnchorElementPreloaderType" expires_after="2023-06-04"> + <owner>spelchat@chromium.org</owner> + <owner>curranmax@chromium.org</owner> + <owner>chrome-brapp-loading@google.com</owner> + <summary> + Logged once for each preconnection request sent by renderer to the browser + when intercepting pointerdown events. Note that the browser may ignore some + of those requests (like duplicate requests or requests made by users that + disabled preloading via the UI) and will not always forward the preconnect + request to the network service. Associated with the Source ID of the page + triggering the preconnection. + </summary> +</histogram> + +<histogram + name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.TriggeringOutcome" + enum="PreloadingTriggeringOutcome" expires_after="M115"> + <owner>spelchat@chromium.org</owner> + <owner>sreejakshetty@chromium.org</owner> + <owner>jbroman@chromium.org</owner> + <owner>liuwilliam@chromium.org</owner> + <owner>chrome-brapp-loading@chromium.org</owner> + <summary> + Records the triggering outcome of a preloading attempt of type + {PreloadingType} and triggered by {PreloadingPredictor} that happened on the + previous page load at the time a new navigation is started. + </summary> + <token key="PreloadingType" variants="PreloadingType"/> + <token key="PreloadingPredictor" variants="PreloadingPredictor"/> +</histogram> + +</histograms> + +</histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/privacy/histograms.xml b/tools/metrics/histograms/metadata/privacy/histograms.xml index 8239b0a73..c8e6b33 100644 --- a/tools/metrics/histograms/metadata/privacy/histograms.xml +++ b/tools/metrics/histograms/metadata/privacy/histograms.xml
@@ -706,10 +706,11 @@ <owner>linnan@chromium.org</owner> <summary> Records whether a call to PrivateAggregationHost::SendHistogramReport() - successfully resulted in a report request being forwarded to the manager - and, if not, the reason for failure. Note that, even if successfully - forwarded, the report may still be rejected by the budgeter or in the - aggregation_service layer. Recorded for every call. + successfully resulted in the report request being forwarded to the manager + and, if not, the reason for failure. Further, breaks out the case of too + many contributions, where the request is forwarded but is truncated. Note + that, even if successfully forwarded, the report may still be rejected by + the budgeter or in the aggregation_service layer. Recorded for every call. </summary> </histogram>
diff --git a/tools/metrics/histograms/metadata/profile/histograms.xml b/tools/metrics/histograms/metadata/profile/histograms.xml index 93d61a4..20b5ccc6 100644 --- a/tools/metrics/histograms/metadata/profile/histograms.xml +++ b/tools/metrics/histograms/metadata/profile/histograms.xml
@@ -252,7 +252,7 @@ </histogram> <histogram name="Profile.Incognito.MovedToBackgroundAfterDuration" - units="minutes" expires_after="2023-03-19"> + units="minutes" expires_after="2023-07-23"> <owner>rhalavati@chromium.org</owner> <owner>chrome-incognito@google.com</owner> <summary> @@ -399,7 +399,7 @@ </histogram> <histogram name="Profile.NukeFromDisk.Result" enum="NukeProfileResult" - expires_after="2023-04-01"> + expires_after="2023-07-23"> <owner>nicolaso@chromium.org</owner> <owner>cbe-eng@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/quota/histograms.xml b/tools/metrics/histograms/metadata/quota/histograms.xml index ec761b3..593860b77 100644 --- a/tools/metrics/histograms/metadata/quota/histograms.xml +++ b/tools/metrics/histograms/metadata/quota/histograms.xml
@@ -99,7 +99,7 @@ </histogram> <histogram name="Quota.EvictedBucketDaysSinceAccess" units="units" - expires_after="2023-05-18"> + expires_after="2023-07-23"> <owner>ayui@chromium.org</owner> <owner>chrome-owp-storage@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml index f87326f..29dbcfd 100644 --- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -358,7 +358,7 @@ <histogram name="SafeBrowsing.ClientSafeBrowsingReport.DownloadWarningActionSize" - units="units" expires_after="2023-05-22"> + units="units" expires_after="2023-07-23"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -787,7 +787,7 @@ </histogram> <histogram name="SafeBrowsing.FileTypeUpdate.DynamicUpdateVersion" - units="FileTypePolicies Version" expires_after="2023-04-16"> + units="FileTypePolicies Version" expires_after="2023-07-23"> <owner>drubery@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -911,6 +911,17 @@ </summary> </histogram> +<histogram name="SafeBrowsing.HPRT.FoundUnmatchedFullHashes" + enum="BooleanFound" expires_after="2023-07-20"> + <owner>thefrog@chromium.org</owner> + <owner>chrome-counter-abuse-alerts@google.com</owner> + <summary> + Records whether the response from the hash-prefix real-time lookup contained + any full hashes that did not match the requested hash prefixes. This is + logged after the network request for the lookup returns. + </summary> +</histogram> + <histogram name="SafeBrowsing.HPRT.GetCache.Time" units="ms" expires_after="2023-07-20"> <owner>thefrog@chromium.org</owner> @@ -1559,7 +1570,7 @@ </histogram> <histogram name="SafeBrowsing.RT.Network.Result" - enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-07-16"> + enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-07-23"> <owner>vakh@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -1650,7 +1661,7 @@ </histogram> <histogram name="SafeBrowsing.RT.Response.VerdictType" - enum="SafeBrowsingRTLookupResponseVerdictType" expires_after="2023-07-16"> + enum="SafeBrowsingRTLookupResponseVerdictType" expires_after="2023-07-23"> <owner>xinghuilu@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> @@ -2039,7 +2050,7 @@ </histogram> <histogram name="SafeBrowsing.V4GetHash.Result.BackoffErrorCount" units="times" - expires_after="2023-05-22"> + expires_after="2023-07-23"> <owner>skrakowi@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml index 80024d3..1594c67 100644 --- a/tools/metrics/histograms/metadata/sb_client/histograms.xml +++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -173,7 +173,7 @@ </histogram> <histogram name="SBClientDownload.DownloadRequestDuration" units="ms" - expires_after="2023-07-16"> + expires_after="2023-07-23"> <owner>vakh@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <owner>mattm@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml b/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml index edafae93..3223898 100644 --- a/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml +++ b/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml
@@ -122,7 +122,7 @@ <histogram name="SegmentationPlatform.AdaptiveToolbar.SegmentSelection.Computed" - enum="AdaptiveToolbarButtonVariant" expires_after="2023-07-16"> + enum="AdaptiveToolbarButtonVariant" expires_after="2023-07-23"> <owner>shaktisahu@chromium.org</owner> <owner>chrome-segmentation-platform@google.com</owner> <summary> @@ -542,7 +542,7 @@ </histogram> <histogram name="SegmentationPlatform.SelectionFailedReason" - enum="SegmentationSelectionFailureReason" expires_after="2023-07-16"> + enum="SegmentationSelectionFailureReason" expires_after="2023-07-23"> <owner>ssid@chromium.org</owner> <owner>chrome-segmentation-platform@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml index 475895e..8c6383b 100644 --- a/tools/metrics/histograms/metadata/signin/histograms.xml +++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -22,7 +22,7 @@ <histograms> -<histogram name="Signin" enum="SigninHelperFlow" expires_after="2023-07-16"> +<histogram name="Signin" enum="SigninHelperFlow" expires_after="2023-07-23"> <owner>mlerman@chromium.org</owner> <summary> Tracks user interactions as they sign in through a flow. The suffix of the @@ -248,7 +248,7 @@ </histogram> <histogram name="Signin.AndroidIsFREStudyGroupConsistent" - enum="BooleanConsistent" expires_after="2023-05-20"> + enum="BooleanConsistent" expires_after="2023-07-23"> <owner>bsazonov@chromium.org</owner> <owner>chrome-signin-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/stability/histograms.xml b/tools/metrics/histograms/metadata/stability/histograms.xml index 9f507ce..f65f4fd 100644 --- a/tools/metrics/histograms/metadata/stability/histograms.xml +++ b/tools/metrics/histograms/metadata/stability/histograms.xml
@@ -105,7 +105,7 @@ </histogram> <histogram name="Stability.Android.ProcessedRealMinidumps" - enum="AndroidProcessedMinidumps" expires_after="2023-05-24"> + enum="AndroidProcessedMinidumps" expires_after="2023-07-23"> <owner>wnwen@chromium.org</owner> <owner>src/components/minidump_uploader/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index 952c8d8..00a3eb4 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -1520,7 +1520,7 @@ <histogram name="Sync.TrustedVaultHintDegradedRecoverabilityChangedReason2" enum="TrustedVaultHintDegradedRecoverabilityChangedReason" - expires_after="2023-04-09"> + expires_after="2023-07-23"> <owner>mmrashad@google.com</owner> <owner>mmoskvitin@google.com</owner> <component>Services>Sync</component>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml index d49cd80..32f37426 100644 --- a/tools/metrics/histograms/metadata/tab/histograms.xml +++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -2095,7 +2095,7 @@ </histogram> <histogram name="Tabs.TabSearch.CloseAction" enum="TabSearchCloseActions" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -2111,7 +2111,7 @@ </histogram> <histogram name="Tabs.TabSearch.Mojo.SwitchToTab" units="ms" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>kerenzhu@chromium.org</owner> <owner>romanarora@chromium.org</owner> <owner>yuhengh@chromium.org</owner> @@ -2124,7 +2124,7 @@ </histogram> <histogram name="Tabs.TabSearch.Mojo.SwitchToTab.IsOverlap" enum="Boolean" - expires_after="2023-02-26"> + expires_after="2023-12-13"> <owner>kerenzhu@chromium.org</owner> <owner>romanarora@chromium.org</owner> <owner>yuhengh@chromium.org</owner> @@ -2137,7 +2137,7 @@ </histogram> <histogram name="Tabs.TabSearch.Mojo.TabUpdated" units="ms" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>kerenzhu@chromium.org</owner> <owner>romanarora@chromium.org</owner> <owner>yuhengh@chromium.org</owner> @@ -2151,7 +2151,7 @@ </histogram> <histogram name="Tabs.TabSearch.Mojo.TabUpdated.IsOverlap" enum="Boolean" - expires_after="2023-02-26"> + expires_after="2023-12-13"> <owner>kerenzhu@chromium.org</owner> <owner>romanarora@chromium.org</owner> <owner>yuhengh@chromium.org</owner> @@ -2164,7 +2164,7 @@ </histogram> <histogram name="Tabs.TabSearch.NumTabsClosedPerInstance" units="tabs" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -2177,7 +2177,7 @@ </histogram> <histogram name="Tabs.TabSearch.NumTabsOnOpen" units="tabs" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -2188,7 +2188,7 @@ </histogram> <histogram name="Tabs.TabSearch.NumWindowsOnOpen" units="windows" - expires_after="2023-02-26"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -2200,7 +2200,7 @@ </histogram> <histogram name="Tabs.TabSearch.OpenAction" enum="TabSearchOpenActions" - expires_after="2023-02-26"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -2215,7 +2215,7 @@ </histogram> <histogram name="Tabs.TabSearch.PageHandlerConstructionDelay" units="ms" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <owner>yuhengh@chromium.org</owner> @@ -2234,7 +2234,7 @@ </histogram> <histogram name="Tabs.TabSearch.RecentlyClosedSectionToggleAction" - enum="TabSearchRecentlyClosedToggleActions" expires_after="2023-07-02"> + enum="TabSearchRecentlyClosedToggleActions" expires_after="2023-12-13"> <owner>romanarora@chromium.org</owner> <owner>robliao@chromium.org</owner> <owner>tluk@chromium.org</owner> @@ -2251,7 +2251,7 @@ </histogram> <histogram name="Tabs.TabSearch.RecentlyClosedSectionToggleStateOnOpen" - enum="TabSearchRecentlyClosedToggleActions" expires_after="2023-02-26"> + enum="TabSearchRecentlyClosedToggleActions" expires_after="2023-12-13"> <owner>romanarora@chromium.org</owner> <owner>robliao@chromium.org</owner> <owner>tluk@chromium.org</owner> @@ -2414,7 +2414,7 @@ </histogram> <histogram name="Tabs.TabSearch.WindowDisplayedDuration3" units="ms" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <summary> @@ -2437,7 +2437,7 @@ </histogram> <histogram name="Tabs.TabSearch.WindowTimeToShowCachedWebView" units="ms" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <owner>yuhengh@chromium.org</owner> @@ -2456,7 +2456,7 @@ </histogram> <histogram name="Tabs.TabSearch.WindowTimeToShowUncachedWebView" units="ms" - expires_after="2023-07-02"> + expires_after="2023-12-13"> <owner>tluk@chromium.org</owner> <owner>robliao@chromium.org</owner> <owner>yuhengh@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/uma/histograms.xml b/tools/metrics/histograms/metadata/uma/histograms.xml index 9625278..1e76180861 100644 --- a/tools/metrics/histograms/metadata/uma/histograms.xml +++ b/tools/metrics/histograms/metadata/uma/histograms.xml
@@ -879,7 +879,7 @@ </histogram> <histogram name="UMA.TruncatedEvents.UserAction" units="events" - expires_after="2023-07-16"> + expires_after="2023-07-23"> <owner>rkaplow@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index f8a66bc..29e75ace 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -2170,6 +2170,21 @@ are from |autofill::ServerFieldType|. </summary> </metric> + <metric name="HtmlFieldMode" enum="AutocompleteHtmlFieldMode"> + <summary> + The mode according to the autocomplete attribute of a field. Only set if a + field has a valid autocomplete attribute. Currently this is used to + specify if the field is part of the billing or shipping address. See + autofill::mojom::HtmlFieldMode. + </summary> + </metric> + <metric name="HtmlFieldType" enum="AutocompleteHtmlFieldType"> + <summary> + The field type specified in the autocomplete attribute of the field. Only + set if a field has a valid autocomplete attribute. See + autofill::mojom::HtmlFieldType. + </summary> + </metric> <metric name="IsFocusable" enum="Boolean"> <summary> Whether the field is focusable to the user. This is an approximation of
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 34e2c04..221fa52d 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,16 +5,16 @@ "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm64/trace_processor_shell" }, "win": { - "hash": "9f9590c00b2f11f7b0e5fe571460aadfbc485caa", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/61f6f28a07752c9a38fa2309d20557d5d8647eaf/trace_processor_shell.exe" + "hash": "b54aa5268f396311caadc4c2a29ddf93ccec53a9", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/f1c4ce9b46ee662faed75adf6bfbff99ab2ca3e2/trace_processor_shell.exe" }, "linux_arm": { "hash": "6373f26144aad58f230d11d6a91efda5a09c9873", "full_remote_path": "perfetto-luci-artifacts/v31.0/linux-arm/trace_processor_shell" }, "mac": { - "hash": "69203849a5dd2ad4ba1b3abe28144ab3b2763f7f", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/61f6f28a07752c9a38fa2309d20557d5d8647eaf/trace_processor_shell" + "hash": "937cd28ca5cefd6006a6347364eef04273e7a082", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/f1c4ce9b46ee662faed75adf6bfbff99ab2ca3e2/trace_processor_shell" }, "mac_arm64": { "hash": "5f47ee79e59d00bf3889d30ca52315522c158040",
diff --git a/tools/typescript/definitions/input_method_private.d.ts b/tools/typescript/definitions/input_method_private.d.ts new file mode 100644 index 0000000..212dad19 --- /dev/null +++ b/tools/typescript/definitions/input_method_private.d.ts
@@ -0,0 +1,22 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** @fileoverview Definitions for chrome.inputMethodPrivate API */ +// TODO(crbug.com/1203307): Auto-generate this file. + +import {ChromeEvent} from './chrome_event.js'; + +declare global { + export namespace chrome { + export namespace inputMethodPrivate { + export function getCurrentInputMethod(): Promise<string>; + export function setCurrentInputMethod(inputMethodId: string): + Promise<void>; + + export function openOptionsPage(id: string): void; + + export const onChanged: ChromeEvent<(newInputMethodId: string) => void>; + } + } +}
diff --git a/ui/base/cocoa/cursor_utils.h b/ui/base/cocoa/cursor_utils.h index 935e9f8..eabafcf 100644 --- a/ui/base/cocoa/cursor_utils.h +++ b/ui/base/cocoa/cursor_utils.h
@@ -5,14 +5,16 @@ #ifndef UI_BASE_COCOA_CURSOR_UTILS_H_ #define UI_BASE_COCOA_CURSOR_UTILS_H_ +#import <AppKit/AppKit.h> + #include "base/component_export.h" -#include "ui/base/cursor/cursor.h" -#include "ui/gfx/native_widget_types.h" namespace ui { +class Cursor; + COMPONENT_EXPORT(UI_BASE) -gfx::NativeCursor GetNativeCursor(const ui::Cursor& cursor); +NSCursor* GetNativeCursor(const ui::Cursor& cursor); } // namespace ui
diff --git a/ui/base/cocoa/cursor_utils.mm b/ui/base/cocoa/cursor_utils.mm index 3173aee..2a3091f 100644 --- a/ui/base/cocoa/cursor_utils.mm +++ b/ui/base/cocoa/cursor_utils.mm
@@ -158,7 +158,7 @@ namespace ui { // Match Safari's cursor choices; see platform/mac/CursorMac.mm . -gfx::NativeCursor GetNativeCursor(const ui::Cursor& cursor) { +NSCursor* GetNativeCursor(const ui::Cursor& cursor) { switch (cursor.type()) { case ui::mojom::CursorType::kPointer: return [NSCursor arrowCursor];
diff --git a/ui/color/BUILD.gn b/ui/color/BUILD.gn index a0a7737..3a9623e3 100644 --- a/ui/color/BUILD.gn +++ b/ui/color/BUILD.gn
@@ -56,6 +56,7 @@ ":color_headers", "//base", "//skia", + "//ui/base:features", "//ui/gfx:color_utils", ]
diff --git a/ui/color/DEPS b/ui/color/DEPS index 8aa4d01d..e2653c0 100644 --- a/ui/color/DEPS +++ b/ui/color/DEPS
@@ -4,4 +4,5 @@ "+skia/ext", "+ui/base", "+ui/gfx", + "+ui/base", ]
diff --git a/ui/color/color_id.h b/ui/color/color_id.h index 9307a2c..c8727dc 100644 --- a/ui/color/color_id.h +++ b/ui/color/color_id.h
@@ -333,6 +333,7 @@ E_CPONLY(kColorToggleButtonShadow) \ E_CPONLY(kColorToggleButtonThumbOff) \ E_CPONLY(kColorToggleButtonThumbOn) \ + E_CPONLY(kColorToggleButtonThumbOnIcon) \ E_CPONLY(kColorToggleButtonTrackOff) \ E_CPONLY(kColorToggleButtonTrackOn) \ E_CPONLY(kColorTooltipBackground) \
diff --git a/ui/color/material_ui_color_mixer.cc b/ui/color/material_ui_color_mixer.cc index f021b5e..3c92d68 100644 --- a/ui/color/material_ui_color_mixer.cc +++ b/ui/color/material_ui_color_mixer.cc
@@ -46,6 +46,7 @@ mixer[kColorToggleButtonThumbOn] = {kColorSysOnPrimary}; mixer[kColorToggleButtonTrackOff] = {kColorSysSurfaceVariant}; mixer[kColorToggleButtonTrackOn] = {kColorSysPrimary}; + mixer[kColorToggleButtonThumbOnIcon] = {kColorSysOnPrimaryContainer}; } } // namespace ui
diff --git a/ui/file_manager/file_manager/background/js/file_operation_handler.js b/ui/file_manager/file_manager/background/js/file_operation_handler.js index 0e52dd4..adc5a21 100644 --- a/ui/file_manager/file_manager/background/js/file_operation_handler.js +++ b/ui/file_manager/file_manager/background/js/file_operation_handler.js
@@ -83,6 +83,7 @@ item.remainingTime = event.remainingSeconds; break; case chrome.fileManagerPrivate.IOTaskState.IN_PROGRESS: + case chrome.fileManagerPrivate.IOTaskState.PAUSED: item.progressMax = event.totalBytes; item.progressValue = event.bytesTransferred; item.remainingTime = event.remainingSeconds; @@ -126,10 +127,12 @@ default: console.error(`Invalid IOTaskState: ${event.state}`); } + if (!event.showNotification) { // Set state to canceled so notification doesn't display. item.state = ProgressItemState.CANCELED; } + this.progressCenter_.updateItem(item); }
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js index f9cd433..bae29d4 100644 --- a/ui/file_manager/file_manager/common/js/util.js +++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1148,8 +1148,9 @@ return loadTimeData.getBoolean('FILES_SEARCH_V2'); }; -util.isGoogleOneOfferFilesBannerEnabled = () => { - return loadTimeData.getBoolean('GOOGLE_ONE_OFFER_FILES_BANNER'); +util.isGoogleOneOfferFilesBannerEligibleAndEnabled = () => { + return loadTimeData.getBoolean( + 'ELIGIBLE_AND_ENABLED_GOOGLE_ONE_OFFER_FILES_BANNER'); }; /**
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css index da1909b..7395283 100644 --- a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css +++ b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
@@ -1772,11 +1772,6 @@ align-items: center; } -#list-container li.table-row { - height: 40px; - line-height: 40px; -} - /* The icon in the name column. See file_types.css for specific icons. */ .detail-icon { height: 24px; @@ -1803,10 +1798,10 @@ width: 24px; } -body.files-ng #list-container list li .detail-icon { +#list-container list li .detail-icon { color: var(--cros-icon-color-primary); height: 40px; - margin-inline-end: 8px; + margin-inline-end: 12px; margin-inline-start: 8px; width: 40px; } @@ -2074,14 +2069,9 @@ text-overflow: ellipsis; } -/** Size column is aligned to right. */ -.table-header-label.size .table-label-container { - justify-content: flex-end; -} - -body.files-ng #list-container li.table-row { +#list-container li.table-row { box-sizing: border-box; - height: 40px; + height: 48px; line-height: 20px; } @@ -2140,9 +2130,9 @@ --cr-icon-button-hover-background-color: none; } -body.files-ng #list-container .table-row-cell .size { +#list-container .table-row-cell .size { padding-inline-end: 5px; - padding-inline-start: 22px; + padding-inline-start: 32px; } body.files-ng.check-select list:focus li[selected] .table-row-cell > * {
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js index c179b4f4..0f18adc 100644 --- a/ui/file_manager/file_manager/foreground/js/actions_model.js +++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -12,6 +12,7 @@ import {DriveSyncHandler} from '../../externs/background/drive_sync_handler.js'; import {VolumeManager} from '../../externs/volume_manager.js'; +import {constants} from './constants.js'; import {FolderShortcutsDataModel} from './folder_shortcuts_data_model.js'; import {MetadataModel} from './metadata/metadata_model.js'; import {ActionModelUI} from './ui/action_model_ui.js'; @@ -814,6 +815,14 @@ chrome.runtime.lastError.message); } else { customActions.forEach(action => { + // Skip fake actions that should not be displayed to the + // user, for example actions that just expose OneDrive + // URLs. + // TODO(b/237216270): Restrict to the ODFS extension ID. + if (action.id === + constants.FSP_ACTION_HIDDEN_ODFS_URL) { + return; + } actions[action.id] = new CustomAction( this.entries_, action.id, action.title || null, this.invalidate_.bind(this));
diff --git a/ui/file_manager/file_manager/foreground/js/banner_controller.js b/ui/file_manager/file_manager/foreground/js/banner_controller.js index a9bb224..6add268 100644 --- a/ui/file_manager/file_manager/foreground/js/banner_controller.js +++ b/ui/file_manager/file_manager/foreground/js/banner_controller.js
@@ -313,7 +313,8 @@ DriveLowIndividualSpaceBanner, ]); - const educationalBanners = util.isGoogleOneOfferFilesBannerEnabled() ? + const educationalBanners = + util.isGoogleOneOfferFilesBannerEligibleAndEnabled() ? [GoogleOneOfferBannerTagName] : [DriveWelcomeBannerTagName]; educationalBanners.push(
diff --git a/ui/file_manager/file_manager/foreground/js/constants.js b/ui/file_manager/file_manager/foreground/js/constants.js index d40a7154..fa20f61 100644 --- a/ui/file_manager/file_manager/foreground/js/constants.js +++ b/ui/file_manager/file_manager/foreground/js/constants.js
@@ -108,3 +108,10 @@ * @const {string} */ constants.CROSTINI_CONNECT_ERR = 'CrostiniConnectErr'; + +/** + * ID of the fake fileSystemProvider custom action containing OneDrive document + * URLs. + * @const {string} + */ +constants.FSP_ACTION_HIDDEN_ODFS_URL = 'HIDDEN_ODFS_URL';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js index 58646e0..9e5b9e9 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -468,8 +468,9 @@ nameColumn.renderFunction = self.renderName_.bind(self); nameColumn.headerRenderFunction = renderHeader_; - const sizeColumn = - new TableColumn('size', str('SIZE_COLUMN_LABEL'), 110, true); + const sizeColumn = new TableColumn( + 'size', str('SIZE_COLUMN_LABEL'), 110, + util.isJellyEnabled() ? false : true); sizeColumn.renderFunction = self.renderSize_.bind(self); sizeColumn.defaultOrder = 'desc'; sizeColumn.headerRenderFunction = renderHeader_;
diff --git a/ui/file_manager/file_manager/widgets/xf_conflict_dialog.ts b/ui/file_manager/file_manager/widgets/xf_conflict_dialog.ts index f2771af..a608a51c 100644 --- a/ui/file_manager/file_manager/widgets/xf_conflict_dialog.ts +++ b/ui/file_manager/file_manager/widgets/xf_conflict_dialog.ts
@@ -123,7 +123,7 @@ /** * The conflict dialog has no title. Remove the <cr-dialog> title child that * would focus, remove its <dialog> aria-labelledby and aria-describedby, so - * ARIA announces the #message element that is the initial focus. + * ARIA announces the #message (that is the initial focus) once. * * Per https://w3c.github.io/aria-practices/#dialog_roles_states_props, adds * aria-modal='true' meaning all content outside the <dialog> is inert. @@ -181,8 +181,8 @@ this.getReplaceButton().innerText = str('CONFLICT_DIALOG_REPLACE'); } - this.toggleAttribute('checked', checked); this.getCheckboxElement().focus(); + this.toggleAttribute('checked', checked); } /**
diff --git a/ui/file_manager/file_manager/widgets/xf_conflict_dialog_unittest.ts b/ui/file_manager/file_manager/widgets/xf_conflict_dialog_unittest.ts index f4ca2b00..d3a73b25 100644 --- a/ui/file_manager/file_manager/widgets/xf_conflict_dialog_unittest.ts +++ b/ui/file_manager/file_manager/widgets/xf_conflict_dialog_unittest.ts
@@ -198,6 +198,9 @@ assertEquals('Keep all', keepboth.innerText); assertEquals('Replace all', replace.innerText); + // Check: the checkbox should gain the focus. + await waitUntil(() => element.shadowRoot!.activeElement === checkbox); + // Check: clicking the checkbox should change the checked state. checkbox.click(); await waitUntil(() => !element.hasAttribute('checked')); @@ -206,6 +209,9 @@ assertEquals('Keep both', keepboth.innerText); assertEquals('Replace', replace.innerText); + // Check: the checkbox should retain the focus. + await waitUntil(() => element.shadowRoot!.activeElement === checkbox); + done(); }
diff --git a/ui/gl/dc_layer_overlay_image.cc b/ui/gl/dc_layer_overlay_image.cc index 8b7c96c8..24f8e18 100644 --- a/ui/gl/dc_layer_overlay_image.cc +++ b/ui/gl/dc_layer_overlay_image.cc
@@ -18,11 +18,13 @@ DCLayerOverlayImage::DCLayerOverlayImage( const gfx::Size& size, Microsoft::WRL::ComPtr<ID3D11Texture2D> nv12_texture, - size_t array_slice) + size_t array_slice, + Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex) : type_(DCLayerOverlayType::kNV12Texture), size_(size), nv12_texture_(std::move(nv12_texture)), - texture_array_slice_(array_slice) {} + texture_array_slice_(array_slice), + keyed_mutex_(std::move(keyed_mutex)) {} DCLayerOverlayImage::DCLayerOverlayImage(const gfx::Size& size, const uint8_t* nv12_pixmap,
diff --git a/ui/gl/dc_layer_overlay_image.h b/ui/gl/dc_layer_overlay_image.h index bdde085..161c249d 100644 --- a/ui/gl/dc_layer_overlay_image.h +++ b/ui/gl/dc_layer_overlay_image.h
@@ -13,6 +13,7 @@ class ID3D11Texture2D; class IDCompositionSurface; +class IDXGIKeyedMutex; class IDXGISwapChain1; class IUnknown; @@ -32,9 +33,11 @@ // Holds DComp content needed to update the DComp layer tree class GL_EXPORT DCLayerOverlayImage { public: - DCLayerOverlayImage(const gfx::Size& size, - Microsoft::WRL::ComPtr<ID3D11Texture2D> nv12_texture, - size_t array_slice = 0u); + DCLayerOverlayImage( + const gfx::Size& size, + Microsoft::WRL::ComPtr<ID3D11Texture2D> nv12_texture, + size_t array_slice = 0u, + Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex = nullptr); DCLayerOverlayImage(const gfx::Size& size, const uint8_t* nv12_pixmap, size_t stride); @@ -52,6 +55,8 @@ ID3D11Texture2D* nv12_texture() const { return nv12_texture_.Get(); } size_t texture_array_slice() const { return texture_array_slice_; } + // TODO(sunnyps): Remove after removing GLImage usage in DXVA decoder. + IDXGIKeyedMutex* keyed_mutex() const { return keyed_mutex_.Get(); } const uint8_t* nv12_pixmap() const { return nv12_pixmap_; } size_t pixmap_stride() const { return pixmap_stride_; } @@ -65,12 +70,14 @@ bool operator==(const DCLayerOverlayImage& other) const { return std::tie(type_, size_, nv12_texture_, texture_array_slice_, - nv12_pixmap_, pixmap_stride_, dcomp_visual_content_, - dcomp_surface_serial_, dcomp_surface_proxy_) == + keyed_mutex_, nv12_pixmap_, pixmap_stride_, + dcomp_visual_content_, dcomp_surface_serial_, + dcomp_surface_proxy_) == std::tie(other.type_, other.size_, other.nv12_texture_, - other.texture_array_slice_, other.nv12_pixmap_, - other.pixmap_stride_, other.dcomp_visual_content_, - other.dcomp_surface_serial_, other.dcomp_surface_proxy_); + other.texture_array_slice_, other.keyed_mutex_, + other.nv12_pixmap_, other.pixmap_stride_, + other.dcomp_visual_content_, other.dcomp_surface_serial_, + other.dcomp_surface_proxy_); } private: @@ -82,6 +89,8 @@ Microsoft::WRL::ComPtr<ID3D11Texture2D> nv12_texture_; // Array slice/index if |texture_| is a texture array. size_t texture_array_slice_ = 0; + // Set if the consumer should synchronize texture access using a keyed mutex. + Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex_; // Software decoder NV12 frame pixmap. const uint8_t* nv12_pixmap_ = nullptr; // Software video pixmap stride. Y and UV planes have the same stride in NV12.
diff --git a/ui/gl/init/gl_display_initializer.cc b/ui/gl/init/gl_display_initializer.cc index cbfa8ab..43a19ee 100644 --- a/ui/gl/init/gl_display_initializer.cc +++ b/ui/gl/init/gl_display_initializer.cc
@@ -66,7 +66,8 @@ // } if (supports_angle_null && - requested_renderer == kANGLEImplementationNullName) { + (requested_renderer == kANGLEImplementationNullName || + gl::GetANGLEImplementation() == ANGLEImplementation::kNull)) { AddInitDisplay(init_displays, ANGLE_NULL); return; }
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc index 3118090..73df596 100644 --- a/ui/gl/swap_chain_presenter.cc +++ b/ui/gl/swap_chain_presenter.cc
@@ -1192,9 +1192,9 @@ input_level = 0; } - // Keyed mutex may not exist. - Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex; - input_texture.As(&keyed_mutex); + // Keyed mutex is not present if access is synchronized by the shared image. + Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex = + params.overlay_image->keyed_mutex(); absl::optional<DXGI_HDR_METADATA_HDR10> stream_metadata; if (params.hdr_metadata.IsValid()) { @@ -1202,9 +1202,9 @@ gl::HDRMetadataHelperWin::HDRMetadataToDXGI(params.hdr_metadata); } - if (!VideoProcessorBlt(input_texture, input_level, keyed_mutex, - params.content_rect, input_color_space, content_is_hdr, - stream_metadata)) { + if (!VideoProcessorBlt(std::move(input_texture), input_level, + std::move(keyed_mutex), params.content_rect, + input_color_space, content_is_hdr, stream_metadata)) { return false; }
diff --git a/ui/gl/test/gl_surface_test_support.cc b/ui/gl/test/gl_surface_test_support.cc index 673e3e7..4d273ef 100644 --- a/ui/gl/test/gl_surface_test_support.cc +++ b/ui/gl/test/gl_surface_test_support.cc
@@ -10,6 +10,7 @@ #include "base/command_line.h" #include "build/build_config.h" #include "ui/gl/gl_context.h" +#include "ui/gl/gl_features.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_switches.h" #include "ui/gl/init/gl_factory.h" @@ -126,9 +127,16 @@ params.single_process = true; ui::OzonePlatform::InitializeForGPU(params); #endif + if (features::UsePassthroughCommandDecoder()) { + auto* display = InitializeOneOffImplementation( + GLImplementationParts(gl::ANGLEImplementation::kNull), false); - return InitializeOneOffImplementation( - GLImplementationParts(kGLImplementationStubGL), false); + DCHECK_EQ(gl::GetANGLEImplementation(), gl::ANGLEImplementation::kNull); + return display; + } else { + return InitializeOneOffImplementation( + GLImplementationParts(kGLImplementationStubGL), false); + } } // static
diff --git a/ui/message_center/fake_message_center.cc b/ui/message_center/fake_message_center.cc index ef8e2e1..8ff2c0b 100644 --- a/ui/message_center/fake_message_center.cc +++ b/ui/message_center/fake_message_center.cc
@@ -4,6 +4,7 @@ #include "ui/message_center/fake_message_center.h" +#include <string> #include <utility> #include "base/strings/string_util.h" @@ -186,6 +187,14 @@ return false; } +ExpandState FakeMessageCenter::GetNotificationExpandState( + const std::string& id) { + return ExpandState::DEFAULT; +} + +void FakeMessageCenter::SetNotificationExpandState(const std::string& id, + const ExpandState state) {} + void FakeMessageCenter::SetHasMessageCenterView(bool has_message_center_view) { has_message_center_view_ = has_message_center_view; }
diff --git a/ui/message_center/fake_message_center.h b/ui/message_center/fake_message_center.h index 30e5aa231..e2b631f 100644 --- a/ui/message_center/fake_message_center.h +++ b/ui/message_center/fake_message_center.h
@@ -80,6 +80,9 @@ void EnterQuietModeWithExpire(const base::TimeDelta& expires_in) override; void SetVisibility(Visibility visible) override; bool IsMessageCenterVisible() const override; + ExpandState GetNotificationExpandState(const std::string& id) override; + void SetNotificationExpandState(const std::string& id, + const ExpandState state) override; void SetHasMessageCenterView(bool has_message_center_view) override; bool HasMessageCenterView() const override; void RestartPopupTimers() override;
diff --git a/ui/message_center/message_center.h b/ui/message_center/message_center.h index 7895238..3ad9532 100644 --- a/ui/message_center/message_center.h +++ b/ui/message_center/message_center.h
@@ -218,6 +218,15 @@ // Allows querying the visibility of the center. virtual bool IsMessageCenterVisible() const = 0; + // Access for the `ExpandState` stored for each notification in the + // `NotificationList`. The `ExpandState` is kept alongside other + // notifications' state information in the `NotificationState` struct. The + // `ExpandState signifies whether the notification has been manually expanded + // or collapsed by the user. + virtual ExpandState GetNotificationExpandState(const std::string& id) = 0; + virtual void SetNotificationExpandState(const std::string& id, + const ExpandState state) = 0; + // Informs the MessageCenter whether there's a bubble anchored to a system // tray which holds notifications. If false, only toasts are shown (e.g. on // desktop Linux and Windows). When there's no message center view, updated
diff --git a/ui/message_center/message_center_impl.cc b/ui/message_center/message_center_impl.cc index 3592c86..d1ea8eb0 100644 --- a/ui/message_center/message_center_impl.cc +++ b/ui/message_center/message_center_impl.cc
@@ -124,6 +124,21 @@ return visible_; } +ExpandState MessageCenterImpl::GetNotificationExpandState( + const std::string& id) { + DCHECK(FindVisibleNotificationById(id)); + + return notification_list_->GetNotificationExpandState(id); +} + +void MessageCenterImpl::SetNotificationExpandState( + const std::string& id, + const ExpandState expand_state) { + DCHECK(FindVisibleNotificationById(id)); + + notification_list_->SetNotificationExpandState(id, expand_state); +} + void MessageCenterImpl::SetHasMessageCenterView(bool has_message_center_view) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); has_message_center_view_ = has_message_center_view;
diff --git a/ui/message_center/message_center_impl.h b/ui/message_center/message_center_impl.h index 87b1304f..8b8b8d2 100644 --- a/ui/message_center/message_center_impl.h +++ b/ui/message_center/message_center_impl.h
@@ -49,6 +49,9 @@ void RemoveNotificationBlocker(NotificationBlocker* blocker) override; void SetVisibility(Visibility visible) override; bool IsMessageCenterVisible() const override; + ExpandState GetNotificationExpandState(const std::string& id) override; + void SetNotificationExpandState(const std::string& id, + const ExpandState state) override; void SetHasMessageCenterView(bool has_message_center_view) override; bool HasMessageCenterView() const override; size_t NotificationCount() const override;
diff --git a/ui/message_center/notification_list.cc b/ui/message_center/notification_list.cc index 3c9c0de..d15d38d 100644 --- a/ui/message_center/notification_list.cc +++ b/ui/message_center/notification_list.cc
@@ -315,6 +315,28 @@ // `shown_as_popup` should be true if quiet mode is enabled. state->shown_as_popup = quiet_mode_; state->is_read = false; + state->expand_state = ExpandState::DEFAULT; +} + +ExpandState NotificationList::GetNotificationExpandState( + const std::string& id) { + auto iter = GetNotification(id); + if (iter == notifications_.end()) { + return ExpandState::DEFAULT; + } + + return iter->second.expand_state; +} + +void NotificationList::SetNotificationExpandState( + const std::string& id, + const ExpandState expand_state) { + auto iter = GetNotification(id); + if (iter == notifications_.end()) { + return; + } + + iter->second.expand_state = expand_state; } NotificationDelegate* NotificationList::GetNotificationDelegate(
diff --git a/ui/message_center/notification_list.h b/ui/message_center/notification_list.h index ff09e8f1..4343144 100644 --- a/ui/message_center/notification_list.h +++ b/ui/message_center/notification_list.h
@@ -36,6 +36,8 @@ class NotificationDelegate; struct NotifierId; +enum class ExpandState { DEFAULT = 0, USER_EXPANDED = 1, USER_COLLAPSED = 2 }; + // Comparers used to auto-sort the lists of Notifications. struct MESSAGE_CENTER_EXPORT ComparePriorityTimestampSerial { bool operator()(Notification* n1, Notification* n2) const; @@ -63,6 +65,7 @@ bool shown_as_popup = false; bool is_read = false; + ExpandState expand_state = ExpandState::DEFAULT; }; // Auto-sorted set. Matches the order in which Notifications are shown in @@ -155,6 +158,12 @@ // bring up a grouped notification when a new item is added to it. void ResetSinglePopup(const std::string& id); + // `ExpandState` signifies whether the notification with the specified `id` + // has been manually expanded or collapsed by the user. + ExpandState GetNotificationExpandState(const std::string& id); + void SetNotificationExpandState(const std::string& id, + ExpandState expand_state); + NotificationDelegate* GetNotificationDelegate(const std::string& id); bool quiet_mode() const { return quiet_mode_; } @@ -180,8 +189,7 @@ private: friend class NotificationListTest; - FRIEND_TEST_ALL_PREFIXES(NotificationListTest, - TestPushingShownNotification); + FRIEND_TEST_ALL_PREFIXES(NotificationListTest, TestPushingShownNotification); // Iterates through the list and returns the first notification matching |id|. OwnedNotifications::iterator GetNotification(const std::string& id); @@ -199,4 +207,4 @@ } // namespace message_center -#endif // UI_MESSAGE_CENTER_NOTIFICATION_LIST_H_ +#endif // UI_MESSAGE_CENTER_NOTIFICATION_LIST_H_
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc index 92b4c7a..a61fd4d 100644 --- a/ui/message_center/views/message_view.cc +++ b/ui/message_center/views/message_view.cc
@@ -183,7 +183,7 @@ return false; } -void MessageView::SetManuallyExpandedOrCollapsed(bool value) { +void MessageView::SetManuallyExpandedOrCollapsed(ExpandState state) { // Not implemented by default. }
diff --git a/ui/message_center/views/message_view.h b/ui/message_center/views/message_view.h index 39bf6681..fff3957 100644 --- a/ui/message_center/views/message_view.h +++ b/ui/message_center/views/message_view.h
@@ -18,6 +18,7 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" #include "ui/message_center/message_center_export.h" +#include "ui/message_center/notification_list.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_delegate.h" #include "ui/message_center/public/cpp/notifier_id.h" @@ -125,7 +126,7 @@ virtual bool IsExpanded() const; virtual bool IsAutoExpandingAllowed() const; virtual bool IsManuallyExpandedOrCollapsed() const; - virtual void SetManuallyExpandedOrCollapsed(bool value); + virtual void SetManuallyExpandedOrCollapsed(ExpandState state); virtual void CloseSwipeControl(); virtual void SlideOutAndClose(int direction);
diff --git a/ui/message_center/views/notification_view.cc b/ui/message_center/views/notification_view.cc index 51f44b7..e22d864 100644 --- a/ui/message_center/views/notification_view.cc +++ b/ui/message_center/views/notification_view.cc
@@ -674,11 +674,15 @@ if (!IsExpandable() || !content_row()->GetVisible()) return; + const bool target_expanded_state = !IsExpanded(); + // Tapping anywhere on |header_row_| can expand the notification, though only // |expand_button| can be focused by TAB. - SetManuallyExpandedOrCollapsed(true); + SetManuallyExpandedOrCollapsed( + target_expanded_state ? message_center::ExpandState::USER_EXPANDED + : message_center::ExpandState::USER_COLLAPSED); auto weak_ptr = weak_ptr_factory_.GetWeakPtr(); - SetExpanded(!IsExpanded()); + SetExpanded(target_expanded_state); // Check |this| is valid before continuing, because ToggleExpanded() might // cause |this| to be deleted. if (!weak_ptr)
diff --git a/ui/message_center/views/notification_view_base.cc b/ui/message_center/views/notification_view_base.cc index 376633c..8a3e960 100644 --- a/ui/message_center/views/notification_view_base.cc +++ b/ui/message_center/views/notification_view_base.cc
@@ -38,6 +38,7 @@ #include "ui/gfx/text_constants.h" #include "ui/gfx/text_elider.h" #include "ui/message_center/message_center.h" +#include "ui/message_center/notification_list.h" #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_types.h" @@ -927,11 +928,12 @@ } bool NotificationViewBase::IsManuallyExpandedOrCollapsed() const { - return manually_expanded_or_collapsed_; + return MessageCenter::Get()->GetNotificationExpandState(notification_id()) != + ExpandState::DEFAULT; } -void NotificationViewBase::SetManuallyExpandedOrCollapsed(bool value) { - manually_expanded_or_collapsed_ = value; +void NotificationViewBase::SetManuallyExpandedOrCollapsed(ExpandState state) { + MessageCenter::Get()->SetNotificationExpandState(notification_id(), state); } void NotificationViewBase::OnSettingsButtonPressed(const ui::Event& event) {
diff --git a/ui/message_center/views/notification_view_base.h b/ui/message_center/views/notification_view_base.h index 6246cd7..e29e688d 100644 --- a/ui/message_center/views/notification_view_base.h +++ b/ui/message_center/views/notification_view_base.h
@@ -15,6 +15,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/message_center/message_center_export.h" +#include "ui/message_center/notification_list.h" #include "ui/message_center/views/message_view.h" #include "ui/message_center/views/notification_input_container.h" #include "ui/views/animation/ink_drop.h" @@ -127,7 +128,7 @@ bool IsExpanded() const override; void SetExpanded(bool expanded) override; bool IsManuallyExpandedOrCollapsed() const override; - void SetManuallyExpandedOrCollapsed(bool value) override; + void SetManuallyExpandedOrCollapsed(ExpandState state) override; void OnSettingsButtonPressed(const ui::Event& event) override; // views::InkDropObserver:
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn index 77eb42a..5429ba7 100644 --- a/ui/ozone/platform/drm/BUILD.gn +++ b/ui/ozone/platform/drm/BUILD.gn
@@ -219,7 +219,6 @@ # the system. "//third_party/libdrm", "//ui/base/ime", - "//ui/display/fake:fake", "//ui/gfx", "//ui/gfx/linux:drm", "//ui/gfx/linux:gbm",
diff --git a/ui/ozone/platform/drm/common/drm_util.cc b/ui/ozone/platform/drm/common/drm_util.cc index e0bbb075..f014731b 100644 --- a/ui/ozone/platform/drm/common/drm_util.cc +++ b/ui/ozone/platform/drm/common/drm_util.cc
@@ -523,6 +523,7 @@ int fd, const base::FilePath& sys_path, uint8_t device_index, + const gfx::Point& origin, const display::DrmFormatsAndModifiers& drm_formats_and_modifiers) { const uint8_t display_index = display::ConnectorIndex8(device_index, info->index()); @@ -558,7 +559,7 @@ std::string display_name; // Make sure the ID contains non index part. int64_t port_display_id = display_index | 0x100; - int64_t edid_display_id = port_display_id; + int64_t edid_display_id = display::kInvalidDisplayId; int64_t product_code = display::DisplaySnapshot::kInvalidProductCode; int32_t year_of_manufacture = display::kInvalidYearOfManufacture; bool has_overscan = false; @@ -611,7 +612,7 @@ return std::make_unique<display::DisplaySnapshot>( port_display_id, port_display_id, edid_display_id, connector_index, - gfx::Point(), physical_size, type, base_connector_id, path_topology, + origin, physical_size, type, base_connector_id, path_topology, is_aspect_preserving_scaling, has_overscan, privacy_screen_state, has_color_correction_matrix, color_correction_in_linear_space, display_color_space, bits_per_channel, hdr_static_metadata, display_name,
diff --git a/ui/ozone/platform/drm/common/drm_util.h b/ui/ozone/platform/drm/common/drm_util.h index 2aaa4a4..6fdb5c6 100644 --- a/ui/ozone/platform/drm/common/drm_util.h +++ b/ui/ozone/platform/drm/common/drm_util.h
@@ -29,6 +29,10 @@ class DisplayMode; } // namespace display +namespace gfx { +class Point; +} + namespace ui { // It is safe to assume there will be no more than 256 connected DRM devices. @@ -136,6 +140,7 @@ int fd, const base::FilePath& sys_path, uint8_t device_index, + const gfx::Point& origin, const display::DrmFormatsAndModifiers& drm_formats_and_modifiers); int GetFourCCFormatForOpaqueFramebuffer(gfx::BufferFormat format);
diff --git a/ui/ozone/platform/drm/gpu/drm_display.cc b/ui/ozone/platform/drm/gpu/drm_display.cc index 4681d34..6e68687 100644 --- a/ui/ozone/platform/drm/gpu/drm_display.cc +++ b/ui/ozone/platform/drm/gpu/drm_display.cc
@@ -139,27 +139,8 @@ return privacy_screen_legacy_.get(); } -DrmDisplay::DrmDisplay(const scoped_refptr<DrmDevice>& drm, - HardwareDisplayControllerInfo* info, - const display::DisplaySnapshot* display_snapshot) - : display_id_(display_snapshot->display_id()), - base_connector_id_(display_snapshot->base_connector_id()), - drm_(drm), - crtc_(info->crtc()->crtc_id), - connector_(info->ReleaseConnector()) { - modes_ = GetDrmModeVector(connector_.get()); - origin_ = display_snapshot->origin(); - is_hdr_capable_ = display_snapshot->bits_per_channel() > 8 && - display_snapshot->color_space().IsHDR(); -#if BUILDFLAG(IS_CHROMEOS_ASH) - is_hdr_capable_ = - is_hdr_capable_ && - base::FeatureList::IsEnabled(display::features::kUseHDRTransferFunction); -#endif - current_color_space_ = gfx::ColorSpace::CreateSRGB(); - privacy_screen_property_ = - std::make_unique<PrivacyScreenProperty>(drm_, connector_.get()); -} +DrmDisplay::DrmDisplay(const scoped_refptr<DrmDevice>& drm) + : drm_(drm), current_color_space_(gfx::ColorSpace::CreateSRGB()) {} DrmDisplay::~DrmDisplay() = default; @@ -168,6 +149,30 @@ return connector_->connector_id; } +void DrmDisplay::Update(HardwareDisplayControllerInfo* info, + const display::DisplaySnapshot* display_snapshot) { + // We take ownership of |info|'s connector because it will not be used again + // beyond this point. It is safe to assume that |connector_| is populated + // since it was obtained from GetDisplayInfosAndInvalidCrtcs(), which discards + // invalid (nullptr) connectors. + connector_ = info->ReleaseConnector(); + DCHECK(connector_); + + crtc_ = info->crtc()->crtc_id; + display_id_ = display_snapshot->display_id(); + base_connector_id_ = display_snapshot->base_connector_id(); + modes_ = GetDrmModeVector(connector_.get()); + is_hdr_capable_ = display_snapshot->bits_per_channel() > 8 && + display_snapshot->color_space().IsHDR(); + privacy_screen_property_ = + std::make_unique<PrivacyScreenProperty>(drm(), connector_.get()); +#if BUILDFLAG(IS_CHROMEOS_ASH) + is_hdr_capable_ = + is_hdr_capable_ && + base::FeatureList::IsEnabled(display::features::kUseHDRTransferFunction); +#endif +} + // When reading DRM state always check that it's still valid. Any sort of events // (such as disconnects) may invalidate the state. bool DrmDisplay::GetHDCPState(
diff --git a/ui/ozone/platform/drm/gpu/drm_display.h b/ui/ozone/platform/drm/gpu/drm_display.h index 160fbbce..3565ae2 100644 --- a/ui/ozone/platform/drm/gpu/drm_display.h +++ b/ui/ozone/platform/drm/gpu/drm_display.h
@@ -56,11 +56,7 @@ ScopedDrmPropertyPtr privacy_screen_legacy_; }; - // Note that some of |info|'s references ownership will be handed to this - // DrmDisplay instance. - explicit DrmDisplay(const scoped_refptr<DrmDevice>& drm, - HardwareDisplayControllerInfo* info, - const display::DisplaySnapshot* display_snapshot); + explicit DrmDisplay(const scoped_refptr<DrmDevice>& drm); DrmDisplay(const DrmDisplay&) = delete; DrmDisplay& operator=(const DrmDisplay&) = delete; @@ -75,6 +71,10 @@ const std::vector<drmModeModeInfo>& modes() const { return modes_; } const gfx::Point& origin() { return origin_; } + // Updates the internal state of this display in accordance to |info| and + // |display_snapshot|. + void Update(HardwareDisplayControllerInfo* info, + const display::DisplaySnapshot* display_snapshot); void SetOrigin(const gfx::Point origin) { origin_ = origin; } bool GetHDCPState(display::HDCPState* state, display::ContentProtectionMethod* protection_method); @@ -96,11 +96,11 @@ const std::vector<display::GammaRampRGBEntry>& degamma_lut, const std::vector<display::GammaRampRGBEntry>& gamma_lut); - const int64_t display_id_; - const int64_t base_connector_id_; + int64_t display_id_ = -1; + int64_t base_connector_id_ = 0; const scoped_refptr<DrmDevice> drm_; - const uint32_t crtc_; - const ScopedDrmConnectorPtr connector_; + uint32_t crtc_ = 0; + ScopedDrmConnectorPtr connector_; std::vector<drmModeModeInfo> modes_; gfx::Point origin_; bool is_hdr_capable_ = false;
diff --git a/ui/ozone/platform/drm/gpu/drm_display_unittest.cc b/ui/ozone/platform/drm/gpu/drm_display_unittest.cc index 80d0764..3246cd1df 100644 --- a/ui/ozone/platform/drm/gpu/drm_display_unittest.cc +++ b/ui/ozone/platform/drm/gpu/drm_display_unittest.cc
@@ -9,10 +9,8 @@ #include "base/test/task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/display/fake/fake_display_snapshot.h" #include "ui/gfx/color_space.h" #include "ui/gfx/linux/test/mock_gbm_device.h" -#include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h" #include "ui/ozone/platform/drm/gpu/mock_drm_device.h" @@ -43,39 +41,6 @@ namespace ui { namespace { -constexpr gfx::Size kNativeDisplaySize(1920, 1080); - -std::unique_ptr<HardwareDisplayControllerInfo> GetDisplayInfo( - uint8_t index = 0) { - // Initialize a list of display modes. - constexpr size_t kNumModes = 5; - drmModeModeInfo modes[kNumModes] = { - {.hdisplay = 640, .vdisplay = 400}, - {.hdisplay = 640, .vdisplay = 480}, - {.hdisplay = 800, .vdisplay = 600}, - {.hdisplay = 1024, .vdisplay = 768}, - // Last mode, which should be the largest, is the native mode. - {.hdisplay = kNativeDisplaySize.width(), - .vdisplay = kNativeDisplaySize.height()}}; - - // Initialize a connector. - ScopedDrmConnectorPtr connector(DrmAllocator<drmModeConnector>()); - connector->connector_id = 123; - connector->connection = DRM_MODE_CONNECTED; - connector->count_props = 0; - connector->count_modes = kNumModes; - connector->modes = DrmAllocator<drmModeModeInfo>(kNumModes); - std::memcpy(connector->modes, &modes[0], kNumModes * sizeof(drmModeModeInfo)); - - // Initialize a CRTC. - ScopedDrmCrtcPtr crtc(DrmAllocator<drmModeCrtc>()); - crtc->crtc_id = 456; - crtc->mode_valid = 1; - crtc->mode = connector->modes[kNumModes - 1]; - - return std::make_unique<HardwareDisplayControllerInfo>( - std::move(connector), std::move(crtc), index); -} class MockHardwareDisplayPlaneManager : public HardwareDisplayPlaneManager { public: @@ -150,18 +115,8 @@ protected: DrmDisplayTest() : mock_drm_device_(base::MakeRefCounted<MockDrmDevice>( - std::make_unique<MockGbmDevice>())) { - auto info = GetDisplayInfo(); - auto snapshot = display::FakeDisplaySnapshot::Builder() - .SetId(123456) - .SetBaseConnectorId(info->connector()->connector_id) - .SetNativeMode(kNativeDisplaySize) - .SetCurrentMode(kNativeDisplaySize) - .SetColorSpace(gfx::ColorSpace::CreateSRGB()) - .Build(); - drm_display_ = std::make_unique<DrmDisplay>(mock_drm_device_, info.get(), - snapshot.get()); - } + std::make_unique<MockGbmDevice>())), + drm_display_(mock_drm_device_) {} MockHardwareDisplayPlaneManager* AddMockHardwareDisplayPlaneManager() { auto mock_hardware_display_plane_manager = @@ -176,11 +131,11 @@ base::test::TaskEnvironment env_; scoped_refptr<DrmDevice> mock_drm_device_; - std::unique_ptr<DrmDisplay> drm_display_; + DrmDisplay drm_display_; }; TEST_F(DrmDisplayTest, SetColorSpace) { - drm_display_->set_is_hdr_capable_for_testing(true); + drm_display_.set_is_hdr_capable_for_testing(true); MockHardwareDisplayPlaneManager* plane_manager = AddMockHardwareDisplayPlaneManager(); @@ -189,7 +144,7 @@ const auto kHDRColorSpace = gfx::ColorSpace::CreateHDR10(); EXPECT_CALL(*plane_manager, SetGammaCorrection(_, SizeIs(0), SizeIs(0))); - drm_display_->SetColorSpace(kHDRColorSpace); + drm_display_.SetColorSpace(kHDRColorSpace); const auto kSDRColorSpace = gfx::ColorSpace::CreateREC709(); constexpr float kSDRLevel = 0.85; @@ -197,7 +152,7 @@ EXPECT_CALL(*plane_manager, SetGammaCorrection(_, SizeIs(0), MatchesPowerFunction(kSDRLevel, kExponent))); - drm_display_->SetColorSpace(kSDRColorSpace); + drm_display_.SetColorSpace(kSDRColorSpace); } TEST_F(DrmDisplayTest, SetEmptyGammaCorrectionNonHDRDisplay) { @@ -208,12 +163,12 @@ .WillByDefault(::testing::Return(true)); EXPECT_CALL(*plane_manager, SetGammaCorrection(_, SizeIs(0), SizeIs(0))); - drm_display_->SetGammaCorrection(std::vector<display::GammaRampRGBEntry>(), - std::vector<display::GammaRampRGBEntry>()); + drm_display_.SetGammaCorrection(std::vector<display::GammaRampRGBEntry>(), + std::vector<display::GammaRampRGBEntry>()); } TEST_F(DrmDisplayTest, SetEmptyGammaCorrectionHDRDisplay) { - drm_display_->set_is_hdr_capable_for_testing(true); + drm_display_.set_is_hdr_capable_for_testing(true); MockHardwareDisplayPlaneManager* plane_manager = AddMockHardwareDisplayPlaneManager(); @@ -225,8 +180,8 @@ EXPECT_CALL(*plane_manager, SetGammaCorrection(_, SizeIs(0), MatchesPowerFunction(kSDRLevel, kExponent))); - drm_display_->SetGammaCorrection(std::vector<display::GammaRampRGBEntry>(), - std::vector<display::GammaRampRGBEntry>()); + drm_display_.SetGammaCorrection(std::vector<display::GammaRampRGBEntry>(), + std::vector<display::GammaRampRGBEntry>()); } TEST_F(DrmDisplayTest, SetVrrEnabled) { @@ -234,10 +189,10 @@ AddMockHardwareDisplayPlaneManager(); EXPECT_CALL(*plane_manager, SetVrrEnabled(_, _)).WillOnce(Return(false)); - EXPECT_FALSE(drm_display_->SetVrrEnabled(true)); + EXPECT_FALSE(drm_display_.SetVrrEnabled(true)); EXPECT_CALL(*plane_manager, SetVrrEnabled(_, _)).WillOnce(Return(true)); - EXPECT_TRUE(drm_display_->SetVrrEnabled(true)); + EXPECT_TRUE(drm_display_.SetVrrEnabled(true)); } } // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc index 3916394..71ed147 100644 --- a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc +++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -128,8 +128,6 @@ displays_configured_callback_ = std::move(callback); } -// TODO(b/261628945): Refactor this code to utilize DrmDevice instead of using -// DRM FDs directly. That way, this code can be tested via MockDrmDevice. MovableDisplaySnapshots DrmGpuDisplayManager::GetDisplays() { std::vector<std::unique_ptr<DrmDisplay>> old_displays; old_displays.swap(displays_); @@ -150,10 +148,20 @@ // Receiving a signal that DRM state was updated. Need to reset the plane // manager's resource cache since IDs may have changed. drm->plane_manager()->ResetConnectorsCache(drm->GetResources()); - - // Create new DisplaySnapshots and resolve display ID collisions. auto display_infos = GetDisplayInfosAndUpdateCrtcs(drm->get_fd()); for (const auto& display_info : display_infos) { + auto it = base::ranges::find_if( + old_displays, + DisplayComparator(drm, display_info->crtc()->crtc_id, + display_info->connector()->connector_id)); + std::unique_ptr<DrmDisplay> current_drm_display; + if (it != old_displays.end()) { + current_drm_display = std::move(*it); + old_displays.erase(it); + } else { + current_drm_display = std::make_unique<DrmDisplay>(drm); + } + // Create list of supported drm formats and modifiers display::DrmFormatsAndModifiers drm_formats_and_modifiers; for (uint32_t format : drm->plane_manager()->GetSupportedFormats()) { @@ -163,17 +171,21 @@ drm_formats_and_modifiers.emplace(format, modifiers); } - params_list.emplace_back(CreateDisplaySnapshot( - display_info.get(), drm->get_fd(), drm->device_path(), - static_cast<uint8_t>(device_index), drm_formats_and_modifiers)); + // Create the new DisplaySnapshot and resolve display ID collisions. + std::unique_ptr<display::DisplaySnapshot> current_display_snapshot = + CreateDisplaySnapshot( + display_info.get(), current_drm_display->drm()->get_fd(), + current_drm_display->drm()->device_path(), + static_cast<uint8_t>(device_index), current_drm_display->origin(), + drm_formats_and_modifiers); - display::DisplaySnapshot* current_display_snapshot = - params_list.back().get(); const auto colliding_display_snapshot_iter = edid_id_collision_map.find( current_display_snapshot->edid_display_id()); if (colliding_display_snapshot_iter != edid_id_collision_map.end()) { collision_detected = true; + // Resolve collisions by adding each colliding display's connector index + // to its display ID. current_display_snapshot->AddIndexToDisplayId(); display::DisplaySnapshot* colliding_display_snapshot = @@ -182,29 +194,17 @@ edid_id_collision_map[colliding_display_snapshot->edid_display_id()] = colliding_display_snapshot; } + + // Do not use |display_info| beyond this point, since some of its internal + // references will be surrendered. + current_drm_display->Update(display_info.get(), + current_display_snapshot.get()); + + // Update the map with the new (or potentially resolved) display snapshot. edid_id_collision_map[current_display_snapshot->edid_display_id()] = - current_display_snapshot; - } - DCHECK_EQ(display_infos.size(), params_list.size()); - - // Create a new DrmDisplay with each of the corresponding display info and - // display snapshot. Note: do not use |display_infos| beyond this point, - // since some of the objects' internal references will be surrendered. - for (size_t i = 0; i < display_infos.size(); ++i) { - // If the DrmDisplay was present previously, copy its origin to the - // corresponding DisplaySnapshot before creating a new DrmDisplay. - const auto& display_info = display_infos[i]; - auto old_drm_display_it = base::ranges::find_if( - old_displays, - DisplayComparator(drm, display_info->crtc()->crtc_id, - display_info->connector()->connector_id)); - if (old_drm_display_it != old_displays.end()) { - params_list[i]->set_origin(old_drm_display_it->get()->origin()); - old_displays.erase(old_drm_display_it); - } - - displays_.emplace_back(std::make_unique<DrmDisplay>( - drm, display_info.get(), params_list[i].get())); + current_display_snapshot.get(); + params_list.push_back(std::move(current_display_snapshot)); + displays_.push_back(std::move(current_drm_display)); } device_index++; } @@ -324,7 +324,8 @@ if (displays_configured_callback_) displays_configured_callback_.Run(); - if (config_success && modeset_flag != display::kTestModeset) { + const bool test_only = modeset_flag == display::kTestModeset; + if (!test_only && config_success) { for (const auto& controller : controllers_to_configure) FindDisplay(controller.display_id)->SetOrigin(controller.origin); }
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/ui/ozone/platform/drm/gpu/mock_drm_device.cc index 3cfec99..ddb208e 100644 --- a/ui/ozone/platform/drm/gpu/mock_drm_device.cc +++ b/ui/ozone/platform/drm/gpu/mock_drm_device.cc
@@ -52,6 +52,11 @@ // pageflip, or other atomic property changes that do not require modesetting. constexpr uint32_t kSeamlessModesetFlags = 0; +template <class Object> +Object* DrmAllocator() { + return static_cast<Object*>(drmMalloc(sizeof(Object))); +} + const std::map<uint32_t, std::string> kCrtcRequiredPropertyNames = { {kActivePropId, "ACTIVE"}, {kModePropId, "MODE_ID"},
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.h b/ui/ozone/platform/drm/gpu/mock_drm_device.h index 27ae28a7..fc2cd688 100644 --- a/ui/ozone/platform/drm/gpu/mock_drm_device.h +++ b/ui/ozone/platform/drm/gpu/mock_drm_device.h
@@ -72,11 +72,6 @@ constexpr uint32_t kPlaneCtmId = 5002; constexpr uint32_t kRotationPropId = 5003; -template <class Object> -Object* DrmAllocator(size_t num_of_objects = 1) { - return static_cast<Object*>(drmMalloc(num_of_objects * sizeof(Object))); -} - // The real DrmDevice makes actual DRM calls which we can't use in unit tests. class MockDrmDevice : public DrmDevice { public:
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc index 5d055b2..5c711a0 100644 --- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc +++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -215,7 +215,7 @@ CreateDisplaySnapshot(display_info.get(), primary_drm_device_handle_->fd(), primary_drm_device_handle_->sys_path(), 0, - display::DrmFormatsAndModifiers()); + gfx::Point(), display::DrmFormatsAndModifiers()); const auto colliding_display_snapshot_iter = edid_id_collision_map.find(current_display_snapshot->edid_display_id());
diff --git a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc index 6057976..bf0bb342a8 100644 --- a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc +++ b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
@@ -27,7 +27,7 @@ namespace { // The maximum number of buffers we allow to be created. -constexpr uint32_t kMaxNumbferOfBuffers = 3; +constexpr size_t kMaxNumberOfBuffers = 3; } // namespace @@ -39,10 +39,8 @@ class WaylandCanvasSurface::SharedMemoryBuffer { public: - SharedMemoryBuffer(gfx::AcceleratedWidget widget, - WaylandBufferManagerGpu* buffer_manager) + explicit SharedMemoryBuffer(WaylandBufferManagerGpu* buffer_manager) : buffer_id_(buffer_manager->AllocateBufferID()), - widget_(widget), buffer_manager_(buffer_manager) { DCHECK(buffer_manager_); } @@ -99,12 +97,6 @@ dirty_region_.setRect(gfx::RectToSkIRect(gfx::Rect(size))); } - void CommitBuffer(const gfx::Rect& damage, float buffer_scale) { - buffer_manager_->CommitBuffer(widget_, buffer_id_, /*frame_id*/ buffer_id_, - frame_data_, gfx::Rect(size_), - gfx::RoundedCornersF(), buffer_scale, damage); - } - void OnUse() { DCHECK(!used_); used_ = true; @@ -143,8 +135,6 @@ return pending_damage_region_; } - void set_frame_data(const gfx::FrameData& data) { frame_data_ = data; } - private: // The size of the buffer. gfx::Size size_; @@ -155,9 +145,6 @@ // Whether this buffer is currently being used. bool used_ = false; - // The widget this buffer is created for. - const gfx::AcceleratedWidget widget_; - // Non-owned pointer to the buffer manager on the gpu process/thread side. const raw_ptr<WaylandBufferManagerGpu> buffer_manager_; @@ -172,9 +159,6 @@ // Pending damage region if the buffer is pending to be submitted. gfx::Rect pending_damage_region_; - - // Frame data. - gfx::FrameData frame_data_; }; class WaylandCanvasSurface::VSyncProvider : public gfx::VSyncProvider { @@ -212,6 +196,28 @@ base::WeakPtr<WaylandCanvasSurface> surface_; }; +WaylandCanvasSurface::PendingFrame::PendingFrame( + uint32_t frame_id, + const gfx::Size& surface_size, + SwapBuffersCallback callback, + gfx::FrameData frame_data, + SharedMemoryBuffer* frame_buffer) + : frame_id(frame_id), + surface_size(surface_size), + swap_ack_callback(std::move(callback)), + data(std::move(frame_data)), + frame_buffer(frame_buffer) { + // The frame might be invalid if there is no frame buffer. However, if there + // is a buffer, it must be marked as used. + DCHECK(!frame_buffer || frame_buffer->used()); +} + +WaylandCanvasSurface::PendingFrame::~PendingFrame() { + if (swap_ack_callback) { + std::move(swap_ack_callback).Run(surface_size); + } +} + WaylandCanvasSurface::WaylandCanvasSurface( WaylandBufferManagerGpu* buffer_manager, gfx::AcceleratedWidget widget) @@ -235,11 +241,9 @@ } if (!pending_buffer_) { - if (buffers_.size() >= kMaxNumbferOfBuffers) { - // We have achieved the maximum number of buffers we can create. Wait for - // a free buffer. - return nullptr; - } + // It must be impossible that the maximum number of buffers that can be + // created is achieved. + DCHECK_LE(buffers_.size(), kMaxNumberOfBuffers); auto buffer = CreateSharedMemoryBuffer(); pending_buffer_ = buffer.get(); buffers_.push_back(std::move(buffer)); @@ -259,10 +263,20 @@ // the new size still fits (but still reallocate if the new size is much // smaller than the old size). buffers_.clear(); - current_buffer_ = nullptr; previous_buffer_ = nullptr; pending_buffer_ = nullptr; - unsubmitted_buffers_.clear(); + + // First clear submitted frame, which will execute the pending swap ack + // callback and only then clear unsubmitted ones. This helps to preserve order + // of swap ack callbacks. + submitted_frame_.reset(); + + // We must preserve FIFO. Thus, manually destroy pending frames. + for (auto& frame : unsubmitted_frames_) { + frame.reset(); + } + unsubmitted_frames_.clear(); + size_ = viewport_size; viewport_scale_ = scale; } @@ -280,16 +294,12 @@ void WaylandCanvasSurface::OnSwapBuffers(SwapBuffersCallback swap_ack_callback, gfx::FrameData data) { - if (pending_buffer_) { - pending_buffer_->set_frame_data(data); - unsubmitted_buffers_.push_back(pending_buffer_); - pending_buffer_ = nullptr; - } + unsubmitted_frames_.push_back(std::make_unique<PendingFrame>( + next_frame_id(), size_, std::move(swap_ack_callback), std::move(data), + pending_buffer_)); + pending_buffer_ = nullptr; - if (!unsubmitted_buffers_.empty()) - ProcessUnsubmittedBuffers(); - base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, base::BindOnce(std::move(swap_ack_callback), size_)); + MaybeProcessUnsubmittedFrames(); } std::unique_ptr<gfx::VSyncProvider> @@ -302,64 +312,82 @@ return true; } -void WaylandCanvasSurface::ProcessUnsubmittedBuffers() { - DCHECK(!unsubmitted_buffers_.empty() && unsubmitted_buffers_.front()->used()); - - // Don't submit a new buffer if there's one already submitted being +void WaylandCanvasSurface::MaybeProcessUnsubmittedFrames() { + // Don't submit a new frame if there's one already submitted being // processed. - if (current_buffer_) + if (submitted_frame_ || unsubmitted_frames_.empty()) { return; + } - current_buffer_ = std::move(unsubmitted_buffers_.front()); - unsubmitted_buffers_.erase(unsubmitted_buffers_.begin()); + auto frame = std::move(unsubmitted_frames_.front()); + unsubmitted_frames_.erase(unsubmitted_frames_.begin()); - gfx::Rect damage = current_buffer_->pending_damage_region(); + auto* frame_buffer = frame->frame_buffer.get(); + // There was no frame buffer associated with this frame. Skip that and process + // the next frame. + if (!frame_buffer) { + // Reset the frame so that it executes the swap ack callback. + frame.reset(); + MaybeProcessUnsubmittedFrames(); + return; + } + + gfx::Rect damage = frame_buffer->pending_damage_region(); // The buffer has been updated. Thus, the |damage| can be subtracted // from its dirty region. - current_buffer_->UpdateDirtyRegion(damage, SkRegion::kDifference_Op); + frame_buffer->UpdateDirtyRegion(damage, SkRegion::kDifference_Op); // Make sure the buffer is up-to-date by copying the outdated region from // the previous buffer. - if (previous_buffer_ && previous_buffer_ != current_buffer_) - current_buffer_->CopyDirtyRegionFrom(previous_buffer_); + if (previous_buffer_ && previous_buffer_ != frame_buffer) { + frame_buffer->CopyDirtyRegionFrom(previous_buffer_); + } - // As long as the |current_buffer_| has been updated, add dirty region to + // As long as the current frame's buffer has been updated, add dirty region to // other buffers to make sure their regions will be updated with up-to-date // content. for (auto& buffer : buffers_) { - if (buffer.get() != current_buffer_) + if (buffer.get() != frame_buffer) { buffer->UpdateDirtyRegion(damage, SkRegion::kUnion_Op); + } } - current_buffer_->CommitBuffer(damage, viewport_scale_); + buffer_manager_->CommitBuffer( + widget_, frame->frame_id, frame_buffer->buffer_id(), + std::move(frame->data), gfx::Rect(size_), gfx::RoundedCornersF(), + viewport_scale_, damage); + + submitted_frame_ = std::move((frame)); } void WaylandCanvasSurface::OnSubmission(uint32_t frame_id, const gfx::SwapResult& swap_result, gfx::GpuFenceHandle release_fence) { DCHECK(release_fence.is_null()); - // We may get an OnSubmission callback for a buffer that was submitted - // before a ResizeCanvas call, which clears all our buffers. Check to - // see if we still know about this buffer. If we know about this buffer - // it must be |current_buffer_| because we only submit new buffers when - // |current_buffer_| is nullptr, and it is only set to nullptr in - // |OnSubmission| and |ResizeCanvas|. In |ResizeCanvas|, |buffers_| is cleared - // so we will not know about |frame_id|. - if (!base::Contains(buffers_, frame_id, &SharedMemoryBuffer::buffer_id)) + // We may get an OnSubmission callback for a frame that was submitted + // before a ResizeCanvas call, which clears all our submitted frame. Check to + // see if we still know about this frame. If we know about this frame + // it must have the same |frame_id| because we only submit new frames when + // |submitted_frame_| is nullptr, and it is only set to nullptr in + // |OnSubmission| and |ResizeCanvas|. In |ResizeCanvas|, |submitted_frame_| + // is cleared so we will not know about |frame_id|. In addition to that, if + // the frame_id is stale, the gpu process may have just recovered from a crash + // so this frame_id can also be ignored. + if (!submitted_frame_ || submitted_frame_->frame_id != frame_id) { return; + } - DCHECK(current_buffer_); - DCHECK_EQ(current_buffer_->buffer_id(), frame_id); + DCHECK_EQ(size_, submitted_frame_->surface_size); if (previous_buffer_) previous_buffer_->OnRelease(); - previous_buffer_ = current_buffer_; - current_buffer_ = nullptr; + previous_buffer_ = submitted_frame_->frame_buffer; + // The frame will automatically execute the swap ack callback on destruction. + submitted_frame_.reset(); - if (!unsubmitted_buffers_.empty()) - ProcessUnsubmittedBuffers(); + MaybeProcessUnsubmittedFrames(); } void WaylandCanvasSurface::OnPresentation( @@ -374,8 +402,7 @@ WaylandCanvasSurface::CreateSharedMemoryBuffer() { DCHECK(!size_.IsEmpty()); - auto canvas_buffer = - std::make_unique<SharedMemoryBuffer>(widget_, buffer_manager_); + auto canvas_buffer = std::make_unique<SharedMemoryBuffer>(buffer_manager_); canvas_buffer->Initialize(size_); return canvas_buffer; }
diff --git a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h index 7b76ec5..a05123e 100644 --- a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h +++ b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.h
@@ -75,7 +75,31 @@ // Internal implementation of gfx::VSyncProvider. class VSyncProvider; - void ProcessUnsubmittedBuffers(); + struct PendingFrame { + PendingFrame(uint32_t frame_id, + const gfx::Size& surface_size, + SwapBuffersCallback callback, + gfx::FrameData frame_data, + SharedMemoryBuffer* frame_buffer); + ~PendingFrame(); + + // Unique identifier of the frame within this AcceleratedWidget. + const uint32_t frame_id; + + // Current surface size. This is required for the |swap_ack_callback|. + const gfx::Size surface_size; + + SwapBuffersCallback swap_ack_callback; + gfx::FrameData data; + + // Buffer associated with this frame. If null, the frame is invalid and + // requires execution of the |swap_ack_callback| as viz may still request + // to swap buffers without calling GetCanvas first. In that case, it skips + // drawing a root render pass and there is nothing to present. + const raw_ptr<SharedMemoryBuffer, DanglingUntriaged> frame_buffer; + }; + + void MaybeProcessUnsubmittedFrames(); // WaylandSurfaceGpu overrides: void OnSubmission(uint32_t frame_id, @@ -94,17 +118,17 @@ float viewport_scale_ = 1.f; std::vector<std::unique_ptr<SharedMemoryBuffer>> buffers_; - // Contains pending to be submitted buffers. The vector is processed as FIFO. - std::vector<SharedMemoryBuffer*> unsubmitted_buffers_; + // Contains pending to be submitted frames. The vector is processed as FIFO. + std::vector<std::unique_ptr<PendingFrame>> unsubmitted_frames_; + + // Currently submitted frame that waits OnSubmission. Set on OnSwapBuffers and + // release on OnSubmission() call. + std::unique_ptr<PendingFrame> submitted_frame_; // Pending buffer that is to be placed into the |unsubmitted_buffers_| to be // processed. raw_ptr<SharedMemoryBuffer, DanglingUntriaged> pending_buffer_ = nullptr; - // Currently used buffer. Set on PresentCanvas() and released on - // OnSubmission() call. - raw_ptr<SharedMemoryBuffer, DanglingUntriaged> current_buffer_ = nullptr; - // Previously used buffer. Set on OnSubmission(). raw_ptr<SharedMemoryBuffer, DanglingUntriaged> previous_buffer_ = nullptr;
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc index 762c1791..3cdfe4be 100644 --- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc +++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -150,6 +150,20 @@ pending_local_swap_ids_.front() > local_swap_id); } + // Corresponds to SoftwareOutputDevice::SwapBuffersCallback so that it can be + // used with canvas surfaces. + void CanvasSwapBuffersCallback(uint64_t local_swap_id, + const gfx::Size& pixel_size) { + last_finish_swap_id_ = pending_local_swap_ids_.front(); + pending_local_swap_ids_.pop(); + DCHECK_EQ(local_swap_id, last_finish_swap_id_); + last_canvas_swap_pixel_size_ = pixel_size; + } + + gfx::Size GetLastCanvasSwapPixelSize() const { + return std::move(last_canvas_swap_pixel_size_); + } + private: uint32_t local_swap_id_ = 0; // Make sure that local_swap_id_ != last_finish_swap_id_. @@ -158,6 +172,10 @@ // Keeps track of a displayed image. std::vector<scoped_refptr<OverlayImageHolder>> displayed_images_; + + // Keeps track of last swap pixel size. Used only for the path that uses + // canvas. + gfx::Size last_canvas_swap_pixel_size_; }; } // namespace @@ -982,6 +1000,272 @@ }); } +// Checks that buffer swap ack is called only after Wayland calls OnSubmission. +TEST_P(WaylandSurfaceFactoryTest, CanvasBufferSwapAck) { + constexpr float kDefaultScaleFactor = 1u; + auto canvas = CreateCanvas(widget_); + ASSERT_TRUE(canvas); + + auto bounds_px = window_->GetBoundsInPixels(); + + canvas->ResizeCanvas(bounds_px.size(), kDefaultScaleFactor); + + const uint32_t surface_id = window_->root_surface()->get_surface_id(); + + // Send the first buffer. OnSubmission must be received immediately. + { + auto* sk_canvas = canvas->GetCanvas(); + ASSERT_TRUE(sk_canvas); + + canvas->PresentCanvas(gfx::Rect(5, 10, 20, 15)); + CallbacksHelper cbs_helper; + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), + cbs_helper.GetNextLocalSwapId()), + gfx::FrameData()); + + // Wait until the mojo calls are done. + base::RunLoop().RunUntilIdle(); + + PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) { + auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id); + mock_surface->SendFrameCallback(); + }); + + base::RunLoop().RunUntilIdle(); + + // The first OnSubmission comes immediately regardless on buffer releases. + EXPECT_EQ(cbs_helper.GetLastCanvasSwapPixelSize(), bounds_px.size()); + } + + // Now submit the second buffer. OnSubmission must come only after the buffer + // is released. + { + auto* sk_canvas = canvas->GetCanvas(); + ASSERT_TRUE(sk_canvas); + + canvas->PresentCanvas(gfx::Rect(1, 1, 30, 55)); + CallbacksHelper cbs_helper; + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), + cbs_helper.GetNextLocalSwapId()), + gfx::FrameData()); + + // Wait until the mojo calls are done. + base::RunLoop().RunUntilIdle(); + + PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) { + auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id); + mock_surface->SendFrameCallback(); + }); + + base::RunLoop().RunUntilIdle(); + + // The second OnSubmission will come only after a buffer is released. + EXPECT_TRUE(cbs_helper.GetLastCanvasSwapPixelSize().IsEmpty()); + + PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) { + auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id); + auto* buffer_resource = mock_surface->prev_attached_buffer(); + ASSERT_TRUE(buffer_resource); + mock_surface->ReleaseBufferFenced(buffer_resource, {}); + }); + + base::RunLoop().RunUntilIdle(); + + // The second OnSubmission will come only after a buffer is released. + EXPECT_EQ(cbs_helper.GetLastCanvasSwapPixelSize(), bounds_px.size()); + } +} + +// Checks that buffer swap ack for an invalid frame is called after the previous +// valid frames receive their OnSubmission calls. +TEST_P(WaylandSurfaceFactoryTest, CanvasBufferSwapAck2) { + constexpr float kDefaultScaleFactor = 1u; + auto canvas = CreateCanvas(widget_); + ASSERT_TRUE(canvas); + + auto bounds_px = window_->GetBoundsInPixels(); + + canvas->ResizeCanvas(bounds_px.size(), kDefaultScaleFactor); + + const uint32_t surface_id = window_->root_surface()->get_surface_id(); + + // Send the first buffer. OnSubmission must be received immediately. + { + auto* sk_canvas = canvas->GetCanvas(); + ASSERT_TRUE(sk_canvas); + + canvas->PresentCanvas(gfx::Rect(5, 10, 20, 15)); + CallbacksHelper cbs_helper; + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), + cbs_helper.GetNextLocalSwapId()), + gfx::FrameData()); + + // Wait until the mojo calls are done. + base::RunLoop().RunUntilIdle(); + + PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) { + auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id); + mock_surface->SendFrameCallback(); + }); + + base::RunLoop().RunUntilIdle(); + + // The first OnSubmission comes immediately regardless on buffer releases. + EXPECT_EQ(cbs_helper.GetLastCanvasSwapPixelSize(), bounds_px.size()); + } + + // Now submit the second buffer/frame and the third buffer/frame. Two + // OnSubmission must come in a correct order - one for the valid frame and + // another for the invalid frame. + { + auto* sk_canvas = canvas->GetCanvas(); + ASSERT_TRUE(sk_canvas); + + canvas->PresentCanvas(gfx::Rect(1, 1, 30, 55)); + CallbacksHelper cbs_helper; + uint32_t second_buffer_swap_id = cbs_helper.GetNextLocalSwapId(); + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), second_buffer_swap_id), + gfx::FrameData()); + + // Submit an invalid frame. It must be acked after the previous buffer/frame + // gets OnSubmission. + const uint32_t invalid_frame_swap_id = cbs_helper.GetNextLocalSwapId(); + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), invalid_frame_swap_id), + gfx::FrameData()); + + // Submit a second invalid frame. This is required to ensure the correct + // order of swaps. + const uint32_t invalid_frame_swap_id2 = cbs_helper.GetNextLocalSwapId(); + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), invalid_frame_swap_id2), + gfx::FrameData()); + + // Wait until the mojo calls are done. + base::RunLoop().RunUntilIdle(); + + PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) { + auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id); + mock_surface->SendFrameCallback(); + }); + + base::RunLoop().RunUntilIdle(); + + // The second (and the third) OnSubmission will come only after a buffer is + // released. + EXPECT_TRUE(cbs_helper.GetLastCanvasSwapPixelSize().IsEmpty()); + EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), + std::numeric_limits<uint32_t>::max()); + + PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) { + auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id); + auto* buffer_resource = mock_surface->prev_attached_buffer(); + ASSERT_TRUE(buffer_resource); + mock_surface->ReleaseBufferFenced(buffer_resource, {}); + }); + + base::RunLoop().RunUntilIdle(); + + // The second OnSubmission will come only after a buffer is released. + EXPECT_EQ(cbs_helper.GetLastCanvasSwapPixelSize(), bounds_px.size()); + // It must be the very last frame's swap id. + EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), invalid_frame_swap_id2); + } +} + +// Check OnSubmission is called on resize. +TEST_P(WaylandSurfaceFactoryTest, CanvasBufferSwapAck3) { + constexpr float kDefaultScaleFactor = 1u; + auto canvas = CreateCanvas(widget_); + ASSERT_TRUE(canvas); + + auto bounds_px = window_->GetBoundsInPixels(); + + canvas->ResizeCanvas(bounds_px.size(), kDefaultScaleFactor); + + const uint32_t surface_id = window_->root_surface()->get_surface_id(); + + // Send the first buffer. OnSubmission must be received immediately. + { + auto* sk_canvas = canvas->GetCanvas(); + ASSERT_TRUE(sk_canvas); + + canvas->PresentCanvas(gfx::Rect(5, 10, 20, 15)); + CallbacksHelper cbs_helper; + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), + cbs_helper.GetNextLocalSwapId()), + gfx::FrameData()); + + // Wait until the mojo calls are done. + base::RunLoop().RunUntilIdle(); + + PostToServerAndWait([surface_id](wl::TestWaylandServerThread* server) { + auto* mock_surface = server->GetObject<wl::MockSurface>(surface_id); + mock_surface->SendFrameCallback(); + }); + + base::RunLoop().RunUntilIdle(); + + // The first OnSubmission comes immediately regardless on buffer releases. + EXPECT_EQ(cbs_helper.GetLastCanvasSwapPixelSize(), bounds_px.size()); + } + + // Now submit the second buffer/frame and couple of empty frames. All of + // them must call OnSubmission as soon as Resize is called. + { + auto* sk_canvas = canvas->GetCanvas(); + ASSERT_TRUE(sk_canvas); + + canvas->PresentCanvas(gfx::Rect(1, 1, 30, 55)); + CallbacksHelper cbs_helper; + uint32_t second_buffer_swap_id = cbs_helper.GetNextLocalSwapId(); + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), second_buffer_swap_id), + gfx::FrameData()); + + const uint32_t invalid_frame_swap_id = cbs_helper.GetNextLocalSwapId(); + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), invalid_frame_swap_id), + gfx::FrameData()); + + const uint32_t invalid_frame_swap_id2 = cbs_helper.GetNextLocalSwapId(); + canvas->OnSwapBuffers( + base::BindOnce(&CallbacksHelper::CanvasSwapBuffersCallback, + base::Unretained(&cbs_helper), invalid_frame_swap_id2), + gfx::FrameData()); + + // Wait until the mojo calls are done. + base::RunLoop().RunUntilIdle(); + + // Nothing must come yet. + EXPECT_TRUE(cbs_helper.GetLastCanvasSwapPixelSize().IsEmpty()); + EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), + std::numeric_limits<uint32_t>::max()); + + gfx::Size new_size = bounds_px.size() + gfx::Size(2, 2); + canvas->ResizeCanvas(new_size, kDefaultScaleFactor); + + // OnSubmission must be called. The last swap id corresponds to the very + // last frame. + EXPECT_EQ(cbs_helper.GetLastCanvasSwapPixelSize(), bounds_px.size()); + EXPECT_EQ(cbs_helper.GetLastFinishedSwapId(), invalid_frame_swap_id2); + } +} + TEST_P(WaylandSurfaceFactoryTest, CreateSurfaceCheckGbm) { gl::SetGLImplementation(gl::kGLImplementationEGLGLES2);
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc index 665e7ce..3d7db92 100644 --- a/ui/ozone/platform/wayland/host/wayland_screen.cc +++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -226,10 +226,11 @@ color_spaces.SetOutputColorSpaceAndBufferFormat( gfx::ContentColorUsage::kWideColorGamut, false, gfx::ColorSpace::CreateDisplayP3D65(), image_format_no_alpha_.value()); - // SRGB10Bit was designed to provide 5x relative brightness. - color_spaces.SetHDRMaxLuminanceRelative(5); - // sRGB is defined to have a luminance level of 80 nits. - color_spaces.SetSDRMaxLuminanceNits(80); + // While SRGB10bit is designed to have a relative luminance of 5x, + // Ash does not rely on this EOTF when finally composited. A value of 10x + // is consistent with what is used by Ash in display_util.cc + // CreateDisplayColorSpaces() + color_spaces.SetHDRMaxLuminanceRelative(10); } #endif
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index f445c83..2d51e7c 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -44,6 +44,7 @@ "pin.icon", "radio_button_active.icon", "radio_button_normal.icon", + "toggle_button_check.icon", "uninstall.icon", "unpin.icon", ]
diff --git a/ui/views/controls/button/toggle_button.cc b/ui/views/controls/button/toggle_button.cc index ada3cf13..6a85c1c 100644 --- a/ui/views/controls/button/toggle_button.cc +++ b/ui/views/controls/button/toggle_button.cc
@@ -11,9 +11,12 @@ #include "base/functional/bind.h" #include "cc/paint/paint_flags.h" #include "third_party/skia/include/core/SkDrawLooper.h" +#include "third_party/skia/include/core/SkRect.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/ui_base_features.h" #include "ui/color/color_id.h" #include "ui/color/color_provider.h" #include "ui/events/event.h" @@ -21,14 +24,18 @@ #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/skia_conversions.h" +#include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/shadow_value.h" #include "ui/gfx/skia_paint_util.h" #include "ui/views/animation/ink_drop.h" +#include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/animation/ink_drop_ripple.h" #include "ui/views/controls/focus_ring.h" #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/painter.h" +#include "ui/views/vector_icons.h" namespace views { @@ -42,6 +49,25 @@ // Inset from the rounded edge of the thumb to the rounded edge of the track. constexpr int kThumbInset = 2; +// ChromeRefresh2023 specific values. +constexpr gfx::Size kRefreshTrackSize = gfx::Size(26, 16); +constexpr int kRefreshThumbIconSize = 8; +constexpr int kRefreshThumbInset = -4; +constexpr int kRefreshThumbInsetSelected = -2; +constexpr int kRefreshThumbPressedOutset = 1; +constexpr int kRefreshHoverDiameter = 20; + +const gfx::Size GetTrackSize() { + return features::IsChromeRefresh2023() ? kRefreshTrackSize : kTrackSize; +} + +int GetThumbInset(bool is_on) { + if (features::IsChromeRefresh2023()) { + return is_on ? kRefreshThumbInsetSelected : kRefreshThumbInset; + } + return kThumbInset; +} + } // namespace class ToggleButton::FocusRingHighlightPathGenerator @@ -55,6 +81,7 @@ // Class representing the thumb (the circle that slides horizontally). class ToggleButton::ThumbView : public View { public: + METADATA_HEADER(ThumbView); ThumbView() { // Make the thumb behave as part of the parent for event handling. SetCanProcessEventsWithinSubtree(false); @@ -63,17 +90,20 @@ ThumbView& operator=(const ThumbView&) = delete; ~ThumbView() override = default; - void Update(const gfx::Rect& bounds, float color_ratio) { + void Update(const gfx::Rect& bounds, float color_ratio, bool is_on) { SetBoundsRect(bounds); color_ratio_ = color_ratio; + is_on_ = is_on; SchedulePaint(); } // Returns the extra space needed to draw the shadows around the thumb. Since // the extra space is around the thumb, the insets will be negative. static gfx::Insets GetShadowOutsets() { - return gfx::Insets(-kShadowBlur) + - gfx::Vector2d(kShadowOffsetX, kShadowOffsetY); + return features::IsChromeRefresh2023() + ? gfx::Insets() + : gfx::Insets(-kShadowBlur) + + gfx::Vector2d(kShadowOffsetX, kShadowOffsetY); } void SetThumbColor(bool is_on, const absl::optional<SkColor>& thumb_color) { @@ -93,13 +123,15 @@ void OnPaint(gfx::Canvas* canvas) override { const float dsf = canvas->UndoDeviceScaleFactor(); const ui::ColorProvider* color_provider = GetColorProvider(); - std::vector<gfx::ShadowValue> shadows; - gfx::ShadowValue shadow( - gfx::Vector2d(kShadowOffsetX, kShadowOffsetY), 2 * kShadowBlur, - color_provider->GetColor(ui::kColorToggleButtonShadow)); - shadows.push_back(shadow.Scale(dsf)); cc::PaintFlags thumb_flags; - thumb_flags.setLooper(gfx::CreateShadowDrawLooper(shadows)); + if (!features::IsChromeRefresh2023()) { + std::vector<gfx::ShadowValue> shadows; + gfx::ShadowValue shadow( + gfx::Vector2d(kShadowOffsetX, kShadowOffsetY), 2 * kShadowBlur, + color_provider->GetColor(ui::kColorToggleButtonShadow)); + shadows.push_back(shadow.Scale(dsf)); + thumb_flags.setLooper(gfx::CreateShadowDrawLooper(shadows)); + } thumb_flags.setAntiAlias(true); const SkColor thumb_on_color = thumb_on_color_.value_or( color_provider->GetColor(ui::kColorToggleButtonThumbOn)); @@ -117,12 +149,24 @@ thumb_bounds = gfx::RectF(gfx::ToEnclosingRect(thumb_bounds)); canvas->DrawCircle(thumb_bounds.CenterPoint(), thumb_bounds.height() / 2.f, thumb_flags); + if (is_on_ && features::IsChromeRefresh2023()) { + const gfx::ImageSkia image = gfx::CreateVectorIcon( + kToggleButtonCheckIcon, kRefreshThumbIconSize * dsf, + color_provider->GetColor(ui::kColorToggleButtonTrackOn)); + const gfx::PointF pos = { + thumb_bounds.CenterPoint().x() - image.width() / 2, + thumb_bounds.CenterPoint().y() - image.height() / 2}; + canvas->DrawImageInt(image, pos.x(), pos.y()); + } } // Colors used for the thumb. absl::optional<SkColor> thumb_on_color_; absl::optional<SkColor> thumb_off_color_; + // Thumb paints differently when on under ChromeRefresh2023. + bool is_on_ = false; + // Color ratio between 0 and 1 that controls the thumb color. float color_ratio_ = 0.0f; }; @@ -138,8 +182,9 @@ views::InstallEmptyHighlightPathGenerator(this); // InkDrop event triggering is handled in NotifyClick(). SetHasInkDropActionOnClick(false); - InkDrop::UseInkDropForSquareRipple(InkDrop::Get(this), - /*highlight_on_hover=*/false); + InkDrop::UseInkDropForSquareRipple( + InkDrop::Get(this), + /*highlight_on_hover=*/features::IsChromeRefresh2023()); InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating( [](ToggleButton* host) { gfx::Rect rect = host->thumb_view_->GetLocalBounds(); @@ -152,6 +197,20 @@ return host->GetTrackColor(host->GetIsOn() || host->HasFocus()); }, this)); + if (features::IsChromeRefresh2023()) { + InkDrop::Get(this)->SetCreateHighlightCallback(base::BindRepeating( + [](ToggleButton* host) { + gfx::Rect thumb_bounds = host->thumb_view_->GetLocalBounds(); + thumb_bounds.Outset((kRefreshHoverDiameter - thumb_bounds.height()) / + 2); + const gfx::Size thumb_size = thumb_bounds.size(); + return std::make_unique<InkDropHighlight>( + thumb_size, thumb_size.height() / 2, + gfx::PointF(thumb_bounds.CenterPoint()), + host->GetTrackColor(host->GetIsOn())); + }, + this)); + } // Even though ToggleButton doesn't paint anything, declare us as flipped in // RTL mode so that FocusRing correctly flips as well. @@ -247,7 +306,7 @@ } gfx::Size ToggleButton::CalculatePreferredSize() const { - gfx::Rect rect(kTrackSize); + gfx::Rect rect(GetTrackSize()); rect.Inset(gfx::Insets::VH(-kTrackVerticalMargin, -kTrackHorizontalMargin)); rect.Inset(-GetInsets()); return rect.size(); @@ -255,25 +314,29 @@ gfx::Rect ToggleButton::GetTrackBounds() const { gfx::Rect track_bounds(GetContentsBounds()); - track_bounds.ClampToCenteredSize(kTrackSize); + track_bounds.ClampToCenteredSize(GetTrackSize()); return track_bounds; } gfx::Rect ToggleButton::GetThumbBounds() const { gfx::Rect thumb_bounds(GetTrackBounds()); - thumb_bounds.Inset(gfx::Insets(-kThumbInset)); + thumb_bounds.Inset(gfx::Insets(-GetThumbInset(GetIsOn()))); thumb_bounds.set_x(thumb_bounds.x() + slide_animation_.GetCurrentValue() * (thumb_bounds.width() - thumb_bounds.height())); // The thumb is a circle, so the width should match the height. thumb_bounds.set_width(thumb_bounds.height()); thumb_bounds.Inset(ThumbView::GetShadowOutsets()); + if (GetState() == STATE_PRESSED && features::IsChromeRefresh2023()) { + thumb_bounds.Outset(kRefreshThumbPressedOutset); + } return thumb_bounds; } void ToggleButton::UpdateThumb() { thumb_view_->Update(GetThumbBounds(), - static_cast<float>(slide_animation_.GetCurrentValue())); + static_cast<float>(slide_animation_.GetCurrentValue()), + GetIsOn()); if (FocusRing::Get(this)) { // Updating the thumb changes the result of GetFocusRingPath(), make sure // the focus ring gets updated to match this new state. @@ -310,7 +373,7 @@ // focused state correctly. This is set up to highlight on focus, but the // highlight does not come back after the ripple is triggered. Then remove // this and add back SetHasInkDropActionOnClick(true) in the constructor. - if (!HasFocus()) { + if (!HasFocus() || features::IsChromeRefresh2023()) { InkDrop::Get(this)->AnimateToState(InkDropState::ACTION_TRIGGERED, ui::LocatedEvent::FromIfValid(&event)); } @@ -318,11 +381,27 @@ Button::NotifyClick(event); } +void ToggleButton::StateChanged(ButtonState old_state) { + Button::StateChanged(old_state); + if (features::IsChromeRefresh2023() && + (GetState() == STATE_PRESSED || old_state == STATE_PRESSED)) { + UpdateThumb(); + } +} + SkPath ToggleButton::GetFocusRingPath() const { SkPath path; - const gfx::Point center = GetThumbBounds().CenterPoint(); - const int kFocusRingRadius = 16; - path.addCircle(center.x(), center.y(), kFocusRingRadius); + if (features::IsChromeRefresh2023()) { + gfx::Rect bounds = GetLocalBounds(); + constexpr int kFocusRingInset = 3; + bounds.Inset(kFocusRingInset); + const SkRect sk_rect = gfx::RectToSkRect(bounds); + path.addRoundRect(sk_rect, 0, sk_rect.height() / 2); + } else { + const gfx::Point center = GetThumbBounds().CenterPoint(); + constexpr int kFocusRingRadius = 16; + path.addCircle(center.x(), center.y(), kFocusRingRadius); + } return path; } @@ -336,21 +415,26 @@ void ToggleButton::OnFocus() { Button::OnFocus(); - InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTION_PENDING, - nullptr); - SchedulePaint(); + if (!features::IsChromeRefresh2023()) { + InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTION_PENDING, + nullptr); + SchedulePaint(); + } } void ToggleButton::OnBlur() { Button::OnBlur(); - // The ink drop may have already gone away if the user clicked after focusing. - if (InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == - views::InkDropState::ACTION_PENDING) { - InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTION_TRIGGERED, - nullptr); + if (!features::IsChromeRefresh2023()) { + // The ink drop may have already gone away if the user clicked after + // focusing. + if (InkDrop::Get(this)->GetInkDrop()->GetTargetInkDropState() == + views::InkDropState::ACTION_PENDING) { + InkDrop::Get(this)->AnimateToState(views::InkDropState::ACTION_TRIGGERED, + nullptr); + } + SchedulePaint(); } - SchedulePaint(); } void ToggleButton::PaintButtonContents(gfx::Canvas* canvas) { @@ -361,13 +445,21 @@ gfx::RectF track_rect(GetTrackBounds()); track_rect.Scale(dsf); track_rect = gfx::RectF(gfx::ToEnclosingRect(track_rect)); + const SkScalar radius = track_rect.height() / 2; cc::PaintFlags track_flags; track_flags.setAntiAlias(true); const float color_ratio = static_cast<float>(slide_animation_.GetCurrentValue()); track_flags.setColor(color_utils::AlphaBlend( GetTrackColor(true), GetTrackColor(false), color_ratio)); - canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_flags); + canvas->DrawRoundRect(track_rect, radius, track_flags); + if (!GetIsOn() && features::IsChromeRefresh2023()) { + track_flags.setColor( + GetColorProvider()->GetColor(ui::kColorToggleButtonShadow)); + track_flags.setStrokeWidth(0.5f); + track_flags.setStyle(cc::PaintFlags::kStroke_Style); + canvas->DrawRoundRect(track_rect, radius, track_flags); + } canvas->Restore(); } @@ -382,6 +474,9 @@ Button::AnimationProgressed(animation); } +BEGIN_METADATA(ToggleButton, ThumbView, View) +END_METADATA + BEGIN_METADATA(ToggleButton, Button) ADD_PROPERTY_METADATA(bool, IsOn) ADD_PROPERTY_METADATA(bool, AcceptsEvents)
diff --git a/ui/views/controls/button/toggle_button.h b/ui/views/controls/button/toggle_button.h index a6a86fda..4f2d690 100644 --- a/ui/views/controls/button/toggle_button.h +++ b/ui/views/controls/button/toggle_button.h
@@ -7,6 +7,7 @@ #include "base/memory/raw_ptr.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/views/controls/button/button.h" @@ -58,6 +59,7 @@ // views::Button: void NotifyClick(const ui::Event& event) override; + void StateChanged(ButtonState old_state) override; // Returns the path to draw the focus ring around for this ToggleButton. SkPath GetFocusRingPath() const;
diff --git a/ui/views/examples/toggle_button_example.cc b/ui/views/examples/toggle_button_example.cc index 03c9e3b..4e37a99e 100644 --- a/ui/views/examples/toggle_button_example.cc +++ b/ui/views/examples/toggle_button_example.cc
@@ -43,6 +43,15 @@ button->SetAccessibleName( l10n_util::GetStringUTF16(IDS_TOGGLE_BUTTON_NAME_2)); button->SetIsOn(true); + button = container->AddChildView( + std::make_unique<ToggleButton>(base::BindRepeating( + [](ToggleButtonExample* example) { + PrintStatus("Pressed 3! count: %d", ++example->count_2_); + }, + base::Unretained(this)))); + button->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_TOGGLE_BUTTON_NAME_3)); + button->SetEnabled(false); } } // namespace views::examples
diff --git a/ui/views/examples/views_examples_resources.grd b/ui/views/examples/views_examples_resources.grd index a513927..f6510c6 100644 --- a/ui/views/examples/views_examples_resources.grd +++ b/ui/views/examples/views_examples_resources.grd
@@ -439,6 +439,9 @@ <message translateable="false" name="IDS_TOGGLE_BUTTON_NAME_2"> Toggle Button 2 </message> + <message translateable="false" name="IDS_TOGGLE_BUTTON_NAME_3"> + Toggle Button 3 + </message> <!-- tree view example --> <message translateable="false" name="IDS_TREE_VIEW_SELECTED_LABEL">
diff --git a/ui/views/metadata/view_factory.h b/ui/views/metadata/view_factory.h index d7dce6e..466475d3 100644 --- a/ui/views/metadata/view_factory.h +++ b/ui/views/metadata/view_factory.h
@@ -35,25 +35,14 @@ BaseViewBuilderT& operator=(BaseViewBuilderT&&) = default; ~BaseViewBuilderT() override = default; - template <typename View> - Builder& CopyAddressTo(View** view_address) & { + template <typename ViewPtr> + Builder& CopyAddressTo(ViewPtr* view_address) & { *view_address = view_ ? view_.get() : root_view_.get(); return *static_cast<Builder*>(this); } - template <typename View> - Builder&& CopyAddressTo(View** view_address) && { - return std::move(this->CopyAddressTo(view_address)); - } - - template <typename View, typename Traits> - Builder& CopyAddressTo(raw_ptr<View, Traits>* view_address) & { - *view_address = view_ ? view_.get() : root_view_.get(); - return *static_cast<Builder*>(this); - } - - template <typename View, typename Traits> - Builder&& CopyAddressTo(raw_ptr<View, Traits>* view_address) && { + template <typename ViewPtr> + Builder&& CopyAddressTo(ViewPtr* view_address) && { return std::move(this->CopyAddressTo(view_address)); }
diff --git a/ui/views/vector_icons/toggle_button_check.icon b/ui/views/vector_icons/toggle_button_check.icon new file mode 100644 index 0000000..930a127 --- /dev/null +++ b/ui/views/vector_icons/toggle_button_check.icon
@@ -0,0 +1,12 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 8, +MOVE_TO, 3.18f, 6, +LINE_TO, 1.29f, 4.1f, +LINE_TO, 1.76f, 3.63f, +LINE_TO, 3.18f, 5.05f, +LINE_TO, 6.24f, 1.99f, +LINE_TO, 6.71f, 2.46f, +CLOSE
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc index 9092e5c..8f760f4 100644 --- a/ui/views/window/dialog_client_view.cc +++ b/ui/views/window/dialog_client_view.cc
@@ -84,7 +84,9 @@ DialogClientView::DialogClientView(Widget* owner, View* contents_view) : ClientView(owner, contents_view), button_row_insets_( - LayoutProvider::Get()->GetInsetsMetric(INSETS_DIALOG_BUTTON_ROW)) { + LayoutProvider::Get()->GetInsetsMetric(INSETS_DIALOG_BUTTON_ROW)), + input_protector_( + std::make_unique<views::InputEventActivationProtector>()) { // Doing this now ensures this accelerator will have lower priority than // one set by the contents view. AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); @@ -154,7 +156,7 @@ void DialogClientView::VisibilityChanged(View* starting_from, bool is_visible) { ClientView::VisibilityChanged(starting_from, is_visible); - input_protector_.VisibilityChanged(is_visible); + input_protector_->VisibilityChanged(is_visible); } void DialogClientView::Layout() { @@ -227,11 +229,11 @@ } void DialogClientView::UpdateInputProtectorTimeStamp() { - input_protector_.UpdateViewShownTimeStamp(); + input_protector_->UpdateViewShownTimeStamp(); } void DialogClientView::ResetViewShownTimeStampForTesting() { - input_protector_.ResetForTesting(); + input_protector_->ResetForTesting(); // IN-TEST } DialogDelegate* DialogClientView::GetDialogDelegate() const { @@ -246,7 +248,7 @@ } void DialogClientView::TriggerInputProtection() { - input_protector_.UpdateViewShownTimeStamp(); + input_protector_->UpdateViewShownTimeStamp(); } void DialogClientView::OnDialogChanged() { @@ -302,7 +304,7 @@ void DialogClientView::ButtonPressed(ui::DialogButton type, const ui::Event& event) { DialogDelegate* const delegate = GetDialogDelegate(); - if (delegate && !input_protector_.IsPossiblyUnintendedInteraction(event)) { + if (delegate && !input_protector_->IsPossiblyUnintendedInteraction(event)) { (type == ui::DIALOG_BUTTON_OK) ? delegate->AcceptDialog() : delegate->CancelDialog(); }
diff --git a/ui/views/window/dialog_client_view.h b/ui/views/window/dialog_client_view.h index ac01e4e..0b3d5510 100644 --- a/ui/views/window/dialog_client_view.h +++ b/ui/views/window/dialog_client_view.h
@@ -5,6 +5,9 @@ #ifndef UI_VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_ #define UI_VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_ +#include <memory> +#include <utility> + #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "ui/base/ui_base_types.h" @@ -84,6 +87,13 @@ // See IsPossiblyUnintendedInteraction(). void ResetViewShownTimeStampForTesting(); + // Override the internal input protector for testing; usually to inject a mock + // version whose return value can be controlled. + void SetInputProtectorForTesting( + std::unique_ptr<views::InputEventActivationProtector> input_protector) { + input_protector_ = std::move(input_protector); + } + private: enum { // The number of buttons that DialogClientView can support. @@ -155,7 +165,7 @@ // SetupLayout(). Everything will be manually updated afterwards. bool adding_or_removing_views_ = false; - InputEventActivationProtector input_protector_; + std::unique_ptr<InputEventActivationProtector> input_protector_; }; BEGIN_VIEW_BUILDER(VIEWS_EXPORT, DialogClientView, ClientView)
diff --git a/ui/webui/examples/browser/ui/web/webui.cc b/ui/webui/examples/browser/ui/web/webui.cc index 1254c06..952b030 100644 --- a/ui/webui/examples/browser/ui/web/webui.cc +++ b/ui/webui/examples/browser/ui/web/webui.cc
@@ -9,6 +9,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" +#include "ui/base/ui_base_features.h" #include "ui/webui/examples/grit/webui_examples_resources.h" namespace webui_examples { @@ -44,6 +45,9 @@ int default_resource) { SetJSModuleDefaults(source); EnableTrustedTypesCSP(source); + source->AddString( + "chromeRefresh2023Attribute", + features::IsChromeRefresh2023() ? "chrome-refresh-2023" : ""); source->AddResourcePaths(resources); source->AddResourcePath("", default_resource); }
diff --git a/ui/webui/resources/cr_components/app_management/BUILD.gn b/ui/webui/resources/cr_components/app_management/BUILD.gn index 13d3322a..f70d23b 100644 --- a/ui/webui/resources/cr_components/app_management/BUILD.gn +++ b/ui/webui/resources/cr_components/app_management/BUILD.gn
@@ -3,13 +3,8 @@ # found in the LICENSE file. import("//mojo/public/tools/bindings/mojom.gni") -import("//tools/grit/preprocess_if_expr.gni") -import("//tools/polymer/css_to_wrapper.gni") -import("//tools/polymer/html_to_wrapper.gni") -import("//tools/typescript/ts_library.gni") -import("//ui/webui/resources/tools/generate_grd.gni") import("//ui/webui/webui_features.gni") -import("app_management.gni") +import("../../tools/build_cr_component.gni") assert(!is_android && !is_ios) @@ -76,65 +71,46 @@ ] } -preprocess_folder = - "$root_gen_dir/ui/webui/resources/preprocessed/cr_components/app_management" +build_cr_component("build") { + grd_prefix = "cr_components_app_management" -preprocess_if_expr("preprocess") { - visibility = [ - ":build_ts", - ":css_wrapper_files", - ":html_wrapper_files", + web_component_files = [ + "file_handling_item.ts", + "more_permissions_item.ts", + "permission_item.ts", + "run_on_os_login_item.ts", + "toggle_row.ts", + "uninstall_button.ts", + "window_mode_item.ts", ] - in_folder = "." - out_folder = target_gen_dir - in_files = ts_files + html_files + html_icons_files + css_files -} -html_to_wrapper("html_wrapper_files") { - deps = [ ":preprocess" ] - in_folder = target_gen_dir - out_folder = target_gen_dir - in_files = html_files + html_icons_files - minify = optimize_webui -} + non_web_component_files = [ + "constants.ts", + "permission_constants.ts", + "permission_util.ts", + "browser_proxy.ts", + "util.ts", + ] -css_to_wrapper("css_wrapper_files") { - deps = [ ":preprocess" ] - in_folder = target_gen_dir - out_folder = target_gen_dir - in_files = css_files - minify = optimize_webui -} + icons_html_files = [ "icons.html" ] -ts_library("build_ts") { - root_dir = target_gen_dir - out_dir = preprocess_folder - composite = true - tsconfig_base = "tsconfig_base.json" - in_files = ts_files + html_wrapper_files + css_wrapper_files + mojo_files + css_files = [ + "app_management_shared_style.css", + "shared_vars.css", + ] - definitions = [ "//tools/typescript/definitions/metrics_private.d.ts" ] + mojo_files_deps = [ ":mojo_bindings_ts__generator" ] + mojo_files = [ "$target_gen_dir/app_management.mojom-webui.ts" ] - deps = [ + tsc_dir = "$root_gen_dir/ui/webui/resources/preprocessed/cr_components/app_management" + ts_deps = [ "//third_party/polymer/v3_0:library", "//ui/webui/resources:library", "//ui/webui/resources/mojo:library", ] - extra_deps = [ - ":css_wrapper_files", - ":html_wrapper_files", - ":mojo_bindings_ts__generator", - ":preprocess", - ] -} + ts_definitions = [ "//tools/typescript/definitions/metrics_private.d.ts" ] -generate_grd("build_grdp") { - grd_prefix = "cr_components_app_management" - out_grd = "$target_gen_dir/resources.grdp" - public_deps = [ ":build_ts" ] - manifest_files = - filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ]) - resource_path_prefix = "cr_components/app_management" + optimize = optimize_webui } source_set("unit_tests") {
diff --git a/ui/webui/resources/cr_components/app_management/app_management.gni b/ui/webui/resources/cr_components/app_management/app_management.gni deleted file mode 100644 index 9bc732e839..0000000 --- a/ui/webui/resources/cr_components/app_management/app_management.gni +++ /dev/null
@@ -1,51 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -_web_component_files = [ - "file_handling_item.ts", - "more_permissions_item.ts", - "permission_item.ts", - "run_on_os_login_item.ts", - "toggle_row.ts", - "uninstall_button.ts", - "window_mode_item.ts", -] - -# Files that are passed as input to html_to_wrapper(). -html_files = [] -foreach(f, _web_component_files) { - html_files += [ string_replace(f, ".ts", ".html") ] -} - -html_icons_files = [ "icons.html" ] - -# Files that are generated by html_to_wrapper(). -html_wrapper_files = [] -foreach(f, html_files + html_icons_files) { - html_wrapper_files += [ f + ".ts" ] -} - -_non_web_component_files = [ - "constants.ts", - "permission_constants.ts", - "permission_util.ts", - "browser_proxy.ts", - "util.ts", -] - -mojo_files = [ "app_management.mojom-webui.ts" ] - -# Files that are passed as input to css_to_wrapper(). -css_files = [ - "app_management_shared_style.css", - "shared_vars.css", -] - -# Files that are generated by css_to_wrapper(). -css_wrapper_files = [] -foreach(f, css_files) { - css_wrapper_files += [ f + ".ts" ] -} - -ts_files = _web_component_files + _non_web_component_files
diff --git a/ui/webui/resources/cr_components/help_bubble/BUILD.gn b/ui/webui/resources/cr_components/help_bubble/BUILD.gn index 5f20883..0eccddd 100644 --- a/ui/webui/resources/cr_components/help_bubble/BUILD.gn +++ b/ui/webui/resources/cr_components/help_bubble/BUILD.gn
@@ -3,11 +3,7 @@ # found in the LICENSE file. import("//mojo/public/tools/bindings/mojom.gni") -import("//tools/grit/preprocess_if_expr.gni") -import("//tools/polymer/html_to_wrapper.gni") -import("//tools/typescript/ts_library.gni") -import("//ui/webui/resources/tools/generate_grd.gni") -import("help_bubble.gni") +import("../../tools/build_cr_component.gni") assert(!is_android && !is_ios) @@ -23,60 +19,26 @@ webui_module_path = "chrome://resources/cr_components/help_bubble/" } -html_to_wrapper("html_wrapper_files") { - in_files = html_files -} +build_cr_component("build") { + grd_prefix = "cr_components_help_bubble" -# Output folder used to hold preprocess_if_expr() output. -preprocess_folder_tmp = "$root_gen_dir/ui/webui/resources/preprocessed/cr_components/help_bubble_tmp" + web_component_files = [ "help_bubble.ts" ] + non_web_component_files = [ + "help_bubble_mixin.ts", + "help_bubble_proxy.ts", + "help_bubble_controller.ts", + ] -# Output folder used to hold ts_library() output. -preprocess_folder = - "$root_gen_dir/ui/webui/resources/preprocessed/cr_components/help_bubble" + icons_html_files = [ "help_bubble_icons.html" ] -ts_library("build_ts") { - root_dir = preprocess_folder_tmp - out_dir = preprocess_folder - composite = true - tsconfig_base = "tsconfig_base.json" - in_files = ts_files + html_wrapper_files + mojo_files + mojo_files_deps = [ ":mojo_bindings_ts__generator" ] + mojo_files = [ "$target_gen_dir/help_bubble.mojom-webui.ts" ] - deps = [ + tsc_dir = + "$root_gen_dir/ui/webui/resources/preprocessed/cr_components/help_bubble" + ts_deps = [ "//third_party/polymer/v3_0:library", "//ui/webui/resources:library", "//ui/webui/resources/mojo:library", ] - extra_deps = [ - ":copy_mojom", - ":preprocess_generated", - ":preprocess_src", - ] -} - -preprocess_if_expr("preprocess_src") { - in_folder = "." - out_folder = preprocess_folder_tmp - in_files = ts_files -} - -preprocess_if_expr("preprocess_generated") { - deps = [ ":html_wrapper_files" ] - in_folder = target_gen_dir - out_folder = preprocess_folder_tmp - in_files = html_wrapper_files -} - -copy("copy_mojom") { - deps = [ ":mojo_bindings_ts__generator" ] - sources = [ "$target_gen_dir/help_bubble.mojom-webui.ts" ] - outputs = [ "$preprocess_folder_tmp/{{source_file_part}}" ] -} - -generate_grd("build_grdp") { - grd_prefix = "cr_components_help_bubble" - out_grd = "$target_gen_dir/resources.grdp" - deps = [ ":build_ts" ] - manifest_files = - filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ]) - resource_path_prefix = "cr_components/help_bubble" }
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble.gni b/ui/webui/resources/cr_components/help_bubble/help_bubble.gni deleted file mode 100644 index 01b45f4..0000000 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble.gni +++ /dev/null
@@ -1,30 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Files holding a Polymer element definition AND have an equivalent .html file. -_web_component_files = [ "help_bubble.ts" ] - -_icon_files = [ "help_bubble_icons.ts" ] - -# Files that are passed as input to html_to_wrapper(). -html_files = [] -foreach(f, _web_component_files + _icon_files) { - html_files += [ string_replace(f, ".ts", ".html") ] -} - -# Files that are generated by html_to_wrapper(). -html_wrapper_files = [] -foreach(f, html_files) { - html_wrapper_files += [ f + ".ts" ] -} - -_non_web_component_files = [ - "help_bubble_mixin.ts", - "help_bubble_proxy.ts", - "help_bubble_controller.ts", -] - -mojo_files = [ "help_bubble.mojom-webui.ts" ] - -ts_files = _web_component_files + _non_web_component_files
diff --git a/ui/webui/resources/cr_components/most_visited/BUILD.gn b/ui/webui/resources/cr_components/most_visited/BUILD.gn index c1d671873..53c35e1 100644 --- a/ui/webui/resources/cr_components/most_visited/BUILD.gn +++ b/ui/webui/resources/cr_components/most_visited/BUILD.gn
@@ -3,17 +3,11 @@ # found in the LICENSE file. import("//mojo/public/tools/bindings/mojom.gni") -import("//tools/polymer/html_to_wrapper.gni") -import("//tools/typescript/ts_library.gni") -import("//ui/webui/resources/tools/generate_grd.gni") import("//ui/webui/webui_features.gni") -import("most_visited.gni") +import("../../tools/build_cr_component.gni") assert(!is_android && !is_ios) -preprocess_folder = - "$root_gen_dir/ui/webui/resources/preprocessed/cr_components/most_visited" - mojom("mojom") { sources = [ "most_visited.mojom" ] public_deps = [ @@ -25,40 +19,26 @@ webui_module_path = "chrome://resources/cr_components/most_visited/" } -html_to_wrapper("html_wrapper_files") { - in_files = html_files - minify = optimize_webui -} +build_cr_component("build") { + grd_prefix = "cr_components_most_visited" -copy("copy_src") { - sources = ts_files - outputs = [ "$target_gen_dir/{{source_file_part}}" ] -} + web_component_files = [ "most_visited.ts" ] -ts_library("build_ts") { - root_dir = target_gen_dir - out_dir = preprocess_folder - composite = true - tsconfig_base = "tsconfig_base.json" - in_files = ts_files + html_wrapper_files + mojo_files - deps = [ + non_web_component_files = [ + "browser_proxy.ts", + "window_proxy.ts", + ] + + mojo_files_deps = [ ":mojom_ts__generator" ] + mojo_files = [ "$target_gen_dir/most_visited.mojom-webui.ts" ] + + tsc_dir = + "$root_gen_dir/ui/webui/resources/preprocessed/cr_components/most_visited" + ts_deps = [ "//third_party/polymer/v3_0:library", "//ui/webui/resources:library", "//ui/webui/resources/mojo:library", ] - extra_deps = [ - ":copy_src", - ":html_wrapper_files", - ":mojom_ts__generator", - ] -} -generate_grd("build_grdp") { - grd_prefix = "cr_components_most_visited" - out_grd = "$target_gen_dir/resources.grdp" - - public_deps = [ ":build_ts" ] - manifest_files = - filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ]) - resource_path_prefix = "cr_components/most_visited" + optimize = optimize_webui }
diff --git a/ui/webui/resources/cr_components/most_visited/most_visited.gni b/ui/webui/resources/cr_components/most_visited/most_visited.gni deleted file mode 100644 index 4e6dc9a..0000000 --- a/ui/webui/resources/cr_components/most_visited/most_visited.gni +++ /dev/null
@@ -1,27 +0,0 @@ -# Copyright 2022 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Files holding a Polymer element definition AND have an equivalent .html file. -_web_component_files = [ "most_visited.ts" ] - -# Files that are passed as input to html_to_wrapper(). -html_files = [] -foreach(f, _web_component_files) { - html_files += [ string_replace(f, ".ts", ".html") ] -} - -# Files that are generated by html_to_wrapper(). -html_wrapper_files = [] -foreach(f, html_files) { - html_wrapper_files += [ f + ".ts" ] -} - -_non_web_component_files = [ - "browser_proxy.ts", - "window_proxy.ts", -] - -mojo_files = [ "most_visited.mojom-webui.ts" ] - -ts_files = _web_component_files + _non_web_component_files
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_action.ts b/ui/webui/resources/cr_components/omnibox/realbox_action.ts index c7199eb..6af6c4e 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_action.ts +++ b/ui/webui/resources/cr_components/omnibox/realbox_action.ts
@@ -15,7 +15,7 @@ // Browsing History, etc.) class RealboxActionElement extends PolymerElement { static get is() { - return 'ntp-realbox-action'; + return 'cr-realbox-action'; } static get template() {
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_browser_proxy.ts b/ui/webui/resources/cr_components/omnibox/realbox_browser_proxy.ts index a783eeed..cdab08ba 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_browser_proxy.ts +++ b/ui/webui/resources/cr_components/omnibox/realbox_browser_proxy.ts
@@ -6,8 +6,8 @@ /** * @fileoverview This file provides a singleton class that exposes the Mojo - * handler interface used for bidirectional communication between the NTP - * realbox JS and the browser. + * handler interface used for bidirectional communication between the + * <ntp-realbox> or the <cr-realbox-dropdown> and the browser. */ let instance: RealboxBrowserProxy|null = null;
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_dropdown.html b/ui/webui/resources/cr_components/omnibox/realbox_dropdown.html index c3a8d6a..f97eca6 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_dropdown.html +++ b/ui/webui/resources/cr_components/omnibox/realbox_dropdown.html
@@ -5,17 +5,17 @@ #selector { background-color: var(--color-realbox-results-background); - border-radius: calc(0.25 * var(--ntp-realbox-height)); - box-shadow: var(--ntp-realbox-shadow); + border-radius: calc(0.25 * var(--cr-realbox-height)); + box-shadow: var(--cr-realbox-shadow); display: block; margin-bottom: 8px; overflow: hidden; padding-bottom: 8px; - padding-top: var(--ntp-realbox-height); + padding-top: var(--cr-realbox-height); } :host([round-corners]) #selector { - border-radius: calc(0.5 * var(--ntp-realbox-height)); + border-radius: calc(0.5 * var(--cr-realbox-height)); padding-bottom: 18px; } @@ -25,7 +25,7 @@ } } - ntp-realbox-match { + cr-realbox-match { color: var(--color-realbox-results-foreground); } @@ -58,20 +58,20 @@ var(--color-realbox-results-icon-selected); } - ntp-realbox-match:-webkit-any(:hover, :focus-within, .selected), + cr-realbox-match:-webkit-any(:hover, :focus-within, .selected), .header:-webkit-any(:hover, :focus-within) { background-color: var(--color-realbox-results-background-hovered); } @media (forced-colors: active) { - ntp-realbox-match:-webkit-any(:hover, :focus-within, .selected), + cr-realbox-match:-webkit-any(:hover, :focus-within, .selected), .header:-webkit-any(:hover, :focus-within) { background-color: Highlight; } } </style> -<iron-selector id="selector" selectable="ntp-realbox-match" +<iron-selector id="selector" selectable="cr-realbox-match" items="{{selectableMatchElements_}}" selected="{{selectedMatchIndex}}" selected-class="selected"> <template is="dom-repeat" items="[[groupIds_(result.matches.*)]]" @@ -95,9 +95,9 @@ <template is="dom-repeat" items="[[result.matches]]" as="match" filter="[[matchIsInGroupFilter_(groupId)]]" on-dom-change="onResultRepaint_"> - <ntp-realbox-match tabindex="0" role="option" match="[[match]]" + <cr-realbox-match tabindex="0" role="option" match="[[match]]" match-index="[[matchIndex_(match)]]"> - </ntp-realbox-match> + </cr-realbox-match> </template> </template> </template>
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_dropdown.ts b/ui/webui/resources/cr_components/omnibox/realbox_dropdown.ts index 96ea90f..53f6488b9 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_dropdown.ts +++ b/ui/webui/resources/cr_components/omnibox/realbox_dropdown.ts
@@ -35,7 +35,7 @@ // the embedder (i.e., <ntp-realbox>) to change the selection. export class RealboxDropdownElement extends PolymerElement { static get is() { - return 'ntp-realbox-dropdown'; + return 'cr-realbox-dropdown'; } static get template() {
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_icon.html b/ui/webui/resources/cr_components/omnibox/realbox_icon.html index fdab6bb..cf6df78 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_icon.html +++ b/ui/webui/resources/cr_components/omnibox/realbox_icon.html
@@ -18,12 +18,12 @@ } /* Entities may feature a dominant color background until image loads. */ - :host-context(ntp-realbox-match[has-image]) #container { + :host-context(cr-realbox-match[has-image]) #container { background-color: var(--container-bg-color); } /* Calculator answer and suggestion answer icons feature a blue background. */ - :host-context(ntp-realbox-match[is-rich-suggestion]:not([has-image])) #container { + :host-context(cr-realbox-match[is-rich-suggestion]:not([has-image])) #container { background-color: var(--google-blue-600); border-radius: 50%; height: 24px; @@ -36,7 +36,7 @@ max-width: 32px; } - :host-context(ntp-realbox-match[has-image]) #image { + :host-context(cr-realbox-match[has-image]) #image { display: initial; } @@ -57,11 +57,11 @@ width: 24px; } - :host-context(ntp-realbox-match[has-image]) #icon { + :host-context(cr-realbox-match[has-image]) #icon { display: none; } - :host-context(ntp-realbox-match[is-rich-suggestion]) #icon { + :host-context(cr-realbox-match[is-rich-suggestion]) #icon { background-color: white; }
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_icon.ts b/ui/webui/resources/cr_components/omnibox/realbox_icon.ts index c493f7f..3cdee1ce 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_icon.ts +++ b/ui/webui/resources/cr_components/omnibox/realbox_icon.ts
@@ -23,7 +23,7 @@ // render icons, favicons, and entity images. export class RealboxIconElement extends PolymerElement { static get is() { - return 'ntp-realbox-icon'; + return 'cr-realbox-icon'; } static get template() {
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_match.html b/ui/webui/resources/cr_components/omnibox/realbox_match.html index adb8bd3..f4af212 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_match.html +++ b/ui/webui/resources/cr_components/omnibox/realbox_match.html
@@ -102,8 +102,8 @@ } /* Uses a dimmed color for description for entities. */ - :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)):host([is-entity-suggestion]) #description, - :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)) .dim { + :host-context(cr-realbox-match:-webkit-any(:focus-within, .selected)):host([is-entity-suggestion]) #description, + :host-context(cr-realbox-match:-webkit-any(:focus-within, .selected)) .dim { color: var(--color-realbox-results-dim-selected); } @@ -111,7 +111,7 @@ color: var(--color-realbox-results-url); } - :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)) .url { + :host-context(cr-realbox-match:-webkit-any(:focus-within, .selected)) .url { color: var(--color-realbox-results-url-selected); } @@ -120,11 +120,11 @@ opacity: 0; /* Hides the button while keeping it in tab order. */ } - :host-context(ntp-realbox-match:hover) #remove { + :host-context(cr-realbox-match:hover) #remove { opacity: 1; } - :host-context(ntp-realbox-match:-webkit-any(:focus-within, .selected)) #remove { + :host-context(cr-realbox-match:-webkit-any(:focus-within, .selected)) #remove { --cr-icon-button-fill-color: var(--color-realbox-results-icon-selected); opacity: 1; @@ -133,7 +133,7 @@ </style> <div class="container" aria-hidden="true"> <div id="focus-indicator"></div> - <ntp-realbox-icon id="icon" match="[[match]]"></ntp-realbox-icon> + <cr-realbox-icon id="icon" match="[[match]]"></cr-realbox-icon> <div id="text-container"> <span id="tail-suggest-prefix" hidden$="[[!tailSuggestPrefix_]]"> <span id="prefix">[[tailSuggestPrefix_]]</span> @@ -154,9 +154,9 @@ </div> <template is="dom-if" if="[[actionIsVisible_]]"> <div class="container" aria-hidden="true"> - <ntp-realbox-action id="action" action="[[match.action]]" + <cr-realbox-action id="action" action="[[match.action]]" tabindex="1" on-click="onActionClick_" on-keydown="onActionKeyDown_"> - </ntp-realbox-action> + </cr-realbox-action> </div> </template>
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_match.ts b/ui/webui/resources/cr_components/omnibox/realbox_match.ts index 6e6ba09..f9250af 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_match.ts +++ b/ui/webui/resources/cr_components/omnibox/realbox_match.ts
@@ -51,7 +51,7 @@ // Displays an autocomplete match similar to those in the Omnibox. export class RealboxMatchElement extends PolymerElement { static get is() { - return 'ntp-realbox-match'; + return 'cr-realbox-match'; } static get template() { @@ -414,7 +414,7 @@ declare global { interface HTMLElementTagNameMap { - 'ntp-realbox-match': RealboxMatchElement; + 'cr-realbox-match': RealboxMatchElement; } }
diff --git a/ui/webui/resources/cr_elements/cr_button/cr_button.html b/ui/webui/resources/cr_elements/cr_button/cr_button.html index b687037..e5d5dfa 100644 --- a/ui/webui/resources/cr_elements/cr_button/cr_button.html +++ b/ui/webui/resources/cr_elements/cr_button/cr_button.html
@@ -206,6 +206,20 @@ line-height: 154%; } + :host-context([chrome-refresh-2023]):host(.tonal-button) { + background-color: var(--color-button-background-tonal, + var(--cr-color-token-secondary-container)); + color: var(--color-button-foreground-tonal, + var(--cr-color-token-on-secondary-container)); + } + + :host-context([chrome-refresh-2023]):host(.tonal-button[disabled]) { + background-color: var(--color-button-background-tonal-disabled, + rgba(var(--cr-color-token-on-surface-rgb), .12)); + border: none; + color: var(--disabled-text-color); + } + paper-ripple { color: var(--ink-color); height: var(--paper-ripple-height);
diff --git a/ui/webui/resources/cr_elements/cr_shared_vars.css b/ui/webui/resources/cr_elements/cr_shared_vars.css index db779ca..8d33226 100644 --- a/ui/webui/resources/cr_elements/cr_shared_vars.css +++ b/ui/webui/resources/cr_elements/cr_shared_vars.css
@@ -238,6 +238,8 @@ --cr-color-token-on-primary: rgb(255, 255, 255); --cr-color-token-primary-container: rgb(211, 227, 253); --cr-color-token-on-primary-container: rgb(4, 30, 73); + --cr-color-token-secondary-container: rgb(194, 231, 255); + --cr-color-token-on-secondary-container: rgb(0, 29, 53); --cr-color-token-on-surface-rgb: 31, 31, 31; --cr-color-token-on-surface: rgb(var(--cr-color-token-on-surface-rgb)); @@ -252,6 +254,8 @@ --cr-color-token-on-primary: rgb(6, 46, 111); --cr-color-token-primary-container: rgb(8, 66, 160); --cr-color-token-on-primary-container: rgb(211, 227, 253); + --cr-color-token-secondary-container: rgb(0, 74, 119); + --cr-color-token-on-secondary-container: rgb(194, 231, 255); --cr-color-token-on-surface-rgb: 227, 227, 227; } }