diff --git a/BUILD.gn b/BUILD.gn index 3e422d7..aa2cb7b 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -249,6 +249,7 @@ if (!is_ios && !is_fuchsia) { deps += [ + "//chrome/test:telemetry_perf_unittests", "//chrome/test:unit_tests", "//components:components_browsertests", "//device:device_unittests", @@ -257,9 +258,7 @@ "//media/cast:cast_unittests", "//third_party/catapult/telemetry:bitmaptools($host_toolchain)", ] - if (!is_android) { - deps += [ "//chrome/test:telemetry_perf_unittests" ] - } else { + if (is_android) { import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") foreach(_target_suffix, telemetry_android_browser_target_suffixes) { deps += [ "//chrome/test:telemetry_perf_unittests${_target_suffix}" ] @@ -829,10 +828,9 @@ "//chrome/browser/vr:vr_common_perftests", "//chrome/browser/vr:vr_common_unittests", "//chrome/browser/vr:vr_pixeltests", + "//tools/perf/contrib/vr_benchmarks:vr_perf_tests", ] - if (!is_android) { - deps += [ "//tools/perf/contrib/vr_benchmarks:vr_perf_tests" ] - } else { + if (is_android) { deps += [ "//chrome/browser/android/vr:vr_android_unittests" ] import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") foreach(_target_suffix, telemetry_android_browser_target_suffixes) {
diff --git a/DEPS b/DEPS index 8c29008..ffb8e48e 100644 --- a/DEPS +++ b/DEPS
@@ -222,7 +222,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'e2a9bdfba448ca308bf0430ea53958976ee98194', + 'skia_revision': '657e375a16e651da6db2683941fad4600587eb72', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -234,7 +234,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '397fc145b8b330605ac3eb4010cc1990411fea7e', + 'angle_revision': 'ab440fe932ff235f228bf4f4efd214869bb87504', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -269,7 +269,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': 'd9b3fa4b519b8b2ad6ca9ea544d787f833e32a28', + 'nacl_revision': '96c11240b652b05d2708e73c9ce837dfea2208cc', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -293,7 +293,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': '88e3e034773b9925f8ae6d0e858d9523bece5edc', + 'catapult_revision': '7a1b1a88c5cd469e81442471d9a5e01e27ce2b9c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -301,7 +301,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': '68569d97cfbbd3b7fc2117a037288b58d9c9cb26', + 'devtools_frontend_revision': '9a168fb4ad0ec9f952090aa7399e8a6daa22aabb', # 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. @@ -341,7 +341,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': '8d05400b405225f4115b422c73a83b40ca984c7d', + 'dawn_revision': 'bd45a2014044eb11ac46b7ebba1a56272e8901c9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -581,7 +581,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '4b3e0691e973ce343b02d11c2147677e8d42ecb3', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'ab888ec4b58c304d85cdb0228f7587cca40670cf', 'condition': 'checkout_ios', }, @@ -738,7 +738,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '4TJowTg6khWl4yuneqtj7HHyMIuSVpcOie01pubHj-UC', + 'version': 'UAMCrUju8eVq7BoerUp34C1tN7f6snsrm-nKamz4gBYC', }, ], 'condition': 'checkout_android', @@ -1360,7 +1360,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '90b2155f7c11dbf3b4b1d02131d20a942120ff9c', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '390161883794a40acb72e661d14c39b712cd70ec', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1553,7 +1553,7 @@ 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '1ade45cbadfd19298d2c47dc538962d4425ad2dd', - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@36456846a4affb738fc3f012cc8f1c8c86ef0595', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@df0528b581a1709ccad790c205d3c11d0b657ed6', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'f67d7fa397e83060b76a1ec53579116a0bbdff7a', @@ -1592,7 +1592,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '10efeb0c9ee186d3a44c9b629ccf252017f7243c', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '51969310ef432a9c340bb091eea1f1553ca01587', + Var('webrtc_git') + '/src.git' + '@' + '1f88aba9bd481d8918c8fecf885675631eda5228', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1653,7 +1653,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@abcfbf062bb0ebaddf28d767475e15a612c5079b', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c65a7761f0b44b0154b1d73784ab205313640351', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.cc b/android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.cc index 0679b86..4a9dfc4 100644 --- a/android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.cc +++ b/android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.cc
@@ -93,6 +93,7 @@ if (!record.has_value()) { VLOG(2) << "Failed to load WebView apps package allowlist"; + return; } VLOG(2) << "WebView apps package allowlist version "
diff --git a/android_webview/test/shell/AndroidManifest.xml b/android_webview/test/shell/AndroidManifest.xml index a916e4c..a7bc734 100644 --- a/android_webview/test/shell/AndroidManifest.xml +++ b/android_webview/test/shell/AndroidManifest.xml
@@ -26,7 +26,8 @@ android:hardwareAccelerated="true"> <activity android:name="org.chromium.android_webview.shell.AwShellActivity" android:label="Android WebView Test Shell" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize"> + android:configChanges="orientation|keyboardHidden|keyboard|screenSize" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> @@ -41,7 +42,8 @@ </intent-filter> </activity> <activity android:name="org.chromium.android_webview.test.AwTestRunnerActivity" - android:label="AwTestRunnerActivity"> + android:label="AwTestRunnerActivity" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
diff --git a/ash/public/cpp/desk_template.cc b/ash/public/cpp/desk_template.cc index 8ac1ebd..acf9c2e 100644 --- a/ash/public/cpp/desk_template.cc +++ b/ash/public/cpp/desk_template.cc
@@ -23,13 +23,4 @@ DeskTemplate::~DeskTemplate() = default; -std::unique_ptr<DeskTemplate> DeskTemplate::Clone() { - std::unique_ptr<DeskTemplate> desk_template = std::make_unique<DeskTemplate>( - uuid_.AsLowercaseString(), base::UTF16ToUTF8(template_name_), - created_time_); - if (desk_restore_data_) - desk_template->set_desk_restore_data(desk_restore_data_->Clone()); - return desk_template; -} - } // namespace ash \ No newline at end of file
diff --git a/ash/public/cpp/desk_template.h b/ash/public/cpp/desk_template.h index 08a6550..ed8bf84 100644 --- a/ash/public/cpp/desk_template.h +++ b/ash/public/cpp/desk_template.h
@@ -29,12 +29,6 @@ DeskTemplate& operator=(const DeskTemplate&) = delete; ~DeskTemplate(); - // Used in cases where copies of a DeskTemplate are needed to be made. - // This specifically used in the DeskSyncBridge which requires a map - // of DeskTemplate unique pointers to be valid and needs to pass - // that information in DeskModel callbacks. - std::unique_ptr<DeskTemplate> Clone(); - base::GUID uuid() const { return uuid_; } base::Time created_time() const { return created_time_; } const std::u16string& template_name() const { return template_name_; }
diff --git a/base/profiler/native_unwinder_ios.cc b/base/profiler/native_unwinder_ios.cc index 8d5c80e3..dd9567fc 100644 --- a/base/profiler/native_unwinder_ios.cc +++ b/base/profiler/native_unwinder_ios.cc
@@ -37,13 +37,20 @@ uintptr_t next_frame = thread_context->__rbp; #endif + const auto is_fp_valid = [&](uintptr_t fp) { + return fp >= stack_bottom && fp < stack_top && (fp & align_mask) == 0; + }; + + if (!is_fp_valid(next_frame)) { + return UnwindResult::ABORTED; + } + for (;;) { uintptr_t retaddr; uintptr_t frame = next_frame; next_frame = pthread_stack_frame_decode_np(frame, &retaddr); - if (frame < stack_bottom || frame > stack_top || - (frame & align_mask) != 0 || next_frame <= frame) { + if (!is_fp_valid(frame) || next_frame <= frame) { return UnwindResult::COMPLETED; }
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc index b6d47fdd..07683eca 100644 --- a/base/profiler/stack_sampling_profiler.cc +++ b/base/profiler/stack_sampling_profiler.cc
@@ -749,8 +749,9 @@ // The profiler is currently supported for Windows x64, MacOSX x64, and Android // ARM32. bool StackSamplingProfiler::IsSupportedForCurrentPlatform() { -#if (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) || \ - (defined(OS_MAC) && defined(ARCH_CPU_X86_64)) || \ +#if (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) || \ + (defined(OS_MAC) && defined(ARCH_CPU_X86_64)) || \ + (defined(OS_IOS) && defined(ARCH_CPU_64_BITS)) || \ (defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)) #if defined(OS_MAC) // TODO(https://crbug.com/1098119): Fix unwinding on macOS 11. The OS has
diff --git a/base/threading/hang_watcher.cc b/base/threading/hang_watcher.cc index c88adfc..7e8bfcb 100644 --- a/base/threading/hang_watcher.cc +++ b/base/threading/hang_watcher.cc
@@ -274,12 +274,6 @@ } // static -bool HangWatcher::IsUIThreadHangWatchingEnabled() { - return g_ui_thread_log_level.load(std::memory_order_relaxed) != - LoggingLevel::kNone; -} - -// static bool HangWatcher::IsCrashReportingEnabled() { if (g_ui_thread_log_level.load(std::memory_order_relaxed) == LoggingLevel::kUmaAndCrash) {
diff --git a/base/threading/hang_watcher.h b/base/threading/hang_watcher.h index a8803645..9ba7f49 100644 --- a/base/threading/hang_watcher.h +++ b/base/threading/hang_watcher.h
@@ -138,7 +138,6 @@ static bool IsEnabled(); static bool IsThreadPoolHangWatchingEnabled(); static bool IsIOThreadHangWatchingEnabled(); - static bool IsUIThreadHangWatchingEnabled(); // Returns true if crash dump reporting is configured for any thread type. static bool IsCrashReportingEnabled();
diff --git a/base/token.cc b/base/token.cc index f252925..6b9f3f9 100644 --- a/base/token.cc +++ b/base/token.cc
@@ -24,7 +24,7 @@ } std::string Token::ToString() const { - return base::StringPrintf("%016" PRIX64 "%016" PRIX64, high_, low_); + return base::StringPrintf("%016" PRIX64 "%016" PRIX64, words_[0], words_[1]); } void WriteTokenToPickle(Pickle* pickle, const Token& token) {
diff --git a/base/token.h b/base/token.h index df981afe..2490aba 100644 --- a/base/token.h +++ b/base/token.h
@@ -11,6 +11,7 @@ #include <tuple> #include "base/base_export.h" +#include "base/containers/span.h" #include "base/hash/hash.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -28,7 +29,7 @@ constexpr Token() = default; // Constructs a Token with |high| and |low| as its contents. - constexpr Token(uint64_t high, uint64_t low) : high_(high), low_(low) {} + constexpr Token(uint64_t high, uint64_t low) : words_{high, low} {} constexpr Token(const Token&) = default; constexpr Token& operator=(const Token&) = default; @@ -40,13 +41,17 @@ static Token CreateRandom(); // The high and low 64 bits of this Token. - constexpr uint64_t high() const { return high_; } - constexpr uint64_t low() const { return low_; } + constexpr uint64_t high() const { return words_[0]; } + constexpr uint64_t low() const { return words_[1]; } - constexpr bool is_zero() const { return high_ == 0 && low_ == 0; } + constexpr bool is_zero() const { return words_[0] == 0 && words_[1] == 0; } + + span<const uint8_t, 16> AsBytes() const { + return as_bytes(make_span(words_)); + } constexpr bool operator==(const Token& other) const { - return high_ == other.high_ && low_ == other.low_; + return words_[0] == other.words_[0] && words_[1] == other.words_[1]; } constexpr bool operator!=(const Token& other) const { @@ -54,7 +59,8 @@ } constexpr bool operator<(const Token& other) const { - return std::tie(high_, low_) < std::tie(other.high_, other.low_); + return std::tie(words_[0], words_[1]) < + std::tie(other.words_[0], other.words_[1]); } // Generates a string representation of this Token useful for e.g. logging. @@ -64,8 +70,8 @@ // Note: Two uint64_t are used instead of uint8_t[16] in order to have a // simpler implementation, paricularly for |ToString()|, |is_zero()|, and // constexpr value construction. - uint64_t high_ = 0; - uint64_t low_ = 0; + + uint64_t words_[2] = {0, 0}; }; // For use in std::unordered_map.
diff --git a/base/unguessable_token.cc b/base/unguessable_token.cc index f74579e3e..d156be55 100644 --- a/base/unguessable_token.cc +++ b/base/unguessable_token.cc
@@ -8,6 +8,11 @@ #include "base/format_macros.h" #include "base/rand_util.h" +#include "build/build_config.h" + +#if !defined(OS_NACL) +#include "third_party/boringssl/src/include/openssl/mem.h" +#endif namespace base { @@ -35,6 +40,17 @@ return UnguessableToken(Token{high, low}); } +bool UnguessableToken::operator==(const UnguessableToken& other) const { +#if defined(OS_NACL) + // BoringSSL is unavailable for NaCl builds so it remains timing dependent. + return token_ == other.token_; +#else + auto bytes = token_.AsBytes(); + auto other_bytes = other.token_.AsBytes(); + return CRYPTO_memcmp(bytes.data(), other_bytes.data(), bytes.size()) == 0; +#endif +} + std::ostream& operator<<(std::ostream& out, const UnguessableToken& token) { return out << "(" << token.ToString() << ")"; }
diff --git a/base/unguessable_token.h b/base/unguessable_token.h index dbd1d32..83a2286 100644 --- a/base/unguessable_token.h +++ b/base/unguessable_token.h
@@ -22,8 +22,9 @@ // UnguessableToken is, like Token, a randomly chosen 128-bit value. Unlike // Token, a new UnguessableToken is always generated at runtime from a // cryptographically strong random source (or copied or serialized and -// deserialized from another such UnguessableToken). It can be used as part of a -// larger aggregate type, or as an ID in and of itself. +// deserialized from another such UnguessableToken). Also unlike Token, the == +// and != operators are constant time. It can be used as part of a larger +// aggregate type, or as an ID in and of itself. // // An UnguessableToken is a strong *bearer token*. Bearer tokens are like HTTP // cookies: if a caller has the token, the callee thereby considers the caller @@ -90,16 +91,16 @@ explicit constexpr operator bool() const { return !is_empty(); } + span<const uint8_t, 16> AsBytes() const { return token_.AsBytes(); } + constexpr bool operator<(const UnguessableToken& other) const { return token_ < other.token_; } - constexpr bool operator==(const UnguessableToken& other) const { - return token_ == other.token_; - } + bool operator==(const UnguessableToken& other) const; - constexpr bool operator!=(const UnguessableToken& other) const { - return !(*this == other); + bool operator!=(const UnguessableToken& other) const { + return !(token_ == other.token_); } private:
diff --git a/base/unguessable_token_unittest.cc b/base/unguessable_token_unittest.cc index 5d4ecc98..d36ebc5 100644 --- a/base/unguessable_token_unittest.cc +++ b/base/unguessable_token_unittest.cc
@@ -19,6 +19,24 @@ EXPECT_FALSE(b < a); } +TEST(UnguessableTokenTest, VerifyEveryBit) { + UnguessableToken token = UnguessableToken::Deserialize(1, 2); + uint64_t high = 1; + uint64_t low = 2; + + for (uint64_t bit = 1; bit != 0; bit <<= 1) { + uint64_t new_high = high ^ bit; + UnguessableToken new_token = UnguessableToken::Deserialize(new_high, low); + EXPECT_FALSE(token == new_token); + } + + for (uint64_t bit = 1; bit != 0; bit <<= 1) { + uint64_t new_low = low ^ bit; + UnguessableToken new_token = UnguessableToken::Deserialize(high, new_low); + EXPECT_FALSE(token == new_token); + } +} + TEST(UnguessableTokenTest, VerifyEqualityOperators) { // Deserialize is used for testing purposes. // Use UnguessableToken::Create() in production code instead.
diff --git a/build/android/gyp/java_google_api_keys.py b/build/android/gyp/java_google_api_keys.py index a58628a..d2bd34f 100755 --- a/build/android/gyp/java_google_api_keys.py +++ b/build/android/gyp/java_google_api_keys.py
@@ -95,8 +95,8 @@ values = {} values['GOOGLE_API_KEY'] = google_api_keys.GetAPIKey() - values['GOOGLE_API_KEY_PHYSICAL_WEB_TEST'] = (google_api_keys. - GetAPIKeyPhysicalWebTest()) + values['GOOGLE_API_KEY_ANDROID_NON_STABLE'] = ( + google_api_keys.GetAPIKeyAndroidNonStable()) values['GOOGLE_CLIENT_ID_MAIN'] = google_api_keys.GetClientID('MAIN') values['GOOGLE_CLIENT_SECRET_MAIN'] = google_api_keys.GetClientSecret('MAIN') values['GOOGLE_CLIENT_ID_CLOUD_PRINT'] = google_api_keys.GetClientID(
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 13ed917..b66569d 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -674,12 +674,17 @@ # TODO(thakis): Check if '=0' (that is, number of cores, instead # of "all" which means number of hardware threads) is faster. ldflags += [ "-Wl,--thinlto-jobs=all" ] + if (is_mac) { + ldflags += + [ "-Wl,-cache_path_lto," + + rebase_path("$root_out_dir/thinlto-cache", root_build_dir) ] + } else { + ldflags += + [ "-Wl,--thinlto-cache-dir=" + + rebase_path("$root_out_dir/thinlto-cache", root_build_dir) ] + } - ldflags += [ - "-Wl,--thinlto-cache-dir=" + - rebase_path("$root_out_dir/thinlto-cache", root_build_dir), - "-Wl,--thinlto-cache-policy,$cache_policy", - ] + ldflags += [ "-Wl,--thinlto-cache-policy=$cache_policy" ] if (is_chromeos_ash) { # Not much performance difference was noted between the default (100)
diff --git a/buildtools/reclient_cfgs/win-cross-experiments/rewrapper_windows_nacl.cfg b/buildtools/reclient_cfgs/win-cross-experiments/rewrapper_windows_nacl.cfg index dbaaf3e..94481b15 100644 --- a/buildtools/reclient_cfgs/win-cross-experiments/rewrapper_windows_nacl.cfg +++ b/buildtools/reclient_cfgs/win-cross-experiments/rewrapper_windows_nacl.cfg
@@ -1,4 +1,4 @@ -platform=container-image=docker://gcr.io/goma-foundry-experiments/re-client/chromium-win-nacl-cross@sha256:54b6b74aaaa023083112f37d32891800d0731984b2bcc63fcb35fb0b8c2b3f65,OSFamily=Linux +platform=container-image=docker://gcr.io/goma-foundry-experiments/re-client/chromium-win-nacl-cross@sha256:8278b149df7a5b2f32089c39fdc70742f0f5689f6e24c9f7ac3ed25d16581dfd,OSFamily=Linux server_address=pipe://reproxy.pipe labels=type=compile,compiler=nacl,lang=cpp exec_strategy=remote_local_fallback
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index a03f50e..566aaf7 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -1056,6 +1056,7 @@ "java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java", "java/src/org/chromium/chrome/browser/signin/SigninBridge.java", "java/src/org/chromium/chrome/browser/signin/SigninChecker.java", + "java/src/org/chromium/chrome/browser/signin/SigninFirstRunFragment.java", "java/src/org/chromium/chrome/browser/signin/SigninHelperProvider.java", "java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java", "java/src/org/chromium/chrome/browser/signin/SyncConsentActivity.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index 002c203c..1c492aa4 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -501,6 +501,7 @@ "javatests/src/org/chromium/chrome/browser/share/ShareUrlTest.java", "javatests/src/org/chromium/chrome/browser/signin/IdentityManagerIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/signin/SigninCheckerTest.java", + "javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java", "javatests/src/org/chromium/chrome/browser/signin/SigninHeaderTest.java", "javatests/src/org/chromium/chrome/browser/signin/SigninSignoutIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java",
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedV2NewTabPageTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedV2NewTabPageTest.java index 48408af..11e8a052 100644 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedV2NewTabPageTest.java +++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedV2NewTabPageTest.java
@@ -20,9 +20,6 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; import static org.chromium.ui.test.util.ViewUtils.VIEW_NULL; import static org.chromium.ui.test.util.ViewUtils.waitForView; @@ -128,12 +125,13 @@ Swipe.FAST, GeneralLocation.CENTER, GeneralLocation.CENTER_LEFT, Press.FINGER); private boolean mIsCachePopulatedInAccountManagerFacade = true; + private boolean mCanOfferExtendedSyncPromos = true; private final ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); private final FakeAccountManagerFacade mFakeAccountManagerFacade = - spy(new FakeAccountManagerFacade(null) { + new FakeAccountManagerFacade(null) { @Override public Promise<List<Account>> getAccounts() { // Attention. When cache is not populated, the Promise shouldn't be fulfilled. @@ -142,7 +140,12 @@ } return new Promise<>(); } - }); + + @Override + public Optional<Boolean> canOfferExtendedSyncPromos(Account account) { + return Optional.of(mCanOfferExtendedSyncPromos); + } + }; @Rule public final SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule(); @@ -358,13 +361,10 @@ @MediumTest @Feature({"FeedNewTabPage"}) @EnableFeatures(ChromeFeatureList.MINOR_MODE_SUPPORT) - @DisabledTest(message = "Flaky -- crbug.com/1225429") public void testSignInPromoWhenDefaultAccountCanNotOfferExtendedSyncPromos() { mAccountManagerTestRule.addAccount("test@gmail.com"); mIsCachePopulatedInAccountManagerFacade = true; - doReturn(Optional.of(false)) - .when(mFakeAccountManagerFacade) - .canOfferExtendedSyncPromos(any()); + mCanOfferExtendedSyncPromos = false; openNewTabPage(); onView(withId(R.id.feed_stream_recycler_view))
diff --git a/chrome/android/java/res/layout/autofill_save_address_profile_prompt.xml b/chrome/android/java/res/layout/autofill_save_address_profile_prompt.xml index e2eea02..baf44c7 100644 --- a/chrome/android/java/res/layout/autofill_save_address_profile_prompt.xml +++ b/chrome/android/java/res/layout/autofill_save_address_profile_prompt.xml
@@ -2,17 +2,19 @@ <!-- Copyright 2021 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<org.chromium.components.browser_ui.widget.FadingEdgeScrollView +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent" - android:fadeScrollbars="false"> + android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:focusable="true" + android:focusableInTouchMode="true" + android:importantForAccessibility="no"> <org.chromium.ui.widget.ChromeImageButton android:id="@+id/edit_button" @@ -29,6 +31,7 @@ tools:src="@drawable/edit_icon" /> <LinearLayout + android:id="@+id/address_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toStartOf="@id/edit_button" @@ -59,6 +62,34 @@ android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.TextLarge.Secondary" tools:text="+1 858 230 4000" /> + </LinearLayout> + + <!-- TODO(crbug.com/1167061): Use localized strings. --> + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/nickname_input_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="6dp" + android:layout_marginTop="12dp" + android:layout_marginStart="21dp" + android:layout_marginEnd="21dp" + android:layout_below="@id/address_data" + android:paddingStart="0dp" + android:paddingEnd="0dp" + android:hint="Add a label" + app:placeholderText="Home, Work, etc." + app:placeholderTextAppearance="@style/TextAppearance.TextMedium.Secondary" + tools:ignore="HardcodedText"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/nickname_input" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="flagNoExtractUi" + android:minHeight="48dp" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.TextLarge.Secondary" /> + </com.google.android.material.textfield.TextInputLayout> </RelativeLayout> -</org.chromium.components.browser_ui.widget.FadingEdgeScrollView> +</ScrollView>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePrompt.java index 2110a22a..a84b66e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePrompt.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePrompt.java
@@ -8,18 +8,23 @@ import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; +import android.widget.EditText; import android.widget.TextView; import androidx.annotation.Nullable; +import com.google.android.material.textfield.TextInputLayout; + import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNIAdditionalImport; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.R; import org.chromium.chrome.browser.autofill.prefeditor.EditorDialog; import org.chromium.chrome.browser.autofill.settings.AddressEditor; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.payments.AutofillAddress; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.ui.KeyboardVisibilityDelegate; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; @@ -54,6 +59,7 @@ mDialogView = inflater.inflate(isUpdate ? R.layout.autofill_update_address_profile_prompt : R.layout.autofill_save_address_profile_prompt, null); + if (!isUpdate) setupAddressNickname(); PropertyModel.Builder builder = new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS) @@ -201,4 +207,26 @@ mDialogView.findViewById(R.id.no_header_space) .setVisibility(show ? View.GONE : View.VISIBLE); } + + private void setupAddressNickname() { + TextInputLayout nicknameInputLayout = mDialogView.findViewById(R.id.nickname_input_layout); + if (!ChromeFeatureList.isEnabled( + ChromeFeatureList.AUTOFILL_ADDRESS_PROFILE_SAVE_PROMPT_NICKNAME_SUPPORT)) { + nicknameInputLayout.setVisibility(View.GONE); + return; + } + EditText nicknameInput = mDialogView.findViewById(R.id.nickname_input); + nicknameInput.setOnFocusChangeListener( + (v, hasFocus) + -> nicknameInputLayout.setHint( + !hasFocus && TextUtils.isEmpty(nicknameInput.getText()) + // TODO(crbug.com/1167061): Use localized strings. + ? "Add a label" + : "Label")); + + // Prevent input from being focused when keyboard is closed. + KeyboardVisibilityDelegate.getInstance().addKeyboardVisibilityListener(isShowing -> { + if (!isShowing && nicknameInput.hasFocus()) nicknameInput.clearFocus(); + }); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java index de7b322..b400ea39 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AddressEditor.java
@@ -66,6 +66,8 @@ @Nullable private EditorFieldModel mEmailField; @Nullable + private EditorFieldModel mNicknameField; + @Nullable private List<AddressUiComponent> mAddressUiComponents; @Nullable private String mCustomDoneButtonText; @@ -134,6 +136,7 @@ * [ an address field ] / * [ phone number field ] <----- phone is always present. * [ email address field ] <----- only present if purpose is Purpose.AUTOFILL_SETTINGS. + * [ address nickname ] <----- only present if nickname support is enabled. */ @Override public void edit(@Nullable final AutofillAddress toEdit, @@ -270,6 +273,15 @@ mEmailField.setValue(mProfile.getEmailAddress()); } + if (ChromeFeatureList.isEnabled( + ChromeFeatureList.AUTOFILL_ADDRESS_PROFILE_SAVE_PROMPT_NICKNAME_SUPPORT)) { + if (mNicknameField == null) { + mNicknameField = EditorFieldModel.createTextInput(); + // TODO(crbug.com/1167061): Use localized string. + mNicknameField.setLabel("Label"); + } + } + // If the user clicks [Cancel], send |toEdit| address back to the caller, which was the // original state (could be null, a complete address, a partial address). mEditor.setCancelCallback(() -> cancelCallback.onResult(toEdit)); @@ -430,9 +442,10 @@ mEditor.addField(field); } - // Phone number (and email if applicable) are the last fields of the address. + // Phone number (and email/nickname if applicable) are the last fields of the address. mEditor.addField(mPhoneField); if (mEmailField != null) mEditor.addField(mEmailField); + if (mNicknameField != null) mEditor.addField(mNicknameField); } /** Country based phone number validator. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFirstRunFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFirstRunFragment.java new file mode 100644 index 0000000..a99cb59 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFirstRunFragment.java
@@ -0,0 +1,72 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.signin; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.fragment.app.Fragment; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.firstrun.FirstRunFragment; +import org.chromium.chrome.browser.signin.ui.frebottomgroup.FREBottomGroupCoordinator; +import org.chromium.ui.modaldialog.ModalDialogManager; +import org.chromium.ui.modaldialog.ModalDialogManagerHolder; + +/** + * This fragment handles the sign-in without sync consent during the FRE. + */ +public class SigninFirstRunFragment + extends Fragment implements FirstRunFragment, FREBottomGroupCoordinator.Listener { + private ModalDialogManager mModalDialogManager; + private FREBottomGroupCoordinator mFREBottomGroupCoordinator; + + public SigninFirstRunFragment() {} + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mModalDialogManager = ((ModalDialogManagerHolder) getActivity()).getModalDialogManager(); + } + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final View view = inflater.inflate(R.layout.signin_first_run_view, container, false); + mFREBottomGroupCoordinator = new FREBottomGroupCoordinator(requireContext(), + view.findViewById(R.id.signin_fre_bottom_group), mModalDialogManager, this); + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + mFREBottomGroupCoordinator.destroy(); + } + + /** + * Implements {@link FirstRunFragment}. + */ + @Override + public void setInitialA11yFocus() {} + + /** + * Implements {@link FREBottomGroupCoordinator.Listener}. + * TODO(crbug/1227319): Implement account addition. + */ + @Override + public void addAccount() {} + + /** + * Implements {@link FREBottomGroupCoordinator.Listener}. + */ + @Override + public void advanceToNextPage() { + getPageDelegate().acceptTermsOfService(true); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java new file mode 100644 index 0000000..9661f1d --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentTest.java
@@ -0,0 +1,103 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.signin; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.RootMatchers.isDialog; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +import android.support.test.runner.lifecycle.Stage; + +import androidx.test.filters.MediumTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.ApplicationTestUtils; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.R; +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.signin.AccountManagerTestRule; +import org.chromium.components.signin.test.util.FakeAccountInfoService; +import org.chromium.content_public.browser.test.util.TestThreadUtils; + +/** + * Tests for the class {@link SigninFirstRunFragment}. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class SigninFirstRunFragmentTest { + private static final String TEST_EMAIL1 = "test.account1@gmail.com"; + private static final String FULL_NAME1 = "Test Account1"; + private static final String GIVEN_NAME1 = "Account1"; + private static final String TEST_EMAIL2 = "test.account2@gmail.com"; + + @Rule + public final AccountManagerTestRule mAccountManagerTestRule = + new AccountManagerTestRule(new FakeAccountInfoService()); + + @Rule + public final ChromeTabbedActivityTestRule mChromeActivityTestRule = + new ChromeTabbedActivityTestRule(); + + @Before + public void setUp() { + mChromeActivityTestRule.startMainActivityOnBlankPage(); + } + + @Test + @MediumTest + public void testFragmentWithDefaultAccount() { + mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null); + + launchActivityWithFragment(); + + onView(withText(R.string.fre_welcome)).check(matches(isDisplayed())); + onView(withText(TEST_EMAIL1)).check(matches(isDisplayed())); + onView(withText(FULL_NAME1)).check(matches(isDisplayed())); + final String continueAsText = mChromeActivityTestRule.getActivity().getString( + R.string.signin_promo_continue_as, GIVEN_NAME1); + onView(withText(continueAsText)).check(matches(isDisplayed())); + onView(withText(R.string.signin_account_picker_dismiss_button)) + .check(matches(isDisplayed())); + } + + @Test + @MediumTest + public void testFragmentWhenChoosingAnotherAccount() { + mAccountManagerTestRule.addAccount(TEST_EMAIL1, FULL_NAME1, GIVEN_NAME1, null); + mAccountManagerTestRule.addAccount(TEST_EMAIL2); + launchActivityWithFragment(); + onView(withText(TEST_EMAIL1)).perform(click()); + + onView(withText(TEST_EMAIL2)).inRoot(isDialog()).perform(click()); + + onView(withText(TEST_EMAIL2)).check(matches(isDisplayed())); + final String continueAsText = mChromeActivityTestRule.getActivity().getString( + R.string.signin_promo_continue_as, TEST_EMAIL2); + onView(withText(continueAsText)).check(matches(isDisplayed())); + onView(withText(R.string.signin_account_picker_dismiss_button)) + .check(matches(isDisplayed())); + } + + private void launchActivityWithFragment() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mChromeActivityTestRule.getActivity() + .getSupportFragmentManager() + .beginTransaction() + .add(android.R.id.content, new SigninFirstRunFragment()) + .commit(); + }); + ApplicationTestUtils.waitForActivityState( + mChromeActivityTestRule.getActivity(), Stage.RESUMED); + } +}
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 7521487..c8b2b28 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -2737,6 +2737,9 @@ </message> <!-- Strings for the enterprise enrollment page --> + <message name="IDS_ENTERPRISE_ENROLLMENT_STATUS_CLOUD_READY_NOT_ALLOWED" desc="Error message shown on the enrollment screen if enrollment is not allowed because of CloudReady."> + Enrollment is only supported after installation. To manage this device, install CloudReady first. + </message> <message name="IDS_ENTERPRISE_ENROLLMENT_STATUS_REGISTRATION_FAILED" desc="Error message shown on the enrollment screen upon failed device registration."> Error when registering the device with the server: <ph name="CLIENT_ERROR">$1<ex>Failed to connect to the server</ex></ph>. </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ENTERPRISE_ENROLLMENT_STATUS_CLOUD_READY_NOT_ALLOWED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_ENTERPRISE_ENROLLMENT_STATUS_CLOUD_READY_NOT_ALLOWED.png.sha1 new file mode 100644 index 0000000..c30c180 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_ENTERPRISE_ENROLLMENT_STATUS_CLOUD_READY_NOT_ALLOWED.png.sha1
@@ -0,0 +1 @@ +717839c1ba999e5c086305ed33f93677210f5d8c \ No newline at end of file
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index 5af1c214..f0c482b 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -9,17 +9,17 @@ Get help with Chrome </message> <if expr="not chromeos"> - <message name="IDS_SETTINGS_UPGRADE_UPDATING" desc="Status label: Updating Google Chrome"> - Updating Google Chrome + <message name="IDS_SETTINGS_UPGRADE_UPDATING" desc="Status label: Updating Chrome"> + Updating Chrome </message> - <message name="IDS_SETTINGS_UPGRADE_UPDATING_PERCENT" desc="Status label: Updating Google Chrome (90%)"> - Updating Google Chrome (<ph name="PROGRESS_PERCENT">$1<ex>90%</ex></ph>) + <message name="IDS_SETTINGS_UPGRADE_UPDATING_PERCENT" desc="Status label: Updating Chrome (90%)"> + Updating Chrome (<ph name="PROGRESS_PERCENT">$1<ex>90%</ex></ph>) </message> - <message name="IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH" desc="Status label: Successfully updated Google Chrome"> - Nearly up to date! Relaunch Google Chrome to finish updating. Incognito windows won't reopen. + <message name="IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH" desc="Status label: Successfully updated Chrome"> + Nearly up to date! Relaunch Chrome to finish updating. Incognito windows won't reopen. </message> - <message name="IDS_SETTINGS_UPGRADE_UP_TO_DATE" desc="Status label: Already up to date (Google Chrome)"> - Google Chrome is up to date + <message name="IDS_SETTINGS_UPGRADE_UP_TO_DATE" desc="Status label: Already up to date (Chrome)"> + Chrome is up to date </message> </if> <if expr="chromeos">
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml b/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml index e79b7a97..4987c1d 100644 --- a/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml +++ b/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml
@@ -26,7 +26,8 @@ <activity android:name="org.chromium.customtabsclient.MainActivity" - android:label="@string/app_name"> + android:label="@string/app_name" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
diff --git a/chrome/browser/android/explore_sites/get_images_task.cc b/chrome/browser/android/explore_sites/get_images_task.cc index 09da74e..38f98e3 100644 --- a/chrome/browser/android/explore_sites/get_images_task.cc +++ b/chrome/browser/android/explore_sites/get_images_task.cc
@@ -51,8 +51,7 @@ EncodedImageList result; while (category_statement.Step()) { - int byte_length = category_statement.ColumnByteLength(0); - result.push_back(std::make_unique<std::vector<uint8_t>>(byte_length)); + result.push_back(std::make_unique<std::vector<uint8_t>>()); category_statement.ColumnBlobAsVector(0, result.back().get()); } if (!category_statement.Succeeded()) @@ -81,8 +80,7 @@ EncodedImageList result; while (category_statement.Step()) { - int byte_length = category_statement.ColumnByteLength(0); - result.push_back(std::make_unique<std::vector<uint8_t>>(byte_length)); + result.push_back(std::make_unique<std::vector<uint8_t>>()); category_statement.ColumnBlobAsVector(0, result.back().get()); } if (!category_statement.Succeeded()) @@ -99,8 +97,7 @@ EncodedImageList result; while (site_statement.Step()) { - int byte_length = site_statement.ColumnByteLength(0); - result.push_back(std::make_unique<std::vector<uint8_t>>(byte_length)); + result.push_back(std::make_unique<std::vector<uint8_t>>()); site_statement.ColumnBlobAsVector(0, result.back().get()); } if (!site_statement.Succeeded())
diff --git a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc index 155b708..721dccd 100644 --- a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc +++ b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc
@@ -118,4 +118,9 @@ void FakeLacrosWebAppsHost::OpenNativeSettings(const std::string& app_id) { NOTIMPLEMENTED(); } + +void SetWindowMode(const std::string& app_id, + apps::mojom::WindowMode window_mode) { + NOTIMPLEMENTED(); +} } // namespace apps
diff --git a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.h b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.h index ba3ff16..8248455 100644 --- a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.h +++ b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.h
@@ -43,6 +43,8 @@ int32_t size_hint_in_dip, LoadIconCallback callback) override; void OpenNativeSettings(const std::string& app_id) override; + void SetWindowMode(const std::string& app_id, + apps::mojom::WindowMode window_mode) override; mojo::Receiver<crosapi::mojom::AppController> receiver_{this}; };
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc index 936a9ab3..b1940ae 100644 --- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc +++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
@@ -215,6 +215,11 @@ controller_->OpenNativeSettings(app_id); } +void WebAppsCrosapi::SetWindowMode(const std::string& app_id, + apps::mojom::WindowMode window_mode) { + controller_->SetWindowMode(app_id, window_mode); +} + void WebAppsCrosapi::OnApps(std::vector<apps::mojom::AppPtr> deltas) { if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) return;
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h index e413396..cedc1cd 100644 --- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h +++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h
@@ -68,6 +68,8 @@ void PauseApp(const std::string& app_id) override; void UnpauseApp(const std::string& app_id) override; void OpenNativeSettings(const std::string& app_id) override; + void SetWindowMode(const std::string& app_id, + apps::mojom::WindowMode window_mode) override; // crosapi::mojom::AppPublisher overrides. void OnApps(std::vector<apps::mojom::AppPtr> deltas) override;
diff --git a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc index 8a574e0..4ef3ae6 100644 --- a/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc +++ b/chrome/browser/ash/accessibility/select_to_speak_browsertest.cc
@@ -565,7 +565,13 @@ sm_.Replay(); } -IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, WorksWithStickyKeys) { +// Flaky on ChromeOS MSAN bots: https://crbug.com/1227368 +#if defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER) +#define MAYBE_WorksWithStickyKeys DISABLED_WorksWithStickyKeys +#else +#define MAYBE_WorksWithStickyKeys WorksWithStickyKeys +#endif +IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, MAYBE_WorksWithStickyKeys) { AccessibilityManager::Get()->EnableStickyKeys(true); ui_test_utils::NavigateToURL(
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc index 0d288a22..42a950e4 100644 --- a/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc +++ b/chrome/browser/ash/accessibility/spoken_feedback_browsertest.cc
@@ -242,11 +242,9 @@ }); sm_.ExpectSpeech( "Quick Settings, Press search plus left to access the notification " - "center."); + "center., window"); sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_LEFT); }); - sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_LEFT); }); - // If you are hitting this in the course of changing the UI, please fix. This // item needs a label. sm_.ExpectSpeech("List item"); @@ -669,7 +667,7 @@ }); sm_.ExpectSpeech( "Quick Settings, Press search plus left to access the notification " - "center."); + "center., window"); sm_.Replay(); } @@ -684,7 +682,7 @@ }); sm_.ExpectSpeech( "Quick Settings, Press search plus left to access the notification " - "center."); + "center., window"); // Avatar button. Disabled for guest account. if (GetParam() != kTestAsGuestUser) {
diff --git a/chrome/browser/ash/arc/accessibility/arc_accessibility_tree_tracker.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_tree_tracker.cc index ede6648..02f93d3 100644 --- a/chrome/browser/ash/arc/accessibility/arc_accessibility_tree_tracker.cc +++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_tree_tracker.cc
@@ -590,6 +590,8 @@ window->SetProperty(aura::client::kAccessibilityTouchExplorationPassThrough, use_talkback); window->SetProperty(ash::kSearchKeyAcceleratorReservedKey, use_talkback); + window->SetProperty(aura::client::kAccessibilityFocusFallsbackToWidgetKey, + !use_talkback); if (use_talkback) { SetChildAxTreeIDForWindow(window, ui::AXTreeIDUnknown());
diff --git a/chrome/browser/ash/arc/arc_optin_uma.cc b/chrome/browser/ash/arc/arc_optin_uma.cc index 95cd761..7572692 100644 --- a/chrome/browser/ash/arc/arc_optin_uma.cc +++ b/chrome/browser/ash/arc/arc_optin_uma.cc
@@ -23,6 +23,13 @@ namespace { +// Logs UMA enum values to facilitate finding feedback reports in Xamine. +template <typename T> +void LogStabilityUmaEnum(const std::string& name, T sample) { + base::UmaHistogramEnumeration(name, sample); + VLOG(1) << name << ": " << static_cast<std::underlying_type_t<T>>(sample); +} + ArcEnabledState ComputeEnabledState(bool enabled, const Profile* profile) { if (!IsArcAllowedForProfile(profile)) { return enabled ? ArcEnabledState::ENABLED_NOT_ALLOWED @@ -71,39 +78,39 @@ } void UpdateOptInFlowResultUMA(OptInFlowResult result) { - base::UmaHistogramEnumeration("Arc.OptInResult", result); + LogStabilityUmaEnum("Arc.OptInResult", result); } void UpdateProvisioningStatusUMA(ProvisioningStatus status, const Profile* profile) { DCHECK_NE(status, ProvisioningStatus::CHROME_SERVER_COMMUNICATION_ERROR); - base::UmaHistogramEnumeration( + LogStabilityUmaEnum( GetHistogramNameByUserType("Arc.Provisioning.Status", profile), status); } void UpdateCloudProvisionFlowErrorUMA(mojom::CloudProvisionFlowError error, const Profile* profile) { - base::UmaHistogramEnumeration( + LogStabilityUmaEnum( GetHistogramNameByUserType("Arc.Provisioning.CloudFlowError", profile), error); } void UpdateGMSSignInErrorUMA(mojom::GMSSignInError error, const Profile* profile) { - base::UmaHistogramEnumeration( + LogStabilityUmaEnum( GetHistogramNameByUserType("Arc.Provisioning.SignInError", profile), error); } void UpdateGMSCheckInErrorUMA(mojom::GMSCheckInError error, const Profile* profile) { - base::UmaHistogramEnumeration( + LogStabilityUmaEnum( GetHistogramNameByUserType("Arc.Provisioning.CheckInError", profile), error); } void UpdateSecondarySigninResultUMA(ProvisioningStatus status) { - base::UmaHistogramEnumeration("Arc.Secondary.Signin.Result", status); + LogStabilityUmaEnum("Arc.Secondary.Signin.Result", status); } void UpdateProvisioningTiming(const base::TimeDelta& elapsed_time, @@ -121,7 +128,7 @@ void UpdateReauthorizationResultUMA(ProvisioningStatus status, const Profile* profile) { - base::UmaHistogramEnumeration( + LogStabilityUmaEnum( GetHistogramNameByUserType("Arc.Reauthorization.Result", profile), status); } @@ -184,7 +191,7 @@ void UpdateAuthAccountCheckStatus(mojom::AccountCheckStatus status, const Profile* profile) { DCHECK_LE(status, mojom::AccountCheckStatus::CHECK_FAILED); - base::UmaHistogramEnumeration( + LogStabilityUmaEnum( GetHistogramNameByUserType("Arc.Auth.AccountCheck.Status", profile), status); } @@ -198,7 +205,7 @@ void UpdateAccountReauthReason(mojom::ReauthReason reason, const Profile* profile) { - base::UmaHistogramEnumeration( + LogStabilityUmaEnum( GetHistogramNameByUserType("Arc.Auth.Reauth.Reason", profile), reason); } @@ -206,30 +213,27 @@ const Profile* profile, mojom::MainAccountResolutionStatus status) { DCHECK(mojom::IsKnownEnumValue(status)); - base::UmaHistogramEnumeration( - GetHistogramNameByUserType("Arc.Auth.MainAccountResolution.Status", - profile), - status); + LogStabilityUmaEnum(GetHistogramNameByUserType( + "Arc.Auth.MainAccountResolution.Status", profile), + status); } void UpdateSilentAuthCodeUMA(OptInSilentAuthCode state) { - base::UmaHistogramEnumeration("Arc.OptInSilentAuthCode", state); + LogStabilityUmaEnum("Arc.OptInSilentAuthCode", state); } // TODO(tantoshchuk): rename UMA histogram to "Arc.Management.Transition.Result" void UpdateSupervisionTransitionResultUMA( mojom::ManagementChangeStatus result) { - base::UmaHistogramEnumeration("Arc.Supervision.Transition.Result", result); + LogStabilityUmaEnum("Arc.Supervision.Transition.Result", result); } void UpdateReauthorizationSilentAuthCodeUMA(OptInSilentAuthCode state) { - base::UmaHistogramEnumeration("Arc.OptInSilentAuthCode.Reauthorization", - state); + LogStabilityUmaEnum("Arc.OptInSilentAuthCode.Reauthorization", state); } void UpdateSecondaryAccountSilentAuthCodeUMA(OptInSilentAuthCode state) { - base::UmaHistogramEnumeration("Arc.OptInSilentAuthCode.SecondaryAccount", - state); + LogStabilityUmaEnum("Arc.OptInSilentAuthCode.SecondaryAccount", state); } ProvisioningStatus GetProvisioningStatus(
diff --git a/chrome/browser/ash/arc/nearby_share/nearby_share_session_impl.cc b/chrome/browser/ash/arc/nearby_share/nearby_share_session_impl.cc index b87a006..0e950935 100644 --- a/chrome/browser/ash/arc/nearby_share/nearby_share_session_impl.cc +++ b/chrome/browser/ash/arc/nearby_share/nearby_share_session_impl.cc
@@ -65,7 +65,7 @@ FROM_HERE, base::BindOnce(&NearbyShareSessionImpl::OnArcWindowFound, weak_ptr_factory_.GetWeakPtr(), arc_window)); } else { - VLOG(1) << "No ARC window found for task ID " << task_id_; + VLOG(1) << "No ARC window found for task ID: " << task_id_; env_observation_.Observe(aura::Env::GetInstance()); window_initialization_timer_.Start(FROM_HERE, kWindowInitializationTimeout, this, @@ -285,7 +285,8 @@ aura::Window* const arc_window = GetArcWindow(task_id_); if (!arc_window) { LOG(ERROR) << "Unable to close sharesheet bubble. No ARC window found for " - << "task ID " << task_id_; + << "task ID: " << task_id_; + std::move(session_finished_callback_).Run(task_id_); return; } @@ -295,6 +296,7 @@ if (!sharesheet_service) { LOG(ERROR) << "Unable to close sharesheet bubble. Cannot find sharesheet " "service."; + std::move(session_finished_callback_).Run(task_id_); return; } sharesheet_service->CloseBubble(arc_window);
diff --git a/chrome/browser/ash/arc/nearby_share/share_info_file_handler.h b/chrome/browser/ash/arc/nearby_share/share_info_file_handler.h index 126b81d..ecb1f13 100644 --- a/chrome/browser/ash/arc/nearby_share/share_info_file_handler.h +++ b/chrome/browser/ash/arc/nearby_share/share_info_file_handler.h
@@ -46,7 +46,7 @@ // IO thread. FileShareConfig is a convenience subclass for containing related // files information needed to create a Chrome share intent. class ShareInfoFileHandler : public base::RefCountedThreadSafe< - ShareInfoFileStreamAdapter, + ShareInfoFileHandler, content::BrowserThread::DeleteOnIOThread> { public: // |result| signifies state of shared files after streaming has completed. @@ -85,7 +85,7 @@ private: friend struct content::BrowserThread::DeleteOnThread< content::BrowserThread::IO>; - friend class base::DeleteHelper<ShareInfoFileStreamAdapter>; + friend class base::DeleteHelper<ShareInfoFileHandler>; ~ShareInfoFileHandler();
diff --git a/chrome/browser/ash/login/enrollment/enrollment_screen.cc b/chrome/browser/ash/login/enrollment/enrollment_screen.cc index b6a02bb..663db2a 100644 --- a/chrome/browser/ash/login/enrollment/enrollment_screen.cc +++ b/chrome/browser/ash/login/enrollment/enrollment_screen.cc
@@ -7,6 +7,7 @@ #include <memory> #include "ash/constants/ash_features.h" +#include "ash/constants/ash_switches.h" #include "base/bind.h" #include "base/callback.h" #include "base/callback_helpers.h" @@ -237,6 +238,11 @@ view_->SetEnrollmentController(this); UMA(policy::kMetricEnrollmentTriggered); UpdateFlowType(); + if (switches::IsOsInstallAllowed()) { + view_->Show(); + view_->ShowEnrollmentCloudReadyNotAllowedError(); + return; + } switch (current_auth_) { case AUTH_OAUTH: ShowInteractiveScreen();
diff --git a/chrome/browser/ash/login/enrollment/enrollment_screen_view.h b/chrome/browser/ash/login/enrollment/enrollment_screen_view.h index d8f1801..0843e1e5 100644 --- a/chrome/browser/ash/login/enrollment/enrollment_screen_view.h +++ b/chrome/browser/ash/login/enrollment/enrollment_screen_view.h
@@ -77,6 +77,9 @@ virtual void ShowUserError(UserErrorType error_type, const std::string& email) = 0; + // Shows error that enrollment is not allowed during CloudReady run. + virtual void ShowEnrollmentCloudReadyNotAllowedError() = 0; + // Shows the Active Directory domain joining screen. virtual void ShowActiveDirectoryScreen(const std::string& domain_join_config, const std::string& machine_name,
diff --git a/chrome/browser/ash/login/enrollment/mock_enrollment_screen.h b/chrome/browser/ash/login/enrollment/mock_enrollment_screen.h index c9b1b47..a7981d33 100644 --- a/chrome/browser/ash/login/enrollment/mock_enrollment_screen.h +++ b/chrome/browser/ash/login/enrollment/mock_enrollment_screen.h
@@ -45,6 +45,7 @@ MOCK_METHOD(void, ShowUserError, (UserErrorType error_type, const std::string& email)); + MOCK_METHOD(void, ShowEnrollmentCloudReadyNotAllowedError, ()); MOCK_METHOD(void, ShowLicenseTypeSelectionScreen, (const base::DictionaryValue&));
diff --git a/chrome/browser/ash/login/quick_unlock/auth_token.h b/chrome/browser/ash/login/quick_unlock/auth_token.h index f31659e..c77b8e6 100644 --- a/chrome/browser/ash/login/quick_unlock/auth_token.h +++ b/chrome/browser/ash/login/quick_unlock/auth_token.h
@@ -14,9 +14,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" namespace chromeos { - class UserContext; -class QuickUnlockStorageUnitTest; namespace quick_unlock { @@ -45,7 +43,7 @@ } private: - friend class chromeos::QuickUnlockStorageUnitTest; + friend class QuickUnlockStorageUnitTest; // Expires the token. In particular this makes the identifier string // inaccessible from outside the class.
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h index 7449eed..245c782 100644 --- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h +++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h
@@ -14,11 +14,7 @@ class Profile; namespace chromeos { - -class FingerprintStorageTestApi; - namespace quick_unlock { - class FingerprintMetricsReporter; class QuickUnlockStorage; @@ -77,7 +73,7 @@ void OnGetRecords(const base::flat_map<std::string, std::string>& fingerprints_list_mapping); - friend class chromeos::FingerprintStorageTestApi; + friend class FingerprintStorageTestApi; friend class QuickUnlockStorage; Profile* const profile_;
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc b/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc index e2dcf25..b50794e 100644 --- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc +++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc
@@ -16,6 +16,7 @@ #include "testing/gtest/include/gtest/gtest.h" namespace chromeos { +namespace quick_unlock { namespace { class FingerprintStorageUnitTest : public testing::Test { @@ -24,9 +25,9 @@ ~FingerprintStorageUnitTest() override {} // testing::Test: - void SetUp() override { quick_unlock::EnabledForTesting(true); } + void SetUp() override { EnabledForTesting(true); } - void TearDown() override { quick_unlock::EnabledForTesting(false); } + void TearDown() override { EnabledForTesting(false); } void SetRecords(int records_number) { profile_->GetPrefs()->SetInteger(prefs::kQuickUnlockFingerprintRecord, @@ -45,8 +46,7 @@ class FingerprintStorageTestApi { public: // Does *not* take ownership over `fingerprint_storage`. - explicit FingerprintStorageTestApi( - quick_unlock::FingerprintStorage* fingerprint_storage) + explicit FingerprintStorageTestApi(FingerprintStorage* fingerprint_storage) : fingerprint_storage_(fingerprint_storage) {} bool IsFingerprintAvailable() const { @@ -54,7 +54,7 @@ } private: - quick_unlock::FingerprintStorage* fingerprint_storage_; + FingerprintStorage* fingerprint_storage_; DISALLOW_COPY_AND_ASSIGN(FingerprintStorageTestApi); }; @@ -64,9 +64,8 @@ // 2. Attempting unlock attempts correctly increases unlock attempt count. // 3. Resetting unlock attempt count correctly sets attempt count to 0. TEST_F(FingerprintStorageUnitTest, UnlockAttemptCount) { - quick_unlock::FingerprintStorage* fingerprint_storage = - quick_unlock::QuickUnlockFactory::GetForProfile(profile_.get()) - ->fingerprint_storage(); + FingerprintStorage* fingerprint_storage = + QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage(); EXPECT_EQ(0, fingerprint_storage->unlock_attempt_count()); @@ -83,9 +82,8 @@ // 1. No fingerprint records registered. // 2. Too many authentication attempts. TEST_F(FingerprintStorageUnitTest, AuthenticationUnAvailable) { - quick_unlock::FingerprintStorage* fingerprint_storage = - quick_unlock::QuickUnlockFactory::GetForProfile(profile_.get()) - ->fingerprint_storage(); + FingerprintStorage* fingerprint_storage = + QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage(); FingerprintStorageTestApi test_api(fingerprint_storage); EXPECT_FALSE(fingerprint_storage->HasRecord()); @@ -104,8 +102,7 @@ // Too many authentication attempts make fingerprint authentication // unavailable. - for (int i = 0; i < quick_unlock::FingerprintStorage::kMaximumUnlockAttempts; - ++i) { + for (int i = 0; i < FingerprintStorage::kMaximumUnlockAttempts; ++i) { fingerprint_storage->AddUnlockAttempt(); } EXPECT_FALSE(test_api.IsFingerprintAvailable()); @@ -113,4 +110,5 @@ EXPECT_TRUE(test_api.IsFingerprintAvailable()); } +} // namespace quick_unlock } // namespace chromeos
diff --git a/chrome/browser/ash/login/quick_unlock/pin_storage_prefs_unittest.cc b/chrome/browser/ash/login/quick_unlock/pin_storage_prefs_unittest.cc index c8f4e31c..48ccf76 100644 --- a/chrome/browser/ash/login/quick_unlock/pin_storage_prefs_unittest.cc +++ b/chrome/browser/ash/login/quick_unlock/pin_storage_prefs_unittest.cc
@@ -15,6 +15,7 @@ #include "testing/gtest/include/gtest/gtest.h" namespace chromeos { +namespace quick_unlock { namespace { class PinStoragePrefsUnitTest : public testing::Test { @@ -23,12 +24,12 @@ ~PinStoragePrefsUnitTest() override = default; // testing::Test: - void SetUp() override { quick_unlock::EnabledForTesting(true); } + void SetUp() override { EnabledForTesting(true); } - void TearDown() override { quick_unlock::EnabledForTesting(false); } + void TearDown() override { EnabledForTesting(false); } - quick_unlock::PinStoragePrefs* PinStoragePrefs() const { - return quick_unlock::QuickUnlockFactory::GetForProfile(profile_.get()) + PinStoragePrefs* PinStoragePrefs() const { + return QuickUnlockFactory::GetForProfile(profile_.get()) ->pin_storage_prefs(); } @@ -44,7 +45,7 @@ class PinStoragePrefsTestApi { public: // Does *not* take ownership over `pin_storage`. - explicit PinStoragePrefsTestApi(quick_unlock::PinStoragePrefs* pin_storage) + explicit PinStoragePrefsTestApi(PinStoragePrefs* pin_storage) : pin_storage_(pin_storage) {} std::string PinSalt() const { return pin_storage_->PinSalt(); } @@ -59,7 +60,7 @@ } private: - quick_unlock::PinStoragePrefs* pin_storage_; + PinStoragePrefs* pin_storage_; DISALLOW_COPY_AND_ASSIGN(PinStoragePrefsTestApi); }; @@ -126,8 +127,7 @@ // Use up all of the authentication attempts so authentication fails. EXPECT_TRUE(pin_storage_test.IsPinAuthenticationAvailable()); - for (int i = 0; i < quick_unlock::PinStoragePrefs::kMaximumUnlockAttempts; - ++i) { + for (int i = 0; i < PinStoragePrefs::kMaximumUnlockAttempts; ++i) { EXPECT_FALSE(pin_storage_test.TryAuthenticatePin( "foobar", Key::KEY_TYPE_PASSWORD_PLAIN)); } @@ -140,12 +140,9 @@ // Verifies that hashed pin can be used to authenticate. TEST_F(PinStoragePrefsUnitTest, AuthenticationWithHashedPin) { - quick_unlock::PinStoragePrefs* pin_storage = - quick_unlock::QuickUnlockFactory::GetForProfile(profile_.get()) - ->pin_storage_prefs(); - PinStoragePrefsTestApi pin_storage_test(pin_storage); + PinStoragePrefsTestApi pin_storage_test(PinStoragePrefs()); - pin_storage->SetPin("1111"); + PinStoragePrefs()->SetPin("1111"); std::string hashed_pin = pin_storage_test.PinSecret(); // Verify that hashed pin can be used to authenticate. @@ -158,4 +155,5 @@ hashed_pin, Key::KEY_TYPE_PASSWORD_PLAIN)); } +} // namespace quick_unlock } // namespace chromeos
diff --git a/chrome/browser/ash/login/quick_unlock/quick_unlock_storage.h b/chrome/browser/ash/login/quick_unlock/quick_unlock_storage.h index af04767..d5d8801c4 100644 --- a/chrome/browser/ash/login/quick_unlock/quick_unlock_storage.h +++ b/chrome/browser/ash/login/quick_unlock/quick_unlock_storage.h
@@ -13,15 +13,10 @@ class Profile; namespace chromeos { - -class QuickUnlockStorageTestApi; -class QuickUnlockStorageUnitTest; - namespace quick_unlock { - +class AuthToken; class FingerprintStorage; class PinStoragePrefs; -class AuthToken; // Helper class for managing state for quick unlock services (pin and // fingerprint), and general lock screen management (tokens for extension API @@ -85,8 +80,8 @@ PinStoragePrefs* pin_storage_prefs() { return pin_storage_prefs_.get(); } private: - friend class chromeos::QuickUnlockStorageTestApi; - friend class chromeos::QuickUnlockStorageUnitTest; + friend class QuickUnlockStorageTestApi; + friend class QuickUnlockStorageUnitTest; // KeyedService: void Shutdown() override;
diff --git a/chrome/browser/ash/login/quick_unlock/quick_unlock_storage_unittest.cc b/chrome/browser/ash/login/quick_unlock/quick_unlock_storage_unittest.cc index 7fd7c7c8..85173c9 100644 --- a/chrome/browser/ash/login/quick_unlock/quick_unlock_storage_unittest.cc +++ b/chrome/browser/ash/login/quick_unlock/quick_unlock_storage_unittest.cc
@@ -20,23 +20,19 @@ #include "testing/gtest/include/gtest/gtest.h" namespace chromeos { - -using AuthToken = quick_unlock::AuthToken; -using QuickUnlockStorage = quick_unlock::QuickUnlockStorage; - +namespace quick_unlock { namespace { -void SetConfirmationFrequency( - PrefService* pref_service, - quick_unlock::PasswordConfirmationFrequency frequency) { +void SetConfirmationFrequency(PrefService* pref_service, + PasswordConfirmationFrequency frequency) { pref_service->SetInteger(prefs::kQuickUnlockTimeout, static_cast<int>(frequency)); } base::TimeDelta GetExpirationTime(PrefService* pref_service) { int frequency = pref_service->GetInteger(prefs::kQuickUnlockTimeout); - return quick_unlock::PasswordConfirmationFrequencyToTimeDelta( - static_cast<quick_unlock::PasswordConfirmationFrequency>(frequency)); + return PasswordConfirmationFrequencyToTimeDelta( + static_cast<PasswordConfirmationFrequency>(frequency)); } } // namespace @@ -47,12 +43,11 @@ ~QuickUnlockStorageUnitTest() override {} // testing::Test: - void SetUp() override { quick_unlock::EnabledForTesting(true); } - void TearDown() override { quick_unlock::EnabledForTesting(false); } + void SetUp() override { EnabledForTesting(true); } + void TearDown() override { EnabledForTesting(false); } void ExpireAuthToken() { - quick_unlock::QuickUnlockFactory::GetForProfile(profile_.get()) - ->auth_token_->Reset(); + QuickUnlockFactory::GetForProfile(profile_.get())->auth_token_->Reset(); } content::BrowserTaskEnvironment task_environment_; @@ -88,7 +83,7 @@ TEST_F(QuickUnlockStorageUnitTest, TimeSinceLastStrongAuthReturnsPositiveValue) { QuickUnlockStorage* quick_unlock_storage = - quick_unlock::QuickUnlockFactory::GetForProfile(profile_.get()); + QuickUnlockFactory::GetForProfile(profile_.get()); PrefService* pref_service = profile_->GetPrefs(); QuickUnlockStorageTestApi test_api(quick_unlock_storage); @@ -109,7 +104,7 @@ TEST_F(QuickUnlockStorageUnitTest, QuickUnlockPasswordConfirmationFrequencyPreference) { QuickUnlockStorage* quick_unlock_storage = - quick_unlock::QuickUnlockFactory::GetForProfile(profile_.get()); + QuickUnlockFactory::GetForProfile(profile_.get()); PrefService* pref_service = profile_->GetPrefs(); QuickUnlockStorageTestApi test_api(quick_unlock_storage); @@ -130,8 +125,8 @@ // not trigger a request for strong auth, but moving it by an additional 3 // hours will. quick_unlock_storage->MarkStrongAuth(); - SetConfirmationFrequency( - pref_service, quick_unlock::PasswordConfirmationFrequency::SIX_HOURS); + SetConfirmationFrequency(pref_service, + PasswordConfirmationFrequency::SIX_HOURS); expiration_time = GetExpirationTime(pref_service); test_api.ReduceRemainingStrongAuthTimeBy(expiration_time / 2); EXPECT_TRUE(quick_unlock_storage->HasStrongAuth()); @@ -141,33 +136,33 @@ // A valid strong auth becomes invalid if the confirmation frequency is // shortened to less than the expiration time. quick_unlock_storage->MarkStrongAuth(); - SetConfirmationFrequency( - pref_service, quick_unlock::PasswordConfirmationFrequency::TWELVE_HOURS); + SetConfirmationFrequency(pref_service, + PasswordConfirmationFrequency::TWELVE_HOURS); expiration_time = GetExpirationTime(pref_service); EXPECT_TRUE(quick_unlock_storage->HasStrongAuth()); test_api.ReduceRemainingStrongAuthTimeBy(expiration_time / 2); EXPECT_TRUE(quick_unlock_storage->HasStrongAuth()); - SetConfirmationFrequency( - pref_service, quick_unlock::PasswordConfirmationFrequency::SIX_HOURS); + SetConfirmationFrequency(pref_service, + PasswordConfirmationFrequency::SIX_HOURS); EXPECT_FALSE(quick_unlock_storage->HasStrongAuth()); // An expired strong auth becomes usable if the confirmation frequency gets // extended past the expiration time. quick_unlock_storage->MarkStrongAuth(); - SetConfirmationFrequency( - pref_service, quick_unlock::PasswordConfirmationFrequency::SIX_HOURS); + SetConfirmationFrequency(pref_service, + PasswordConfirmationFrequency::SIX_HOURS); expiration_time = GetExpirationTime(pref_service); EXPECT_TRUE(quick_unlock_storage->HasStrongAuth()); test_api.ReduceRemainingStrongAuthTimeBy(expiration_time); EXPECT_FALSE(quick_unlock_storage->HasStrongAuth()); - SetConfirmationFrequency( - pref_service, quick_unlock::PasswordConfirmationFrequency::TWELVE_HOURS); + SetConfirmationFrequency(pref_service, + PasswordConfirmationFrequency::TWELVE_HOURS); EXPECT_TRUE(quick_unlock_storage->HasStrongAuth()); } TEST_F(QuickUnlockStorageUnitTest, AuthToken) { QuickUnlockStorage* quick_unlock_storage = - quick_unlock::QuickUnlockFactory::GetForProfile(profile_.get()); + QuickUnlockFactory::GetForProfile(profile_.get()); EXPECT_FALSE(quick_unlock_storage->GetAuthToken()); chromeos::UserContext context; @@ -180,4 +175,5 @@ EXPECT_FALSE(quick_unlock_storage->GetAuthToken()); } +} // namespace quick_unlock } // namespace chromeos
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_browsertest.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager_browsertest.cc index 775e33f..0b2a5fa 100644 --- a/chrome/browser/ash/policy/dlp/dlp_content_manager_browsertest.cc +++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_browsertest.cc
@@ -26,6 +26,7 @@ #include "chrome/browser/notifications/notification_display_service_tester.h" #include "chrome/browser/policy/messaging_layer/public/report_queue_impl.h" #include "chrome/browser/policy/policy_test_utils.h" +#include "chrome/browser/printing/print_view_manager.h" #include "chrome/browser/printing/print_view_manager_common.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/chrome_capture_mode_delegate.h" @@ -37,6 +38,7 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/policy/core/common/policy_map.h" #include "components/policy/policy_constants.h" +#include "components/printing/common/print.mojom.h" #include "components/reporting/storage/test_storage_module.h" #include "content/public/browser/desktop_media_id.h" #include "content/public/test/browser_test.h" @@ -87,6 +89,64 @@ constexpr char kUrl3[] = "https://example3.com"; constexpr char kUrl4[] = "https://example4.com"; constexpr char kSrcPattern[] = "example.com"; + +class TestPrintViewManager : public printing::PrintViewManager { + public: + explicit TestPrintViewManager(content::WebContents* web_contents) + : PrintViewManager(web_contents) {} + TestPrintViewManager(const TestPrintViewManager&) = delete; + TestPrintViewManager& operator=(const TestPrintViewManager&) = delete; + ~TestPrintViewManager() override = default; + + static TestPrintViewManager* FromWebContents( + content::WebContents* web_contents) { + return static_cast<TestPrintViewManager*>( + printing::PrintViewManager::FromWebContents(web_contents)); + } + + // Create TestPrintViewManager with PrintViewManager::UserDataKey() so that + // PrintViewManager::FromWebContents() in printing path returns + // TestPrintViewManager*. + static void CreateForWebContents(content::WebContents* web_contents) { + web_contents->SetUserData( + printing::PrintViewManager::UserDataKey(), + std::make_unique<TestPrintViewManager>(web_contents)); + } + + void set_quit_closure(base::OnceClosure quit_closure) { + quit_closure_ = std::move(quit_closure); + } + + private: + // printing::mojom::PrintManagerHost: + void RequestPrintPreview( + printing::mojom::RequestPrintPreviewParamsPtr params) override { + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(quit_closure_)); + printing::PrintViewManager::RequestPrintPreview(std::move(params)); + } + + base::OnceClosure quit_closure_; +}; + +class PrintPreviewDialogClonedObserver : public content::WebContentsObserver { + public: + explicit PrintPreviewDialogClonedObserver(content::WebContents* dialog) + : WebContentsObserver(dialog) {} + PrintPreviewDialogClonedObserver(const PrintPreviewDialogClonedObserver&) = + delete; + PrintPreviewDialogClonedObserver& operator=( + const PrintPreviewDialogClonedObserver&) = delete; + ~PrintPreviewDialogClonedObserver() override = default; + + private: + // content::WebContentsObserver implementation. + void DidCloneToNewWebContents( + content::WebContents* old_web_contents, + content::WebContents* new_web_contents) override { + TestPrintViewManager::CreateForWebContents(new_web_contents); + } +}; } // namespace class DlpContentManagerBrowserTest : public InProcessBrowserTest { @@ -578,6 +638,24 @@ class DlpContentManagerReportingBrowserTest : public DlpContentManagerBrowserTest { public: + void SetUpOnMainThread() override { + content::WebContents* first_tab = + browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(first_tab); + + // Open a new tab so |cloned_tab_observer_| can see it and create a + // TestPrintViewManager for it before the real PrintViewManager gets + // created. Since TestPrintViewManager is created with + // PrintViewManager::UserDataKey(), the real PrintViewManager is not + // created and TestPrintViewManager gets mojo messages for the + // purposes of this test. + cloned_tab_observer_ = + std::make_unique<PrintPreviewDialogClonedObserver>(first_tab); + chrome::DuplicateTab(browser()); + } + + void TearDownOnMainThread() override { cloned_tab_observer_.reset(); } + // Sets up real report queue together with TestStorageModule void SetupReportQueue() { const std::string dm_token_ = "FAKE_DM_TOKEN"; @@ -651,6 +729,7 @@ mocked_policy_check_; reporting::ReportQueueConfiguration::PolicyCheckCallback policy_check_callback_; + std::unique_ptr<PrintPreviewDialogClonedObserver> cloned_tab_observer_; }; IN_PROC_BROWSER_TEST_F(DlpContentManagerReportingBrowserTest, @@ -678,15 +757,28 @@ // Check that IsPrintingRestricted emitted an event. EXPECT_TRUE(helper_.GetContentManager()->IsPrintingRestricted(web_contents)); + // Start printing and wait for the end of + // printing::PrintViewManager::RequestPrintPreview(). StartPrint() is an + // asynchronous function, which initializes mojo communication with a renderer + // process. We need to wait for the DLP restriction check in + // RequestPrintPreview(), which happens after the renderer process + // communicates back to the browser process. + base::RunLoop run_loop; + TestPrintViewManager::FromWebContents(web_contents) + ->set_quit_closure(run_loop.QuitClosure()); printing::StartPrint(web_contents, /*print_renderer=*/mojo::NullAssociatedRemote(), /*print_preview_disabled=*/false, /*print_only_selection=*/false); + run_loop.Run(); + // Check for notification about printing restriction. EXPECT_TRUE( display_service_tester.GetNotification(kPrintBlockedNotificationId)); } +// For better understanding of this test see comments in +// DlpContentManagerReportingBrowserTest.PrintingRestricted test. IN_PROC_BROWSER_TEST_F(DlpContentManagerReportingBrowserTest, PrintingReported) { SetupDlpRulesManager(); @@ -705,19 +797,17 @@ EXPECT_FALSE(helper_.GetContentManager()->IsPrintingRestricted(web_contents)); + base::RunLoop run_loop; + TestPrintViewManager::FromWebContents(web_contents) + ->set_quit_closure(run_loop.QuitClosure()); printing::StartPrint(web_contents, /*print_renderer=*/mojo::NullAssociatedRemote(), /*print_preview_disabled=*/false, /*print_only_selection=*/false); + run_loop.Run(); + EXPECT_FALSE( display_service_tester.GetNotification(kPrintBlockedNotificationId)); - - // TODO(crbug/1213872, jkopanski): A hack to make this test working on - // linux-chromeos-rel. For some reason, gtest calls RequestPrintPreview after - // the test fixture, which triggers a DLP reporting event. This happens only - // for linux-chromeos-rel build and in this PrintingReported test, does not - // occur in PrintingRestricted test. - helper_.ChangeConfidentiality(web_contents, kPrintAllowed); } class DlpContentManagerPolicyBrowserTest : public LoginPolicyTestBase {
diff --git a/chrome/browser/autofill/autofill_server_browsertest.cc b/chrome/browser/autofill/autofill_server_browsertest.cc index 7cb4b9a..c0d8ea68 100644 --- a/chrome/browser/autofill/autofill_server_browsertest.cc +++ b/chrome/browser/autofill/autofill_server_browsertest.cc
@@ -28,9 +28,11 @@ #include "content/public/test/test_utils.h" #include "content/public/test/url_loader_interceptor.h" #include "services/network/test/test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/third_party/mozilla/url_parse.h" +using testing::Matcher; using version_info::GetProductNameAndVersionForUserAgent; namespace autofill { @@ -63,7 +65,7 @@ class WindowedNetworkObserver { public: - explicit WindowedNetworkObserver(const std::string& expected_upload_data) + explicit WindowedNetworkObserver(Matcher<std::string> expected_upload_data) : expected_upload_data_(expected_upload_data), message_loop_runner_(new content::MessageLoopRunner) { interceptor_ = @@ -111,14 +113,14 @@ ? GetLookupContent(resource_request.url.path()) : network::GetUploadData(resource_request); - if (data == expected_upload_data_) + if (expected_upload_data_.Matches(data)) message_loop_runner_->Quit(); return false; } private: - const std::string expected_upload_data_; + Matcher<std::string> expected_upload_data_; scoped_refptr<content::MessageLoopRunner> message_loop_runner_; std::unique_ptr<content::URLLoaderInterceptor> interceptor_; @@ -138,7 +140,7 @@ // Enabled. {features::kAutofillAllowNonHttpActivation}, // Disabled. - {features::kAutofillMetadataUploads}); + {}); // Note that features MUST be enabled/disabled before continuing with // SetUp(); otherwise, the feature state doesn't propagate to the test @@ -156,6 +158,29 @@ base::test::ScopedFeatureList scoped_feature_list_; }; +MATCHER_P(EqualsUploadProto, expected_const, "") { + AutofillUploadRequest expected = expected_const; + AutofillUploadRequest request; + if (!request.ParseFromString(arg)) + return false; + + // Remove metadata because it is randomised and won't match. + request.mutable_upload()->clear_randomized_form_metadata(); + expected.mutable_upload()->clear_randomized_form_metadata(); + if (request.upload().field_size() != expected.upload().field_size()) + return false; + for (int i = 0; i < request.upload().field_size(); i++) { + request.mutable_upload() + ->mutable_field(i) + ->clear_randomized_field_metadata(); + expected.mutable_upload() + ->mutable_field(i) + ->clear_randomized_field_metadata(); + } + + return request.SerializeAsString() == expected.SerializeAsString(); +} + // Regression test for http://crbug.com/177419 IN_PROC_BROWSER_TEST_F(AutofillServerTest, QueryAndUploadBothIncludeFieldsWithAutocompleteOff) { @@ -250,6 +275,9 @@ upload->set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_HTML_FORM_SUBMISSION); upload->set_has_form_tag(true); + // For metadata, we only set the language. The matcher will ignore the + // randomized metadata values. + upload->set_language("und"); // Enabling raw form data uploading (e.g., field name) is too complicated in // this test. So, don't expect it in the upload. @@ -262,10 +290,7 @@ test::FillUploadField(upload->add_field(), 1236501728U, nullptr, nullptr, nullptr, 2U); - std::string expected_upload_string; - ASSERT_TRUE(request.SerializeToString(&expected_upload_string)); - - WindowedNetworkObserver upload_network_observer(expected_upload_string); + WindowedNetworkObserver upload_network_observer(EqualsUploadProto(request)); content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); content::SimulateMouseClick(web_contents, 0,
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index dff0a32..8983617 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -316,7 +316,6 @@ #if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER) #include "chrome/browser/spellchecker/spellcheck_factory.h" -#include "chrome/browser/spellchecker/spellcheck_service.h" #include "components/spellcheck/browser/pref_names.h" #include "components/spellcheck/common/spellcheck_features.h" #endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER) @@ -499,11 +498,8 @@ StartupData* startup_data) : parameters_(parameters), parsed_command_line_(parameters.command_line), - result_code_(content::RESULT_CODE_NORMAL_EXIT), should_call_pre_main_loop_start_startup_on_variations_service_( !parameters.ui_task), - profile_(nullptr), - run_message_loop_(true), startup_data_(startup_data) { DCHECK(startup_data_); // If we're running tests (ui_task is non-null). @@ -1408,30 +1404,16 @@ StartupProfileInfo profile_info = CreatePrimaryProfile( parameters(), /*cur_dir=*/base::FilePath(), parsed_command_line()); - switch (profile_info.mode) { - case StartupProfileMode::kBrowserWindow: - case StartupProfileMode::kProfilePicker: - profile_ = profile_info.profile; - break; - case StartupProfileMode::kError: - return content::RESULT_CODE_NORMAL_EXIT; - } + profile_ = profile_info.profile; + if (profile_info.mode == StartupProfileMode::kError) + return content::RESULT_CODE_NORMAL_EXIT; #if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER) - if (first_run::IsChromeFirstRun()) { - // The installed Windows language packs aren't determined until - // the spellcheck service is initialized. Make sure the primary - // preferred language is enabled for spellchecking until the user - // opts out later. If there is no dictionary support for the language - // then it will later be automatically disabled. - SpellcheckService::EnableFirstUserLanguageForSpellcheck( - profile_->GetPrefs()); - } - // Create the spellcheck service. This will asynchronously retrieve the // Windows platform spellcheck dictionary language tags used to populate the // context menu for editable content. - if (spellcheck::UseBrowserSpellChecker() && + if (profile_info.mode == StartupProfileMode::kBrowserWindow && + spellcheck::UseBrowserSpellChecker() && profile_->GetPrefs()->GetBoolean(spellcheck::prefs::kSpellCheckEnable) && !base::FeatureList::IsEnabled( spellcheck::kWinDelaySpellcheckServiceInit)) {
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h index ef9c223..bea1d7a 100644 --- a/chrome/browser/chrome_browser_main.h +++ b/chrome/browser/chrome_browser_main.h
@@ -20,6 +20,7 @@ #include "chrome/common/buildflags.h" #include "content/public/browser/browser_main_parts.h" #include "content/public/common/main_function_params.h" +#include "content/public/common/result_codes.h" #if BUILDFLAG(ENABLE_DOWNGRADE_PROCESSING) #include "chrome/browser/downgrade/downgrade_manager.h" @@ -142,7 +143,7 @@ // TODO(sky): remove this. This class (and related calls), may mutate the // CommandLine, so it is misleading keeping a const ref here. const base::CommandLine& parsed_command_line_; - int result_code_; + int result_code_ = content::RESULT_CODE_NORMAL_EXIT; #if !defined(OS_ANDROID) // Create ShutdownWatcherHelper object for watching jank during shutdown. @@ -199,8 +200,8 @@ std::unique_ptr<first_run::MasterPrefs> master_prefs_; #endif - Profile* profile_; - bool run_message_loop_; + Profile* profile_ = nullptr; + bool run_message_loop_ = true; base::FilePath user_data_dir_;
diff --git a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc index 751e41b..9644070 100644 --- a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc +++ b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/net_benchmarking.h" +#include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/predictors/loading_predictor.h" #include "chrome/browser/predictors/loading_predictor_factory.h" #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h" @@ -319,6 +320,13 @@ render_frame_host); return true; } + if (interface_name == autofill::mojom::PasswordGenerationDriver::Name_) { + ChromePasswordManagerClient::BindPasswordGenerationDriver( + mojo::PendingAssociatedReceiver< + autofill::mojom::PasswordGenerationDriver>(std::move(*handle)), + render_frame_host); + return true; + } if (interface_name == autofill::mojom::PasswordManagerDriver::Name_) { password_manager::ContentPasswordManagerDriverFactory:: BindPasswordManagerDriver(
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc index 9943e59..f5980860 100644 --- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc +++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -37,7 +37,7 @@ const ComponentConfig kConfigs[] = { {"epson-inkjet-printer-escpr", ComponentConfig::PolicyType::kEnvVersion, "5.0", "1913a5e0a6cad30b6f03e176177e0d7ed62c5d6700a9c66da556d7c3f5d6a47e"}, - {"cros-termina", ComponentConfig::PolicyType::kEnvVersion, "930.1", + {"cros-termina", ComponentConfig::PolicyType::kEnvVersion, "940.1", "e9d960f84f628e1f42d05de4046bb5b3154b6f1f65c08412c6af57a29aecaffb"}, {"rtanalytics-light", ComponentConfig::PolicyType::kEnvVersion, "92.0", "69f09d33c439c2ab55bbbe24b47ab55cb3f6c0bd1f1ef46eefea3216ec925038"},
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc index 15b3fbe..d9c39356 100644 --- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc +++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
@@ -175,9 +175,9 @@ CertificateProviderApiTest() {} void SetUpInProcessBrowserTestFixture() override { - ON_CALL(provider_, IsInitializationComplete(_)).WillByDefault(Return(true)); - ON_CALL(provider_, IsFirstPolicyLoadComplete(_)) - .WillByDefault(Return(true)); + provider_.SetDefaultReturns( + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); extensions::ExtensionApiTest::SetUpInProcessBrowserTestFixture();
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc index 41fe37b..57224ac 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -30,7 +30,6 @@ #include "chrome/test/base/test_browser_window.h" #include "chrome/test/base/testing_profile.h" #include "components/crx_file/id_util.h" -#include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/browser/notification_service.h" @@ -180,7 +179,6 @@ std::unique_ptr<Browser> browser_; std::vector<std::unique_ptr<TestExtensionDir>> test_extension_dirs_; - policy::MockConfigurationPolicyProvider mock_policy_provider_; DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateApiUnitTest); };
diff --git a/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc b/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc index 46e8cd7..614599f 100644 --- a/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc +++ b/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc
@@ -57,10 +57,9 @@ chromeos::SessionManagerClient::InitializeFakeInMemory(); // Init the user policy provider. - EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_)) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(policy_provider_, IsFirstPolicyLoadComplete(testing::_)) - .WillRepeatedly(testing::Return(true)); + policy_provider_.SetDefaultReturns( + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); policy_provider_.SetAutoRefresh(); policy::BrowserPolicyConnector::SetPolicyProviderForTesting( &policy_provider_);
diff --git a/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h b/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h index 647bf0c..1629764c 100644 --- a/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h +++ b/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h
@@ -52,7 +52,7 @@ const GURL& page_url, const base::Value& custom_arg_value); - policy::MockConfigurationPolicyProvider policy_provider_; + testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_; chromeos::ScopedStubInstallAttributes test_install_attributes_; policy::DevicePolicyCrosTestHelper test_helper_; policy::AffiliationMixin affiliation_mixin_{&mixin_host_, &test_helper_};
diff --git a/chrome/browser/extensions/api/management/management_browsertest.cc b/chrome/browser/extensions/api/management/management_browsertest.cc index 7de0ccc..5fcf4485 100644 --- a/chrome/browser/extensions/api/management/management_browsertest.cc +++ b/chrome/browser/extensions/api/management/management_browsertest.cc
@@ -115,10 +115,9 @@ class ExtensionManagementTest : public extensions::ExtensionBrowserTest { public: void SetUpInProcessBrowserTestFixture() override { - ON_CALL(policy_provider_, IsInitializationComplete(_)) - .WillByDefault(Return(true)); - ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(_)) - .WillByDefault(Return(true)); + policy_provider_.SetDefaultReturns( + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); policy::BrowserPolicyConnector::SetPolicyProviderForTesting( &policy_provider_); }
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 578084c2..1e52b4d 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
@@ -157,9 +157,9 @@ } void SetUpInProcessBrowserTestFixture() override { - ON_CALL(provider_, IsInitializationComplete(_)).WillByDefault(Return(true)); - ON_CALL(provider_, IsFirstPolicyLoadComplete(_)) - .WillByDefault(Return(true)); + provider_.SetDefaultReturns( + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); extensions::ExtensionApiTest::SetUpInProcessBrowserTestFixture();
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc index 2c62da9..db413fb 100644 --- a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc +++ b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
@@ -121,10 +121,9 @@ &user_policy, account_id_, user_affiliation_ids)); } - ON_CALL(mock_policy_provider_, IsInitializationComplete(testing::_)) - .WillByDefault(testing::Return(true)); - ON_CALL(mock_policy_provider_, IsFirstPolicyLoadComplete(testing::_)) - .WillByDefault(testing::Return(true)); + mock_policy_provider_.SetDefaultReturns( + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); mock_policy_provider_.SetAutoRefresh(); policy::BrowserPolicyConnector::SetPolicyProviderForTesting( &mock_policy_provider_);
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h index fb6cdb66..8c46c9d 100644 --- a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h +++ b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
@@ -97,7 +97,8 @@ policy::DevicePolicyCrosTestHelper device_policy_test_helper_; std::unique_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_; - policy::MockConfigurationPolicyProvider mock_policy_provider_; + testing::NiceMock<policy::MockConfigurationPolicyProvider> + mock_policy_provider_; FakeGaia fake_gaia_; chromeos::HTTPSForwarder gaia_https_forwarder_; chromeos::ScopedStubInstallAttributes install_attributes_;
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc index c42ea40..34cba20 100644 --- a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc +++ b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
@@ -56,9 +56,9 @@ SettingsPrivateApiTest& operator=(const SettingsPrivateApiTest&) = delete; void SetUpInProcessBrowserTestFixture() override { - ON_CALL(provider_, IsInitializationComplete(_)).WillByDefault(Return(true)); - ON_CALL(provider_, IsFirstPolicyLoadComplete(_)) - .WillByDefault(Return(true)); + provider_.SetDefaultReturns( + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); ExtensionApiTest::SetUpInProcessBrowserTestFixture(); }
diff --git a/chrome/browser/extensions/api/storage/settings_apitest.cc b/chrome/browser/extensions/api/storage/settings_apitest.cc index 3ce9d19..d463a16f 100644 --- a/chrome/browser/extensions/api/storage/settings_apitest.cc +++ b/chrome/browser/extensions/api/storage/settings_apitest.cc
@@ -79,10 +79,9 @@ void SetUpInProcessBrowserTestFixture() override { ExtensionApiTest::SetUpInProcessBrowserTestFixture(); - ON_CALL(policy_provider_, IsInitializationComplete(_)) - .WillByDefault(Return(true)); - ON_CALL(policy_provider_, IsFirstPolicyLoadComplete(_)) - .WillByDefault(Return(true)); + policy_provider_.SetDefaultReturns( + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); policy_provider_.SetAutoRefresh(); policy::BrowserPolicyConnector::SetPolicyProviderForTesting( &policy_provider_);
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc index 480f1bd..2203169 100644 --- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc +++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
@@ -701,10 +701,9 @@ } void SetUpInProcessBrowserTestFixture() override { - ON_CALL(provider_, IsInitializationComplete(testing::_)) - .WillByDefault(testing::Return(true)); - ON_CALL(provider_, IsFirstPolicyLoadComplete(testing::_)) - .WillByDefault(testing::Return(true)); + provider_.SetDefaultReturns( + /*is_initialization_complete_return=*/true, + /*is_first_policy_load_complete_return=*/true); policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); policy::PolicyMap values;
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 1e1ae08..c5c91d2a 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -75,6 +75,7 @@ // this array may either refer to features defined in the header of this file or // in other locations in the code base (e.g. chrome/, components/, etc). const base::Feature* const kFeaturesExposedToJava[] = { + &autofill::features::kAutofillAddressProfileSavePromptNicknameSupport, &autofill::features::kAutofillCreditCardAuthentication, &autofill::features::kAutofillEnablePasswordInfoBarAccountIndicationFooter, &autofill::features::kAutofillEnableSaveCardInfoBarAccountIndicationFooter,
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 169b0e45..009113f 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
@@ -218,6 +218,8 @@ public static final String ALLOW_NEW_INCOGNITO_TAB_INTENTS = "AllowNewIncognitoTabIntents"; public static final String ALLOW_REMOTE_CONTEXT_FOR_NOTIFICATIONS = "AllowRemoteContextForNotifications"; + public static final String AUTOFILL_ADDRESS_PROFILE_SAVE_PROMPT_NICKNAME_SUPPORT = + "AutofillAddressProfileSavePromptNicknameSupport"; public static final String AUTOFILL_ALLOW_NON_HTTP_ACTIVATION = "AutofillAllowNonHttpActivation"; public static final String AUTOFILL_CREDIT_CARD_AUTHENTICATION =
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc index fd6293d..461b6ac2 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -713,7 +713,7 @@ } // Disabled due to flakiness on Linux https://crbug.com/1229601 -#if defined(OS_LINUX) +#if defined(OS_LINUX) || (defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER)) #define MAYBE_CreativeOriginStatusWithThrottlingNestedThrottled \ DISABLED_CreativeOriginStatusWithThrottlingNestedThrottled #else
diff --git a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreview.java b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreview.java index 1210bb4d..44650ab5 100644 --- a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreview.java +++ b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreview.java
@@ -17,6 +17,7 @@ import org.chromium.base.TraceEvent; import org.chromium.base.UserData; import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabService; import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabServiceFactory; import org.chromium.chrome.browser.tab.EmptyTabObserver; @@ -103,6 +104,11 @@ getService().captureTab(mTab, successCallback); } + private boolean shouldCompressBitmaps() { + return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + ChromeFeatureList.PAINT_PREVIEW_SHOW_ON_STARTUP, "compress_bitmaps", true); + } + /** * Shows a Paint Preview for the provided tab if it exists. * @param listener An interface used for notifying events originated from the player. @@ -124,7 +130,7 @@ mPlayerManager = new PlayerManager(mTab.getUrl(), mTab.getContext(), getService(), String.valueOf(mTab.getId()), listener, ChromeColors.getPrimaryBackgroundColor(mTab.getContext().getResources(), false), - /*ignoreInitialScrollOffset=*/false); + /*ignoreInitialScrollOffset=*/false, shouldCompressBitmaps()); mTab.getTabViewManager().addTabViewProvider(mTabbedPainPreviewViewProvider); mIsAttachedToTab = true; mWasEverShown = true;
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index 1eb79e85..b37c178 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -259,6 +259,21 @@ contents, autofill_client))); } +// static +void ChromePasswordManagerClient::BindPasswordGenerationDriver( + mojo::PendingAssociatedReceiver<autofill::mojom::PasswordGenerationDriver> + receiver, + content::RenderFrameHost* rfh) { + auto* web_contents = content::WebContents::FromRenderFrameHost(rfh); + if (!web_contents) + return; + auto* tab_helper = ChromePasswordManagerClient::FromWebContents(web_contents); + if (!tab_helper) + return; + tab_helper->password_generation_driver_receivers_.Bind(rfh, + std::move(receiver)); +} + ChromePasswordManagerClient::~ChromePasswordManagerClient() = default; bool ChromePasswordManagerClient::IsSavingAndFillingEnabled( @@ -1178,10 +1193,7 @@ password_reuse_detection_manager_(this), driver_factory_(nullptr), content_credential_manager_(this), - password_generation_driver_receivers_( - web_contents, - this, - content::WebContentsFrameReceiverSetPassKey()), + password_generation_driver_receivers_(web_contents, this), observer_(nullptr), #if BUILDFLAG(ENABLE_DICE_SUPPORT) credentials_filter_(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h index 10986bba..0561684d 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.h +++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -36,9 +36,9 @@ #include "components/prefs/pref_member.h" #include "components/safe_browsing/buildflags.h" #include "components/signin/public/base/signin_buildflags.h" +#include "content/public/browser/render_frame_host_receiver_set.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_receiver_set.h" #include "content/public/browser/web_contents_user_data.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" @@ -86,6 +86,10 @@ static void CreateForWebContentsWithAutofillClient( content::WebContents* contents, autofill::AutofillClient* autofill_client); + static void BindPasswordGenerationDriver( + mojo::PendingAssociatedReceiver<autofill::mojom::PasswordGenerationDriver> + receiver, + content::RenderFrameHost* rfh); ~ChromePasswordManagerClient() override; @@ -379,8 +383,7 @@ // once main frame host was created. password_manager::ContentCredentialManager content_credential_manager_; - content::WebContentsFrameReceiverSet< - autofill::mojom::PasswordGenerationDriver> + content::RenderFrameHostReceiverSet<autofill::mojom::PasswordGenerationDriver> password_generation_driver_receivers_; // Observer for password generation popup.
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc index 6903c821..355caaa 100644 --- a/chrome/browser/password_manager/password_store_factory.cc +++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -100,7 +100,15 @@ scoped_refptr<PasswordStore> ps; #if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID) || \ defined(OS_MAC) || defined(USE_X11) || defined(USE_OZONE) - ps = new password_manager::PasswordStoreImpl(std::move(login_db)); + + // TODO(crbug.com/1217071): Remove feature-guard once PasswordStoreImpl does + // not implement the PasswordStore abstract class anymore. + if (base::FeatureList::IsEnabled( + password_manager::features::kUnifiedPasswordManagerAndroid)) { + ps = new password_manager::PasswordStore(nullptr); + } else { + ps = new password_manager::PasswordStoreImpl(std::move(login_db)); + } #else NOTIMPLEMENTED(); #endif
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc index f5b34ce..3f3e7f1 100644 --- a/chrome/browser/printing/print_view_manager.cc +++ b/chrome/browser/printing/print_view_manager.cc
@@ -192,6 +192,7 @@ if (!IsPrintingRestricted()) return false; GetPrintRenderFrame(rfh)->OnPrintPreviewDialogClosed(); + PrintPreviewDone(); #if BUILDFLAG(IS_CHROMEOS_ASH) policy::ShowDlpPrintDisabledNotification(); #endif @@ -228,13 +229,6 @@ if (IsCrashed()) return false; - if (IsPrintingRestricted()) { -#if BUILDFLAG(IS_CHROMEOS_ASH) - policy::ShowDlpPrintDisabledNotification(); -#endif - return false; - } - GetPrintRenderFrame(rfh)->InitiatePrintPreview(std::move(print_renderer), has_selection);
diff --git a/chrome/browser/privacy/BUILD.gn b/chrome/browser/privacy/BUILD.gn index cd1f57e0..6b48742 100644 --- a/chrome/browser/privacy/BUILD.gn +++ b/chrome/browser/privacy/BUILD.gn
@@ -93,11 +93,13 @@ ] proto_deps = [ "//components/policy:full_runtime_code_generate" ] proto_out_dir = "/chrome/browser/privacy" + generate_cc = false } proto_library("traffic_annotation_proto") { sources = [ "traffic_annotation.proto" ] proto_deps = [ ":chrome_settings_full_runtime" ] import_dirs = [ "$root_gen_dir" + "/components/policy/proto" ] + generate_cc = false } }
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 5d87d4fff..d42acc00 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -144,6 +144,7 @@ #include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/site_isolation/site_isolation_policy.h" +#include "components/spellcheck/spellcheck_buildflags.h" #include "components/sync_preferences/pref_service_syncable.h" #include "components/url_formatter/url_fixer.h" #include "components/user_prefs/user_prefs.h" @@ -243,6 +244,10 @@ #include "components/signin/public/base/signin_switches.h" #endif +#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER) +#include "chrome/browser/spellchecker/spellcheck_service.h" +#endif + using base::TimeDelta; using bookmarks::BookmarkModel; using content::BrowserThread; @@ -756,6 +761,17 @@ content::URLDataSource::Add(this, std::make_unique<PrefsInternalsSource>(this)); +#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER) + if (IsNewProfile()) { + // The installed Windows language packs aren't determined until + // the spellcheck service is initialized. Make sure the primary + // preferred language is enabled for spellchecking until the user + // opts out later. If there is no dictionary support for the language + // then it will later be automatically disabled. + SpellcheckService::EnableFirstUserLanguageForSpellcheck(prefs_.get()); + } +#endif + if (delegate_) { TRACE_EVENT0("browser", "ProfileImpl::DoFinalInit:DelegateOnProfileCreationFinished");
diff --git a/chrome/browser/push_messaging/push_messaging_notification_manager.cc b/chrome/browser/push_messaging/push_messaging_notification_manager.cc index 40a0decf..8fdfcf2d 100644 --- a/chrome/browser/push_messaging/push_messaging_notification_manager.cc +++ b/chrome/browser/push_messaging/push_messaging_notification_manager.cc
@@ -16,6 +16,7 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" +#include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/notifications/platform_notification_service_factory.h" #include "chrome/browser/notifications/platform_notification_service_impl.h" @@ -93,6 +94,10 @@ database_data.origin = origin; database_data.service_worker_registration_id = service_worker_registration_id; database_data.notification_data = notification_data; + + // Make sure we don't expose this notification to the site. + database_data.is_shown_by_browser = true; + return database_data; } @@ -173,7 +178,8 @@ scoped_refptr<PlatformNotificationContext> notification_context = GetStoragePartition(profile_, origin)->GetPlatformNotificationContext(); notification_context->DeleteAllNotificationDataWithTag( - kPushMessagingForcedNotificationTag, origin, base::DoNothing()); + kPushMessagingForcedNotificationTag, /*is_shown_by_browser=*/true, + origin, base::DoNothing()); } if (notification_needed && !notification_shown) {
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css index 2522d1a1..0d126ac 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.css
@@ -25,22 +25,3 @@ height: 100px; width: 100px; } - -:host-context([orientation=horizontal]) #voice-match-animation { - padding-top: 16px; -} - -#message-vertical-mode { - padding-top: 40px; -} - -:host-context(html:not([new-layout])) #message-vertical-mode, -:host-context([orientation=vertical]) #message-horizontal-mode, -:host-context([orientation=horizontal]) #message-vertical-mode { - display: none; -} - -:host-context([orientation=vertical]) - #voiceMatchIntroDialog div[slot='content'] { - justify-content: flex-start; -}
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html index 799e398e4..c7ebf3e 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
@@ -30,17 +30,13 @@ <h1 slot="title"> [[getDialogTitle_(locale, uiStep, childName_)]] </h1> - <div slot="subtitle" id="message-horizontal-mode" - inner-h-t-m-l= - "[[getSubtitleMessage_(locale, uiStep, childName_, deviceName_)]]"> + <div slot="subtitle" id="voice-match-animation"> + <cr-lottie id="voice-match-lottie" + animation-url="voice_match_animation.json"> + </cr-lottie> </div> - <div slot="content" class="flex layout vertical center center-justified"> - <div id="voice-match-animation"> - <cr-lottie id="voice-match-lottie" - animation-url="voice_match_animation.json"> - </cr-lottie> - </div> - <div id="message-vertical-mode" inner-h-t-m-l= + <div slot="content" class="landscape-vertical-centered"> + <div inner-h-t-m-l= "[[getSubtitleMessage_(locale, uiStep, childName_, deviceName_)]]"> </div> </div>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js index 0f0d488..9e791e9 100644 --- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js +++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js
@@ -251,7 +251,10 @@ */ getSubtitleMessage_(locale, uiStep, childName, deviceName) { if (uiStep == VoiceMatchUIState.INTRO) { - return this.i18nAdvanced('assistantVoiceMatchMessage'); + return childName ? this.i18nAdvanced( + 'assistantVoiceMatchMessageForChild', + {substitutions: [deviceName, childName]}) : + this.i18nAdvanced('assistantVoiceMatchMessage'); } else if (uiStep === VoiceMatchUIState.RECORDING) { return this.i18nAdvanced( 'assistantVoiceMatchFooterForChild', {substitutions: [childName]});
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn index 41084e0..36b8aab 100644 --- a/chrome/browser/resources/settings/BUILD.gn +++ b/chrome/browser/resources/settings/BUILD.gn
@@ -271,6 +271,7 @@ "privacy_page/secure_dns_input.js", "privacy_page/security_page.js", "privacy_page/disable_safebrowsing_dialog.js", + "privacy_page/privacy_review/privacy_review_page.js", "privacy_page/security_keys_bio_enroll_dialog.js", "privacy_page/security_keys_credential_management_dialog.js", "privacy_page/security_keys_pin_field.js", @@ -390,6 +391,7 @@ "people_page:closure_compile", "prefs:closure_compile", "privacy_page:closure_compile", + "privacy_page/privacy_review:closure_compile", "privacy_sandbox:closure_compile", "reset_page:closure_compile", "safety_check_page:closure_compile", @@ -502,6 +504,7 @@ "languages_page:languages_subpage", "privacy_page:cookies_page", "privacy_page:security_page", + "privacy_page/privacy_review:privacy_review_page", "site_settings:category_setting_exceptions", "site_settings:local_data_browser_proxy", "site_settings:protocol_handlers", @@ -588,6 +591,7 @@ "on_startup_page:web_components", "people_page:web_components", "privacy_page:polymer3_elements", + "privacy_page/privacy_review:web_components", "reset_page:web_components", "safety_check_page:web_components", "search_engines_page:web_components",
diff --git a/chrome/browser/resources/settings/lazy_load.js b/chrome/browser/resources/settings/lazy_load.js index 7e147304..4ec38717 100644 --- a/chrome/browser/resources/settings/lazy_load.js +++ b/chrome/browser/resources/settings/lazy_load.js
@@ -10,6 +10,7 @@ import './autofill_page/payments_section.js'; import './clear_browsing_data_dialog/clear_browsing_data_dialog.js'; import './search_engines_page/search_engines_page.js'; +import './privacy_page/privacy_review/privacy_review_page.js'; import './privacy_page/security_keys_subpage.js'; import './privacy_page/security_page.js'; import './site_settings/all_sites.js'; @@ -80,6 +81,7 @@ export {SettingsCollapseRadioButtonElement} from './privacy_page/collapse_radio_button.js'; export {SettingsCookiesPageElement} from './privacy_page/cookies_page.js'; export {SettingsDoNotTrackToggleElement} from './privacy_page/do_not_track_toggle.js'; +export {SettingsPrivacyReviewPageElement} from './privacy_page/privacy_review/privacy_review_page.js'; export {BioEnrollDialogPage} from './privacy_page/security_keys_bio_enroll_dialog.js'; export {Ctap2Status, SampleStatus, SecurityKeysBioEnrollProxyImpl, SecurityKeysCredentialBrowserProxyImpl, SecurityKeysPINBrowserProxyImpl, SecurityKeysResetBrowserProxyImpl} from './privacy_page/security_keys_browser_proxy.js'; export {CredentialManagementDialogPage} from './privacy_page/security_keys_credential_management_dialog.js';
diff --git a/chrome/browser/resources/settings/privacy_page/BUILD.gn b/chrome/browser/resources/settings/privacy_page/BUILD.gn index d8f8e10..77d457b 100644 --- a/chrome/browser/resources/settings/privacy_page/BUILD.gn +++ b/chrome/browser/resources/settings/privacy_page/BUILD.gn
@@ -114,6 +114,7 @@ "..:router", "../controls:settings_toggle_button", "../prefs:prefs_behavior", + "../privacy_page/privacy_review:privacy_review_page", "../site_settings:constants", "../site_settings:site_data_details_subpage", "../site_settings:site_settings_prefs_browser_proxy",
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html index 07c8a1c3..d0d4aaa 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -253,6 +253,16 @@ </template> </settings-subpage> </template> + <template is="dom-if" route-path="/privacy/review"> + <settings-subpage id="privacy-review" + class="multi-card" + page-title="$i18n{privacyReviewLabel}" + associated-control="[[$$('#privacyReviewLinkRow')]]"> + <settings-privacy-review-page prefs="{{prefs}}" + focus-config="[[focusConfig_]]"> + </settings-privacy-review-page> + </settings-subpage> + </template> <template is="dom-if" route-path="/cookies"> <settings-subpage id="cookies" page-title="$i18n{cookiePageTitle}" learn-more-url="$i18n{cookiesSettingsHelpCenterURL}"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js index 8a9c4a08..e09e473 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.js +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -198,6 +198,10 @@ map.set(routes.SITE_SETTINGS.path, '#permissionsLinkRow'); } + if (routes.PRIVACY_REVIEW) { + map.set(routes.PRIVACY_REVIEW.path, '#privacyReviewLinkRow'); + } + return map; }, }, @@ -357,7 +361,8 @@ /** @private */ onPrivacyReviewClick_() { - // TODO(crbug/1215630): Implement navigation and metrics. + // TODO(crbug/1215630): Implement metrics. + Router.getInstance().navigateTo(routes.PRIVACY_REVIEW); } /** @private */
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/BUILD.gn b/chrome/browser/resources/settings/privacy_page/privacy_review/BUILD.gn new file mode 100644 index 0000000..8a439d5 --- /dev/null +++ b/chrome/browser/resources/settings/privacy_page/privacy_review/BUILD.gn
@@ -0,0 +1,23 @@ +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") +import("//tools/polymer/html_to_js.gni") +import("../../settings.gni") + +js_type_check("closure_compile") { + is_polymer3 = true + closure_flags = settings_closure_flags + deps = [ ":privacy_review_page" ] +} + +js_library("privacy_review_page") { + deps = [ + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + ] +} + +html_to_js("web_components") { + js_files = [ "privacy_review_page.js" ] +}
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/OWNERS b/chrome/browser/resources/settings/privacy_page/privacy_review/OWNERS new file mode 100644 index 0000000..77176e9 --- /dev/null +++ b/chrome/browser/resources/settings/privacy_page/privacy_review/OWNERS
@@ -0,0 +1,2 @@ +rainhard@chromium.org +sauski@google.com
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.html b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.html new file mode 100644 index 0000000..6f0d3a4 --- /dev/null +++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.html
@@ -0,0 +1 @@ +<div>$i18n{privacyReviewLabel}</div>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.js b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.js new file mode 100644 index 0000000..37d35890 --- /dev/null +++ b/chrome/browser/resources/settings/privacy_page/privacy_review/privacy_review_page.js
@@ -0,0 +1,24 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * 'settings-privacy-review-page' is the settings page that helps users review + * various privacy settings. + */ +import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +/** @polymer */ +export class SettingsPrivacyReviewPageElement extends PolymerElement { + static get is() { + return 'settings-privacy-review-page'; + } + + static get template() { + return html`{__html_template__}`; + } +} + +customElements.define( + SettingsPrivacyReviewPageElement.is, SettingsPrivacyReviewPageElement);
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js index fe6ea73..cbadf12cf 100644 --- a/chrome/browser/resources/settings/route.js +++ b/chrome/browser/resources/settings/route.js
@@ -17,6 +17,9 @@ r.CLEAR_BROWSER_DATA = r.PRIVACY.createChild('/clearBrowserData'); r.CLEAR_BROWSER_DATA.isNavigableDialog = true; + if (loadTimeData.getBoolean('privacyReviewEnabled')) { + r.PRIVACY_REVIEW = r.PRIVACY.createChild('review'); + } r.SITE_SETTINGS = r.PRIVACY.createChild('/content'); r.COOKIES = r.PRIVACY.createChild('/cookies'); r.SECURITY = r.PRIVACY.createChild('/security');
diff --git a/chrome/browser/resources/settings/settings_routes.js b/chrome/browser/resources/settings/settings_routes.js index 868064b..a95144d 100644 --- a/chrome/browser/resources/settings/settings_routes.js +++ b/chrome/browser/resources/settings/settings_routes.js
@@ -36,6 +36,7 @@ * PAYMENTS: !Route, * PEOPLE: !Route, * PRIVACY: !Route, + * PRIVACY_REVIEW: !Route, * RESET: !Route, * RESET_DIALOG: !Route, * SAFETY_CHECK: !Route,
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc index 47194651..bf0d2392 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
@@ -277,8 +277,9 @@ #if BUILDFLAG(FULL_SAFE_BROWSING) -// Disabled due to flakiness on Linux Asan https://crbug.com/1229592 -#if defined(OS_LINUX) && defined(ADDRESS_SANITIZER) +// Disabled due to flakiness on Linux Asan/Msan https://crbug.com/1229592 +#if defined(OS_LINUX) && \ + (defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER)) #define MAYBE_SavedPassword DISABLED_SavedPassword #else #define MAYBE_SavedPassword SavedPassword
diff --git a/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.cc b/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.cc index 7b7f370..d10faf4 100644 --- a/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.cc +++ b/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.cc
@@ -5,8 +5,6 @@ #include "chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h" #include "base/memory/ptr_util.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/safe_browsing/ui_manager.h" #include "components/safe_browsing/content/browser/safe_browsing_blocking_page.h" #include "components/security_interstitials/content/security_interstitial_tab_helper.h" @@ -19,21 +17,37 @@ SafeBrowsingSubresourceTabHelper::~SafeBrowsingSubresourceTabHelper() {} +// static +void SafeBrowsingSubresourceTabHelper::CreateForWebContents( + content::WebContents* web_contents, + SafeBrowsingUIManager* manager) { + if (FromWebContents(web_contents)) + return; + + web_contents->SetUserData( + kSafeBrowsingSubresourceTabHelperWebContentsUserDataKey, + std::make_unique<SafeBrowsingSubresourceTabHelper>(web_contents, + manager)); +} + +// static +SafeBrowsingSubresourceTabHelper* +SafeBrowsingSubresourceTabHelper::FromWebContents( + content::WebContents* web_contents) { + return static_cast<SafeBrowsingSubresourceTabHelper*>( + web_contents->GetUserData( + kSafeBrowsingSubresourceTabHelperWebContentsUserDataKey)); +} + void SafeBrowsingSubresourceTabHelper::ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) { if (navigation_handle->GetNetErrorCode() == net::ERR_BLOCKED_BY_CLIENT) { - safe_browsing::SafeBrowsingService* service = - g_browser_process->safe_browsing_service(); - if (!service) - return; security_interstitials::UnsafeResource resource; - scoped_refptr<safe_browsing::SafeBrowsingUIManager> manager = - service->ui_manager(); - if (manager->PopUnsafeResourceForURL(navigation_handle->GetURL(), - &resource)) { + if (manager_->PopUnsafeResourceForURL(navigation_handle->GetURL(), + &resource)) { safe_browsing::SafeBrowsingBlockingPage* blocking_page = - manager->blocking_page_factory()->CreateSafeBrowsingPage( - manager.get(), navigation_handle->GetWebContents(), + manager_->blocking_page_factory()->CreateSafeBrowsingPage( + manager_, navigation_handle->GetWebContents(), navigation_handle->GetURL(), {resource}, /*should_trigger_reporting=*/true); security_interstitials::SecurityInterstitialTabHelper:: @@ -45,9 +59,12 @@ } SafeBrowsingSubresourceTabHelper::SafeBrowsingSubresourceTabHelper( - content::WebContents* web_contents) - : WebContentsObserver(web_contents) {} + content::WebContents* web_contents, + SafeBrowsingUIManager* manager) + : WebContentsObserver(web_contents), manager_(manager) {} -WEB_CONTENTS_USER_DATA_KEY_IMPL(SafeBrowsingSubresourceTabHelper) +const char SafeBrowsingSubresourceTabHelper:: + kSafeBrowsingSubresourceTabHelperWebContentsUserDataKey[] = + "safe_browsing_subresource_tab_helper"; } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h b/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h index 039b8877d..c64a864 100644 --- a/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h +++ b/chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h
@@ -5,8 +5,8 @@ #ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SUBRESOURCE_TAB_HELPER_H_ #define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_SUBRESOURCE_TAB_HELPER_H_ +#include "base/supports_user_data.h" #include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" namespace content { class NavigationHandle; @@ -15,21 +15,30 @@ namespace safe_browsing { -class SafeBrowsingSubresourceTabHelper - : public content::WebContentsObserver, - public content::WebContentsUserData<SafeBrowsingSubresourceTabHelper> { +class SafeBrowsingUIManager; + +class SafeBrowsingSubresourceTabHelper : public content::WebContentsObserver, + public base::SupportsUserData::Data { public: + SafeBrowsingSubresourceTabHelper(content::WebContents* web_contents, + SafeBrowsingUIManager* manager); ~SafeBrowsingSubresourceTabHelper() override; + static void CreateForWebContents(content::WebContents* web_contents, + SafeBrowsingUIManager* manager); + + static SafeBrowsingSubresourceTabHelper* FromWebContents( + content::WebContents* web_contents); + // WebContentsObserver:: void ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) override; private: - explicit SafeBrowsingSubresourceTabHelper(content::WebContents* web_contents); - friend class content::WebContentsUserData<SafeBrowsingSubresourceTabHelper>; + static const char kSafeBrowsingSubresourceTabHelperWebContentsUserDataKey[]; - WEB_CONTENTS_USER_DATA_KEY_DECL(); + SafeBrowsingUIManager* manager_; + DISALLOW_COPY_AND_ASSIGN(SafeBrowsingSubresourceTabHelper); };
diff --git a/chrome/browser/safe_browsing/ui_manager.cc b/chrome/browser/safe_browsing/ui_manager.cc index c33f65d..fdf4c7d 100644 --- a/chrome/browser/safe_browsing/ui_manager.cc +++ b/chrome/browser/safe_browsing/ui_manager.cc
@@ -284,7 +284,7 @@ content::WebContents* contents, const GURL& blocked_url, const UnsafeResource& unsafe_resource) { - SafeBrowsingSubresourceTabHelper::CreateForWebContents(contents); + SafeBrowsingSubresourceTabHelper::CreateForWebContents(contents, this); // This blocking page is only used to retrieve the HTML for the page, so we // set |should_trigger_reporting| to false. Reports for subresources are // triggered when creating the blocking page that gets associated in
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc index 41aa1aba..5d6d6b19 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -208,6 +208,14 @@ return; } + if (!web_contents) { + // The tab has been closed (typically during the token exchange, which may + // take some time). + RecordSigninInterceptionHeuristicOutcome( + SigninInterceptionHeuristicOutcome::kAbortTabClosed); + return; + } + if (HasNoBrowser(web_contents)) { // Do not intercept from the profile creation flow. RecordSigninInterceptionHeuristicOutcome(
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.h b/chrome/browser/signin/dice_web_signin_interceptor.h index f3ba677..f7633a48 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor.h +++ b/chrome/browser/signin/dice_web_signin_interceptor.h
@@ -86,7 +86,10 @@ kInterceptEnterpriseForced = 16, kInterceptEnterpriseForcedProfileSwitch = 17, - kMaxValue = kInterceptEnterpriseForcedProfileSwitch, + // The interceptor is not triggered if the tab has already been closed. + kAbortTabClosed = 18, + + kMaxValue = kAbortTabClosed, }; // User selection in the interception bubble.
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc index dbcb793..5b5727e 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc
@@ -614,7 +614,7 @@ } // Checks that no heuristic is returned if signin interception is disabled. -TEST_F(DiceWebSigninInterceptorTest, InterceptionDsiabled) { +TEST_F(DiceWebSigninInterceptorTest, InterceptionDisabled) { // Setup for profile switch interception. std::string email = "bob@gmail.com"; Profile* profile_2 = CreateTestingProfile("Profile 2"); @@ -636,6 +636,16 @@ SigninInterceptionHeuristicOutcome::kAbortInterceptionDisabled); } +TEST_F(DiceWebSigninInterceptorTest, TabClosed) { + base::HistogramTester histogram_tester; + interceptor()->MaybeInterceptWebSignin( + /*web_contents=*/nullptr, CoreAccountId(), + /*is_new_account=*/true, /*is_sync_signin=*/false); + histogram_tester.ExpectUniqueSample( + "Signin.Intercept.HeuristicOutcome", + SigninInterceptionHeuristicOutcome::kAbortTabClosed, 1); +} + TEST_F(DiceWebSigninInterceptorTest, InterceptionInProgress) { // Setup for profile switch interception. std::string email = "bob@example.com";
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCacheRenderTest.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCacheRenderTest.java index ef0333c..6bf73a1a 100644 --- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCacheRenderTest.java +++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDataCacheRenderTest.java
@@ -51,17 +51,13 @@ import org.chromium.chrome.test.DummyUiChromeActivityTestCase; import org.chromium.chrome.test.util.ChromeRenderTestRule; 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.chrome.test.util.browser.signin.AccountManagerTestRule; -import org.chromium.components.signin.ProfileDataSource; import org.chromium.components.signin.base.AccountInfo; import org.chromium.components.signin.base.CoreAccountId; import org.chromium.components.signin.identitymanager.AccountInfoServiceProvider; import org.chromium.components.signin.identitymanager.AccountTrackerService; import org.chromium.components.signin.identitymanager.IdentityManager; import org.chromium.components.signin.identitymanager.IdentityManagerJni; -import org.chromium.components.signin.test.util.FakeProfileDataSource; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.widget.ChromeImageView; @@ -74,7 +70,7 @@ */ @RunWith(ParameterizedRunner.class) @UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) -@DisableFeatures({ChromeFeatureList.DEPRECATE_MENAGERIE_API}) +@Features.EnableFeatures({ChromeFeatureList.DEPRECATE_MENAGERIE_API}) @Batch(ProfileDataCacheRenderTest.PROFILE_DATA_BATCH_NAME) public class ProfileDataCacheRenderTest extends DummyUiChromeActivityTestCase { public static final String PROFILE_DATA_BATCH_NAME = "profile_data"; @@ -100,14 +96,13 @@ public final Features.JUnitProcessor mProcessor = new Features.JUnitProcessor(); @Rule - public final AccountManagerTestRule mAccountManagerTestRule = - new AccountManagerTestRule(new FakeProfileDataSource()); + public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule(); @Rule public final JniMocker mocker = new JniMocker(); @Rule - public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.LENIENT); @Mock private AccountTrackerService mAccountTrackerServiceMock; @@ -131,6 +126,10 @@ public void setUp() { mocker.mock(IdentityManagerJni.TEST_HOOKS, mIdentityManagerNativeMock); AccountInfoServiceProvider.init(mIdentityManager, mAccountTrackerServiceMock); + doAnswer(AdditionalAnswers.answerVoid(Runnable::run)) + .when(mAccountTrackerServiceMock) + .seedAccountsIfNeeded(any(Runnable.class)); + TestThreadUtils.runOnUiThreadBlocking(() -> { Activity activity = getActivity(); mContentView = new FrameLayout(activity); @@ -140,8 +139,6 @@ mProfileDataCache = new ProfileDataCache(activity, mImageSize, /*badgeConfig=*/null); - // ProfileDataCache only populates the cache when an observer is added. - mProfileDataCache.addObserver(accountId -> {}); }); } @@ -153,36 +150,6 @@ @Test @MediumTest @Feature("RenderTest") - public void testProfileDataWithAvatarFromIdentityManager() throws IOException { - doAnswer(AdditionalAnswers.answerVoid(Runnable::run)) - .when(mAccountTrackerServiceMock) - .seedAccountsIfNeeded(any(Runnable.class)); - when(mIdentityManagerNativeMock.findExtendedAccountInfoByEmailAddress( - anyLong(), eq(ACCOUNT_EMAIL))) - .thenReturn(mAccountInfoWithAvatar); - mAccountManagerTestRule.addAccount( - new ProfileDataSource.ProfileData(ACCOUNT_EMAIL, null, "Full Name", "Given Name")); - TestThreadUtils.runOnUiThreadBlocking(() -> { checkImageIsScaled(ACCOUNT_EMAIL); }); - mRenderTestRule.render(mImageView, "profile_data_cache_avatar" + mImageSize); - } - - @Test - @MediumTest - @Feature("RenderTest") - public void testProfileDataUpdatedFromIdentityManagerObserver() throws IOException { - doAnswer(AdditionalAnswers.answerVoid(Runnable::run)) - .when(mAccountTrackerServiceMock) - .seedAccountsIfNeeded(any(Runnable.class)); - mAccountManagerTestRule.addAccount( - new ProfileDataSource.ProfileData(ACCOUNT_EMAIL, null, "Full Name", "Given Name")); - mIdentityManager.onExtendedAccountInfoUpdated(mAccountInfoWithAvatar); - TestThreadUtils.runOnUiThreadBlocking(() -> { checkImageIsScaled(ACCOUNT_EMAIL); }); - mRenderTestRule.render(mImageView, "profile_data_cache_avatar" + mImageSize); - } - - @Test - @MediumTest - @Feature("RenderTest") public void testProfileDataPopulatedFromIdentityManagerObserver() throws IOException { mIdentityManager.onExtendedAccountInfoUpdated(mAccountInfoWithAvatar); TestThreadUtils.runOnUiThreadBlocking( @@ -192,12 +159,8 @@ @Test @MediumTest - @EnableFeatures({ChromeFeatureList.DEPRECATE_MENAGERIE_API}) @Feature("RenderTest") public void testProfileDataPopulatedWithoutGmsProfileDataSource() throws IOException { - doAnswer(AdditionalAnswers.answerVoid(Runnable::run)) - .when(mAccountTrackerServiceMock) - .seedAccountsIfNeeded(any(Runnable.class)); when(mIdentityManagerNativeMock.findExtendedAccountInfoByEmailAddress( anyLong(), eq(ACCOUNT_EMAIL))) .thenReturn(mAccountInfoWithAvatar); @@ -240,8 +203,9 @@ @MediumTest @Feature("RenderTest") public void testPlaceholderIsScaled() throws IOException { - TestThreadUtils.runOnUiThreadBlocking( - () -> { checkImageIsScaled("no.data.for.this.account@example.com"); }); + final String email = "no.data.for.this.account@example.com"; + mAccountManagerTestRule.addAccount(email); + TestThreadUtils.runOnUiThreadBlocking(() -> { checkImageIsScaled(email); }); mRenderTestRule.render(mImageView, "profile_data_cache_placeholder" + mImageSize); } @@ -249,9 +213,10 @@ @MediumTest @Feature("RenderTest") public void testAvatarIsScaled() throws IOException { - ProfileDataSource.ProfileData profileData = new ProfileDataSource.ProfileData( - ACCOUNT_EMAIL, createAvatar(), "Full Name", "Given Name"); - mAccountManagerTestRule.addAccount(profileData); + when(mIdentityManagerNativeMock.findExtendedAccountInfoByEmailAddress( + anyLong(), eq(ACCOUNT_EMAIL))) + .thenReturn(mAccountInfoWithAvatar); + mAccountManagerTestRule.addAccount(ACCOUNT_EMAIL); TestThreadUtils.runOnUiThreadBlocking(() -> { checkImageIsScaled(ACCOUNT_EMAIL); }); mRenderTestRule.render(mImageView, "profile_data_cache_avatar" + mImageSize); }
diff --git a/chrome/browser/signin/ui/android/BUILD.gn b/chrome/browser/signin/ui/android/BUILD.gn index b355803..098246d0 100644 --- a/chrome/browser/signin/ui/android/BUILD.gn +++ b/chrome/browser/signin/ui/android/BUILD.gn
@@ -65,6 +65,10 @@ "java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerProperties.java", "java/src/org/chromium/chrome/browser/signin/ui/account_picker/ExistingAccountRowViewBinder.java", "java/src/org/chromium/chrome/browser/signin/ui/account_picker/OnClickListenerViewBinder.java", + "java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupCoordinator.java", + "java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java", + "java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupProperties.java", + "java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupViewBinder.java", ] resources_package = "org.chromium.chrome.browser.signin.ui" } @@ -97,6 +101,7 @@ "java/res/layout/personalized_signin_promo_view_modern_content_suggestions.xml", "java/res/layout/personalized_signin_promo_view_recent_tabs.xml", "java/res/layout/personalized_signin_promo_view_settings.xml", + "java/res/layout/signin_first_run_view.xml", "java/res/layout/signin_progress_bar_dialog.xml", "java/res/layout/signin_view.xml", "java/res/layout/signout_wipe_storage_dialog.xml",
diff --git a/chrome/browser/signin/ui/android/java/res/layout/signin_first_run_view.xml b/chrome/browser/signin/ui/android/java/res/layout/signin_first_run_view.xml new file mode 100644 index 0000000..e49484a --- /dev/null +++ b/chrome/browser/signin/ui/android/java/res/layout/signin_first_run_view.xml
@@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2021 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:orientation="vertical" + android:gravity="center_horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:id="@+id/fre_logo" + android:layout_width="match_parent" + android:layout_height="@dimen/fre_tos_image_height" + android:layout_marginTop="80dp" + android:layout_marginBottom="24dp" + android:importantForAccessibility="no" + android:src="@drawable/fre_product_logo" /> + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/fre_welcome" + android:layout_below="@id/fre_logo" + style="@style/FreWelcomePageTitle" /> + + <LinearLayout + android:id="@+id/signin_fre_bottom_group" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:gravity="center_horizontal" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/signin_fre_selected_account" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" + android:gravity="center_vertical" + android:orientation="horizontal" + android:paddingStart="24dp" + android:paddingEnd="24dp" + android:paddingTop="8dp" + android:paddingBottom="8dp"> + + <include layout="@layout/account_row" /> + + <ImageView + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginStart="16dp" + app:srcCompat="@drawable/ic_expand_more_in_circle_24dp" + android:importantForAccessibility="no" /> + </LinearLayout> + + <include + android:id="@+id/signin_fre_continue_button" + layout="@layout/account_picker_bottom_sheet_continue_button" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginEnd="24dp" /> + + <org.chromium.ui.widget.ButtonCompat + android:id="@+id/signin_fre_dismiss_button" + style="@style/TextButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginEnd="24dp" + android:text="@string/signin_account_picker_dismiss_button" /> + + <!-- TODO(crbug/1228155): Use the correct string for the footer --> + <org.chromium.ui.widget.TextViewWithLeading + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginEnd="24dp" + android:layout_marginBottom="8dp" + android:gravity="center_horizontal" + android:textAppearance="@style/TextAppearance.TextMedium.Secondary" + android:text="@string/signin_account_picker_bottom_sheet_subtitle" + app:leading="@dimen/text_size_medium_leading" /> + </LinearLayout> +</RelativeLayout> \ No newline at end of file
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/ExistingAccountRowViewBinder.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/ExistingAccountRowViewBinder.java index c5b5bcec5..0014c3cf 100644 --- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/ExistingAccountRowViewBinder.java +++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/ExistingAccountRowViewBinder.java
@@ -20,7 +20,7 @@ * This class regroups the buildView and bindView util methods of the * existing account row. */ -class ExistingAccountRowViewBinder implements ViewBinder<PropertyModel, View, PropertyKey> { +public class ExistingAccountRowViewBinder implements ViewBinder<PropertyModel, View, PropertyKey> { /** * View binder that associates an existing account view with the model of * {@link ExistingAccountRowProperties}. @@ -46,7 +46,7 @@ * @param profileData profile data needs to bind. * @param view A view object inflated from @layout/account_picker_row. */ - static void bindAccountView(DisplayableProfileData profileData, View view) { + public static void bindAccountView(DisplayableProfileData profileData, View view) { ImageView accountImage = view.findViewById(R.id.account_image); accountImage.setImageDrawable(profileData.getImage());
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupCoordinator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupCoordinator.java new file mode 100644 index 0000000..6b994a2 --- /dev/null +++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupCoordinator.java
@@ -0,0 +1,55 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.signin.ui.frebottomgroup; + +import android.content.Context; +import android.view.View; + +import androidx.annotation.MainThread; + +import org.chromium.ui.modaldialog.ModalDialogManager; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; + +/** + * The coordinator handles the update and interaction of the bottom group of the FRE sign-in + * screen. It is composed of a selected account, a continue button and a dismiss button. + */ +public class FREBottomGroupCoordinator { + /** + * Listener for FREBottomGroup. + */ + public interface Listener { + /** + * Notifies when the user clicked the "add account" button. + */ + void addAccount(); + + /** + * Notifies when the user clicked the dismiss button. + */ + void advanceToNextPage(); + } + + private final FREBottomGroupMediator mMediator; + + /** + * Constructs a coordinator instance. + */ + @MainThread + public FREBottomGroupCoordinator( + Context context, View view, ModalDialogManager modalDialogManager, Listener listener) { + mMediator = new FREBottomGroupMediator(context, modalDialogManager, listener); + PropertyModelChangeProcessor.create( + mMediator.getModel(), view, FREBottomGroupViewBinder::bind); + } + + /** + * Releases the resources used by the coordinator. + */ + @MainThread + public void destroy() { + mMediator.destroy(); + } +}
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java new file mode 100644 index 0000000..ac50b2e --- /dev/null +++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupMediator.java
@@ -0,0 +1,131 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.signin.ui.frebottomgroup; + +import android.accounts.Account; +import android.content.Context; +import android.text.TextUtils; + +import androidx.annotation.NonNull; + +import org.chromium.chrome.browser.signin.services.ProfileDataCache; +import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerCoordinator; +import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerDialogCoordinator; +import org.chromium.chrome.browser.signin.ui.frebottomgroup.FREBottomGroupCoordinator.Listener; +import org.chromium.components.signin.AccountManagerFacade; +import org.chromium.components.signin.AccountManagerFacadeProvider; +import org.chromium.components.signin.AccountUtils; +import org.chromium.components.signin.AccountsChangeObserver; +import org.chromium.ui.modaldialog.ModalDialogManager; +import org.chromium.ui.modelutil.PropertyModel; + +import java.util.List; + +class FREBottomGroupMediator implements AccountsChangeObserver, ProfileDataCache.Observer, + AccountPickerCoordinator.Listener { + private final Context mContext; + private final ModalDialogManager mModalDialogManager; + private final AccountManagerFacade mAccountManagerFacade; + private final Listener mListener; + private final PropertyModel mModel; + // TODO(crbug/1227314): ProfileDataCache needs to be adjusted for supervised accounts users. + private @NonNull ProfileDataCache mProfileDataCache; + private AccountPickerDialogCoordinator mDialogCoordinator; + private String mSelectedAccountName; + + FREBottomGroupMediator( + Context context, ModalDialogManager modalDialogManager, Listener listener) { + mContext = context; + mModalDialogManager = modalDialogManager; + mListener = listener; + mProfileDataCache = ProfileDataCache.createWithDefaultImageSizeAndNoBadge(mContext); + mModel = FREBottomGroupProperties.createModel(this::onSelectedAccountClicked, + this::onContinueAsClicked, mListener::advanceToNextPage); + + mProfileDataCache.addObserver(this); + + mAccountManagerFacade = AccountManagerFacadeProvider.getInstance(); + mAccountManagerFacade.addObserver(this); + updateAccounts( + AccountUtils.getAccountsIfFulfilledOrEmpty(mAccountManagerFacade.getAccounts())); + } + + PropertyModel getModel() { + return mModel; + } + + void destroy() { + mProfileDataCache.removeObserver(this); + mAccountManagerFacade.removeObserver(this); + } + + /** + * Implements {@link ProfileDataCache.Observer}. + */ + @Override + public void onProfileDataUpdated(String accountEmail) { + updateSelectedAccountData(accountEmail); + } + + /** + * Implements {@link AccountsChangeObserver}. + */ + @Override + public void onAccountsChanged() { + mAccountManagerFacade.getAccounts().then(this::updateAccounts); + } + + @Override + public void onAccountSelected(String accountName, boolean isDefaultAccount) { + setSelectedAccountName(accountName); + mDialogCoordinator.dismissDialog(); + } + + @Override + public void addAccount() { + mListener.addAccount(); + mDialogCoordinator.dismissDialog(); + } + + /** + * Callback for the PropertyKey + * {@link FREBottomGroupProperties#ON_SELECTED_ACCOUNT_CLICKED}. + */ + private void onSelectedAccountClicked() { + mDialogCoordinator = + new AccountPickerDialogCoordinator(mContext, this, mModalDialogManager); + } + + /** + * Callback for the PropertyKey + * {@link FREBottomGroupProperties#ON_CONTINUE_AS_CLICKED}. + * TODO(crbug/1227313): Implement sign-in without sync. + */ + private void onContinueAsClicked() { + mListener.advanceToNextPage(); + } + + private void setSelectedAccountName(String accountName) { + mSelectedAccountName = accountName; + updateSelectedAccountData(mSelectedAccountName); + } + + private void updateSelectedAccountData(String accountEmail) { + if (TextUtils.equals(mSelectedAccountName, accountEmail)) { + mModel.set(FREBottomGroupProperties.SELECTED_ACCOUNT_DATA, + mProfileDataCache.getProfileDataOrDefault(accountEmail)); + } + } + + private void updateAccounts(List<Account> accounts) { + if (accounts.isEmpty()) { + mSelectedAccountName = null; + mModel.set(FREBottomGroupProperties.SELECTED_ACCOUNT_DATA, null); + } else if (mSelectedAccountName == null + || AccountUtils.findAccountByName(accounts, mSelectedAccountName) == null) { + setSelectedAccountName(accounts.get(0).name); + } + } +}
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupProperties.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupProperties.java new file mode 100644 index 0000000..459c70a --- /dev/null +++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupProperties.java
@@ -0,0 +1,46 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.signin.ui.frebottomgroup; + +import android.view.View.OnClickListener; + +import org.chromium.chrome.browser.signin.services.DisplayableProfileData; +import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey; +import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; + +class FREBottomGroupProperties { + static final ReadableObjectPropertyKey<OnClickListener> ON_SELECTED_ACCOUNT_CLICKED = + new ReadableObjectPropertyKey<>("on_selected_account_clicked"); + static final WritableObjectPropertyKey<DisplayableProfileData> SELECTED_ACCOUNT_DATA = + new WritableObjectPropertyKey<>("selected_account_data"); + + // PropertyKey for the button |Continue as ...| + static final ReadableObjectPropertyKey<OnClickListener> ON_CONTINUE_AS_CLICKED = + new ReadableObjectPropertyKey<>("on_continue_as_clicked"); + + // PropertyKey for the dismiss button + static final ReadableObjectPropertyKey<OnClickListener> ON_DISMISS_CLICKED = + new ReadableObjectPropertyKey<>("on_dismiss_clicked"); + + static final PropertyKey[] ALL_KEYS = new PropertyKey[] {ON_SELECTED_ACCOUNT_CLICKED, + SELECTED_ACCOUNT_DATA, ON_CONTINUE_AS_CLICKED, ON_DISMISS_CLICKED}; + + /** + * Creates a default model for FRE bottom group. + */ + static PropertyModel createModel(Runnable onSelectedAccountClicked, + Runnable onContinueAsClicked, Runnable onDismissClicked) { + return new PropertyModel.Builder(ALL_KEYS) + .with(ON_SELECTED_ACCOUNT_CLICKED, v -> onSelectedAccountClicked.run()) + .with(SELECTED_ACCOUNT_DATA, null) + .with(ON_CONTINUE_AS_CLICKED, v -> onContinueAsClicked.run()) + .with(ON_DISMISS_CLICKED, v -> onDismissClicked.run()) + .build(); + } + + private FREBottomGroupProperties() {} +}
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupViewBinder.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupViewBinder.java new file mode 100644 index 0000000..7b0a553 --- /dev/null +++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/frebottomgroup/FREBottomGroupViewBinder.java
@@ -0,0 +1,51 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.signin.ui.frebottomgroup; + +import android.view.View; + +import androidx.annotation.Nullable; + +import org.chromium.chrome.browser.signin.services.DisplayableProfileData; +import org.chromium.chrome.browser.signin.ui.R; +import org.chromium.chrome.browser.signin.ui.account_picker.ExistingAccountRowViewBinder; +import org.chromium.ui.modelutil.PropertyKey; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.widget.ButtonCompat; + +/** + * Stateless FREBottomGroup view binder. + */ +class FREBottomGroupViewBinder { + static void bind(PropertyModel model, View view, PropertyKey propertyKey) { + if (propertyKey == FREBottomGroupProperties.ON_CONTINUE_AS_CLICKED) { + view.findViewById(R.id.signin_fre_continue_button) + .setOnClickListener(model.get(FREBottomGroupProperties.ON_CONTINUE_AS_CLICKED)); + } else if (propertyKey == FREBottomGroupProperties.ON_DISMISS_CLICKED) { + view.findViewById(R.id.signin_fre_dismiss_button) + .setOnClickListener(model.get(FREBottomGroupProperties.ON_DISMISS_CLICKED)); + } else if (propertyKey == FREBottomGroupProperties.ON_SELECTED_ACCOUNT_CLICKED) { + view.findViewById(R.id.signin_fre_selected_account) + .setOnClickListener( + model.get(FREBottomGroupProperties.ON_SELECTED_ACCOUNT_CLICKED)); + } else if (propertyKey == FREBottomGroupProperties.SELECTED_ACCOUNT_DATA) { + final @Nullable DisplayableProfileData profileData = + model.get(FREBottomGroupProperties.SELECTED_ACCOUNT_DATA); + if (profileData == null) { + // TODO(crbug/1227316): Bind view when no account on device + } else { + ExistingAccountRowViewBinder.bindAccountView( + profileData, view.findViewById(R.id.signin_fre_selected_account)); + ButtonCompat button = view.findViewById(R.id.signin_fre_continue_button); + button.setText(view.getContext().getString(R.string.signin_promo_continue_as, + profileData.getGivenNameOrFullNameOrEmail())); + } + } else { + throw new IllegalArgumentException("Unknown property key:" + propertyKey); + } + } + + private FREBottomGroupViewBinder() {} +}
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 1fe92fe..213130ea 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -316,7 +316,7 @@ Allow Chrome sign-in </message> <message name="IDS_ALLOW_CHROME_SIGNIN_SUMMARY" desc="Summary for a checkbox in Google services that controls sign-in and sync prompts."> - Show Chrome sign-in prompts when you sign in to your Google Account + Shows prompts to sign in to Chrome </message> <message name="IDS_AUTOCOMPLETE_SEARCHES_AND_URLS_TITLE" desc="Title for a checkbox in Settings that controls URL and search autocompletion and informs the user about the data shared by this feature."> Autocomplete searches and URLs
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ALLOW_CHROME_SIGNIN_SUMMARY.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ALLOW_CHROME_SIGNIN_SUMMARY.png.sha1 index b0569f5..b84e5d8 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ALLOW_CHROME_SIGNIN_SUMMARY.png.sha1 +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ALLOW_CHROME_SIGNIN_SUMMARY.png.sha1
@@ -1 +1 @@ -2af20c9a88fd75a596cc8464982f6d96f4bd9808 \ No newline at end of file +98abd9993aa8c59edebdf577d6a51b6822e9a740 \ No newline at end of file
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h index be0c7b2..17669a84 100644 --- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h +++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
@@ -91,8 +91,6 @@ FRIEND_TEST_ALL_PREFIXES(AutomationManagerAuraBrowserTest, TableView); FRIEND_TEST_ALL_PREFIXES(AutomationManagerAuraBrowserTest, WebAppearsOnce); FRIEND_TEST_ALL_PREFIXES(AutomationManagerAuraBrowserTest, EventFromAction); - FRIEND_TEST_ALL_PREFIXES(AutomationManagerAuraBrowserTest, - GetFocusOnChildTree); AutomationManagerAura(); ~AutomationManagerAura() override;
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc index f6428a1..f5e76fab 100644 --- a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc +++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
@@ -219,6 +219,7 @@ for (size_t i = 0; i < web_hosts.size(); i++) { ui::AXNodeData node_data; tree->SerializeNode(web_hosts[i], &node_data); + LOG(ERROR) << i << ": " << node_data.ToString(); } } } @@ -592,35 +593,3 @@ manager->Enable(); EXPECT_NE(nullptr, registry->GetActionHandler(tree_id)); } - -IN_PROC_BROWSER_TEST_F(AutomationManagerAuraBrowserTest, GetFocusOnChildTree) { - views::AXAuraObjCache cache; - views::Widget* widget = new views::Widget; - views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); - params.bounds = {0, 0, 200, 200}; - widget->Init(std::move(params)); - widget->Show(); - widget->Activate(); - - cache.set_focused_widget_for_testing(widget); - - // No focus falls back on root view. - EXPECT_EQ(cache.GetOrCreate(widget->GetRootView()), cache.GetFocus()); - - // A child of the client view results in a focus if it has a tree id. - views::View* child = - widget->non_client_view()->client_view()->children().front(); - ASSERT_NE(nullptr, child); - - // No tree id yet. - EXPECT_EQ(cache.GetOrCreate(widget->GetRootView()), cache.GetFocus()); - - // Now, there's a tree id. - child->GetViewAccessibility().OverrideChildTreeID( - ui::AXTreeID::CreateNewAXTreeID()); - EXPECT_EQ(cache.GetOrCreate(child), cache.GetFocus()); - - cache.set_focused_widget_for_testing(nullptr); - - AddFailureOnWidgetAccessibilityError(widget); -}
diff --git a/chrome/browser/ui/hats/trust_safety_sentiment_service.cc b/chrome/browser/ui/hats/trust_safety_sentiment_service.cc index 313236c..20c386a 100644 --- a/chrome/browser/ui/hats/trust_safety_sentiment_service.cc +++ b/chrome/browser/ui/hats/trust_safety_sentiment_service.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/hats/trust_safety_sentiment_service.h" #include "base/containers/cxx20_erase.h" +#include "base/metrics/histogram_functions.h" #include "base/rand_util.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/ui/hats/hats_service.h" @@ -212,7 +213,8 @@ /*success_callback=*/base::DoNothing(), /*failure_callback=*/base::DoNothing(), winning_area_iterator->second.product_specific_data); - + base::UmaHistogramEnumeration("Feedback.TrustSafetySentiment.SurveyRequested", + winning_area_iterator->first); pending_triggers_.clear(); } @@ -383,6 +385,9 @@ if (!ProbabilityCheck(feature_area)) return; + base::UmaHistogramEnumeration("Feedback.TrustSafetySentiment.TriggerOccurred", + feature_area); + // This will overwrite any previous trigger for this feature area. We are // only interested in the most recent trigger, so this is acceptable. pending_triggers_[feature_area] = @@ -392,6 +397,9 @@ void TrustSafetySentimentService::PerformedIneligibleAction() { pending_triggers_[FeatureArea::kIneligible] = PendingTrigger(GetMaxRequiredNtpCount()); + + base::UmaHistogramEnumeration("Feedback.TrustSafetySentiment.TriggerOccurred", + FeatureArea::kIneligible); } /*static*/ bool TrustSafetySentimentService::ShouldBlockSurvey(
diff --git a/chrome/browser/ui/hats/trust_safety_sentiment_service.h b/chrome/browser/ui/hats/trust_safety_sentiment_service.h index 1da7dc0..7af64948 100644 --- a/chrome/browser/ui/hats/trust_safety_sentiment_service.h +++ b/chrome/browser/ui/hats/trust_safety_sentiment_service.h
@@ -74,11 +74,15 @@ // is not associated with any survey, but rather represents the collection of // features for which interaction with should also be considered when // determining elibigility for a survey. + + // These values are persisted to logs and entries should not be renumbered or + // reused. enum class FeatureArea { kIneligible = 0, - kPrivacySettings, - kTrustedSurface, - kTransactions + kPrivacySettings = 1, + kTrustedSurface = 2, + kTransactions = 3, + kMaxValue = kTransactions, }; private:
diff --git a/chrome/browser/ui/hats/trust_safety_sentiment_service_unittest.cc b/chrome/browser/ui/hats/trust_safety_sentiment_service_unittest.cc index 2bb982f..c0d521a 100644 --- a/chrome/browser/ui/hats/trust_safety_sentiment_service_unittest.cc +++ b/chrome/browser/ui/hats/trust_safety_sentiment_service_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/hats/trust_safety_sentiment_service.h" +#include "base/test/metrics/histogram_tester.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/ui/hats/hats_service_factory.h" #include "chrome/browser/ui/hats/mock_hats_service.h" @@ -69,6 +70,25 @@ }); } + void CheckHistograms( + const std::set<TrustSafetySentimentService::FeatureArea>& triggered_areas, + const std::set<TrustSafetySentimentService::FeatureArea>& + surveyed_areas) { + std::map<std::string, std::set<TrustSafetySentimentService::FeatureArea>> + histogram_to_expected = { + {"Feedback.TrustSafetySentiment.TriggerOccurred", triggered_areas}, + {"Feedback.TrustSafetySentiment.SurveyRequested", surveyed_areas}}; + + for (const auto& histogram_expected : histogram_to_expected) { + const auto& histogram_name = histogram_expected.first; + const auto& expected = histogram_expected.second; + histogram_tester()->ExpectTotalCount(histogram_name, expected.size()); + for (auto area : expected) { + histogram_tester()->ExpectBucketCount(histogram_name, area, 1); + } + } + } + TrustSafetySentimentService* service() { return TrustSafetySentimentServiceFactory::GetForProfile(profile()); } @@ -76,6 +96,7 @@ return &task_environment_; } base::test::ScopedFeatureList* feature_list() { return &feature_list_; } + base::HistogramTester* histogram_tester() { return &histogram_tester_; } MockHatsService* mock_hats_service() { return mock_hats_service_; } TestingProfile* profile() { return &profile_; } @@ -84,6 +105,7 @@ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; TestingProfile profile_; base::test::ScopedFeatureList feature_list_; + base::HistogramTester histogram_tester_; MockHatsService* mock_hats_service_; }; @@ -113,6 +135,10 @@ service()->OpenedNewTabPage(); testing::Mock::VerifyAndClearExpectations(mock_hats_service()); + CheckHistograms({TrustSafetySentimentService::FeatureArea::kPrivacySettings, + TrustSafetySentimentService::FeatureArea::kTrustedSurface}, + {}); + // The next NTP should be eligible for a survey. EXPECT_CALL(*mock_hats_service(), LaunchSurvey(testing::_, testing::_, testing::_, testing::_)); @@ -151,6 +177,10 @@ LaunchSurvey(kHatsSurveyTriggerTrustSafetyTrustedSurface, testing::_, testing::_, testing::_)); service()->OpenedNewTabPage(); + + CheckHistograms({TrustSafetySentimentService::FeatureArea::kPrivacySettings, + TrustSafetySentimentService::FeatureArea::kTrustedSurface}, + {TrustSafetySentimentService::FeatureArea::kTrustedSurface}); } TEST_F(TrustSafetySentimentServiceTest, TriggerProbability) { @@ -167,6 +197,7 @@ service()->TriggerOccurred( TrustSafetySentimentService::FeatureArea::kTrustedSurface, {}); service()->OpenedNewTabPage(); + CheckHistograms({}, {}); } TEST_F(TrustSafetySentimentServiceTest, TriggersClearOnLaunch) { @@ -174,6 +205,7 @@ FeatureParams params; params.trusted_surface_probability = "1.0"; params.privacy_settings_probability = "1.0"; + params.transactions_probability = "1.0"; params.min_time_to_prompt = "0s"; params.ntp_visits_min_range = "0"; params.ntp_visits_max_range = "0"; @@ -184,11 +216,21 @@ service()->TriggerOccurred( TrustSafetySentimentService::FeatureArea::kTrustedSurface, {}); + CheckHistograms({TrustSafetySentimentService::FeatureArea::kPrivacySettings, + TrustSafetySentimentService::FeatureArea::kTrustedSurface}, + {}); + // The launched survey will be randomly selected from the two triggers. + std::string requested_survey_trigger; EXPECT_CALL(*mock_hats_service(), - LaunchSurvey(testing::_, testing::_, testing::_, testing::_)); + LaunchSurvey(testing::_, testing::_, testing::_, testing::_)) + .WillOnce(testing::SaveArg<0>(&requested_survey_trigger)); service()->OpenedNewTabPage(); testing::Mock::VerifyAndClearExpectations(mock_hats_service()); + auto surveyed_feature_area = + requested_survey_trigger == kHatsSurveyTriggerTrustSafetyPrivacySettings + ? TrustSafetySentimentService::FeatureArea::kPrivacySettings + : TrustSafetySentimentService::FeatureArea::kTrustedSurface; // The trigger which did not result in a survey should no longer be // considered. @@ -200,11 +242,17 @@ // Repeated triggers post survey launch should however be considered. EXPECT_CALL(*mock_hats_service(), - LaunchSurvey(kHatsSurveyTriggerTrustSafetyTrustedSurface, + LaunchSurvey(kHatsSurveyTriggerTrustSafetyTransactions, testing::_, testing::_, testing::_)); service()->TriggerOccurred( - TrustSafetySentimentService::FeatureArea::kTrustedSurface, {}); + TrustSafetySentimentService::FeatureArea::kTransactions, {}); service()->OpenedNewTabPage(); + + CheckHistograms({TrustSafetySentimentService::FeatureArea::kPrivacySettings, + TrustSafetySentimentService::FeatureArea::kTrustedSurface, + TrustSafetySentimentService::FeatureArea::kTransactions}, + {surveyed_feature_area, + TrustSafetySentimentService::FeatureArea::kTransactions}); } TEST_F(TrustSafetySentimentServiceTest, SettingsWatcher_PrivacySettings) { @@ -485,6 +533,9 @@ LaunchSurvey(kHatsSurveyTriggerTrustSafetyPrivacySettings, testing::_, testing::_, testing::_)); service()->OpenedNewTabPage(); + CheckHistograms({TrustSafetySentimentService::FeatureArea::kPrivacySettings, + TrustSafetySentimentService::FeatureArea::kIneligible}, + {TrustSafetySentimentService::FeatureArea::kPrivacySettings}); } TEST_F(TrustSafetySentimentServiceTest, ClosingIncognitoDelaysSurvey) { @@ -516,6 +567,10 @@ // result in a survey, as the maximum of the range is 2. service()->OpenedNewTabPage(); + CheckHistograms({TrustSafetySentimentService::FeatureArea::kPrivacySettings, + TrustSafetySentimentService::FeatureArea::kIneligible}, + {}); + // The second visit to the NTP should not trigger a survey if it takes place // less than the minimum time to prompt after closing an incognito session. task_environment()->AdvanceClock(base::TimeDelta::FromSeconds(30)); @@ -532,4 +587,8 @@ // minimum time has passed, should trigger a survey. task_environment()->AdvanceClock(base::TimeDelta::FromMinutes(1)); service()->OpenedNewTabPage(); + + CheckHistograms({TrustSafetySentimentService::FeatureArea::kPrivacySettings, + TrustSafetySentimentService::FeatureArea::kIneligible}, + {TrustSafetySentimentService::FeatureArea::kPrivacySettings}); }
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc index 69018a90..3aa00b3 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -276,6 +276,10 @@ } } +void EnrollmentScreenHandler::ShowEnrollmentCloudReadyNotAllowedError() { + ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_CLOUD_READY_NOT_ALLOWED, false); +} + void EnrollmentScreenHandler::ShowActiveDirectoryScreen( const std::string& domain_join_config, const std::string& machine_name,
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h index 52c30aa1..b3742ed33 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
@@ -79,6 +79,7 @@ void ShowSigninScreen() override; void ShowUserError(UserErrorType error_type, const std::string& email) override; + void ShowEnrollmentCloudReadyNotAllowedError() override; void ShowActiveDirectoryScreen(const std::string& domain_join_config, const std::string& machine_name, const std::string& username,
diff --git a/chrome/browser/web_applications/app_service/web_apps_publisher_host.h b/chrome/browser/web_applications/app_service/web_apps_publisher_host.h index 638a7b6f..039d8fd 100644 --- a/chrome/browser/web_applications/app_service/web_apps_publisher_host.h +++ b/chrome/browser/web_applications/app_service/web_apps_publisher_host.h
@@ -77,9 +77,6 @@ void SetPermission(const std::string& app_id, apps::mojom::PermissionPtr permission); - void SetWindowMode(const std::string& app_id, - apps::mojom::WindowMode window_mode); - void ExecuteContextMenuCommand(const std::string& app_id, int32_t item_id, int64_t display_id); @@ -87,6 +84,7 @@ private: FRIEND_TEST_ALL_PREFIXES(WebAppsPublisherHostBrowserTest, PauseUnpause); FRIEND_TEST_ALL_PREFIXES(WebAppsPublisherHostBrowserTest, OpenNativeSettings); + FRIEND_TEST_ALL_PREFIXES(WebAppsPublisherHostBrowserTest, WindowMode); void OnReady(); @@ -105,6 +103,8 @@ int32_t size_hint_in_dip, LoadIconCallback callback) override; void OpenNativeSettings(const std::string& app_id) override; + void SetWindowMode(const std::string& app_id, + apps::mojom::WindowMode window_mode) override; // WebAppPublisherHelper::Delegate: void PublishWebApps(std::vector<apps::mojom::AppPtr> apps) override;
diff --git a/chrome/browser/web_applications/file_handlers_permission_helper.cc b/chrome/browser/web_applications/file_handlers_permission_helper.cc index 4255de23..7fc0503 100644 --- a/chrome/browser/web_applications/file_handlers_permission_helper.cc +++ b/chrome/browser/web_applications/file_handlers_permission_helper.cc
@@ -178,6 +178,8 @@ void FileHandlersPermissionHelper::UpdateAppsMatchingPattern( const ContentSettingsPattern& pattern) { + ScopedRegistryUpdate update( + finalizer_->registry_controller().AsWebAppSyncBridge()); for (const AppId& app_id : finalizer_->registrar().GetAppIds()) { const WebApp* app = finalizer_->GetWebAppRegistrar().GetAppById(app_id); if (!app || !app->is_locally_installed()) @@ -191,8 +193,6 @@ if (permission_blocked == app->file_handler_permission_blocked()) continue; - ScopedRegistryUpdate update( - finalizer_->registry_controller().AsWebAppSyncBridge()); WebApp* app_to_update = update->UpdateApp(app_id); app_to_update->SetFileHandlerPermissionBlocked(permission_blocked); FileHandlerUpdateAction file_handlers_need_os_update =
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_unittest.cc b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_unittest.cc index b657bcd..9169dd85 100644 --- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_unittest.cc +++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_unittest.cc
@@ -171,9 +171,6 @@ &externally_managed_app_manager(), &controller().registrar(), &controller().sync_bridge(), &ui_manager(), &controller().os_integration_manager(), &web_app_policy_manager()); - - install_manager().Start(); - install_finalizer().Start(); } void TearDown() override { @@ -250,6 +247,10 @@ void InitRegistrarWithRegistry(const Registry& registry) { controller().database_factory().WriteRegistry(registry); controller().Init(); + + // Must come after registry controller initialization. + install_manager().Start(); + install_finalizer().Start(); } void InitRegistrarWithSystemApps(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 3e7a173..2e6c31b2 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -616,15 +616,15 @@ } } -if (!is_android) { - group("telemetry_gpu_integration_test") { - testonly = true - data_deps = [ - "//content/test:telemetry_gpu_integration_test_support", - "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", - ] - } -} else { +group("telemetry_gpu_integration_test") { + testonly = true + data_deps = [ + "//content/test:telemetry_gpu_integration_test_support", + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", + ] +} + +if (is_android) { template("telemetry_gpu_integration_test_android_template") { forward_variables_from(invoker, [ "telemetry_target_suffix" ]) group(target_name) { @@ -3990,15 +3990,15 @@ data_deps = [ "//testing:test_scripts_shared" ] } -if (!is_android) { - group("telemetry_perf_unittests") { - testonly = true - data_deps = [ - ":telemetry_perf_unittests_base", - "//tools/perf:perf", - ] - } -} else { +group("telemetry_perf_unittests") { + testonly = true + data_deps = [ + ":telemetry_perf_unittests_base", + "//tools/perf:perf", + ] +} + +if (is_android) { template("telemetry_perf_unittests_android_template") { forward_variables_from(invoker, [ "telemetry_target_suffix" ]) group(target_name) { @@ -4026,15 +4026,15 @@ ] } -if (!is_android) { - group("telemetry_perf_tests") { - testonly = true - data_deps = [ - ":telemetry_perf_tests_base", - "//tools/perf/:perf", - ] - } -} else { +group("telemetry_perf_tests") { + testonly = true + data_deps = [ + ":telemetry_perf_tests_base", + "//tools/perf/:perf", + ] +} + +if (is_android) { template("telemetry_perf_tests_android_template") { forward_variables_from(invoker, [ "telemetry_target_suffix" ]) group(target_name) { @@ -4127,14 +4127,14 @@ } } -if (!is_android) { - template("performance_test_suite_template") { - forward_variables_from(invoker, [ "override_board" ]) - performance_test_suite_template_base(target_name) { - data_deps = [ "//chrome/test:telemetry_perf_tests" ] - } +template("performance_test_suite_template") { + forward_variables_from(invoker, [ "override_board" ]) + performance_test_suite_template_base(target_name) { + data_deps = [ "//chrome/test:telemetry_perf_tests" ] } -} else { +} + +if (is_android) { template("performance_test_suite_template_android") { forward_variables_from(invoker, [ @@ -4148,11 +4148,10 @@ } } -if (!is_android) { - performance_test_suite_template("performance_test_suite") { - } -} else { - import("//tools/perf/chrome_telemetry_build/android_browser_types.gni") +performance_test_suite_template("performance_test_suite") { +} + +if (is_android) { foreach(_target_suffix, telemetry_android_browser_target_suffixes) { performance_test_suite_template_android( "performance_test_suite${_target_suffix}") { @@ -9021,15 +9020,15 @@ data_deps = [ "//testing:test_scripts_shared" ] } - if (!is_android) { - group("rendering_representative_perf_tests") { - testonly = true - data_deps = [ - ":rendering_representative_perf_tests_base", - "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", - ] - } - } else { + group("rendering_representative_perf_tests") { + testonly = true + data_deps = [ + ":rendering_representative_perf_tests_base", + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", + ] + } + + if (is_android) { template("rendering_representative_perf_tests_android_template") { forward_variables_from(invoker, [ "telemetry_target_suffix" ]) group(target_name) {
diff --git a/chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2 b/chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2 index 1fbf6be..b103f198 100644 --- a/chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2 +++ b/chrome/test/android/browsertests_apk/AndroidManifest.xml.jinja2
@@ -35,6 +35,7 @@ android:theme="@style/Theme.Chromium.TabbedMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" + android:exported="true" android:process=":test_process"> <intent-filter> <action android:name="android.intent.action.MAIN"/>
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc index b5826d5a..402e97a 100644 --- a/chrome/test/chromedriver/session_commands.cc +++ b/chrome/test/chromedriver/session_commands.cc
@@ -394,25 +394,25 @@ Status ConfigureHeadlessSession(Session* session, const Capabilities& capabilities) { - if (session->chrome->GetBrowserInfo()->is_headless) { - std::string download_directory; - if (capabilities.prefs && - (capabilities.prefs->GetString("download.default_directory", - &download_directory) || - capabilities.prefs->GetStringWithoutPathExpansion( - "download.default_directory", &download_directory))) - session->headless_download_directory = - std::make_unique<std::string>(download_directory); - else - session->headless_download_directory = std::make_unique<std::string>("."); - WebView* first_view; - session->chrome->GetWebViewById(session->window, &first_view); - Status status = first_view->OverrideDownloadDirectoryIfNeeded( - *session->headless_download_directory); - return status; + if (!session->chrome->GetBrowserInfo()->is_headless) + return Status(kOk); + + const std::string* download_directory = nullptr; + if (capabilities.prefs) { + download_directory = + capabilities.prefs->FindStringPath("download.default_directory"); + if (!download_directory) { + download_directory = + capabilities.prefs->FindStringKey("download.default_directory"); + } } - // session is not headless - return Status(kOk); + session->headless_download_directory = std::make_unique<std::string>( + download_directory ? *download_directory : "."); + + WebView* first_view; + session->chrome->GetWebViewById(session->window, &first_view); + return first_view->OverrideDownloadDirectoryIfNeeded( + *session->headless_download_directory); } } // namespace internal
diff --git a/chrome/test/chromedriver/test/webview_shell/java/AndroidManifest.xml b/chrome/test/chromedriver/test/webview_shell/java/AndroidManifest.xml index 181b43ac..f46473b 100644 --- a/chrome/test/chromedriver/test/webview_shell/java/AndroidManifest.xml +++ b/chrome/test/chromedriver/test/webview_shell/java/AndroidManifest.xml
@@ -18,7 +18,8 @@ <activity android:name=".Main" android:launchMode="singleTask" android:process=":main" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize"> + android:configChanges="orientation|keyboardHidden|keyboard|screenSize" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
diff --git a/chrome/test/data/extensions/api_test/wm_desks_private/background.js b/chrome/test/data/extensions/api_test/wm_desks_private/background.js index d6ef48d..564c0dc2 100644 --- a/chrome/test/data/extensions/api_test/wm_desks_private/background.js +++ b/chrome/test/data/extensions/api_test/wm_desks_private/background.js
@@ -16,4 +16,4 @@ chrome.test.assertTrue(deskTemplate.hasOwnProperty('templateName')); })); }, -]); \ No newline at end of file +]);
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index ccd5c1e3..89f5b7e 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -493,6 +493,11 @@ get browsePreload() { return 'chrome://settings/test_loader.html?module=settings/privacy_page_test.js'; } + + /** @override */ + get featureListInternal() { + return {enabled: ['features::kPrivacyReview']}; + } }; TEST_F('CrSettingsPrivacyPageV3Test', 'PrivacyPageTests', function() {
diff --git a/chrome/test/data/webui/settings/privacy_page_test.js b/chrome/test/data/webui/settings/privacy_page_test.js index 941d2ce..95a8062 100644 --- a/chrome/test/data/webui/settings/privacy_page_test.js +++ b/chrome/test/data/webui/settings/privacy_page_test.js
@@ -246,12 +246,6 @@ /** @type {!SettingsPrivacyPageElement} */ let page; - suiteSetup(function() { - loadTimeData.overrideValues({ - privacyReviewEnabled: true, - }); - }); - setup(function() { document.body.innerHTML = ''; page = /** @type {!SettingsPrivacyPageElement} */ @@ -264,6 +258,12 @@ assertTrue(isChildVisible(page, '#privacyReviewLinkRow')); }); + test('privacyReviewRowClick', function() { + page.shadowRoot.querySelector('#privacyReviewLinkRow').click(); + // Ensure the correct Settings page is shown. + assertEquals(routes.PRIVACY_REVIEW, Router.getInstance().getCurrentRoute()); + }); + test('clearBrowsingDataClass', function() { assertTrue(!!page.shadowRoot.querySelector('#clearBrowsingData') .classList.contains('hr'));
diff --git a/chrome/test/media_router/BUILD.gn b/chrome/test/media_router/BUILD.gn index 0df8230..d2c5191 100644 --- a/chrome/test/media_router/BUILD.gn +++ b/chrome/test/media_router/BUILD.gn
@@ -154,15 +154,15 @@ data_deps = [ "//tools/perf/contrib/media_router_benchmarks:telemetry_extension_resources" ] } - if (!is_android) { - group("media_router_perf_tests") { - testonly = true - data_deps = [ - ":media_router_perf_tests_base", - "//tools/perf:perf", - ] - } - } else { + group("media_router_perf_tests") { + testonly = true + data_deps = [ + ":media_router_perf_tests_base", + "//tools/perf:perf", + ] + } + + if (is_android) { template("media_router_perf_tests_android_template") { forward_variables_from(invoker, [ "telemetry_target_suffix" ]) group(target_name) {
diff --git a/chromeos/components/media_app_ui/resources/js/receiver.js b/chromeos/components/media_app_ui/resources/js/receiver.js index 60b88050..3287b46 100644 --- a/chromeos/components/media_app_ui/resources/js/receiver.js +++ b/chromeos/components/media_app_ui/resources/js/receiver.js
@@ -60,9 +60,7 @@ delete this.renameOriginalFile; } this.error = result.errorName || ''; - this.blob = blob; - this.size = blob.size; - this.mimeType = blob.type; + this.updateFile(blob, this.name); } /** @@ -100,10 +98,7 @@ const message = {blob, oldFileToken: this.token, pickedFileToken}; const result = /** @type {!SaveAsResponse} */ ( await parentMessagePipe.sendMessage(Message.SAVE_AS, message)); - this.name = result.newFilename; - this.blob = blob; - this.size = blob.size; - this.mimeType = blob.type; + this.updateFile(blob, result.newFilename); // Files obtained by a file picker currently can not be renamed/deleted. // TODO(b/163285659): Detect when the new file is in the same folder as an // on-launch file. Those should still be able to be renamed/deleted. @@ -130,6 +125,21 @@ Message.REQUEST_SAVE_FILE, msg)); return new ReceivedFile(response.pickedFileContext); } + + /** + * Updates the wrapped file to reflect a change written to disk. + * @private + * @param {!Blob} blob + * @param {string} name + */ + updateFile(blob, name) { + // Wrap the blob to acquire "now()" as the lastModified time. Note this may + // differ from the actual mtime recorded on the inode. + this.blob = new File([blob], name, {type: blob.type}); + this.size = blob.size; + this.mimeType = blob.type; + this.name = name; + } } /**
diff --git a/chromeos/components/media_app_ui/test/driver_api.js b/chromeos/components/media_app_ui/test/driver_api.js index a62af8f9..f762fa0 100644 --- a/chromeos/components/media_app_ui/test/driver_api.js +++ b/chromeos/components/media_app_ui/test/driver_api.js
@@ -16,7 +16,6 @@ * @typedef {{ * deleteLastFile: (boolean|undefined), * getFileErrors: (boolean|undefined), - * getLastFileName: (boolean|undefined), * navigate: ({direction: string, token: number}|undefined), * openFile: (boolean|undefined), * overwriteLastFile: (string|undefined), @@ -48,6 +47,8 @@ * mimeType: string, * fromClipboard: (boolean|undefined), * error: (string|undefined), + * token: (number|undefined), + * lastModified: number, * hasDelete: boolean, * hasRename: boolean, * }}
diff --git a/chromeos/components/media_app_ui/test/guest_query_receiver.js b/chromeos/components/media_app_ui/test/guest_query_receiver.js index ddb61c6..79f4abe 100644 --- a/chromeos/components/media_app_ui/test/guest_query_receiver.js +++ b/chromeos/components/media_app_ui/test/guest_query_receiver.js
@@ -57,11 +57,36 @@ } /** + * Flatten out primitives from the file object for transfer over message pipe. + * @param {!mediaApp.AbstractFile} file + * @return {!FileSnapshot} + */ +function flattenFile(file) { + const hasDelete = !!file.deleteOriginalFile; + const hasRename = !!file.renameOriginalFile; + const lastModified = /** @type{!File} */ (file.blob).lastModified; + const {blob, name, size, mimeType, fromClipboard, error, token} = file; + return { + blob, + name, + size, + mimeType, + fromClipboard, + error, + token, + lastModified, + hasDelete, + hasRename + }; +} + +/** * Handlers for simple tests run in the guest that return a string result. - * @type{!Object<string, function(!TestMessageQueryData): Promise<string>>} + * @type{!Object<string, function(!TestMessageQueryData, !Object): + * Promise<string>>} */ const SIMPLE_TEST_QUERIES = { - requestSaveFile: async (data) => { + requestSaveFile: async (data, resultData) => { // Call requestSaveFile on the delegate. const existingFile = assertLastReceivedFileList().item(0); if (!existingFile) { @@ -72,13 +97,17 @@ data.simpleArgs ? data.simpleArgs.accept : []); return assertCast(pickedFile.token).toString(); }, - getExportFile: async (data) => { + getExportFile: async (data, resultData) => { const existingFile = assertLastReceivedFileList().item(0); if (!existingFile) { return 'getExportFile failed, no file loaded'; } const pickedFile = await existingFile.getExportFile(data.simpleArgs.accept); return pickedFile.token.toString(); + }, + getLastFile: async (data, resultData) => { + Object.assign(resultData, flattenFile(currentFile())); + return resultData.name; } }; @@ -89,7 +118,7 @@ */ async function runTestQuery(data) { let result = 'no result'; - let extraResultData; + let extraResultData = {}; if (data.testQuery) { const element = await waitForNode(data.testQuery, data.pathToRoot || []); result = element.tagName; @@ -105,7 +134,7 @@ } } } else if (data.simple !== undefined && data.simple in SIMPLE_TEST_QUERIES) { - result = await SIMPLE_TEST_QUERIES[data.simple](data); + result = await SIMPLE_TEST_QUERIES[data.simple](data, extraResultData); } else if (data.navigate !== undefined) { // Simulate a user navigating to the next/prev file. if (data.navigate.direction === 'next') { @@ -186,8 +215,6 @@ } else if (data.openFile) { // Call open file on file list, simulating a user trying to open a new file. await assertLastReceivedFileList().openFile(); - } else if (data.getLastFileName) { - result = currentFile().name; } else if (data.suppressCrashReports) { // TODO(b/172981864): Remove this once we stop triggering crash reports for // NotAFile errors. @@ -270,27 +297,8 @@ parentMessagePipe.registerHandler('get-last-loaded-files', () => { // Note: the `ReceivedFileList` has methods stripped since it gets sent // over a pipe so just send the underlying files. - /** - * @param {!mediaApp.AbstractFile} file - * @return {!FileSnapshot} - */ - function snapshot(file) { - const hasDelete = !!file.deleteOriginalFile; - const hasRename = !!file.renameOriginalFile; - const {blob, name, size, mimeType, fromClipboard, error} = file; - return { - blob, - name, - size, - mimeType, - fromClipboard, - error, - hasDelete, - hasRename - }; - } return /** @type {!LastLoadedFilesResponse} */ ( - {fileList: assertLastReceivedFileList().files.map(snapshot)}); + {fileList: assertLastReceivedFileList().files.map(flattenFile)}); }); // Log errors, rather than send them to console.error. This allows the error
diff --git a/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js b/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js index d92fbb1..73cdb8d 100644 --- a/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js +++ b/chromeos/components/media_app_ui/test/media_app_ui_browsertest.js
@@ -563,6 +563,13 @@ assertEquals(handle.lastWritable.writes.length, 1); assertDeepEquals( handle.lastWritable.writes[0], {position: 0, size: 'Foo'.length}); + + // Ensure there's a last modified property on the file after overwriting. The + // time should be "now", but there isn't a non-flaky way to test that. Just + // check that it's defined and is strictly positive. + const loadedFiles = await getLoadedFiles(); + assertEquals(loadedFiles.length, 1); + assertGE(loadedFiles[0].lastModified, 1); }; MediaAppUIBrowserTest.RejectZeroByteWrites = async () => { @@ -919,8 +926,9 @@ assertEquals(currentFiles[getEntryIndex()].file, null); // The new file has the right name in the untrusted context. - testResponse = await sendTestMessage({getLastFileName: true}); - assertEquals(testResponse.testQueryResult, 'new_file_name.png'); + testResponse = await sendTestMessage({simple: 'getLastFile'}); + const result = /** @type{!FileSnapshot} */ (testResponse.testQueryResultData); + assertEquals(result.name, 'new_file_name.png'); // The new file uses the same token as the old file. assertEquals(currentFiles[getEntryIndex()].token, file2Token); // Check the new file written has the correct data. @@ -1105,6 +1113,10 @@ assertEquals(receivedFilesBefore[0].hasDelete, true); assertEquals(receivedFilesAfter[0].hasRename, false); assertEquals(receivedFilesAfter[0].hasDelete, false); + + // Ensure there's a last modified property on the file after swapping in the + // picked file. + assertGE(receivedFilesAfter[0].lastModified, 1); }; // Tests the error handling behind the saveAs function on received files.
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn index a3423c4..0ea9a11 100644 --- a/chromeos/crosapi/mojom/BUILD.gn +++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -100,6 +100,10 @@ cpp = "::apps::mojom::IconKeyPtr" move_only = true }, + { + mojom = "crosapi.mojom.WindowMode" + cpp = "::apps::mojom::WindowMode" + }, ] traits_headers = [ "//chromeos/crosapi/mojom/app_service_types_mojom_traits.h",
diff --git a/chromeos/crosapi/mojom/app_service.mojom b/chromeos/crosapi/mojom/app_service.mojom index d7440c1b..c96d7ea 100644 --- a/chromeos/crosapi/mojom/app_service.mojom +++ b/chromeos/crosapi/mojom/app_service.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 7 +// Next MinVersion: 8 module crosapi.mojom; @@ -92,4 +92,12 @@ // e.g. for web app, it opens the Chrome site settings page for the app. [MinVersion=6] OpenNativeSettings@6(string app_id); + + // Set the window display mode for the app identified by |app_id|. + // |window_mode| represents how the app will be open in (e.g. in a + // standalone window or in a browser tab). + [MinVersion=7] + SetWindowMode@7( + string app_id, + WindowMode window_mode); };
diff --git a/chromeos/crosapi/mojom/app_service_types.mojom b/chromeos/crosapi/mojom/app_service_types.mojom index 7745e57..37f3c4d 100644 --- a/chromeos/crosapi/mojom/app_service_types.mojom +++ b/chromeos/crosapi/mojom/app_service_types.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 2 +// Next MinVersion: 3 module crosapi.mojom; @@ -19,47 +19,51 @@ // for the structs in this file. [Stable] struct App { - AppType app_type; - string app_id; + AppType app_type@0; + string app_id@1; // The fields above are mandatory. Everything else below is optional. - Readiness readiness; - string? name; - string? short_name; + Readiness readiness@2; + string? name@3; + string? short_name@4; // An optional, publisher-specific ID for this app, e.g. for Android apps, // this field contains the Android package name, and for web apps, it // contains the start URL. - string? publisher_id; - string? description; - string? version; - array<string> additional_search_terms; - IconKey? icon_key; - mojo_base.mojom.Time? last_launch_time; - mojo_base.mojom.Time? install_time; + string? publisher_id@5; + string? description@6; + string? version@7; + array<string> additional_search_terms@8; + IconKey? icon_key@9; + mojo_base.mojom.Time? last_launch_time@10; + mojo_base.mojom.Time? install_time@11; // Whether the app was installed by sync, policy or as a default app. - InstallSource install_source; - OptionalBool recommendable; - OptionalBool searchable; - OptionalBool show_in_launcher; - OptionalBool show_in_shelf; - OptionalBool show_in_search; - OptionalBool show_in_management; + InstallSource install_source@12; + OptionalBool recommendable@13; + OptionalBool searchable@14; + OptionalBool show_in_launcher@15; + OptionalBool show_in_shelf@16; + OptionalBool show_in_search@17; + OptionalBool show_in_management@18; // Whether the app icon should add the notification badging. - OptionalBool has_badge; + OptionalBool has_badge@19; // Paused apps cannot be launched, and any running apps that become paused // will be stopped. This is independent of whether or not the app is ready to // be launched (defined by the Readiness field). - OptionalBool paused; + OptionalBool paused@20; // This vector stores all the intent filters defined in this app. Each // intent filter defines a matching criteria for whether an intent can // be handled by this app. One app can have multiple intent filters. - array<IntentFilter> intent_filters; + array<IntentFilter> intent_filters@21; + + // Whether the app's display mode is in the browser or otherwise. + [MinVersion=2] + WindowMode window_mode@22; }; // The types of apps available in the registry. @@ -256,3 +260,16 @@ string label@0; // The string label, may be empty. gfx.mojom.ImageSkia? image@1; // The image icon, may be null. }; + +[Stable, Extensible] +// The mode that the app will be opened in (e.g. standalone window or browser +// tab). +enum WindowMode { + [Default] kUnknown = 0, + // Opens in a standalone window + kWindow, + // Opens in the default web browser + kBrowser, + // Opens in a tabbed app window + kTabbedWindow, +};
diff --git a/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc b/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc index 91c40ac..cc99015 100644 --- a/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc +++ b/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
@@ -102,6 +102,10 @@ if (!data.ReadIntentFilters(&intent_filters)) return false; + apps::mojom::WindowMode window_mode; + if (!data.ReadWindowMode(&window_mode)) + return false; + auto app = apps::mojom::App::New(); app->app_type = std::move(app_type); app->app_id = app_id; @@ -125,6 +129,7 @@ app->has_badge = has_badge; app->paused = paused; app->intent_filters = std::move(intent_filters); + app->window_mode = window_mode; *out = std::move(app); return true; } @@ -624,4 +629,43 @@ return true; } +crosapi::mojom::WindowMode +EnumTraits<crosapi::mojom::WindowMode, apps::mojom::WindowMode>::ToMojom( + apps::mojom::WindowMode input) { + switch (input) { + case apps::mojom::WindowMode::kUnknown: + return crosapi::mojom::WindowMode::kUnknown; + case apps::mojom::WindowMode::kWindow: + return crosapi::mojom::WindowMode::kWindow; + case apps::mojom::WindowMode::kBrowser: + return crosapi::mojom::WindowMode::kBrowser; + case apps::mojom::WindowMode::kTabbedWindow: + return crosapi::mojom::WindowMode::kTabbedWindow; + } + + NOTREACHED(); +} + +bool EnumTraits<crosapi::mojom::WindowMode, apps::mojom::WindowMode>::FromMojom( + crosapi::mojom::WindowMode input, + apps::mojom::WindowMode* output) { + switch (input) { + case crosapi::mojom::WindowMode::kUnknown: + *output = apps::mojom::WindowMode::kUnknown; + return true; + case crosapi::mojom::WindowMode::kWindow: + *output = apps::mojom::WindowMode::kWindow; + return true; + case crosapi::mojom::WindowMode::kBrowser: + *output = apps::mojom::WindowMode::kBrowser; + return true; + case crosapi::mojom::WindowMode::kTabbedWindow: + *output = apps::mojom::WindowMode::kTabbedWindow; + return true; + } + + NOTREACHED(); + return false; +} + } // namespace mojo
diff --git a/chromeos/crosapi/mojom/app_service_types_mojom_traits.h b/chromeos/crosapi/mojom/app_service_types_mojom_traits.h index 5da5b4e..2aaa907 100644 --- a/chromeos/crosapi/mojom/app_service_types_mojom_traits.h +++ b/chromeos/crosapi/mojom/app_service_types_mojom_traits.h
@@ -119,6 +119,11 @@ return r->intent_filters; } + static const apps::mojom::WindowMode& window_mode( + const apps::mojom::AppPtr& r) { + return r->window_mode; + } + static bool Read(crosapi::mojom::AppDataView data, apps::mojom::AppPtr* out); }; @@ -303,6 +308,13 @@ apps::mojom::IconValuePtr* out); }; +template <> +struct EnumTraits<crosapi::mojom::WindowMode, apps::mojom::WindowMode> { + static crosapi::mojom::WindowMode ToMojom(apps::mojom::WindowMode input); + static bool FromMojom(crosapi::mojom::WindowMode input, + apps::mojom::WindowMode* output); +}; + } // namespace mojo #endif // CHROMEOS_CROSAPI_MOJOM_APP_SERVICE_TYPES_MOJOM_TRAITS_H_
diff --git a/chromeos/crosapi/mojom/app_service_types_traits_unittest.cc b/chromeos/crosapi/mojom/app_service_types_traits_unittest.cc index 6472fe9..2ae4f6b0 100644 --- a/chromeos/crosapi/mojom/app_service_types_traits_unittest.cc +++ b/chromeos/crosapi/mojom/app_service_types_traits_unittest.cc
@@ -54,6 +54,8 @@ intent_filter->activity_label = "activity_label"; input->intent_filters.push_back(std::move(intent_filter)); + input->window_mode = apps::mojom::WindowMode::kWindow; + apps::mojom::AppPtr output; ASSERT_TRUE( mojo::test::SerializeAndDeserialize<crosapi::mojom::App>(input, output)); @@ -97,6 +99,8 @@ apps::mojom::PatternMatchType::kNone); EXPECT_EQ(filter->activity_name, "activity_name"); EXPECT_EQ(filter->activity_label, "activity_label"); + + EXPECT_EQ(output->window_mode, apps::mojom::WindowMode::kWindow); } // Test that serialization and deserialization works with optional fields that @@ -124,6 +128,7 @@ apps::mojom::ConditionType::kScheme, "https", apps::mojom::PatternMatchType::kNone, intent_filter); input->intent_filters.push_back(std::move(intent_filter)); + input->window_mode = apps::mojom::WindowMode::kBrowser; apps::mojom::AppPtr output; ASSERT_TRUE( @@ -154,6 +159,8 @@ EXPECT_EQ(condition->condition_values[0]->value, "https"); EXPECT_EQ(condition->condition_values[0]->match_type, apps::mojom::PatternMatchType::kNone); + + EXPECT_EQ(output->window_mode, apps::mojom::WindowMode::kBrowser); } // Test that serialization and deserialization works with updating app type. @@ -742,3 +749,36 @@ EXPECT_TRUE(output->is_placeholder_icon); } } + +// Test that serialization and deserialization works with window mode. +TEST(AppServiceTypesTraitsTest, RoundTripWindowMode) { + apps::mojom::WindowMode input; + { + input = apps::mojom::WindowMode::kUnknown; + apps::mojom::WindowMode output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<crosapi::mojom::WindowMode>( + input, output)); + EXPECT_EQ(output, apps::mojom::WindowMode::kUnknown); + } + { + input = apps::mojom::WindowMode::kWindow; + apps::mojom::WindowMode output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<crosapi::mojom::WindowMode>( + input, output)); + EXPECT_EQ(output, apps::mojom::WindowMode::kWindow); + } + { + input = apps::mojom::WindowMode::kBrowser; + apps::mojom::WindowMode output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<crosapi::mojom::WindowMode>( + input, output)); + EXPECT_EQ(output, apps::mojom::WindowMode::kBrowser); + } + { + input = apps::mojom::WindowMode::kTabbedWindow; + apps::mojom::WindowMode output; + ASSERT_TRUE(mojo::test::SerializeAndDeserialize<crosapi::mojom::WindowMode>( + input, output)); + EXPECT_EQ(output, apps::mojom::WindowMode::kTabbedWindow); + } +}
diff --git a/components/arc/compat_mode/arc_resize_lock_manager.cc b/components/arc/compat_mode/arc_resize_lock_manager.cc index b9d1bc61..cbf050d 100644 --- a/components/arc/compat_mode/arc_resize_lock_manager.cc +++ b/components/arc/compat_mode/arc_resize_lock_manager.cc
@@ -223,16 +223,20 @@ if (key != ash::kArcResizeLockTypeKey) return; + // We need to always trigger UpdateCompatModeButton regardless of value + // change because it need to be called even when the property is set to + // ArcResizeLockType::RESIZABLE, which is the the default value of + // kArcResizeLockTypeKey, and the new value is the same as |old| in that case. + AppIdObserver::RunOnReady( + window, base::BindOnce(&ArcResizeLockManager::UpdateCompatModeButton, + weak_ptr_factory_.GetWeakPtr())); + const auto new_value = window->GetProperty(ash::kArcResizeLockTypeKey); const auto old_value = static_cast<ash::ArcResizeLockType>(old); if (new_value == old_value) return; - AppIdObserver::RunOnReady( - window, base::BindOnce(&ArcResizeLockManager::UpdateCompatModeButton, - weak_ptr_factory_.GetWeakPtr())); - if (ShouldEnableResizeLock(new_value)) { // Both the resize lock value and app id are needed to enable resize lock. AppIdObserver::RunOnReady( @@ -399,9 +403,9 @@ case ash::ArcResizeLockType::RESIZE_LIMITED: case ash::ArcResizeLockType::RESIZABLE: compat_mode_button->SetEnabled(true); - frame_view->SetToggleResizeLockMenuCallback(base::BindRepeating( - &ArcResizeLockManager::ToggleResizeToggleMenu, - base::Unretained(this), frame_view->frame())); + frame_view->SetToggleResizeLockMenuCallback( + base::BindRepeating(&ArcResizeLockManager::ToggleResizeToggleMenu, + base::Unretained(this), frame_view->frame())); break; case ash::ArcResizeLockType::FULLY_LOCKED: compat_mode_button->SetEnabled(false); @@ -410,8 +414,7 @@ } } -void ArcResizeLockManager::ToggleResizeToggleMenu( - views::Widget* widget) { +void ArcResizeLockManager::ToggleResizeToggleMenu(views::Widget* widget) { aura::Window* window = widget->GetNativeWindow(); if (!window || !ash::IsArcWindow(window)) return;
diff --git a/components/arc/compat_mode/arc_resize_lock_manager.h b/components/arc/compat_mode/arc_resize_lock_manager.h index 84a7f38d..4cd43da 100644 --- a/components/arc/compat_mode/arc_resize_lock_manager.h +++ b/components/arc/compat_mode/arc_resize_lock_manager.h
@@ -69,7 +69,8 @@ void EnableResizeLock(aura::Window* window); void DisableResizeLock(aura::Window* window); - void UpdateCompatModeButton(aura::Window* window); + // virtual for testing. + virtual void UpdateCompatModeButton(aura::Window* window); ArcResizeLockPrefDelegate* pref_delegate_{nullptr};
diff --git a/components/arc/compat_mode/arc_resize_lock_manager_unittest.cc b/components/arc/compat_mode/arc_resize_lock_manager_unittest.cc index 8811c2c..4f2313b2 100644 --- a/components/arc/compat_mode/arc_resize_lock_manager_unittest.cc +++ b/components/arc/compat_mode/arc_resize_lock_manager_unittest.cc
@@ -51,6 +51,23 @@ base::ScopedObservation<aura::Window, aura::WindowObserver> observer_{this}; }; +class TestArcResizeLockManager : public ArcResizeLockManager { + public: + TestArcResizeLockManager() : ArcResizeLockManager(nullptr, nullptr) {} + + bool IsUpdateCompatModeButtonCalled(const aura::Window* window) const { + return update_compat_mode_button_called.contains(window); + } + + // ArcResizeLockManager: + void UpdateCompatModeButton(aura::Window* window) override { + update_compat_mode_button_called.insert(window); + } + + private: + base::flat_set<const aura::Window*> update_compat_mode_button_called; +}; + DEFINE_UI_CLASS_PROPERTY_KEY(bool, kNonInterestedPropKey, false) } // namespace @@ -80,8 +97,12 @@ window); } + bool IsUpdateCompatModeButtonCalled(const aura::Window* window) const { + return arc_resize_lock_manager_.IsUpdateCompatModeButtonCalled(window); + } + private: - ArcResizeLockManager arc_resize_lock_manager_{nullptr, nullptr}; + TestArcResizeLockManager arc_resize_lock_manager_; }; TEST_F(ArcResizeLockManagerTest, ConstructDestruct) {} @@ -333,4 +354,21 @@ } } +// Test that UpdateCompatModeButton is called properly according to the property +// changes. +TEST_F(ArcResizeLockManagerTest, UpdateCompatModeButton) { + auto arc_window = CreateFakeWindow(true); + + // Test for RESIZABLE. + EXPECT_FALSE(IsUpdateCompatModeButtonCalled(arc_window.get())); + arc_window->SetProperty(ash::kArcResizeLockTypeKey, + ash::ArcResizeLockType::RESIZABLE); + EXPECT_FALSE(IsUpdateCompatModeButtonCalled(arc_window.get())); + + arc_window->SetProperty(ash::kAppIDKey, std::string("app-id")); + EXPECT_TRUE(IsUpdateCompatModeButtonCalled(arc_window.get())); + + // TODO(b/191956214): Add more test cases. +} + } // namespace arc
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc index 8d7e3bd8..52a2dbf 100644 --- a/components/autofill/content/browser/content_autofill_driver.cc +++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -731,7 +731,10 @@ void ContentAutofillDriver::ShowOfferNotificationIfApplicable( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame()) + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame()) return; // TODO(crbug.com/1093057): Android webview does not have
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc index 7f4d6ce3..b7ab1ae 100644 --- a/components/autofill/content/browser/content_autofill_driver_factory.cc +++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -171,11 +171,14 @@ void ContentAutofillDriverFactory::DidStartNavigation( content::NavigationHandle* navigation_handle) { // TODO(crbug/1117451): Clean up experiment code. + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. if (base::FeatureList::IsEnabled( features::kAutofillProbableFormSubmissionInBrowser) && navigation_handle->IsRendererInitiated() && !navigation_handle->WasInitiatedByLinkClick() && - navigation_handle->IsInMainFrame()) { + navigation_handle->IsInPrimaryMainFrame()) { content::GlobalRenderFrameHostId id = navigation_handle->GetPreviousRenderFrameHostId(); content::RenderFrameHost* render_frame_host =
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc index 9d06d06..22ef633 100644 --- a/components/autofill/core/browser/autofill_download_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -1851,7 +1851,6 @@ TEST_P(AutofillUploadTest, RichMetadata) { base::test::ScopedFeatureList local_feature; - local_feature.InitAndEnableFeature(features::kAutofillMetadataUploads); FormData form; form.url = GURL("https://origin.com");
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc index d864a080..a44e8ba 100644 --- a/components/autofill/core/browser/form_structure_unittest.cc +++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -107,15 +107,6 @@ return FormStructure(form).ShouldBeQueried(); } - void SetUpForEncoder() { - scoped_feature_list_.Reset(); - scoped_feature_list_.InitWithFeatures( - // Enabled. - {features::kAutofillMetadataUploads}, - // Disabled. - {}); - } - FieldRendererId MakeFieldRendererId() { return FieldRendererId(++id_counter_); } @@ -4619,7 +4610,6 @@ } TEST_F(FormStructureTestImpl, EncodeUploadRequest_RichMetadata) { - SetUpForEncoder(); struct FieldMetadata { const char *id, *name, *label, *placeholder, *aria_label, *aria_description, *css_classes; @@ -4784,7 +4774,6 @@ TEST_F(FormStructureTestImpl, Metadata_OnlySendFullUrlWithUserConsent) { for (bool has_consent : {true, false}) { SCOPED_TRACE(testing::Message() << " has_consent=" << has_consent); - SetUpForEncoder(); FormData form; form.id_attribute = u"form-id"; form.url = GURL("http://www.foo.com/");
diff --git a/components/autofill/core/browser/randomized_encoder.cc b/components/autofill/core/browser/randomized_encoder.cc index 5211562..2556b26c 100644 --- a/components/autofill/core/browser/randomized_encoder.cc +++ b/components/autofill/core/browser/randomized_encoder.cc
@@ -128,58 +128,21 @@ // Returns the "random" encoding type to use for encoding. AutofillRandomizedValue_EncodingType GetEncodingType(const std::string& seed) { DCHECK(!seed.empty()); - // How many bits should be encoded per byte? This value will determine which - // of the encodings are eligible for consideration. - const int kDefaultBitsPerByte = 4; - const int bits_per_byte = - base::FeatureParam<int>(&features::kAutofillMetadataUploads, - switches::kAutofillMetadataUploadEncoding, - kDefaultBitsPerByte) - .Get(); - // Depending on the number of bytes to encode per byte, "randomly" select one - // of eligible encodings. This "random" selection is persistent in that it is - // based directly on the persistent seed. + // "Randomly" select one of eligible encodings. This "random" selection is + // persistent in that it is based directly on the persistent seed. const uint8_t rand_byte = static_cast<uint8_t>(seed.front()); - int encoding_type_as_int = static_cast<int>( - AutofillRandomizedValue_EncodingType_UNSPECIFIED_ENCODING_TYPE); - bool config_is_valid = true; - switch (bits_per_byte) { - case 1: - // Sending one bit per byte means sending any encoding from BIT_0 through - // BIT_7, which are in numeric order. - encoding_type_as_int = - static_cast<int>(AutofillRandomizedValue_EncodingType_BIT_0) + - (rand_byte % 8); - break; - default: - NOTREACHED(); - config_is_valid = false; - FALLTHROUGH; - case 4: - // Sending four bits per byte means sending either the EVEN_BITS or - // ODD_BITS encoding, which are in numeric order. - encoding_type_as_int = - static_cast<int>(AutofillRandomizedValue_EncodingType_EVEN_BITS) + - (rand_byte % 2); - break; - case 8: - encoding_type_as_int = - static_cast<int>(AutofillRandomizedValue_EncodingType_ALL_BITS); - break; - } + // Send either the EVEN_BITS or ODD_BITS. + const AutofillRandomizedValue_EncodingType encoding_type = + rand_byte % 2 ? AutofillRandomizedValue_EncodingType_ODD_BITS + : AutofillRandomizedValue_EncodingType_EVEN_BITS; - UMA_HISTOGRAM_BOOLEAN("Autofill.Upload.MetadataConfigIsValid", - config_is_valid); + UMA_HISTOGRAM_BOOLEAN("Autofill.Upload.MetadataConfigIsValid", true); base::SparseHistogram::FactoryGet( "Autofill.Upload.MetadataEncodingType", base::HistogramBase::kUmaTargetedHistogramFlag) - ->Add(encoding_type_as_int); + ->Add(static_cast<int>(encoding_type)); - // Cast back to a valid encoding type value. - DCHECK(AutofillRandomizedValue_EncodingType_IsValid(encoding_type_as_int)); - const auto encoding_type = - static_cast<AutofillRandomizedValue_EncodingType>(encoding_type_as_int); DCHECK_NE(encoding_type, AutofillRandomizedValue_EncodingType_UNSPECIFIED_ENCODING_TYPE); return encoding_type; @@ -229,8 +192,7 @@ std::unique_ptr<RandomizedEncoder> RandomizedEncoder::Create( PrefService* pref_service) { // Early abort if metadata uploads are not enabled. - if (!pref_service || - !base::FeatureList::IsEnabled(features::kAutofillMetadataUploads)) { + if (!pref_service) { return nullptr; }
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc index 0040feb..26042dd 100644 --- a/components/autofill/core/browser/webdata/autofill_table.cc +++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -168,21 +168,17 @@ int column_index, const AutofillTableEncryptor& encryptor) { std::u16string credit_card_number; - int encrypted_number_len = s.ColumnByteLength(column_index); - if (encrypted_number_len) { - std::string encrypted_number; - encrypted_number.resize(encrypted_number_len); - memcpy(&encrypted_number[0], s.ColumnBlob(column_index), - encrypted_number_len); + std::string encrypted_number; + s.ColumnBlobAsString(column_index, &encrypted_number); + if (!encrypted_number.empty()) encryptor.DecryptString16(encrypted_number, &credit_card_number); - } return credit_card_number; } std::unique_ptr<CreditCard> CreditCardFromStatement( sql::Statement& s, const AutofillTableEncryptor& encryptor) { - std::unique_ptr<CreditCard> credit_card(new CreditCard); + auto credit_card = std::make_unique<CreditCard>(); int index = 0; credit_card->set_guid(s.ColumnString(index++));
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index b92deed..14deb69 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -271,9 +271,6 @@ const base::Feature kAutofillPruneSuggestions{ "AutofillPruneSuggestions", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kAutofillMetadataUploads{"AutofillMetadataUploads", - base::FEATURE_ENABLED_BY_DEFAULT}; - // When enabled, Autofill will load remote patterns via the component updater. // TODO(crbug/1121990): Remove once launched. extern const base::Feature kAutofillParsingPatternsFromRemote{
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index 8f28c8e..8550825 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -106,7 +106,6 @@ COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillLabelAffixRemoval; COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillPruneSuggestions; -COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillMetadataUploads; COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillParsingPatternsFromRemote; COMPONENT_EXPORT(AUTOFILL)
diff --git a/components/autofill/core/common/autofill_switches.cc b/components/autofill/core/common/autofill_switches.cc index b7ee298c..f6f5382 100644 --- a/components/autofill/core/common/autofill_switches.cc +++ b/components/autofill/core/common/autofill_switches.cc
@@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "build/build_config.h" #include "components/autofill/core/common/autofill_switches.h" +#include "build/build_config.h" + namespace autofill { namespace switches { @@ -16,12 +17,6 @@ // Override the default autofill server URL with "scheme://host[:port]/prefix/". const char kAutofillServerURL[] = "autofill-server-url"; -// The randomized encoding type to use when sending metadata uploads. The -// value of the parameter must be one of the valid integer values of the -// AutofillRandomizedValue_EncodingType enum. -const char kAutofillMetadataUploadEncoding[] = - "autofill-metadata-upload-encoding"; - // The number of days after which to reset the registry of autofill events for // which an upload has been sent. const char kAutofillUploadThrottlingPeriodInDays[] = @@ -32,7 +27,7 @@ "ignore-autocomplete-off-autofill"; // Annotates forms with Autofill field type predictions. -const char kShowAutofillTypePredictions[] = "show-autofill-type-predictions"; +const char kShowAutofillTypePredictions[] = "show-autofill-type-predictions"; // Annotates forms and fields with Autofill signatures. const char kShowAutofillSignatures[] = "show-autofill-signatures";
diff --git a/components/autofill/core/common/autofill_switches.h b/components/autofill/core/common/autofill_switches.h index b50faa3..8f32b3c 100644 --- a/components/autofill/core/common/autofill_switches.h +++ b/components/autofill/core/common/autofill_switches.h
@@ -14,7 +14,6 @@ // alongside the definition of their values in the .cc file. extern const char kAutofillAPIKey[]; extern const char kAutofillServerURL[]; -extern const char kAutofillMetadataUploadEncoding[]; extern const char kAutofillUploadThrottlingPeriodInDays[]; extern const char kIgnoreAutocompleteOffForAutofill[]; extern const char kShowAutofillTypePredictions[];
diff --git a/components/autofill_assistant/browser/client_status.cc b/components/autofill_assistant/browser/client_status.cc index 4ff1de094..d0d8fd2 100644 --- a/components/autofill_assistant/browser/client_status.cc +++ b/components/autofill_assistant/browser/client_status.cc
@@ -148,6 +148,9 @@ case ProcessedActionStatusProto::INVALID_TARGET: out << "INVALID_TARGET"; break; + case ProcessedActionStatusProto::ELEMENT_POSITION_NOT_FOUND: + out << "ELEMENT_POSITION_NOT_FOUND"; + break; // Intentionally no default case to make compilation fail if a new value // was added to the enum but not to this list.
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc index bd59de9..360e9d7 100644 --- a/components/autofill_assistant/browser/controller.cc +++ b/components/autofill_assistant/browser/controller.cc
@@ -1884,7 +1884,10 @@ void Controller::DidStartNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || navigation_handle->IsSameDocument()) { return; } @@ -1960,7 +1963,10 @@ content::NavigationHandle* navigation_handle) { // TODO(b/159871774): Rethink how we handle navigation events. The early // return here may prevent us from updating |navigating_to_new_document_|. - if (!navigation_handle->IsInMainFrame() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || navigation_handle->IsSameDocument() || !navigation_handle->HasCommitted() || !IsNavigatingToNewDocument()) { return;
diff --git a/components/autofill_assistant/browser/model.proto b/components/autofill_assistant/browser/model.proto index 1533088..62a980b 100644 --- a/components/autofill_assistant/browser/model.proto +++ b/components/autofill_assistant/browser/model.proto
@@ -87,7 +87,7 @@ // a boolean field would have. message Empty {} -// Next: 29 +// Next: 34 enum ProcessedActionStatusProto { UNKNOWN_ACTION_STATUS = 0; @@ -221,7 +221,11 @@ // called on any element other than <select>. INVALID_TARGET = 31; - reserved 15, 23, 25; + // The element has no or only an empty box model. This can mean the element + // is not rendered (display: none) or simply empty. + ELEMENT_POSITION_NOT_FOUND = 33; + + reserved 15, 23, 25, 32; } // A message to describe a chip.
diff --git a/components/autofill_assistant/browser/starter.cc b/components/autofill_assistant/browser/starter.cc index 77a575c0..3218bbfc 100644 --- a/components/autofill_assistant/browser/starter.cc +++ b/components/autofill_assistant/browser/starter.cc
@@ -190,7 +190,10 @@ void Starter::DidFinishNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame()) { + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame()) { return; }
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc index 74098d7..236ed6e5 100644 --- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc +++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
@@ -337,7 +337,11 @@ // - not in the main frame. // - document does not change (e.g., same page history navigation). // - WebContents stays at the existing URL (e.g., downloads). - if (!is_checking_trigger_conditions_ || !navigation_handle->IsInMainFrame() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!is_checking_trigger_conditions_ || + !navigation_handle->IsInPrimaryMainFrame() || navigation_handle->IsSameDocument() || !navigation_handle->HasCommitted()) { return;
diff --git a/components/autofill_assistant/browser/web/element_position_getter.cc b/components/autofill_assistant/browser/web/element_position_getter.cc index 444f2707..5ea6f3c7 100644 --- a/components/autofill_assistant/browser/web/element_position_getter.cc +++ b/components/autofill_assistant/browser/web/element_position_getter.cc
@@ -15,9 +15,9 @@ namespace { const char* const kScrollIntoViewIfNeededScript = - R"(function(node) { - node.scrollIntoViewIfNeeded(); - })"; + R"(function() { + this.scrollIntoViewIfNeeded(); + })"; } // namespace @@ -75,9 +75,11 @@ void ElementPositionGetter::OnGetBoxModelForStableCheck( const DevtoolsClient::ReplyStatus& reply_status, std::unique_ptr<dom::GetBoxModelResult> result) { - if (!result || !result->GetModel() || !result->GetModel()->GetContent()) { - VLOG(1) << __func__ << " Failed to get box model."; - OnError(JavaScriptErrorStatus(reply_status, __FILE__, __LINE__, nullptr)); + if (!result || !result->GetModel() || !result->GetModel()->GetContent() || + result->GetModel()->GetWidth() == 0 || + result->GetModel()->GetHeight() == 0) { + VLOG(2) << __func__ << " No box model."; + RunNextRound(); return; } @@ -89,7 +91,9 @@ DCHECK(max_rounds_ >= remaining_rounds_); - if (has_point_) { + if (has_point_ || max_rounds_ <= 1) { + // Less than 3 rounds returns immediately, we don't expect stability + // information to be useful with too few rounds. if (max_rounds_ <= 2) { OnResult(new_point_x, new_point_y); return; @@ -111,11 +115,6 @@ } } - if (remaining_rounds_ <= 0) { - OnError(ClientStatus(ELEMENT_UNSTABLE)); - return; - } - bool is_first_round = !has_point_; has_point_ = true; point_x_ = new_point_x; @@ -124,12 +123,9 @@ // Scroll the element into view again if it was moved out of view, starting // from the second round. if (!is_first_round) { - std::vector<std::unique_ptr<runtime::CallArgument>> argument; - AddRuntimeCallArgumentObjectId(object_id_, &argument); devtools_client_->GetRuntime()->CallFunctionOn( runtime::CallFunctionOnParams::Builder() .SetObjectId(object_id_) - .SetArguments(std::move(argument)) .SetFunctionDeclaration(std::string(kScrollIntoViewIfNeededScript)) .SetReturnByValue(true) .Build(), @@ -139,12 +135,7 @@ return; } - --remaining_rounds_; - content::GetUIThreadTaskRunner({})->PostDelayedTask( - FROM_HERE, - base::BindOnce(&ElementPositionGetter::GetAndWaitBoxModelStable, - weak_ptr_factory_.GetWeakPtr()), - check_interval_); + RunNextRound(); } void ElementPositionGetter::OnScrollIntoView( @@ -158,6 +149,16 @@ return; } + RunNextRound(); +} + +void ElementPositionGetter::RunNextRound() { + if (remaining_rounds_ <= 0) { + OnError(ClientStatus(has_point_ ? ELEMENT_UNSTABLE + : ELEMENT_POSITION_NOT_FOUND)); + return; + } + --remaining_rounds_; content::GetUIThreadTaskRunner({})->PostDelayedTask( FROM_HERE,
diff --git a/components/autofill_assistant/browser/web/element_position_getter.h b/components/autofill_assistant/browser/web/element_position_getter.h index 1cd99d8..eff99dc 100644 --- a/components/autofill_assistant/browser/web/element_position_getter.h +++ b/components/autofill_assistant/browser/web/element_position_getter.h
@@ -61,6 +61,7 @@ std::unique_ptr<dom::GetBoxModelResult> result); void OnScrollIntoView(const DevtoolsClient::ReplyStatus& reply_status, std::unique_ptr<runtime::CallFunctionOnResult> result); + void RunNextRound(); void OnResult(int x, int y); void OnError(const ClientStatus& status);
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc index 92a7c8a..fa140d2 100644 --- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc +++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -2509,10 +2509,10 @@ } IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, WaitForElementToBecomeStable) { - ClientStatus status; + ClientStatus element_status; ElementFinder::Result element; - FindElement(Selector({"#touch_area_one"}), &status, &element); - ASSERT_TRUE(status.ok()); + FindElement(Selector({"#touch_area_one"}), &element_status, &element); + ASSERT_TRUE(element_status.ok()); // Move the element indefinitely. EXPECT_TRUE(ExecJs(shell(), R"( @@ -2524,27 +2524,52 @@ `${10 * i++}px`; }, 100); })())")); - status = WaitUntilElementIsStable(element, 10, - base::TimeDelta::FromMilliseconds(100)); - EXPECT_EQ(ELEMENT_UNSTABLE, status.proto_status()); + EXPECT_EQ(ELEMENT_UNSTABLE, + WaitUntilElementIsStable(element, 10, + base::TimeDelta::FromMilliseconds(100)) + .proto_status()); // Stop moving the element. EXPECT_TRUE(ExecJs(shell(), "clearInterval(document.browserTestInterval);")); - status = WaitUntilElementIsStable(element, 10, - base::TimeDelta::FromMilliseconds(100)); - EXPECT_TRUE(status.ok()); + EXPECT_TRUE(WaitUntilElementIsStable(element, 10, + base::TimeDelta::FromMilliseconds(100)) + .ok()); +} + +IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, + WaitForElementToBecomeStableForEmptyBoxModel) { + ClientStatus element_status; + + // The element has an empty box model. + ElementFinder::Result empty_element; + FindElement(Selector({"#emptydiv"}), &element_status, &empty_element); + ASSERT_TRUE(element_status.ok()); + EXPECT_EQ(ELEMENT_POSITION_NOT_FOUND, + WaitUntilElementIsStable(empty_element, 10, + base::TimeDelta::FromMilliseconds(10)) + .proto_status()); + + // The element is always hidden and has no box model. + ElementFinder::Result hidden_element; + FindElement(Selector({"#hidden"}), &element_status, &hidden_element); + ASSERT_TRUE(element_status.ok()); + EXPECT_EQ(ELEMENT_POSITION_NOT_FOUND, + WaitUntilElementIsStable(hidden_element, 10, + base::TimeDelta::FromMilliseconds(10)) + .proto_status()); } IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, WaitForElementToBecomeStableDevtoolsFailure) { - // This makes devtools action fail. + // This makes the devtools action fail. ElementFinder::Result element; element.dom_object.object_data.node_frame_id = "doesnotexist"; element.container_frame_host = web_contents()->GetMainFrame(); - ClientStatus status = WaitUntilElementIsStable( - element, 10, base::TimeDelta::FromMilliseconds(100)); - EXPECT_EQ(UNEXPECTED_JS_ERROR, status.proto_status()); + EXPECT_EQ(ELEMENT_POSITION_NOT_FOUND, + WaitUntilElementIsStable(element, 10, + base::TimeDelta::FromMilliseconds(100)) + .proto_status()); } IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ElementQueryIndex) {
diff --git a/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc b/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc index 85c5f6f..6e7403e2e 100644 --- a/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc +++ b/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc
@@ -272,7 +272,10 @@ // navigation is user-initiated. Note that |HasUserGesture| does not capture // browser-initiated navigations. The negation of |IsRendererInitiated| tells // us whether the navigation is browser-generated. - if (navigation_handle->IsInMainFrame() && + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (navigation_handle->IsInPrimaryMainFrame() && (navigation_handle->HasUserGesture() || !navigation_handle->IsRendererInitiated())) { // Flush any remaining dialogs before resetting the counter.
diff --git a/components/components_google_chrome_strings.grd b/components/components_google_chrome_strings.grd index 08f603b..652475a 100644 --- a/components/components_google_chrome_strings.grd +++ b/components/components_google_chrome_strings.grd
@@ -256,7 +256,7 @@ <!-- About Flags UI --> <if expr="not chromeos"> <message name="IDS_FLAGS_UI_RELAUNCH_NOTICE" translateable="false" desc="Notifies the user that they need to relaunch Chrome. Shown next to a button that says 'Relaunch Now'."> - Your changes will take effect the next time you relaunch Google Chrome. + Your changes will take effect the next time you relaunch Chrome. </message> </if> <if expr="chromeos"> @@ -268,7 +268,7 @@ <!-- about:flags/deprecated strings --> <if expr="not chromeos"> <message name="IDS_DEPRECATED_FEATURES_RELAUNCH_NOTICE" desc="Notifies the user that they need to relaunch Chrome. Shown next to a button that says 'Relaunch Now'."> - Your changes will take effect the next time you relaunch Google Chrome. + Your changes will take effect the next time you relaunch Chrome. </message> </if> <if expr="chromeos"> @@ -288,12 +288,12 @@ </message> <message name="IDS_VERSION_UI_LICENSE" desc="The label below the copyright message, containing the URLs."> - Google Chrome is made possible by the <ph name="BEGIN_LINK_CHROMIUM"><a target="_blank" href="$1"></ph>Chromium<ph name="END_LINK_CHROMIUM"></a></ph> open source project and other <ph name="BEGIN_LINK_OSS"><a target="_blank" href="$2"></ph>open source software<ph name="END_LINK_OSS"></a></ph>. + Chrome is made possible by the <ph name="BEGIN_LINK_CHROMIUM"><a target="_blank" href="$1"></ph>Chromium<ph name="END_LINK_CHROMIUM"></a></ph> open source project and other <ph name="BEGIN_LINK_OSS"><a target="_blank" href="$2"></ph>open source software<ph name="END_LINK_OSS"></a></ph>. </message> <!-- Page Info --> <message name="IDS_PAGE_INFO_INTERNAL_PAGE" desc="Message to display in the page info bubble when the page you are on is a chrome:// page or about:something."> - You're viewing a secure Google Chrome page + You're viewing a secure Chrome page </message> <!-- Session Crash -->
diff --git a/components/cronet/android/sample/AndroidManifest.xml b/components/cronet/android/sample/AndroidManifest.xml index 64b7e06..2a7ded8 100644 --- a/components/cronet/android/sample/AndroidManifest.xml +++ b/components/cronet/android/sample/AndroidManifest.xml
@@ -18,7 +18,8 @@ android:launchMode="singleTask" android:theme="@style/Theme.AppCompat.Light" android:configChanges="orientation|keyboardHidden|keyboard|screenSize" - android:hardwareAccelerated="true"> + android:hardwareAccelerated="true" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/components/cronet/android/test/javaperftests/AndroidManifest.xml b/components/cronet/android/test/javaperftests/AndroidManifest.xml index 27090dd..35548fc 100644 --- a/components/cronet/android/test/javaperftests/AndroidManifest.xml +++ b/components/cronet/android/test/javaperftests/AndroidManifest.xml
@@ -9,7 +9,8 @@ way and crashes in Android Marshmallow. https://plus.google.com/105051985738280261832/posts/LjnRzJKWPGW --> <activity android:name="CronetPerfTestActivity" - android:theme="@android:style/Theme.Translucent.NoTitleBar"> + android:theme="@android:style/Theme.Translucent.NoTitleBar" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
diff --git a/components/desks_storage/core/desk_model.cc b/components/desks_storage/core/desk_model.cc index 9eb2402b..5fc2257 100644 --- a/components/desks_storage/core/desk_model.cc +++ b/components/desks_storage/core/desk_model.cc
@@ -4,7 +4,6 @@ #include "components/desks_storage/core/desk_model.h" -#include "ash/public/cpp/desk_template.h" #include "components/desks_storage/core/desk_model_observer.h" namespace desks_storage { @@ -13,20 +12,6 @@ DeskModel::~DeskModel() = default; -GetAllEntriesResult::GetAllEntriesResult( - GetAllEntriesStatus status, - std::vector<ash::DeskTemplate*> entries) - : status(status), entries(std::move(entries)) {} - -GetAllEntriesResult::~GetAllEntriesResult() = default; - -GetEntryByUuidResult::GetEntryByUuidResult( - GetEntryByUuidStatus status, - std::unique_ptr<ash::DeskTemplate> entry) - : status(status), entry(std::move(entry)) {} - -GetEntryByUuidResult::~GetEntryByUuidResult() = default; - void DeskModel::AddObserver(DeskModelObserver* observer) { DCHECK(observer); observers_.AddObserver(observer);
diff --git a/components/desks_storage/core/desk_model.h b/components/desks_storage/core/desk_model.h index c463661..f6e60be 100644 --- a/components/desks_storage/core/desk_model.h +++ b/components/desks_storage/core/desk_model.h
@@ -19,71 +19,6 @@ namespace desks_storage { class DeskModelObserver; - -// TODO: As part of a potential refactor these enums may be moved back into -// the DeskModel definition. They are outside now in order to account -// for the result classes which need to know about the statuses. - -// Status codes for listing all desk template entries. kPartialFailure indicates -// that one or more entries failed to load. -enum class GetAllEntriesStatus { - kOk, - kPartialFailure, - kFailure, -}; - -// Status codes for getting desk template by UUID. -enum class GetEntryByUuidStatus { - kOk, - kFailure, - kNotFound, - kInvalidUuid, -}; - -// Status codes for adding or updating a desk template. -enum class AddOrUpdateEntryStatus { - kOk, - kFailure, - kInvalidArgument, -}; - -// Status codes for deleting desk templates. -enum class DeleteEntryStatus { - kOk, - kFailure, -}; - -// TODO: As part of a potential re-factor these result classes may -// be removed. - -// Result structure for GetAllEntries, contains a status and a vector -// of entry pointers. -class GetAllEntriesResult { - public: - GetAllEntriesResult(GetAllEntriesStatus status, - std::vector<ash::DeskTemplate*> entries); - GetAllEntriesResult(const GetAllEntriesResult&) = delete; - GetAllEntriesResult& operator=(const GetAllEntriesResult&) = delete; - ~GetAllEntriesResult(); - - GetAllEntriesStatus status; - std::vector<ash::DeskTemplate*> entries; -}; - -// Result structure for GetEntryByUuid, contains a status and a unique -// pointer to an entry. -class GetEntryByUuidResult { - public: - GetEntryByUuidResult(GetEntryByUuidStatus status, - std::unique_ptr<ash::DeskTemplate> entry); - GetEntryByUuidResult(const GetEntryByUuidResult&) = delete; - GetEntryByUuidResult& operator=(const GetEntryByUuidResult&) = delete; - ~GetEntryByUuidResult(); - - GetEntryByUuidStatus status; - std::unique_ptr<ash::DeskTemplate> entry; -}; - // The DeskModel is an interface for accessing desk templates. // Actual desk template storage backend (e.g. local file system backend and Sync // backend) classes should implement this interface. Desk template accessor @@ -91,18 +26,47 @@ // to use asynchronous I/O. class DeskModel { public: + // Status codes for listing all desk template UUIDs. + enum class GetAllUuidsStatus { + kOk, + kFailure, + }; + + // Status codes for getting desk template by UUID. + enum class GetEntryByUuidStatus { + kOk, + kFailure, + kNotFound, + kInvalidUuid, + }; + + // Status codes for adding or updating a desk template. + enum class AddOrUpdateEntryStatus { + kOk, + kFailure, + kInvalidArgument, + }; + + // Status codes for deleting desk templates. + enum class DeleteEntryStatus { + kOk, + kFailure, + }; + DeskModel(); DeskModel(const DeskModel&) = delete; DeskModel& operator=(const DeskModel&) = delete; virtual ~DeskModel(); - using GetAllEntriesCallback = base::OnceCallback<void( - const std::unique_ptr<GetAllEntriesResult> result)>; - // Returns a vector of entries in the model. - virtual void GetAllEntries(GetAllEntriesCallback callback) = 0; + using GetAllUuidsCallback = + base::OnceCallback<void(GetAllUuidsStatus status, + const std::vector<std::string>&)>; + // Returns a vector of entry IDs in the model. + virtual void GetAllUuids(GetAllUuidsCallback callback) = 0; - using GetEntryByUuidCallback = base::OnceCallback<void( - const std::unique_ptr<GetEntryByUuidResult> result)>; + using GetEntryByUuidCallback = + base::OnceCallback<void(GetEntryByUuidStatus status, + std::unique_ptr<ash::DeskTemplate>)>; // Get a specific desk template by |uuid|. Actual storage backend does not // need to keep desk templates in memory. The storage backend could load the // specified desk template into memory and then call the |callback| with a
diff --git a/components/desks_storage/core/desk_sync_bridge.cc b/components/desks_storage/core/desk_sync_bridge.cc index 87b6eef..68ae772 100644 --- a/components/desks_storage/core/desk_sync_bridge.cc +++ b/components/desks_storage/core/desk_sync_bridge.cc
@@ -255,45 +255,38 @@ return entity_data.specifics.workspace_desk().uuid(); } -void DeskSyncBridge::GetAllEntries(GetAllEntriesCallback callback) { +void DeskSyncBridge::GetAllUuids(GetAllUuidsCallback callback) { if (!IsReady()) { - std::move(callback).Run(std::make_unique<GetAllEntriesResult>( - GetAllEntriesStatus::kFailure, std::vector<DeskTemplate*>())); + std::move(callback).Run(GetAllUuidsStatus::kFailure, {}); return; } - std::vector<DeskTemplate*> entries; - for (const auto& it : entries_) { - DCHECK_EQ(it.first, it.second->uuid()); - entries.push_back(it.second.get()); - } - - std::move(callback).Run(std::make_unique<GetAllEntriesResult>( - GetAllEntriesStatus::kOk, std::move(entries))); + std::move(callback).Run(GetAllUuidsStatus::kOk, GetAllUuids()); } void DeskSyncBridge::GetEntryByUUID(const std::string& uuid_str, GetEntryByUuidCallback callback) { if (!IsReady()) { - std::move(callback).Run(std::make_unique<GetEntryByUuidResult>( - GetEntryByUuidStatus::kFailure, std::unique_ptr<DeskTemplate>())); + std::move(callback).Run(GetEntryByUuidStatus::kFailure, + std::unique_ptr<DeskTemplate>()); return; } const base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str); if (uuid.is_valid()) { - std::move(callback).Run(std::make_unique<GetEntryByUuidResult>( - GetEntryByUuidStatus::kInvalidUuid, std::unique_ptr<DeskTemplate>())); + std::move(callback).Run(GetEntryByUuidStatus::kInvalidUuid, + std::unique_ptr<DeskTemplate>()); return; } auto it = entries_.find(uuid); if (it == entries_.end()) { - std::move(callback).Run(std::make_unique<GetEntryByUuidResult>( - GetEntryByUuidStatus::kNotFound, std::unique_ptr<DeskTemplate>())); + std::move(callback).Run(GetEntryByUuidStatus::kNotFound, + std::unique_ptr<DeskTemplate>()); } else { - std::move(callback).Run(std::make_unique<GetEntryByUuidResult>( - GetEntryByUuidStatus::kOk, it->second.get()->Clone())); + std::move(callback).Run(GetEntryByUuidStatus::kOk, + DeskSyncBridge::FromProto( + DeskSyncBridge::AsSyncProto(it->second.get()))); } }
diff --git a/components/desks_storage/core/desk_sync_bridge.h b/components/desks_storage/core/desk_sync_bridge.h index 36b8823..f834c43 100644 --- a/components/desks_storage/core/desk_sync_bridge.h +++ b/components/desks_storage/core/desk_sync_bridge.h
@@ -63,7 +63,7 @@ std::string GetStorageKey(const syncer::EntityData& entity_data) override; // DeskModel overrides. - void GetAllEntries(GetAllEntriesCallback callback) override; + void GetAllUuids(GetAllUuidsCallback callback) override; void GetEntryByUUID(const std::string& uuid, GetEntryByUuidCallback callback) override; void AddOrUpdateEntry(std::unique_ptr<ash::DeskTemplate> new_entry,
diff --git a/components/desks_storage/core/desk_sync_bridge_unittest.cc b/components/desks_storage/core/desk_sync_bridge_unittest.cc index fc8b03a..c4b9c77 100644 --- a/components/desks_storage/core/desk_sync_bridge_unittest.cc +++ b/components/desks_storage/core/desk_sync_bridge_unittest.cc
@@ -95,16 +95,18 @@ DeskSyncBridgeTest& operator=(const DeskSyncBridgeTest&) = delete; protected: - static void VerifyAddOrUpdateEntrySuccess(AddOrUpdateEntryStatus status) { - EXPECT_EQ(status, AddOrUpdateEntryStatus::kOk); + static void VerifyAddOrUpdateEntrySuccess( + DeskModel::AddOrUpdateEntryStatus status) { + EXPECT_EQ(status, DeskSyncBridge::AddOrUpdateEntryStatus::kOk); } - static void VerifyAddOrUpdateEntryFailure(AddOrUpdateEntryStatus status) { - EXPECT_EQ(status, AddOrUpdateEntryStatus::kFailure); + static void VerifyAddOrUpdateEntryFailure( + DeskModel::AddOrUpdateEntryStatus status) { + EXPECT_EQ(status, DeskSyncBridge::AddOrUpdateEntryStatus::kFailure); } - static void VerifyDeleteEntrySuccess(DeleteEntryStatus status) { - EXPECT_EQ(status, DeleteEntryStatus::kOk); + static void VerifyDeleteEntrySuccess(DeskModel::DeleteEntryStatus status) { + EXPECT_EQ(status, DeskSyncBridge::DeleteEntryStatus::kOk); } DeskSyncBridgeTest()
diff --git a/components/desks_storage/core/local_desk_data_manager.cc b/components/desks_storage/core/local_desk_data_manager.cc index f4c1173..ce95c7b9 100644 --- a/components/desks_storage/core/local_desk_data_manager.cc +++ b/components/desks_storage/core/local_desk_data_manager.cc
@@ -86,37 +86,6 @@ return converted_value; } -// ReadFileToTemplate is a function that attempts to read a template file into -// a std::unique_ptr<ash::DeskTemplate> given a |fully_qualified_path|. If -// the read is a failure the function returns a nullptr. -std::unique_ptr<ash::DeskTemplate> ReadFileToTemplate( - const base::FilePath& fully_qualified_path) { - base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, - base::BlockingType::MAY_BLOCK); - if (!base::PathExists(fully_qualified_path)) - return nullptr; - - std::string value_string; - bool read_success = - base::ReadFileToString(fully_qualified_path, &value_string); - if (!read_success) - return nullptr; - - std::string error_message; - int error_code; - JSONStringValueDeserializer deserializer(value_string); - auto desk_template_value = - deserializer.Deserialize(&error_code, &error_message); - - if (!desk_template_value) { - DVLOG(0) << "Fail to deserialize json value from string with error code: " - << error_code << " and error message: " << error_message; - return nullptr; - } - - return ConvertDeskTemplateValueToDeskTemplate(*desk_template_value); -} - // WriteTemplateToFile is a method that takes a base::FilePath // |path_to_template| and a DeskTemplate unique pointer |entry| // and writes the entry out in its serialized form to the path @@ -141,7 +110,21 @@ return true; } -// returns the fully qualified path to a template file given the file path to +// AppendTemplateUUID appends a std::string |entry| to a std::vector of uuids. +// in order to be appended |entry| must contain .template within the string. +// This method populates the std::vector as a side effect and has a void return +// type hence |out_uuids|. +void AppendTemplateUUID(const std::string& entry, + std::vector<std::string>* out_uuids) { + const size_t extension_at = entry.find(kFileExtension); + + if (extension_at == std::string::npos) + return; + + out_uuids->push_back(entry.substr(0, extension_at)); +} + +// Returns the fully qualified path to a template file given the file path to // the desk template directory. base::FilePath GetFullyQualifiedPath(base::FilePath file_path, const std::string& uuid) { @@ -151,102 +134,125 @@ file_path.Append(base::FilePath::StringPieceType(filename.c_str()))); } +struct GetAllUuidsResult { + DeskModel::GetAllUuidsStatus status; + std::vector<std::string> uuids; +}; + // This method gets all UUIDs available in the template directory. This // is a task that is posted to the local storage object's task runner. -std::unique_ptr<GetAllEntriesResult> GetAllEntriesTask( - std::vector<std::unique_ptr<ash::DeskTemplate>>* out_desk_template_entries, - const base::FilePath local_template_path) { - DCHECK(out_desk_template_entries != nullptr); - out_desk_template_entries->clear(); +GetAllUuidsResult GetAllUuidsTask(const base::FilePath local_template_path) { base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); base::DirReaderPosix dir_reader(local_template_path.AsUTF8Unsafe().c_str()); if (!dir_reader.IsValid()) { - return std::make_unique<GetAllEntriesResult>( - GetAllEntriesStatus::kFailure, std::vector<ash::DeskTemplate*>()); + return {DeskModel::GetAllUuidsStatus::kFailure, {}}; } - std::vector<ash::DeskTemplate*> entry_pointers; - GetAllEntriesStatus status = GetAllEntriesStatus::kOk; - + std::vector<std::string> uuids; while (dir_reader.Next()) { if (dir_reader.name() == nullptr) continue; - std::unique_ptr<ash::DeskTemplate> recovered_entry = - ReadFileToTemplate(local_template_path.Append(dir_reader.name())); - if (recovered_entry) { - entry_pointers.push_back(recovered_entry.get()); - out_desk_template_entries->push_back(std::move(recovered_entry)); - } else - status = GetAllEntriesStatus::kPartialFailure; + AppendTemplateUUID(std::string(dir_reader.name()), &uuids); } - if (entry_pointers.size() == 0) - return std::make_unique<GetAllEntriesResult>(GetAllEntriesStatus::kFailure, - std::move(entry_pointers)); + return {DeskModel::GetAllUuidsStatus::kOk, std::move(uuids)}; +} - return std::make_unique<GetAllEntriesResult>(status, - std::move(entry_pointers)); +// Handles GetAllUuidsTask and calls the callback with the result. +void HandleGetAllUuidsTask(DeskModel::GetAllUuidsCallback callback, + GetAllUuidsResult result) { + std::move(callback).Run(result.status, std::move(result.uuids)); } // Adds or updates an entry. This is a task that is posted to base::ThreadPool // in order to complete io operations. -AddOrUpdateEntryStatus AddOrUpdateEntryTask( +DeskModel::AddOrUpdateEntryStatus AddOrUpdateEntryTask( const base::FilePath local_template_path, std::unique_ptr<ash::DeskTemplate> new_entry) { const base::FilePath fully_qualified_path = GetFullyQualifiedPath( local_template_path, new_entry->uuid().AsLowercaseString()); if (WriteTemplateFile(fully_qualified_path, std::move(new_entry))) - return AddOrUpdateEntryStatus::kOk; + return DeskModel::AddOrUpdateEntryStatus::kOk; else - return AddOrUpdateEntryStatus::kFailure; + return DeskModel::AddOrUpdateEntryStatus::kFailure; } +struct GetEntryByUuidResult { + DeskModel::GetEntryByUuidStatus status; + std::unique_ptr<ash::DeskTemplate> desk_template; +}; + // This method Handles getting the task of getting an entry by it's Uuid. Unlike // the other statuses this function returns the DeskTemplate pointer instead of // a status. This is because this method has to instantiate the DeskTemplate // itself in order to use the DeskTemplate::FromProto factory method. -std::unique_ptr<GetEntryByUuidResult> GetEntryByUuidTask( +GetEntryByUuidResult GetEntryByUuidTask( const base::FilePath local_template_path, const std::string& uuid) { const base::FilePath fully_qualified_path = GetFullyQualifiedPath(local_template_path, uuid); - std::unique_ptr<ash::DeskTemplate> recovered_entry = - ReadFileToTemplate(fully_qualified_path); + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); + if (!base::PathExists(fully_qualified_path)) + return {DeskModel::GetEntryByUuidStatus::kNotFound, nullptr}; - if (!recovered_entry) - return std::make_unique<GetEntryByUuidResult>( - GetEntryByUuidStatus::kFailure, std::unique_ptr<ash::DeskTemplate>()); + std::string value_string; + bool read_success = + base::ReadFileToString(fully_qualified_path, &value_string); + if (!read_success) + return {DeskModel::GetEntryByUuidStatus::kFailure, nullptr}; - return std::make_unique<GetEntryByUuidResult>(GetEntryByUuidStatus::kOk, - std::move(recovered_entry)); + std::string error_message; + int error_code; + JSONStringValueDeserializer deserializer(value_string); + auto desk_template_value = + deserializer.Deserialize(&error_code, &error_message); + + if (!desk_template_value) { + DVLOG(0) << "Fail to deserialize json value from string with error code: " + << error_code << " and error message: " << error_message; + return {DeskModel::GetEntryByUuidStatus::kFailure, nullptr}; + } + + return {DeskModel::GetEntryByUuidStatus::kOk, + ConvertDeskTemplateValueToDeskTemplate(*desk_template_value)}; +} + +// Handles replies from |GetEntryByUuidTask| and calls callback. +void HandleGetEntryByUuidTask(DeskModel::GetEntryByUuidCallback callback, + GetEntryByUuidResult result) { + std::move(callback).Run(result.status, std::move(result.desk_template)); } // This task deletes a single entry keyed by its |uuid|. -DeleteEntryStatus DeleteSingleEntryTask(const base::FilePath local_file_path, - const std::string& uuid) { +DeskModel::DeleteEntryStatus DeleteSingleEntryTask( + const base::FilePath local_file_path, + const std::string& uuid) { const base::FilePath fully_qualified_path = GetFullyQualifiedPath(local_file_path, uuid); base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); if (base::DeleteFile(fully_qualified_path)) - return DeleteEntryStatus::kOk; + return DeskModel::DeleteEntryStatus::kOk; - return DeleteEntryStatus::kFailure; + return DeskModel::DeleteEntryStatus::kFailure; } // Deletes all entries. -DeleteEntryStatus DeleteAllEntriesTask(const base::FilePath local_file_path) { +DeskModel::DeleteEntryStatus DeleteAllEntriesTask( + const base::FilePath local_file_path) { base::DirReaderPosix dir_reader(local_file_path.AsUTF8Unsafe().c_str()); if (!dir_reader.IsValid()) - return DeleteEntryStatus::kFailure; + return DeskModel::DeleteEntryStatus::kFailure; - DeleteEntryStatus overall_delete_successes = DeleteEntryStatus::kOk; + DeskModel::DeleteEntryStatus overall_delete_successes = + DeskModel::DeleteEntryStatus::kOk; while (dir_reader.Next()) { if (dir_reader.name() == nullptr) continue; @@ -261,8 +267,9 @@ base::ScopedBlockingCall scoped_blocking_call( FROM_HERE, base::BlockingType::MAY_BLOCK); bool delete_success = base::DeleteFile(fully_qualified_path); - if ((overall_delete_successes == DeleteEntryStatus::kOk) && !delete_success) - overall_delete_successes = DeleteEntryStatus::kFailure; + if ((overall_delete_successes == DeskModel::DeleteEntryStatus::kOk) && + !delete_success) + overall_delete_successes = DeskModel::DeleteEntryStatus::kFailure; } return overall_delete_successes; @@ -288,13 +295,11 @@ std::move(callback)); } -void LocalDeskDataManager::GetAllEntries( - DeskModel::GetAllEntriesCallback callback) { +void LocalDeskDataManager::GetAllUuids( + DeskModel::GetAllUuidsCallback callback) { task_runner_->PostTaskAndReplyWithResult( - FROM_HERE, - base::BindOnce(&GetAllEntriesTask, &desk_template_entries_, - base::FilePath(local_path_)), - std::move(callback)); + FROM_HERE, base::BindOnce(&GetAllUuidsTask, base::FilePath(local_path_)), + base::BindOnce(&HandleGetAllUuidsTask, std::move(callback))); } void LocalDeskDataManager::GetEntryByUUID( @@ -303,7 +308,7 @@ task_runner_->PostTaskAndReplyWithResult( FROM_HERE, base::BindOnce(&GetEntryByUuidTask, base::FilePath(local_path_), uuid), - std::move(callback)); + base::BindOnce(&HandleGetEntryByUuidTask, std::move(callback))); } void LocalDeskDataManager::DeleteEntry(
diff --git a/components/desks_storage/core/local_desk_data_manager.h b/components/desks_storage/core/local_desk_data_manager.h index 998a048..9aa0f61 100644 --- a/components/desks_storage/core/local_desk_data_manager.h +++ b/components/desks_storage/core/local_desk_data_manager.h
@@ -34,7 +34,7 @@ ~LocalDeskDataManager() override; // DeskModel: - void GetAllEntries(GetAllEntriesCallback callback) override; + void GetAllUuids(GetAllUuidsCallback callback) override; void DeleteAllEntries(DeleteEntryCallback callback) override; void GetEntryByUUID(const std::string& uuid, GetEntryByUuidCallback callback) override; @@ -48,12 +48,6 @@ // This file path points to the user data directory's subdirectory: // "/path/to/user/data/dir/templates" const base::FilePath local_path_; - // This vector is used so that this class will own desk_templates - // retrieved via GetAllEntries. - // - // TODO implement full cache model instead of using this for just - // GetAllEntries. - std::vector<std::unique_ptr<ash::DeskTemplate>> desk_template_entries_; }; } // namespace desks_storage
diff --git a/components/desks_storage/core/local_desks_data_manager_unittests.cc b/components/desks_storage/core/local_desks_data_manager_unittests.cc index fab1e907..6a9d6b8 100644 --- a/components/desks_storage/core/local_desks_data_manager_unittests.cc +++ b/components/desks_storage/core/local_desks_data_manager_unittests.cc
@@ -29,8 +29,7 @@ constexpr char kJunkFileName[] = "01.template"; constexpr char kJunkData[] = "dsjadsueAUWLKD293958"; -// Search |entry_list| for |entry_query| as a uuid returns true if -// found false if not. +// Search |uuid_list| for |uuid_query| returns true if found false if not. // // we don't know what order the dir_reader will read the files back to us so // instead of relying on the operation returning the uuids in order we can @@ -39,10 +38,9 @@ // we don't use std::find here because we want to run each member through // the string compare method. bool FindUuidInUuidList(const std::string& uuid_query, - const std::vector<ash::DeskTemplate*>& entry_list) { - for (auto* entry : entry_list) { - if (entry->uuid() == - base::GUID::ParseCaseInsensitive(std::string(uuid_query))) + const std::vector<std::string>& uuid_list) { + for (const std::string& uuid : uuid_list) { + if (uuid.compare(uuid_query) == 0) return true; } @@ -50,8 +48,8 @@ } // Verifies that the status passed into it is kOk -void VerifyEntryAddedCorrectly(AddOrUpdateEntryStatus status) { - EXPECT_EQ(status, AddOrUpdateEntryStatus::kOk); +void VerifyEntryAddedCorrectly(DeskModel::AddOrUpdateEntryStatus status) { + EXPECT_EQ(status, DeskModel::AddOrUpdateEntryStatus::kOk); } void WriteJunkData(const base::FilePath& temp_dir) { @@ -137,17 +135,18 @@ // Because we're using a SequencedTaskRunner we can assume that all of the // previous tasks have been completed by the time we actually attempt to - // read the templates. - data_manager.GetAllEntries(base::BindLambdaForTesting( - [](std::unique_ptr<GetAllEntriesResult> result) { - EXPECT_EQ(result->status, GetAllEntriesStatus::kOk); - EXPECT_EQ(result->entries.size(), static_cast<unsigned long>(3)); - EXPECT_TRUE(FindUuidInUuidList(std::string("01"), result->entries)); - EXPECT_TRUE(FindUuidInUuidList(std::string("02"), result->entries)); - EXPECT_TRUE(FindUuidInUuidList(std::string("03"), result->entries)); + // read the UUIDs. + data_manager.GetAllUuids( + base::BindLambdaForTesting([](DeskModel::GetAllUuidsStatus status, + const std::vector<std::string>& uuids) { + EXPECT_EQ(status, DeskModel::GetAllUuidsStatus::kOk); + EXPECT_EQ(uuids.size(), static_cast<unsigned long>(3)); + EXPECT_TRUE(FindUuidInUuidList(std::string("01"), uuids)); + EXPECT_TRUE(FindUuidInUuidList(std::string("02"), uuids)); + EXPECT_TRUE(FindUuidInUuidList(std::string("03"), uuids)); // Sanity check for the search function. - EXPECT_FALSE(FindUuidInUuidList(std::string("04"), result->entries)); + EXPECT_FALSE(FindUuidInUuidList(std::string("04"), uuids)); })); } @@ -163,14 +162,15 @@ data_manager.GetEntryByUUID( std::string("01"), base::BindLambdaForTesting( - [](std::unique_ptr<GetEntryByUuidResult> result) { - EXPECT_EQ(GetEntryByUuidStatus::kOk, result->status); + [](DeskModel::GetEntryByUuidStatus status, + std::unique_ptr<ash::DeskTemplate> result_template) { + EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kOk, status); - EXPECT_EQ(result->entry->uuid(), + EXPECT_EQ(result_template->uuid(), base::GUID::ParseCaseInsensitive(std::string("01"))); - EXPECT_EQ(result->entry->template_name(), + EXPECT_EQ(result_template->template_name(), base::UTF8ToUTF16(std::string("desk_01"))); - EXPECT_EQ(result->entry->created_time(), base::Time()); + EXPECT_EQ(result_template->created_time(), base::Time()); })); } @@ -181,11 +181,11 @@ LocalDeskDataManager data_manager(temp_dir_.GetPath()); data_manager.GetEntryByUUID( - std::string("01"), base::BindLambdaForTesting( - [](std::unique_ptr<GetEntryByUuidResult> result) { - EXPECT_EQ(GetEntryByUuidStatus::kNotFound, - result->status); - })); + std::string("01"), + base::BindLambdaForTesting([](DeskModel::GetEntryByUuidStatus status, + std::unique_ptr<ash::DeskTemplate> _) { + EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kNotFound, status); + })); } TEST_F(LocalDeskDataManagerTest, GetEntryByUuidFailsIfEntryHasBadData) { @@ -199,11 +199,11 @@ LocalDeskDataManager data_manager(temp_dir_.GetPath()); data_manager.GetEntryByUUID( - std::string("01"), base::BindLambdaForTesting( - [](std::unique_ptr<GetEntryByUuidResult> result) { - EXPECT_EQ(GetEntryByUuidStatus::kFailure, - result->status); - })); + std::string("01"), + base::BindLambdaForTesting([](DeskModel::GetEntryByUuidStatus status, + std::unique_ptr<ash::DeskTemplate> _) { + EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kFailure, status); + })); } TEST_F(LocalDeskDataManagerTest, CanUpdateEntry) { @@ -221,14 +221,15 @@ data_manager.GetEntryByUUID( std::string("01"), base::BindLambdaForTesting( - [](std::unique_ptr<GetEntryByUuidResult> result) { - EXPECT_EQ(GetEntryByUuidStatus::kOk, result->status); + [](DeskModel::GetEntryByUuidStatus status, + std::unique_ptr<ash::DeskTemplate> result_template) { + EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kOk, status); - EXPECT_EQ(result->entry->uuid(), + EXPECT_EQ(result_template->uuid(), base::GUID::ParseCaseInsensitive(std::string("01"))); - EXPECT_EQ(result->entry->template_name(), + EXPECT_EQ(result_template->template_name(), base::UTF8ToUTF16(std::string("desk_01_mod"))); - EXPECT_EQ(result->entry->created_time(), base::Time()); + EXPECT_EQ(result_template->created_time(), base::Time()); })); } @@ -243,14 +244,15 @@ data_manager.DeleteEntry( std::string("01"), - base::BindLambdaForTesting([](DeleteEntryStatus status) { - EXPECT_EQ(status, DeleteEntryStatus::kOk); + base::BindLambdaForTesting([](DeskModel::DeleteEntryStatus status) { + EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk); })); - data_manager.GetAllEntries(base::BindLambdaForTesting( - [](std::unique_ptr<GetAllEntriesResult> result) { - EXPECT_EQ(result->status, GetAllEntriesStatus::kOk); - EXPECT_EQ(result->entries.size(), 0ul); + data_manager.GetAllUuids( + base::BindLambdaForTesting([](DeskModel::GetAllUuidsStatus status, + const std::vector<std::string>& uuids) { + EXPECT_EQ(status, DeskModel::GetAllUuidsStatus::kOk); + EXPECT_EQ(uuids.size(), 0ul); })); } @@ -270,14 +272,15 @@ base::BindOnce(&VerifyEntryAddedCorrectly)); data_manager.DeleteAllEntries( - base::BindLambdaForTesting([](DeleteEntryStatus status) { - EXPECT_EQ(status, DeleteEntryStatus::kOk); + base::BindLambdaForTesting([](DeskModel::DeleteEntryStatus status) { + EXPECT_EQ(status, DeskModel::DeleteEntryStatus::kOk); })); - data_manager.GetAllEntries(base::BindLambdaForTesting( - [](std::unique_ptr<GetAllEntriesResult> result) { - EXPECT_EQ(result->status, GetAllEntriesStatus::kOk); - EXPECT_EQ(result->entries.size(), 0ul); + data_manager.GetAllUuids( + base::BindLambdaForTesting([](DeskModel::GetAllUuidsStatus status, + const std::vector<std::string>& uuids) { + EXPECT_EQ(status, DeskModel::GetAllUuidsStatus::kOk); + EXPECT_EQ(uuids.size(), 0ul); })); }
diff --git a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc index 7d6ce90..8064c0f5 100644 --- a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc +++ b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -117,7 +117,11 @@ void DomDistillerViewerSource::RequestViewerHandle::DidFinishNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted()) + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || + !navigation_handle->HasCommitted()) return; const GURL& navigation = navigation_handle->GetURL();
diff --git a/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc b/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc index 54e273f..f2174cc5 100644 --- a/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc +++ b/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
@@ -262,7 +262,7 @@ // Not registered already, so do it now. cloud_management_registrar_->RegisterForCloudManagementWithEnrollmentToken( enrollment_token, client_id, - base::BindRepeating( + base::BindOnce( &ChromeBrowserCloudManagementController:: RegisterForCloudManagementWithEnrollmentTokenCallback, weak_factory_.GetWeakPtr()));
diff --git a/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc b/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc index 225c8bd..7791f98 100644 --- a/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc +++ b/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc
@@ -46,7 +46,7 @@ RegisterForCloudManagementWithEnrollmentToken( const std::string& enrollment_token, const std::string& client_id, - const CloudManagementRegistrationCallback& callback) { + CloudManagementRegistrationCallback callback) { DCHECK(!enrollment_token.empty()); DCHECK(!client_id.empty()); @@ -74,7 +74,7 @@ base::BindOnce(&ChromeBrowserCloudManagementRegistrar:: CallCloudManagementRegistrationCallback, base::Unretained(this), std::move(policy_client), - callback)); + std::move(callback))); } void ChromeBrowserCloudManagementRegistrar:: @@ -83,7 +83,7 @@ CloudManagementRegistrationCallback callback) { registration_helper_.reset(); if (callback) - callback.Run(client->dm_token(), client->client_id()); + std::move(callback).Run(client->dm_token(), client->client_id()); } /* MachineLevelUserCloudPolicyFetcher */
diff --git a/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.h b/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.h index 6cf6626..fb2b5b854 100644 --- a/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.h +++ b/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.h
@@ -39,16 +39,15 @@ // The callback invoked once policy registration is complete. Passed // |dm_token| and |client_id| parameters are empty if policy registration // failed. - // TODO(crbug.com/825321): Update this to OnceCallback. using CloudManagementRegistrationCallback = - base::RepeatingCallback<void(const std::string& dm_token, - const std::string& client_id)>; + base::OnceCallback<void(const std::string& dm_token, + const std::string& client_id)>; // Registers a CloudPolicyClient for fetching machine level user policy. void RegisterForCloudManagementWithEnrollmentToken( const std::string& enrollment_token, const std::string& client_id, - const CloudManagementRegistrationCallback& callback); + CloudManagementRegistrationCallback callback); private: void CallCloudManagementRegistrationCallback(
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc index e8242e87..9e665bc 100644 --- a/components/guest_view/browser/guest_view_base.cc +++ b/components/guest_view/browser/guest_view_base.cc
@@ -582,7 +582,11 @@ void GuestViewBase::DidFinishNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted()) + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || + !navigation_handle->HasCommitted()) return; if (attached() && ZoomPropagatesFromEmbedderToGuest())
diff --git a/components/invalidation/impl/invalidator_registrar_with_memory.cc b/components/invalidation/impl/invalidator_registrar_with_memory.cc index c9e320d1..4637780 100644 --- a/components/invalidation/impl/invalidator_registrar_with_memory.cc +++ b/components/invalidation/impl/invalidator_registrar_with_memory.cc
@@ -98,9 +98,7 @@ handler_name_to_subscribed_topics_map_[handler->GetString()].insert( TopicData(topic_name, is_public->GetBool())); } else if (it.second.is_string()) { - std::string handler_name; - it.second.GetAsString(&handler_name); - handler_name_to_subscribed_topics_map_[handler_name].insert( + handler_name_to_subscribed_topics_map_[it.second.GetString()].insert( TopicData(topic_name, false)); } }
diff --git a/components/invalidation/impl/per_user_topic_subscription_manager.cc b/components/invalidation/impl/per_user_topic_subscription_manager.cc index fb6e735..0c195670 100644 --- a/components/invalidation/impl/per_user_topic_subscription_manager.cc +++ b/components/invalidation/impl/per_user_topic_subscription_manager.cc
@@ -248,11 +248,10 @@ // Load subscribed topics from prefs. for (auto it : update->DictItems()) { Topic topic = it.first; - std::string private_topic_name; - if (it.second.GetAsString(&private_topic_name) && - !private_topic_name.empty()) { - topic_to_private_topic_[topic] = private_topic_name; - private_topic_to_topic_[private_topic_name] = topic; + const std::string* private_topic_name = it.second.GetIfString(); + if (private_topic_name && !private_topic_name->empty()) { + topic_to_private_topic_[topic] = *private_topic_name; + private_topic_to_topic_[*private_topic_name] = topic; } else { // Couldn't decode the pref value; remove it. keys_to_remove.push_back(topic);
diff --git a/components/invalidation/impl/per_user_topic_subscription_manager_unittest.cc b/components/invalidation/impl/per_user_topic_subscription_manager_unittest.cc index 36a34fc1d..320a236 100644 --- a/components/invalidation/impl/per_user_topic_subscription_manager_unittest.cc +++ b/components/invalidation/impl/per_user_topic_subscription_manager_unittest.cc
@@ -645,9 +645,8 @@ const base::Value* private_topic_value = topics->FindKeyOfType(topic.first, base::Value::Type::STRING); ASSERT_NE(private_topic_value, nullptr); - std::string private_topic; - private_topic_value->GetAsString(&private_topic); - EXPECT_EQ(private_topic, "old-token-topic"); + ASSERT_TRUE(private_topic_value->is_string()); + EXPECT_EQ("old-token-topic", private_topic_value->GetString()); } EXPECT_EQ(kFakeInstanceIdToken, @@ -672,9 +671,8 @@ const base::Value* private_topic_value = topics->FindKeyOfType(topic.first, base::Value::Type::STRING); ASSERT_NE(private_topic_value, nullptr); - std::string private_topic; - private_topic_value->GetAsString(&private_topic); - EXPECT_EQ(private_topic, "new-token-topic"); + ASSERT_TRUE(private_topic_value->is_string()); + EXPECT_EQ("new-token-topic", private_topic_value->GetString()); } }
diff --git a/components/media_router/browser/presentation/presentation_navigation_policy.cc b/components/media_router/browser/presentation/presentation_navigation_policy.cc index 3a63d1db..fcb9f455 100644 --- a/components/media_router/browser/presentation/presentation_navigation_policy.cc +++ b/components/media_router/browser/presentation/presentation_navigation_policy.cc
@@ -23,7 +23,10 @@ bool PresentationNavigationPolicy::AllowNavigation( content::NavigationHandle* navigation_handle) { // We only care about top-level navigations that are cross-document. - if (!navigation_handle->IsInMainFrame() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || navigation_handle->IsSameDocument()) { return true; }
diff --git a/components/metrics/structured/event_base.cc b/components/metrics/structured/event_base.cc index 0084541b..a93f9168 100644 --- a/components/metrics/structured/event_base.cc +++ b/components/metrics/structured/event_base.cc
@@ -11,10 +11,12 @@ EventBase::EventBase(uint64_t event_name_hash, uint64_t project_name_hash, - IdType id_type) + IdType id_type, + IdScope id_scope) : event_name_hash_(event_name_hash), project_name_hash_(project_name_hash), - id_type_(id_type) {} + id_type_(id_type), + id_scope_(id_scope) {} EventBase::EventBase(const EventBase& other) = default; EventBase::~EventBase() = default;
diff --git a/components/metrics/structured/event_base.h b/components/metrics/structured/event_base.h index 2d5ac75f..1c0bc11f 100644 --- a/components/metrics/structured/event_base.h +++ b/components/metrics/structured/event_base.h
@@ -29,6 +29,13 @@ kUnidentified = 2, }; + // Specifies whether an identifier is used different for each profile, or is + // shared for all profiles on a device. + enum class IdScope { + kPerProfile = 0, + kPerDevice = 1, + }; + // Specifies which value type a Metric object holds. enum class MetricType { kString = 0, @@ -68,10 +75,13 @@ IdType id_type() const { return id_type_; } + IdScope id_scope() const { return id_scope_; } + protected: - explicit EventBase(uint64_t event_name_hash, - uint64_t project_name_hash, - IdType id_type); + EventBase(uint64_t event_name_hash, + uint64_t project_name_hash, + IdType id_type, + IdScope id_scope); void AddStringMetric(uint64_t name_hash, const std::string& value); @@ -97,6 +107,8 @@ IdType id_type_; + IdScope id_scope_; + std::vector<Metric> metrics_; };
diff --git a/components/metrics/structured/structured_metrics_provider.cc b/components/metrics/structured/structured_metrics_provider.cc index cabd551..e001a20 100644 --- a/components/metrics/structured/structured_metrics_provider.cc +++ b/components/metrics/structured/structured_metrics_provider.cc
@@ -41,7 +41,13 @@ int StructuredMetricsProvider::kMaxEventsPerUpload = 100; -char StructuredMetricsProvider::kStorageDirectory[] = "structured_metrics"; +char StructuredMetricsProvider::kProfileKeyDataPath[] = + "structured_metrics/keys"; + +char StructuredMetricsProvider::kDeviceKeyDataPath[] = + "/var/lib/metrics/structured/chromium/keys"; + +char StructuredMetricsProvider::kUnsentLogsPath[] = "structured_metrics/events"; StructuredMetricsProvider::StructuredMetricsProvider() { Recorder::GetInstance()->AddObserver(this); @@ -63,15 +69,9 @@ void StructuredMetricsProvider::OnKeyDataInitialized() { DCHECK(base::CurrentUIThread::IsSet()); - switch (init_state_) { - case InitState::kProfileAdded: - init_state_ = InitState::kKeysInitialized; - break; - case InitState::kEventsInitialized: - init_state_ = InitState::kInitialized; - break; - default: - NOTREACHED(); + ++init_count_; + if (init_count_ == kTargetInitCount) { + init_state_ = InitState::kInitialized; } } @@ -90,15 +90,9 @@ break; } - switch (init_state_) { - case InitState::kProfileAdded: - init_state_ = InitState::kEventsInitialized; - break; - case InitState::kKeysInitialized: - init_state_ = InitState::kInitialized; - break; - default: - NOTREACHED(); + ++init_count_; + if (init_count_ == kTargetInitCount) { + init_state_ = InitState::kInitialized; } } @@ -129,14 +123,25 @@ return; init_state_ = InitState::kProfileAdded; - const auto storage_directory = profile_path.Append(kStorageDirectory); const auto save_delay = base::TimeDelta::FromMilliseconds(kSaveDelayMs); - key_data_ = std::make_unique<KeyData>( - storage_directory.Append("keys"), save_delay, + + profile_key_data_ = std::make_unique<KeyData>( + profile_path.Append(kProfileKeyDataPath), save_delay, base::BindOnce(&StructuredMetricsProvider::OnKeyDataInitialized, weak_factory_.GetWeakPtr())); + + // TODO(crbug.com/1148168): Change this to receive the key data path in the + // constructor and avoid the test-specific logic. + const auto device_key_data_path = device_key_data_path_for_test_.has_value() + ? device_key_data_path_for_test_.value() + : base::FilePath(kDeviceKeyDataPath); + device_key_data_ = std::make_unique<KeyData>( + base::FilePath(device_key_data_path), save_delay, + base::BindOnce(&StructuredMetricsProvider::OnKeyDataInitialized, + weak_factory_.GetWeakPtr())); + events_ = std::make_unique<PersistentProto<EventsProto>>( - storage_directory.Append("events"), save_delay, + profile_path.Append(kUnsentLogsPath), save_delay, base::BindOnce(&StructuredMetricsProvider::OnRead, weak_factory_.GetWeakPtr()), base::BindRepeating(&StructuredMetricsProvider::OnWrite, @@ -171,7 +176,8 @@ if (!recording_enabled_ || init_state_ != InitState::kInitialized) return; - DCHECK(key_data_->is_initialized()); + DCHECK(profile_key_data_->is_initialized()); + DCHECK(device_key_data_->is_initialized()); // TODO(crbug.com/1148168): We are transitioning to new upload behaviour for // non-client_id-identified metrics. See structured_metrics_features.h for @@ -197,7 +203,38 @@ event_proto = events_.get()->get()->add_non_uma_events(); } - event_proto->set_profile_event_id(key_data_->Id(event.project_name_hash())); + // Choose which KeyData to use for this event. + KeyData* key_data; + switch (event.id_scope()) { + case EventBase::IdScope::kPerProfile: + key_data = profile_key_data_.get(); + break; + case EventBase::IdScope::kPerDevice: + key_data = device_key_data_.get(); + break; + default: + // In case id_scope is uninitialized. + NOTREACHED(); + } + + // Set the ID for this event, if any. + switch (event.id_type()) { + case EventBase::IdType::kProjectId: + event_proto->set_profile_event_id( + key_data->Id(event.project_name_hash())); + break; + case EventBase::IdType::kUmaId: + // TODO(crbug.com/1148168): Unimplemented. + break; + case EventBase::IdType::kUnidentified: + // Do nothing. + break; + default: + // In case id_type is uninitialized. + NOTREACHED(); + break; + } + event_proto->set_event_name_hash(event.name_hash()); for (const auto& metric : event.metrics()) { auto* metric_proto = event_proto->add_metrics(); @@ -208,7 +245,7 @@ metric_proto->set_value_int64(metric.int_value); break; case EventBase::MetricType::kString: - const int64_t hmac = key_data_->HmacMetric( + const int64_t hmac = key_data->HmacMetric( event.project_name_hash(), metric.name_hash, metric.string_value); metric_proto->set_value_hmac(hmac); break; @@ -318,5 +355,13 @@ weak_factory_.GetWeakPtr())); } +void StructuredMetricsProvider::SetDeviceKeyDataPathForTest( + const base::FilePath& path) { + // Updating the path after a profile has been added will have no effect, so + // make it an error. + DCHECK_EQ(init_state_, InitState::kUninitialized); + device_key_data_path_for_test_ = path; +} + } // namespace structured } // namespace metrics
diff --git a/components/metrics/structured/structured_metrics_provider.h b/components/metrics/structured/structured_metrics_provider.h index d7d6b87..f01982f 100644 --- a/components/metrics/structured/structured_metrics_provider.h +++ b/components/metrics/structured/structured_metrics_provider.h
@@ -15,6 +15,7 @@ #include "components/metrics/structured/event_base.h" #include "components/metrics/structured/key_data.h" #include "components/metrics/structured/recorder.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace metrics { namespace structured { @@ -66,19 +67,15 @@ friend class Recorder; friend class StructuredMetricsProviderTest; - // State machine for step 4 of initialization. These are stored in two files - // that are asynchronously read from disk at startup. When both files have + // State machine for step 4 of initialization. These are stored in three files + // that are asynchronously read from disk at startup. When all files have // been read, the provider has been initialized. enum class InitState { kUninitialized = 1, // Set after we observe the recorder, which happens on construction. kProfileAdded = 2, - // Set after the key file is read from disk. - kKeysInitialized = 3, - // Set after the event file is read from disk. - kEventsInitialized = 4, - // Set after both the key and event files are read from disk. - kInitialized = 5, + // Set after all key and event files are read from disk. + kInitialized = 3, }; void OnKeyDataInitialized(); @@ -102,14 +99,24 @@ void WriteNowForTest(); void SetExternalMetricsDirForTest(const base::FilePath& dir); + void SetDeviceKeyDataPathForTest(const base::FilePath& path); // Beyond this number of logging events between successive calls to // ProvideCurrentSessionData, we stop recording events. static int kMaxEventsPerUpload; - // The directory used to store unsent logs and keys. Relative to the user's - // cryptohome. - static char kStorageDirectory[]; + // The path used to store per-profile keys. Relative to the user's + // cryptohome. This file is created by chromium. + static char kProfileKeyDataPath[]; + + // The path used to store per-device keys. This file is created by tmpfiles.d + // on start and has its permissions and ownership set such that it is writable + // by chronos. + static char kDeviceKeyDataPath[]; + + // The directory used to store unsent logs. Relative to the user's cryptohome. + // This file is created by chromium. + static char kUnsentLogsPath[]; // Whether the metrics provider has completed initialization. Initialization // occurs across OnProfileAdded and OnInitializationCompleted. No incoming @@ -120,12 +127,18 @@ // - OnProfileAdded is called, which constructs |storage_| and // asynchronously reads events and keys. // - OnInitializationCompleted is called once reading from disk is complete, - // which sets |initialized_| to true. + // which sets |init_count_| to kInitialized. // // The metrics provider does not handle multiprofile: initialization happens // only once, for the first-logged-in account aka. primary user. // + // After a profile is added, three files need to be read from disk: + // per-profile keys, per-device keys, and unsent events. |init_count_| tracks + // how many of these have been read and, when it reaches 3, we set + // |init_state_| to kInitialized. InitState init_state_ = InitState::kUninitialized; + int init_count_ = 0; + static constexpr int kTargetInitCount = 3; // Tracks the recording state signalled to the metrics provider by // OnRecordingEnabled and OnRecordingDisabled. This is false until @@ -148,8 +161,14 @@ std::unique_ptr<PersistentProto<EventsProto>> events_; // Storage for all event's keys, and hashing logic for values. This stores - // keys on disk. - std::unique_ptr<KeyData> key_data_; + // keys on disk. |profile_key_data_| stores keys for per-profile projects, + // and |device_key_data_| stores keys for per-device projects. + std::unique_ptr<KeyData> profile_key_data_; + std::unique_ptr<KeyData> device_key_data_; + + // Used to override the otherwise hardcoded path for device keys in unit tests + // only. + absl::optional<base::FilePath> device_key_data_path_for_test_; base::WeakPtrFactory<StructuredMetricsProvider> weak_factory_{this}; };
diff --git a/components/metrics/structured/structured_metrics_provider_unittest.cc b/components/metrics/structured/structured_metrics_provider_unittest.cc index 99f906a..e2cee85 100644 --- a/components/metrics/structured/structured_metrics_provider_unittest.cc +++ b/components/metrics/structured/structured_metrics_provider_unittest.cc
@@ -31,22 +31,15 @@ namespace { // These project, event, and metric names are used for testing. -// - project: TestProjectOne -// - event: TestEventOne -// - metric: TestMetricOne -// - metric: TestMetricTwo -// - project: TestProjectTwo -// - event: TestEventTwo -// - metric: TestMetricThree -// - event: TestEventThree -// - metric: TestMetricFour // The name hash of "TestProjectOne". constexpr uint64_t kProjectOneHash = UINT64_C(16881314472396226433); // The name hash of "TestProjectTwo". constexpr uint64_t kProjectTwoHash = UINT64_C(5876808001962504629); -// The name hash of "TestProjectTwo". +// The name hash of "TestProjectThree". constexpr uint64_t kProjectThreeHash = UINT64_C(10860358748803291132); +// The name hash of "TestProjectFour". +constexpr uint64_t kProjectFourHash = UINT64_C(6801665881746546626); // The name hash of "chrome::TestProjectOne::TestEventOne". constexpr uint64_t kEventOneHash = UINT64_C(13593049295042080097); @@ -56,6 +49,8 @@ constexpr uint64_t kEventThreeHash = UINT64_C(5848687377041124372); // The name hash of "chrome::TestProjectThree::TestEventFour". constexpr uint64_t kEventFourHash = UINT64_C(1718797808092246258); +// The name hash of "chrome::TestProjectFour::TestEventFive". +constexpr uint64_t kEventFiveHash = UINT64_C(7045523601811399253); // The name hash of "TestMetricOne". constexpr uint64_t kMetricOneHash = UINT64_C(637929385654885975); @@ -65,13 +60,15 @@ constexpr uint64_t kMetricThreeHash = UINT64_C(13469300759843809564); // The name hash of "TestMetricFour". constexpr uint64_t kMetricFourHash = UINT64_C(2917855408523247722); +// The name hash of "TestMetricFive". +constexpr uint64_t kMetricFiveHash = UINT64_C(8665976921794972190); // The hex-encoded first 8 bytes of SHA256("aaa...a") constexpr char kProjectOneId[] = "3BA3F5F43B926026"; // The hex-encoded first 8 bytes of SHA256("bbb...b") constexpr char kProjectTwoId[] = "BDB339768BC5E4FE"; -// The hex-encoded first 8 bytes of SHA256("ccc...c") -constexpr char kProjectThreeId[] = "CD93782B7FB95559"; +// The hex-encoded first 8 bytes of SHA256("ddd...d") +constexpr char kProjectFourId[] = "FBBBB6DE2AA74C3C"; // Test values. constexpr char kValueOne[] = "value one"; @@ -109,13 +106,19 @@ base::FilePath TempDirPath() { return temp_dir_.GetPath(); } - base::FilePath KeyFilePath() { + base::FilePath ProfileKeyFilePath() { return temp_dir_.GetPath().Append("structured_metrics").Append("keys"); } + base::FilePath DeviceKeyFilePath() { + return temp_dir_.GetPath() + .Append("structured_metrics") + .Append("device_keys"); + } + void Wait() { task_environment_.RunUntilIdle(); } - void WriteTestingKeys() { + void WriteTestingProfileKeys() { const int today = (base::Time::Now() - base::Time::UnixEpoch()).InDays(); KeyDataProto proto; @@ -134,8 +137,24 @@ key_three.set_last_rotation(today); key_three.set_rotation_period(90); - base::CreateDirectory(KeyFilePath().DirName()); - ASSERT_TRUE(base::WriteFile(KeyFilePath(), proto.SerializeAsString())); + base::CreateDirectory(ProfileKeyFilePath().DirName()); + ASSERT_TRUE( + base::WriteFile(ProfileKeyFilePath(), proto.SerializeAsString())); + Wait(); + } + + void WriteTestingDeviceKeys() { + const int today = (base::Time::Now() - base::Time::UnixEpoch()).InDays(); + + KeyDataProto proto; + KeyProto& key = (*proto.mutable_keys())[kProjectFourHash]; + key.set_key("dddddddddddddddddddddddddddddddd"); + key.set_last_rotation(today); + key.set_rotation_period(90); + + base::CreateDirectory(DeviceKeyFilePath().DirName()); + ASSERT_TRUE( + base::WriteFile(DeviceKeyFilePath(), proto.SerializeAsString())); Wait(); } @@ -145,6 +164,9 @@ void Init() { // Create the provider, normally done by the ChromeMetricsServiceClient. provider_ = std::make_unique<StructuredMetricsProvider>(); + // Set the device key data to be within the temp dir, rather than to + // /var/lib/metrics/structured as is default. + provider_->SetDeviceKeyDataPathForTest(DeviceKeyFilePath()); // Enable recording, normally done after the metrics service has checked // consent allows recording. provider_->OnRecordingEnabled(); @@ -329,7 +351,7 @@ } TEST_F(StructuredMetricsProviderTest, UmaEventsReportedCorrectly) { - WriteTestingKeys(); + WriteTestingProfileKeys(); Init(); events::test_project_three::TestEventFour().SetTestMetricFour(12345).Record(); @@ -341,7 +363,9 @@ { // First event const auto& event = data.events(0); EXPECT_EQ(event.event_name_hash(), kEventFourHash); - EXPECT_EQ(HashToHex(event.profile_event_id()), kProjectThreeId); + // TODO(crbug.com/1148168): The UMA ID currently isn't attached to UMA + // events, so just check it isn't set. + EXPECT_FALSE(event.has_profile_event_id()); ASSERT_EQ(event.metrics_size(), 1); const auto& metric = event.metrics(0); EXPECT_EQ(metric.name_hash(), kMetricFourHash); @@ -351,7 +375,9 @@ { // Second event const auto& event = data.events(1); EXPECT_EQ(event.event_name_hash(), kEventFourHash); - EXPECT_EQ(HashToHex(event.profile_event_id()), kProjectThreeId); + // TODO(crbug.com/1148168): The UMA ID currently isn't attached to UMA + // events, so just check it isn't set. + EXPECT_FALSE(event.has_profile_event_id()); ASSERT_EQ(event.metrics_size(), 1); const auto& metric = event.metrics(0); EXPECT_EQ(metric.name_hash(), kMetricFourHash); @@ -362,7 +388,7 @@ } TEST_F(StructuredMetricsProviderTest, IndependentEventsReportedCorrectly) { - WriteTestingKeys(); + WriteTestingProfileKeys(); Init(); events::test_project_one::TestEventOne() @@ -387,7 +413,7 @@ EXPECT_EQ(metric.name_hash(), kMetricOneHash); EXPECT_EQ(HashToHex(metric.value_hmac()), // Value of HMAC_256("aaa...a", concat(hex(kMetricOneHash), - // "value one")) + // kValueOne)) "8C2469269D142715"); } @@ -408,8 +434,8 @@ const auto& metric = event.metrics(0); EXPECT_EQ(metric.name_hash(), kMetricThreeHash); EXPECT_EQ(HashToHex(metric.value_hmac()), - // Value of HMAC_256("bbb...b", concat(hex(kProjectHash), - // "value three")) + // Value of HMAC_256("bbb...b", concat(hex(kProjectTwoHash), + // kValueTwo)) "86F0169868588DC7"); } } @@ -417,6 +443,38 @@ histogram_tester_.ExpectTotalCount("UMA.StructuredMetrics.InternalError", 0); } +TEST_F(StructuredMetricsProviderTest, DeviceKeysUsedForDeviceScopedProjects) { + WriteTestingProfileKeys(); + WriteTestingDeviceKeys(); + Init(); + + // This event's project has device scope set, so should use the per-device + // keys set by WriteTestingDeviceKeys. In this case the expected key is + // "ddd...d", which we observe by checking the ID and HMAC have the correct + // value given that key. + events::test_project_four::TestEventFive() + .SetTestMetricFive("value") + .Record(); + + const auto data = GetIndependentMetrics(); + ASSERT_EQ(data.events_size(), 1); + + const auto& event = data.events(0); + EXPECT_EQ(event.event_name_hash(), kEventFiveHash); + // The hex-encoded first 8 bytes of SHA256("ddd...d"). + EXPECT_EQ(HashToHex(event.profile_event_id()), kProjectFourId); + ASSERT_EQ(event.metrics_size(), 1); + + const auto& metric = event.metrics(0); + EXPECT_EQ(metric.name_hash(), kMetricFiveHash); + EXPECT_EQ(HashToHex(metric.value_hmac()), + // Value of HMAC_256("ddd...d", concat(hex(kMetricFiveHash), + // "value")) + "4CC202FAA78FDC7A"); + + histogram_tester_.ExpectTotalCount("UMA.StructuredMetrics.InternalError", 0); +} + // Check that a full int64 can be recorded, and is not truncated to an int32. TEST_F(StructuredMetricsProviderTest, Int64MetricsNotTruncated) { Init(); @@ -432,7 +490,7 @@ } TEST_F(StructuredMetricsProviderTest, EventsWithinProjectReportedWithSameID) { - WriteTestingKeys(); + WriteTestingProfileKeys(); Init(); events::test_project_one::TestEventOne().Record();
diff --git a/components/no_state_prefetch/browser/no_state_prefetch_contents.cc b/components/no_state_prefetch/browser/no_state_prefetch_contents.cc index f9be099..6931af1 100644 --- a/components/no_state_prefetch/browser/no_state_prefetch_contents.cc +++ b/components/no_state_prefetch/browser/no_state_prefetch_contents.cc
@@ -354,7 +354,10 @@ void NoStatePrefetchContents::DidStartNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || navigation_handle->IsSameDocument()) { return; } @@ -372,7 +375,10 @@ void NoStatePrefetchContents::DidRedirectNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame()) + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame()) return; // If it's a redirect on the top-level resource, the name needs to be @@ -390,7 +396,10 @@ void NoStatePrefetchContents::DidFinishNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || !navigation_handle->HasCommitted()) { return; }
diff --git a/components/optimization_guide/content/browser/page_content_annotations_web_contents_helper.cc b/components/optimization_guide/content/browser/page_content_annotations_web_contents_helper.cc index ce248d8e..262b795 100644 --- a/components/optimization_guide/content/browser/page_content_annotations_web_contents_helper.cc +++ b/components/optimization_guide/content/browser/page_content_annotations_web_contents_helper.cc
@@ -39,7 +39,10 @@ PageContentAnnotationsWebContentsHelper::MaybeRequestFrameTextDump( content::NavigationHandle* navigation_handle) { DCHECK(navigation_handle->HasCommitted()); - DCHECK(navigation_handle->IsInMainFrame()); + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + DCHECK(navigation_handle->IsInPrimaryMainFrame()); if (!navigation_handle->GetURL().SchemeIsHTTPOrHTTPS()) return nullptr;
diff --git a/components/optimization_guide/content/browser/page_text_observer.cc b/components/optimization_guide/content/browser/page_text_observer.cc index 4615df1..d3d7e97a 100644 --- a/components/optimization_guide/content/browser/page_text_observer.cc +++ b/components/optimization_guide/content/browser/page_text_observer.cc
@@ -332,7 +332,10 @@ } void PageTextObserver::DidStartNavigation(content::NavigationHandle* handle) { - if (!handle->IsInMainFrame()) { + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!handle->IsInPrimaryMainFrame()) { return; } @@ -344,7 +347,10 @@ void PageTextObserver::DidFinishNavigation(content::NavigationHandle* handle) { // Only main frames are supported for right now. - if (!handle->IsInMainFrame()) { + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!handle->IsInPrimaryMainFrame()) { return; }
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/PlayerManager.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/PlayerManager.java index c8edaf22..042c8b9 100644 --- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/PlayerManager.java +++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/PlayerManager.java
@@ -104,6 +104,7 @@ private long mNativeAxTree; private PlayerAccessibilityDelegate mAccessibilityDelegate; private WebContentsAccessibilityImpl mWebContentsAccessibility; + private final boolean mShouldCompressBitmaps; // The minimum ratio value of a sub-frame's area to its parent, for the sub-frame to be // considered 'large'. @@ -123,15 +124,17 @@ * @param listener Interface that includes a number of callbacks. * @param ignoreInitialScrollOffset If true the initial scroll state that is recorded at * capture time is ignored. + * @param shouldCompressBitmaps If true bitmaps outside the viewport are compressed. */ public PlayerManager(GURL url, Context context, NativePaintPreviewServiceProvider nativePaintPreviewServiceProvider, String directoryKey, @NonNull Listener listener, int backgroundColor, - boolean ignoreInitialScrollOffset) { + boolean ignoreInitialScrollOffset, boolean shouldCompressBitmaps) { TraceEvent.begin("PlayerManager"); TraceEvent.startAsync(sInitEvent, hashCode()); mContext = context; mListener = listener; + mShouldCompressBitmaps = shouldCompressBitmaps; mDelegate = getCompositorDelegateFactory().create(nativePaintPreviewServiceProvider, url, directoryKey, false, this::onCompositorReady, mListener::onCompositorError); mHostView = new FrameLayout(mContext); @@ -179,7 +182,7 @@ mRootFrameData.getContentHeight(), mRootFrameData.getInitialScrollX(), mRootFrameData.getInitialScrollY(), true, mPlayerSwipeRefreshHandler, mPlayerGestureListener, mListener::onFirstPaint, mListener::isAccessibilityEnabled, - this::initializeAccessibility); + this::initializeAccessibility, mShouldCompressBitmaps); buildSubFrameCoordinators(mRootFrameCoordinator, mRootFrameData); mHostView.addView(mRootFrameCoordinator.getView(), new FrameLayout.LayoutParams( @@ -360,7 +363,7 @@ new PlayerFrameCoordinator(mContext, mDelegate, childFrame.getGuid(), childFrame.getContentWidth(), childFrame.getContentHeight(), childFrame.getInitialScrollX(), childFrame.getInitialScrollY(), false, - null, mPlayerGestureListener, null, null, null); + null, mPlayerGestureListener, null, null, null, mShouldCompressBitmaps); buildSubFrameCoordinators(childCoordinator, childFrame); frameCoordinator.addSubFrame(childCoordinator, frame.getSubFrameClips()[i]); }
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmap.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmap.java index 8ad1dbdd..7fd5b9b 100644 --- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmap.java +++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmap.java
@@ -60,7 +60,8 @@ * @param visible Whether the bitmap is currently visible. If visible, the bitmap won't be * immediately discarded. */ - CompressibleBitmap(Bitmap bitmap, SequencedTaskRunner taskRunner, boolean visible) { + CompressibleBitmap(Bitmap bitmap, SequencedTaskRunner taskRunner, boolean visible, + boolean shouldCompress) { mBitmap = bitmap; mWidth = mBitmap.getWidth(); mHeight = mBitmap.getHeight(); @@ -69,7 +70,9 @@ // ARGB8888 AKA N32Premultiplied. mBitmap.setHasAlpha(true); mTaskRunner = taskRunner; - compressInBackground(visible); + if (shouldCompress) { + compressInBackground(visible); + } } /** @@ -174,13 +177,12 @@ private void compress() { if (mBitmap == null) return; - ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); - Bitmap alphaChannel = mBitmap.extractAlpha(); // Bitmap#compress() doesn't work for Bitmap.Config.ALPHA_8 so use zip instead. mCompressedAlphaBytes = compressAlpha(alphaChannel); alphaChannel.recycle(); + ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); boolean success = mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayStream); if (success) { mCompressedData = byteArrayStream.toByteArray();
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapState.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapState.java index fd3c35c..b65cf06 100644 --- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapState.java +++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapState.java
@@ -48,16 +48,19 @@ private final PlayerFrameBitmapStateController mStateController; private Set<Integer> mInitialMissingVisibleBitmaps = new HashSet<>(); private final SequencedTaskRunner mTaskRunner; + private final boolean mShouldCompressBitmaps; PlayerFrameBitmapState(UnguessableToken guid, int tileWidth, int tileHeight, float scaleFactor, Size contentSize, PlayerCompositorDelegate compositorDelegate, - PlayerFrameBitmapStateController stateController, SequencedTaskRunner taskRunner) { + PlayerFrameBitmapStateController stateController, SequencedTaskRunner taskRunner, + boolean shouldCompressBitmaps) { mGuid = guid; mTileSize = new Size(tileWidth, tileHeight); mScaleFactor = scaleFactor; mCompositorDelegate = compositorDelegate; mStateController = stateController; mTaskRunner = taskRunner; + mShouldCompressBitmaps = shouldCompressBitmaps; // Each tile is as big as the initial view port. Here we determine the number of // columns and rows for the current scale factor. @@ -382,7 +385,7 @@ } mBitmapMatrix[mRequestRow][mRequestCol] = - new CompressibleBitmap(result, mTaskRunner, mVisible); + new CompressibleBitmap(result, mTaskRunner, mVisible, mShouldCompressBitmaps); deleteUnrequiredBitmaps(); markBitmapReceived(mRequestRow, mRequestCol); mPendingBitmapRequests[mRequestRow][mRequestCol] = null;
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapStateController.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapStateController.java index cff5b4e4..9ca4c0a 100644 --- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapStateController.java +++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapStateController.java
@@ -25,10 +25,12 @@ private final PlayerCompositorDelegate mCompositorDelegate; private final PlayerFrameMediatorDelegate mMediatorDelegate; private final SequencedTaskRunner mTaskRunner; + private final boolean mShouldCompressBitmaps; PlayerFrameBitmapStateController(UnguessableToken guid, PlayerFrameViewport viewport, Size contentSize, PlayerCompositorDelegate compositorDelegate, - PlayerFrameMediatorDelegate mediatorDelegate, SequencedTaskRunner taskRunner) { + PlayerFrameMediatorDelegate mediatorDelegate, SequencedTaskRunner taskRunner, + boolean shouldCompressBitmaps) { mGuid = guid; mViewport = viewport; mContentSize = contentSize; @@ -38,6 +40,7 @@ } mMediatorDelegate = mediatorDelegate; mTaskRunner = taskRunner; + mShouldCompressBitmaps = shouldCompressBitmaps; } void destroy() { @@ -76,7 +79,7 @@ invalidateLoadingBitmaps(); mLoadingBitmapState = new PlayerFrameBitmapState(mGuid, mViewport.getWidth(), Math.round(mViewport.getHeight() / 2.0f), mViewport.getScale(), mContentSize, - mCompositorDelegate, this, mTaskRunner); + mCompositorDelegate, this, mTaskRunner, mShouldCompressBitmaps); if (mVisibleBitmapState == null) { mLoadingBitmapState.skipWaitingForVisibleBitmaps(); swap(mLoadingBitmapState);
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java index ca6b890..934b172 100644 --- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java +++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java
@@ -45,14 +45,14 @@ @Nullable OverscrollHandler overscrollHandler, PlayerGestureListener gestureHandler, @Nullable Runnable firstPaintListener, @Nullable Supplier<Boolean> isAccessibilityEnabled, - @Nullable Runnable initialViewportSizeAvailable) { + @Nullable Runnable initialViewportSizeAvailable, boolean shouldCompressBitmaps) { PropertyModel model = new PropertyModel.Builder(PlayerFrameProperties.ALL_KEYS).build(); OverScroller scroller = new OverScroller(context); scroller.setFriction(ViewConfiguration.getScrollFriction() / 2); mMediator = new PlayerFrameMediator(model, compositorDelegate, gestureHandler, frameGuid, new Size(contentWidth, contentHeight), initialScrollX, initialScrollY, - initialViewportSizeAvailable); + initialViewportSizeAvailable, shouldCompressBitmaps); if (canDetectZoom) { mScaleController =
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java index 1419262..39af403 100644 --- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java +++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java
@@ -76,7 +76,8 @@ PlayerFrameMediator(PropertyModel model, PlayerCompositorDelegate compositorDelegate, PlayerGestureListener gestureListener, UnguessableToken frameGuid, Size contentSize, - int initialScrollX, int initialScrollY, Runnable initialViewportSizeAvailable) { + int initialScrollX, int initialScrollY, Runnable initialViewportSizeAvailable, + boolean shouldCompressBitmaps) { mBitmapScaleMatrix = new Matrix(); mModel = model; mModel.set(PlayerFrameProperties.SCALE_MATRIX, mBitmapScaleMatrix); @@ -90,8 +91,8 @@ mContentSize = contentSize; SequencedTaskRunner taskRunner = PostTask.createSequencedTaskRunner(TaskTraits.THREAD_POOL_USER_VISIBLE); - mBitmapStateController = new PlayerFrameBitmapStateController( - mGuid, mViewport, mContentSize, mCompositorDelegate, this, taskRunner); + mBitmapStateController = new PlayerFrameBitmapStateController(mGuid, mViewport, + mContentSize, mCompositorDelegate, this, taskRunner, shouldCompressBitmaps); mViewport.offset(initialScrollX, initialScrollY); mViewport.setScale(0f); mInitialViewportSizeAvailable = initialViewportSizeAvailable;
diff --git a/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java b/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java index 8b753b2..2b16f6d 100644 --- a/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java +++ b/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
@@ -220,7 +220,7 @@ @Override public void onAccessibilityNotSupported() {} - }, 0xffffffff, false); + }, 0xffffffff, false, true); mPlayerManager.setCompressOnClose(false); }); compositorErrorCallback.waitForFirst(); @@ -433,7 +433,7 @@ @Override public void onAccessibilityNotSupported() {} - }, 0xffffffff, false); + }, 0xffffffff, false, true); mPlayerManager.setCompressOnClose(false); getActivity().setContentView(mPlayerManager.getView()); });
diff --git a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmapTest.java b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmapTest.java index e28690dce..0829af2 100644 --- a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmapTest.java +++ b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmapTest.java
@@ -9,6 +9,7 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -55,6 +56,25 @@ } @Test + public void testNoCompression() { + Bitmap bitmap = Mockito.mock(Bitmap.class); + + SequencedTaskRunner taskRunner = Mockito.mock(SequencedTaskRunner.class); + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }) + .when(taskRunner) + .postTask(any()); + + CompressibleBitmap compressibleBitmap = + new CompressibleBitmap(bitmap, taskRunner, false, false); + verify(bitmap, never()).compress(any(), anyInt(), any()); + + Assert.assertNotNull(compressibleBitmap.getBitmap()); + } + + @Test public void testCompressAndDiscard() { Bitmap bitmap = Mockito.mock(Bitmap.class); Bitmap alphaBitmap = Mockito.mock(Bitmap.class); @@ -69,7 +89,8 @@ .when(taskRunner) .postTask(any()); - CompressibleBitmap compressibleBitmap = new CompressibleBitmap(bitmap, taskRunner, false); + CompressibleBitmap compressibleBitmap = + new CompressibleBitmap(bitmap, taskRunner, false, true); verify(bitmap, times(1)).compress(any(), eq(100), any()); verify(bitmap, times(1)).extractAlpha(); @@ -91,7 +112,8 @@ .when(taskRunner) .postTask(any()); - CompressibleBitmap compressibleBitmap = new CompressibleBitmap(bitmap, taskRunner, true); + CompressibleBitmap compressibleBitmap = + new CompressibleBitmap(bitmap, taskRunner, true, true); verify(bitmap, times(1)).compress(any(), eq(100), any()); verify(bitmap, times(1)).extractAlpha(); @@ -118,7 +140,8 @@ .when(taskRunner) .postTask(any()); - CompressibleBitmap compressibleBitmap = new CompressibleBitmap(bitmap, taskRunner, false); + CompressibleBitmap compressibleBitmap = + new CompressibleBitmap(bitmap, taskRunner, false, true); verify(bitmap, times(1)).compress(any(), eq(100), any()); verify(bitmap, times(1)).extractAlpha(); @@ -143,7 +166,8 @@ .when(taskRunner) .postTask(any()); - CompressibleBitmap compressibleBitmap = new CompressibleBitmap(bitmap, taskRunner, false); + CompressibleBitmap compressibleBitmap = + new CompressibleBitmap(bitmap, taskRunner, false, true); verify(bitmap, times(1)).compress(any(), eq(100), any()); verify(bitmap, times(1)).extractAlpha(); Assert.assertNull(compressibleBitmap.getBitmap()); @@ -186,7 +210,8 @@ .when(taskRunner) .postTask(any()); - CompressibleBitmap compressibleBitmap = new CompressibleBitmap(bitmap, taskRunner, false); + CompressibleBitmap compressibleBitmap = + new CompressibleBitmap(bitmap, taskRunner, false, true); verify(bitmap, times(1)).compress(any(), eq(100), any()); verify(bitmap, times(1)).extractAlpha(); Assert.assertNull(compressibleBitmap.getBitmap()); @@ -216,7 +241,8 @@ .when(taskRunner) .postTask(any()); - CompressibleBitmap compressibleBitmap = new CompressibleBitmap(bitmap, taskRunner, true); + CompressibleBitmap compressibleBitmap = + new CompressibleBitmap(bitmap, taskRunner, true, true); verify(bitmap, times(1)).compress(any(), eq(100), any()); verify(bitmap, times(1)).extractAlpha(); Assert.assertTrue(compressibleBitmap.lock());
diff --git a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainterTest.java b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainterTest.java index a3b97ce1c..0f2c744 100644 --- a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainterTest.java +++ b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainterTest.java
@@ -291,22 +291,22 @@ FakeShadowBitmapFactory.setBitmaps(bitmapMap); CompressibleBitmap[][] bitmaps = new CompressibleBitmap[3][2]; CompressibleBitmap compressibleBitmap00 = - new CompressibleBitmap(bitmap00, taskRunner, false); + new CompressibleBitmap(bitmap00, taskRunner, false, true); compressibleBitmap00.setIgnoreMissingAlphaForTesting(true); CompressibleBitmap compressibleBitmap10 = - new CompressibleBitmap(bitmap10, taskRunner, false); + new CompressibleBitmap(bitmap10, taskRunner, false, true); compressibleBitmap10.setIgnoreMissingAlphaForTesting(true); CompressibleBitmap compressibleBitmap01 = - new CompressibleBitmap(bitmap01, taskRunner, false); + new CompressibleBitmap(bitmap01, taskRunner, false, true); compressibleBitmap01.setIgnoreMissingAlphaForTesting(true); CompressibleBitmap compressibleBitmap11 = - new CompressibleBitmap(bitmap11, taskRunner, false); + new CompressibleBitmap(bitmap11, taskRunner, false, true); compressibleBitmap11.setIgnoreMissingAlphaForTesting(true); CompressibleBitmap compressibleBitmap20 = - new CompressibleBitmap(bitmap20, taskRunner, false); + new CompressibleBitmap(bitmap20, taskRunner, false, true); compressibleBitmap20.setIgnoreMissingAlphaForTesting(true); CompressibleBitmap compressibleBitmap21 = - new CompressibleBitmap(bitmap21, taskRunner, false); + new CompressibleBitmap(bitmap21, taskRunner, false, true); compressibleBitmap21.setIgnoreMissingAlphaForTesting(true); bitmaps[0][0] = compressibleBitmap00; bitmaps[1][0] = compressibleBitmap10;
diff --git a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java index 702e336e..dd4c2ba 100644 --- a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java +++ b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java
@@ -30,11 +30,11 @@ PlayerFrameCoordinator rootCoordinator = new PlayerFrameCoordinator( RuntimeEnvironment.systemContext, Mockito.mock(PlayerCompositorDelegate.class), Mockito.mock(UnguessableToken.class), 100, 2000, 0, 0, true, null, - Mockito.mock(PlayerGestureListener.class), null, null, null); + Mockito.mock(PlayerGestureListener.class), null, null, null, true); PlayerFrameCoordinator childCoordinator = new PlayerFrameCoordinator( RuntimeEnvironment.systemContext, Mockito.mock(PlayerCompositorDelegate.class), Mockito.mock(UnguessableToken.class), 100, 200, 0, 0, true, null, - Mockito.mock(PlayerGestureListener.class), null, null, null); + Mockito.mock(PlayerGestureListener.class), null, null, null, true); rootCoordinator.addSubFrame(childCoordinator, new Rect(10, 20, 35, 40)); rootCoordinator.getMediator().setLayoutDimensions(100, 200);
diff --git a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java index 2b5e670..2e2e2454 100644 --- a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java +++ b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
@@ -237,8 +237,8 @@ mScroller = new OverScroller(ContextUtils.getApplicationContext()); mGestureListener = new PlayerGestureListener(null, () -> mHasUserInteraction = true, null); Size contentSize = new Size(CONTENT_WIDTH, CONTENT_HEIGHT); - mMediator = new PlayerFrameMediator( - mModel, mCompositorDelegate, mGestureListener, mFrameGuid, contentSize, 0, 0, null); + mMediator = new PlayerFrameMediator(mModel, mCompositorDelegate, mGestureListener, + mFrameGuid, contentSize, 0, 0, null, true); mScaleController = new PlayerFrameScaleController(mModel.get(PlayerFrameProperties.SCALE_MATRIX), mMediator, null, mGestureListener::onScale); @@ -553,27 +553,27 @@ Bitmap bitmap22 = Mockito.mock(Bitmap.class); SequencedTaskRunner mockTaskRunner = Mockito.mock(SequencedTaskRunner.class); CompressibleBitmap compressibleBitmap00 = - new CompressibleBitmap(bitmap00, mockTaskRunner, true); + new CompressibleBitmap(bitmap00, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap10 = - new CompressibleBitmap(bitmap10, mockTaskRunner, true); + new CompressibleBitmap(bitmap10, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap20 = - new CompressibleBitmap(bitmap20, mockTaskRunner, true); + new CompressibleBitmap(bitmap20, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap30 = - new CompressibleBitmap(bitmap30, mockTaskRunner, true); + new CompressibleBitmap(bitmap30, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap01 = - new CompressibleBitmap(bitmap01, mockTaskRunner, true); + new CompressibleBitmap(bitmap01, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap11 = - new CompressibleBitmap(bitmap11, mockTaskRunner, true); + new CompressibleBitmap(bitmap11, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap21 = - new CompressibleBitmap(bitmap21, mockTaskRunner, true); + new CompressibleBitmap(bitmap21, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap31 = - new CompressibleBitmap(bitmap31, mockTaskRunner, true); + new CompressibleBitmap(bitmap31, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap02 = - new CompressibleBitmap(bitmap02, mockTaskRunner, true); + new CompressibleBitmap(bitmap02, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap12 = - new CompressibleBitmap(bitmap12, mockTaskRunner, true); + new CompressibleBitmap(bitmap12, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap22 = - new CompressibleBitmap(bitmap22, mockTaskRunner, true); + new CompressibleBitmap(bitmap22, mockTaskRunner, true, true); CompressibleBitmap[][] expectedBitmapMatrix = new CompressibleBitmap[12][4]; expectedBitmapMatrix[0][0] = compressibleBitmap00; @@ -1370,15 +1370,15 @@ Bitmap bitmap11 = Mockito.mock(Bitmap.class); SequencedTaskRunner mockTaskRunner = Mockito.mock(SequencedTaskRunner.class); CompressibleBitmap compressibleBitmap00 = - new CompressibleBitmap(bitmap00, mockTaskRunner, true); + new CompressibleBitmap(bitmap00, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap10 = - new CompressibleBitmap(bitmap10, mockTaskRunner, true); + new CompressibleBitmap(bitmap10, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap20 = - new CompressibleBitmap(bitmap20, mockTaskRunner, true); + new CompressibleBitmap(bitmap20, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap01 = - new CompressibleBitmap(bitmap01, mockTaskRunner, true); + new CompressibleBitmap(bitmap01, mockTaskRunner, true, true); CompressibleBitmap compressibleBitmap11 = - new CompressibleBitmap(bitmap11, mockTaskRunner, true); + new CompressibleBitmap(bitmap11, mockTaskRunner, true, true); CompressibleBitmap[][] expectedBitmapMatrix = new CompressibleBitmap[12][4]; expectedBitmapMatrix[0][0] = compressibleBitmap00;
diff --git a/components/password_manager/content/browser/content_password_manager_driver_factory.cc b/components/password_manager/content/browser/content_password_manager_driver_factory.cc index efb9c69..1a4ac3ee 100644 --- a/components/password_manager/content/browser/content_password_manager_driver_factory.cc +++ b/components/password_manager/content/browser/content_password_manager_driver_factory.cc
@@ -86,7 +86,10 @@ void ContentPasswordManagerDriverFactory::DidFinishNavigation( content::NavigationHandle* navigation) { - if (!navigation->IsInMainFrame() || navigation->IsSameDocument() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation->IsInPrimaryMainFrame() || navigation->IsSameDocument() || !navigation->HasCommitted()) { return; }
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index 5c20d0d..8c693d3c 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc
@@ -20,6 +20,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_functions.h" +#include "base/notreached.h" #include "base/ranges/algorithm.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" @@ -131,6 +132,12 @@ PasswordStore::PasswordStore() = default; +PasswordStore::PasswordStore(std::unique_ptr<PasswordStoreBackend> backend) + : PasswordStore() { + backend_deleter_ = std::move(backend); + backend_ = backend_deleter_.get(); +} + bool PasswordStore::Init(PrefService* prefs, base::RepeatingClosure sync_enabled_or_disabled_cb) { main_task_runner_ = base::SequencedTaskRunnerHandle::Get(); @@ -449,6 +456,11 @@ base::Unretained(this))); } +void PasswordStore::SetUnsyncedCredentialsDeletionNotifier( + std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier) { + NOTREACHED() << "Platform doesn't support sync!"; +} + PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); } @@ -489,6 +501,122 @@ {base::MayBlock(), base::TaskPriority::USER_VISIBLE}); } +void PasswordStore::ReportMetricsImpl(const std::string& sync_username, + bool custom_passphrase_sync_enabled, + BulkCheckDone bulk_check_done) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; +} + +bool PasswordStore::RemoveStatisticsByOriginAndTimeImpl( + const base::RepeatingCallback<bool(const GURL&)>& origin_filter, + base::Time delete_begin, + base::Time delete_end) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return false; +} + +PasswordStoreChangeList PasswordStore::DisableAutoSignInForOriginsImpl( + const base::RepeatingCallback<bool(const GURL&)>& origin_filter) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return PasswordStoreChangeList(); +} + +std::vector<std::unique_ptr<PasswordForm>> PasswordStore::FillMatchingLogins( + const PasswordFormDigest& form) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return std::vector<std::unique_ptr<PasswordForm>>(); +} + +std::vector<std::unique_ptr<PasswordForm>> +PasswordStore::FillMatchingLoginsByPassword( + const std::u16string& plain_text_password) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return std::vector<std::unique_ptr<PasswordForm>>(); +} + +void PasswordStore::AddSiteStatsImpl(const InteractionsStats& stats) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; +} + +void PasswordStore::RemoveSiteStatsImpl(const GURL& origin_domain) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; +} + +std::vector<InteractionsStats> PasswordStore::GetSiteStatsImpl( + const GURL& origin_domain) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return std::vector<InteractionsStats>(); +} + +PasswordStoreChangeList PasswordStore::AddInsecureCredentialImpl( + const InsecureCredential& insecure_credential) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return PasswordStoreChangeList(); +} + +PasswordStoreChangeList PasswordStore::RemoveInsecureCredentialsImpl( + const std::string& signon_realm, + const std::u16string& username, + RemoveInsecureCredentialsReason reason) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return PasswordStoreChangeList(); +} + +std::vector<InsecureCredential> PasswordStore::GetAllInsecureCredentialsImpl() { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return std::vector<InsecureCredential>(); +} + +std::vector<InsecureCredential> +PasswordStore::GetMatchingInsecureCredentialsImpl( + const std::string& signon_realm) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return std::vector<InsecureCredential>(); +} + +void PasswordStore::AddFieldInfoImpl(const FieldInfo& field_info) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; +} + +std::vector<FieldInfo> PasswordStore::GetAllFieldInfoImpl() { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return std::vector<FieldInfo>(); +} + +void PasswordStore::RemoveFieldInfoByTimeImpl(base::Time remove_begin, + base::Time remove_end) { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; +} + +bool PasswordStore::IsEmpty() { + // TODO(crbug.com/1217070): Move as implementation detail into backend. + LOG(ERROR) << "Called function without implementation: " << __func__; + return false; +} + +base::WeakPtr<syncer::ModelTypeControllerDelegate> +PasswordStore::GetSyncControllerDelegateOnBackgroundSequence() { + NOTREACHED() << "Platform doesn't support sync!"; + return nullptr; +} + void PasswordStore::InvokeAndNotifyAboutInsecureCredentialsChange( base::OnceCallback<PasswordStoreChangeList()> callback) { DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h index 1691ad6..37630a6 100644 --- a/components/password_manager/core/browser/password_store.h +++ b/components/password_manager/core/browser/password_store.h
@@ -69,7 +69,7 @@ virtual base::WeakPtr<UnsyncedCredentialsDeletionNotifier> GetWeakPtr() = 0; }; - PasswordStore(); + explicit PasswordStore(std::unique_ptr<PasswordStoreBackend> backend); // Always call this too on the UI thread. // TODO(crbug.bom/1218413): Move initialization into the core interface, too. @@ -127,7 +127,6 @@ void RemoveObserver(Observer* observer) override; SmartBubbleStatsStore* GetSmartBubbleStatsStore() override; - // Reports usage metrics for the database. |sync_username|, and // |custom_passphrase_sync_enabled|, and |is_under_advanced_protection| // determine some of the UMA stats that may be reported. @@ -181,8 +180,7 @@ // Sets |deletion_notifier_|. Must not pass a nullptr. virtual void SetUnsyncedCredentialsDeletionNotifier( - std::unique_ptr<UnsyncedCredentialsDeletionNotifier> - deletion_notifier) = 0; + std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier); protected: using LoginsTask = base::OnceCallback<LoginsResult()>; @@ -204,6 +202,9 @@ kFailure, }; + // TODO(crbug.com/1217071): Remove when local backend doesn't inherit from + // this class anymore. + PasswordStore(); ~PasswordStore() override; // SmartBubbleStatsStore: @@ -225,64 +226,64 @@ // Synchronous implementation that reports usage metrics. virtual void ReportMetricsImpl(const std::string& sync_username, bool custom_passphrase_sync_enabled, - BulkCheckDone bulk_check_done) = 0; + BulkCheckDone bulk_check_done); // Synchronous implementation to remove the statistics. virtual bool RemoveStatisticsByOriginAndTimeImpl( const base::RepeatingCallback<bool(const GURL&)>& origin_filter, base::Time delete_begin, - base::Time delete_end) = 0; + base::Time delete_end); // Synchronous implementation to disable auto sign-in. virtual PasswordStoreChangeList DisableAutoSignInForOriginsImpl( - const base::RepeatingCallback<bool(const GURL&)>& origin_filter) = 0; + const base::RepeatingCallback<bool(const GURL&)>& origin_filter); // Finds and returns all PasswordForms with the same signon_realm as |form|, // or with a signon_realm that is a PSL-match to that of |form|. virtual std::vector<std::unique_ptr<PasswordForm>> FillMatchingLogins( - const PasswordFormDigest& form) = 0; + const PasswordFormDigest& form); // Finds and returns all not-blocklisted PasswordForms with the specified // |plain_text_password| stored in the credential database. virtual std::vector<std::unique_ptr<PasswordForm>> - FillMatchingLoginsByPassword(const std::u16string& plain_text_password) = 0; + FillMatchingLoginsByPassword(const std::u16string& plain_text_password); // Synchronous implementation for manipulating with statistics. - virtual void AddSiteStatsImpl(const InteractionsStats& stats) = 0; - virtual void RemoveSiteStatsImpl(const GURL& origin_domain) = 0; + virtual void AddSiteStatsImpl(const InteractionsStats& stats); + virtual void RemoveSiteStatsImpl(const GURL& origin_domain); virtual std::vector<InteractionsStats> GetSiteStatsImpl( - const GURL& origin_domain) = 0; + const GURL& origin_domain); // Synchronous implementation for manipulating with information about // insecure credentials. // Returns PasswordStoreChangeList for the updated password forms. virtual PasswordStoreChangeList AddInsecureCredentialImpl( - const InsecureCredential& insecure_credential) = 0; + const InsecureCredential& insecure_credential); virtual PasswordStoreChangeList RemoveInsecureCredentialsImpl( const std::string& signon_realm, const std::u16string& username, - RemoveInsecureCredentialsReason reason) = 0; - virtual std::vector<InsecureCredential> GetAllInsecureCredentialsImpl() = 0; + RemoveInsecureCredentialsReason reason); + virtual std::vector<InsecureCredential> GetAllInsecureCredentialsImpl(); virtual std::vector<InsecureCredential> GetMatchingInsecureCredentialsImpl( - const std::string& signon_realm) = 0; + const std::string& signon_realm); // Synchronous implementation for manipulating with information about field // info. - virtual void AddFieldInfoImpl(const FieldInfo& field_info) = 0; - virtual std::vector<FieldInfo> GetAllFieldInfoImpl() = 0; + virtual void AddFieldInfoImpl(const FieldInfo& field_info); + virtual std::vector<FieldInfo> GetAllFieldInfoImpl(); virtual void RemoveFieldInfoByTimeImpl(base::Time remove_begin, - base::Time remove_end) = 0; + base::Time remove_end); // Synchronous implementation provided by subclasses to check whether the // store is empty. - virtual bool IsEmpty() = 0; + virtual bool IsEmpty(); // Returns the sync controller delegate for syncing passwords. It must be // called on the background sequence. // TODO(crbug.bom/1226042): Remove this after fully switching to the // PasswordStoreInterface. virtual base::WeakPtr<syncer::ModelTypeControllerDelegate> - GetSyncControllerDelegateOnBackgroundSequence() = 0; + GetSyncControllerDelegateOnBackgroundSequence(); // Invokes callback and notifies observers if there was a change to the list // of insecure passwords. It also informs Sync about the updated password @@ -302,6 +303,7 @@ // TODO(crbug.com/1217071): Make private std::unique_ptr as soon as the // backend is passed into the store instead of it being the store(_impl). PasswordStoreBackend* backend_ = nullptr; + private: using StatsResult = std::vector<InteractionsStats>; using StatsTask = base::OnceCallback<StatsResult()>; @@ -412,6 +414,16 @@ // background sequence. std::unique_ptr<PasswordForm> GetLoginImpl(const PasswordForm& primary_key); + // The local backend is currently a ref-counted type because it still inherits + // from PasswordStore and this would be a self reference. So, if `this` is an + // instance of PasswordStoreImpl, this member is not used. + // + // If the backend is injected via the public constructor, this backend_deleter + // owns the instance and deletes it on destruction. Once backend_ is a + // unique_ptr, too, this deleter can simply be removed. + // TODO(crbug.com/1217071): Remove once once backend_ is a unique_ptr. + std::unique_ptr<PasswordStoreBackend> backend_deleter_ = nullptr; + // TaskRunner for tasks that run on the main sequence (usually the UI thread). scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
diff --git a/components/password_manager/core/browser/password_store_impl_unittest.cc b/components/password_manager/core/browser/password_store_impl_unittest.cc index c0189fb6..c27c5d8 100644 --- a/components/password_manager/core/browser/password_store_impl_unittest.cc +++ b/components/password_manager/core/browser/password_store_impl_unittest.cc
@@ -13,6 +13,7 @@ #include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/mock_callback.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "components/os_crypt/os_crypt_mocker.h" @@ -32,6 +33,27 @@ namespace { +constexpr const char kTestWebRealm1[] = "https://one.example.com/"; +constexpr const char kTestWebOrigin1[] = "https://one.example.com/origin"; +constexpr const char kTestWebRealm2[] = "https://two.example.com/"; +constexpr const char kTestWebOrigin2[] = "https://two.example.com/origin"; +constexpr const char kTestWebRealm3[] = "https://three.example.com/"; +constexpr const char kTestWebOrigin3[] = "https://three.example.com/origin"; +constexpr const char kTestAndroidRealm1[] = + "android://hash@com.example.android/"; +constexpr const char kTestAndroidRealm2[] = + "android://hash@com.example.two.android/"; +constexpr const char kTestAndroidRealm3[] = + "android://hash@com.example.three.android/"; +constexpr const time_t kTestLastUsageTime = 1546300800; // 00:00 Jan 1 2019 UTC + +class MockPasswordStoreConsumer : public PasswordStoreConsumer { + MOCK_METHOD(void, + OnGetPasswordStoreResults, + (std::vector<std::unique_ptr<PasswordForm>> results), + (override)); +}; + class MockPasswordStoreBackendTester { public: MOCK_METHOD(void, HandleChanges, (const PasswordStoreChangeList&)); @@ -266,4 +288,47 @@ RunUntilIdle(); } +TEST_F(PasswordStoreImplTest, GetAllLoginsAsync) { + static constexpr PasswordFormData kTestCredentials[] = { + {PasswordForm::Scheme::kHtml, kTestAndroidRealm1, "", "", u"", u"", u"", + u"username_value_1", u"", kTestLastUsageTime, 1}, + {PasswordForm::Scheme::kHtml, kTestAndroidRealm2, "", "", u"", u"", u"", + u"username_value_2", u"", kTestLastUsageTime, 1}, + {PasswordForm::Scheme::kHtml, kTestAndroidRealm3, "", "", u"", u"", u"", + u"username_value_3", u"", kTestLastUsageTime, 1}, + {PasswordForm::Scheme::kHtml, kTestWebRealm1, kTestWebOrigin1, "", u"", + u"", u"", u"username_value_4", u"", kTestLastUsageTime, 1}, + // A PasswordFormData with nullptr as the username_value will be converted + // in a blocklisted PasswordForm in FillPasswordFormWithData(). + {PasswordForm::Scheme::kHtml, kTestWebRealm2, kTestWebOrigin2, "", u"", + u"", u"", nullptr, u"", kTestLastUsageTime, 1}, + {PasswordForm::Scheme::kHtml, kTestWebRealm3, kTestWebOrigin3, "", u"", + u"", u"", nullptr, u"", kTestLastUsageTime, 1}}; + PasswordStoreBackend* backend = Initialize(); + + // Populate store with test credentials. + std::vector<std::unique_ptr<PasswordForm>> all_credentials; + base::MockCallback<PasswordStoreChangeListReply> reply; + EXPECT_CALL(reply, Run).Times(6); + for (const auto& test_credential : kTestCredentials) { + all_credentials.push_back(FillPasswordFormWithData(test_credential)); + // TODO(crbug.com/1217071): Call AddLoginAsync once it is implemented. + // store()->AddLogin(*all_credentials.back()); + backend->AddLoginAsync(*all_credentials.back(), reply.Get()); + } + RunUntilIdle(); + + // Verify that the store returns all test credentials. + MockPasswordStoreConsumer mock_consumer; + std::vector<std::unique_ptr<PasswordForm>> expected_results; + for (const auto& credential : all_credentials) + expected_results.push_back(std::make_unique<PasswordForm>(*credential)); + base::MockCallback<LoginsReply> mock_reply; + EXPECT_CALL(mock_reply, + Run(UnorderedPasswordFormElementsAre(&expected_results))); + backend->GetAllLoginsAsync(mock_reply.Get()); + + RunUntilIdle(); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc index 21c82bd..751a637 100644 --- a/components/password_manager/core/browser/password_store_unittest.cc +++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -32,6 +32,7 @@ #include "components/password_manager/core/browser/password_reuse_detector.h" #include "components/password_manager/core/browser/password_reuse_manager.h" #include "components/password_manager/core/browser/password_store.h" +#include "components/password_manager/core/browser/password_store_backend.h" #include "components/password_manager/core/browser/password_store_consumer.h" #include "components/password_manager/core/browser/password_store_impl.h" #include "components/password_manager/core/browser/password_store_signin_notifier.h" @@ -174,6 +175,55 @@ MockMetadataStore metadata_store_; }; +class MockPasswordStoreBackend : public PasswordStoreBackend { + public: + // TODO(crbug.bom/1226042): Rename this to Init after PasswordStoreImpl no + // longer inherits PasswordStore. + MOCK_METHOD(void, + InitBackend, + (RemoteChangesReceived remote_form_changes_received, + base::RepeatingClosure sync_enabled_or_disabled_cb, + base::OnceCallback<void(bool)> completion), + (override)); + + MOCK_METHOD(void, GetAllLoginsAsync, (LoginsReply callback), (override)); + MOCK_METHOD(void, + GetAutofillableLoginsAsync, + (LoginsReply callback), + (override)); + MOCK_METHOD(void, + FillMatchingLoginsAsync, + (LoginsReply callback, + const std::vector<PasswordFormDigest>& forms), + (override)); + MOCK_METHOD(void, + AddLoginAsync, + (const PasswordForm& form, PasswordStoreChangeListReply callback), + (override)); + MOCK_METHOD(void, + UpdateLoginAsync, + (const PasswordForm& form, PasswordStoreChangeListReply callback), + (override)); + MOCK_METHOD(void, + RemoveLoginAsync, + (const PasswordForm& form, PasswordStoreChangeListReply callback), + (override)); + MOCK_METHOD(void, + RemoveLoginsByURLAndTimeAsync, + (const base::RepeatingCallback<bool(const GURL&)>& url_filter, + base::Time delete_begin, + base::Time delete_end, + base::OnceCallback<void(bool)> sync_completion, + PasswordStoreChangeListReply callback), + (override)); + MOCK_METHOD(void, + RemoveLoginsCreatedBetweenAsync, + (base::Time delete_begin, + base::Time delete_end, + PasswordStoreChangeListReply callback), + (override)); +}; + PasswordForm MakePasswordForm(const std::string& signon_realm) { PasswordForm form; form.url = GURL("http://www.origin.com"); @@ -939,6 +989,40 @@ } } +TEST_F(PasswordStoreTest, DelegatesGetAllLoginsToBackend) { + scoped_refptr<PasswordStore> store; + MockPasswordStoreBackend* mock_backend; + { // This scope ensures nobody tries to use `backend` after its move. + auto backend = std::make_unique<MockPasswordStoreBackend>(); + mock_backend = backend.get(); + store = new PasswordStore(std::move(backend)); + } + store->Init(nullptr); + + MockPasswordStoreConsumer mock_consumer; + EXPECT_CALL(*mock_backend, GetAllLoginsAsync(_)); + store->GetAllLogins(&mock_consumer); + WaitForPasswordStore(); + store->ShutdownOnUIThread(); +} + +TEST_F(PasswordStoreTest, DelegatesGetAutofillableLoginsToBackend) { + scoped_refptr<PasswordStore> store; + MockPasswordStoreBackend* mock_backend; + { // This scope ensures nobody tries to use `backend` after its move. + auto backend = std::make_unique<MockPasswordStoreBackend>(); + mock_backend = backend.get(); + store = new PasswordStore(std::move(backend)); + } + store->Init(nullptr); + + MockPasswordStoreConsumer mock_consumer; + EXPECT_CALL(*mock_backend, GetAutofillableLoginsAsync(_)); + store->GetAutofillableLogins(&mock_consumer); + WaitForPasswordStore(); + store->ShutdownOnUIThread(); +} + TEST_F(PasswordStoreTest, GetAllLogins) { static constexpr PasswordFormData kTestCredentials[] = { {PasswordForm::Scheme::kHtml, kTestAndroidRealm1, "", "", u"", u"", u"", @@ -1043,6 +1127,15 @@ } TEST_F(PasswordStoreTest, GetAllLoginsWithAffiliationAndBrandingInformation) { + scoped_refptr<PasswordStore> store; + MockPasswordStoreBackend* mock_backend; + { // This scope ensures nobody tries to use `backend` after its move. + auto backend = std::make_unique<MockPasswordStoreBackend>(); + mock_backend = backend.get(); + store = new PasswordStore(std::move(backend)); + } + store->Init(nullptr); + static constexpr PasswordFormData kTestCredentials[] = { {PasswordForm::Scheme::kHtml, kTestAndroidRealm1, "", "", u"", u"", u"", u"username_value_1", u"", kTestLastUsageTime, 1}, @@ -1059,13 +1152,9 @@ {PasswordForm::Scheme::kHtml, kTestWebRealm3, kTestWebOrigin3, "", u"", u"", u"", nullptr, u"", kTestLastUsageTime, 1}}; - scoped_refptr<PasswordStoreImpl> store = CreatePasswordStore(); - store->Init(nullptr); - std::vector<std::unique_ptr<PasswordForm>> all_credentials; for (const auto& test_credential : kTestCredentials) { all_credentials.push_back(FillPasswordFormWithData(test_credential)); - store->AddLogin(*all_credentials.back()); } MockPasswordStoreConsumer mock_consumer; @@ -1098,6 +1187,11 @@ EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef( UnorderedPasswordFormElementsAre(&expected_results))); + LoginsReply callback; + EXPECT_CALL(*mock_backend, GetAllLoginsAsync) + .WillOnce([&all_credentials](LoginsReply callback) { + std::move(callback).Run(std::move(all_credentials)); + }); store->GetAllLoginsWithAffiliationAndBrandingInformation(&mock_consumer); // Since GetAutofillableLoginsWithAffiliationAndBrandingInformation
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc index 305600a..397c474 100644 --- a/components/password_manager/core/common/password_manager_features.cc +++ b/components/password_manager/core/common/password_manager_features.cc
@@ -107,13 +107,7 @@ // Enables password reuse detection. const base::Feature kPasswordReuseDetectionEnabled = { - "PasswordReuseDetectionEnabled", -#if defined(OS_IOS) - base::FEATURE_DISABLED_BY_DEFAULT -#else - base::FEATURE_ENABLED_BY_DEFAULT -#endif // defined(OS_IOS) -}; + "PasswordReuseDetectionEnabled", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables password scripts fetching for the |PasswordChangeInSettings| feature. const base::Feature kPasswordScriptsFetching = {
diff --git a/components/payments/content/payment_credential.cc b/components/payments/content/payment_credential.cc index 4843621..edf253f 100644 --- a/components/payments/content/payment_credential.cc +++ b/components/payments/content/payment_credential.cc
@@ -152,8 +152,11 @@ void PaymentCredential::DidStartNavigation( content::NavigationHandle* navigation_handle) { // Reset the service before the page navigates away. + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. if (!navigation_handle->IsSameDocument() && - (navigation_handle->IsInMainFrame() || + (navigation_handle->IsInPrimaryMainFrame() || navigation_handle->GetPreviousRenderFrameHostId() == initiator_frame_routing_id_)) { Reset();
diff --git a/components/payments/content/payment_credential_enrollment_controller.cc b/components/payments/content/payment_credential_enrollment_controller.cc index d234a7c..9ebeb16 100644 --- a/components/payments/content/payment_credential_enrollment_controller.cc +++ b/components/payments/content/payment_credential_enrollment_controller.cc
@@ -126,8 +126,11 @@ content::NavigationHandle* navigation_handle) { // Close the dialog if either the initiator frame (which may be an iframe) or // main frame was navigated away. + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. if (!navigation_handle->IsSameDocument() && - (navigation_handle->IsInMainFrame() || + (navigation_handle->IsInPrimaryMainFrame() || navigation_handle->GetPreviousRenderFrameHostId() == initiator_frame_routing_id_)) { CloseDialog();
diff --git a/components/payments/content/payment_request_web_contents_manager.cc b/components/payments/content/payment_request_web_contents_manager.cc index d7a55cb..302b6e5 100644 --- a/components/payments/content/payment_request_web_contents_manager.cc +++ b/components/payments/content/payment_request_web_contents_manager.cc
@@ -43,7 +43,10 @@ content::NavigationHandle* navigation_handle) { // Navigations that are not in the main frame (e.g. iframe) or that are in the // same document do not close the Payment Request. Disregard those. - if (!navigation_handle->IsInMainFrame() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || navigation_handle->IsSameDocument()) { return; }
diff --git a/components/permissions/android/permission_dialog_delegate.cc b/components/permissions/android/permission_dialog_delegate.cc index 4de29c5..6e54ec9 100644 --- a/components/permissions/android/permission_dialog_delegate.cc +++ b/components/permissions/android/permission_dialog_delegate.cc
@@ -111,7 +111,10 @@ void PermissionDialogDelegate::DidFinishNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!navigation_handle->IsInPrimaryMainFrame() || !navigation_handle->HasCommitted() || navigation_handle->IsSameDocument()) { return;
diff --git a/components/policy/core/common/cloud/component_cloud_policy_store.cc b/components/policy/core/common/cloud/component_cloud_policy_store.cc index cf8a28ac..1c29ff9 100644 --- a/components/policy/core/common/cloud/component_cloud_policy_store.cc +++ b/components/policy/core/common/cloud/component_cloud_policy_store.cc
@@ -15,6 +15,8 @@ #include "base/logging.h" #include "base/macros.h" #include "base/sequenced_task_runner.h" +#include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/values.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" @@ -168,9 +170,12 @@ } em::ExternalPolicyData payload; em::PolicyData policy_data; - if (!ValidatePolicy(ns, std::move(proto), &policy_data, &payload)) { - // The policy fetch response is corrupted. Note that the error details - // are logged by ValidatePolicy(). + std::string policy_error; + if (!ValidatePolicy(ns, std::move(proto), &policy_data, &payload, + &policy_error)) { + // The policy fetch response is corrupted. + LOG(ERROR) << "Discarding policy for component " << ns.component_id + << " due to policy validation failure: " << policy_error; Delete(ns); continue; } @@ -183,9 +188,11 @@ continue; } PolicyMap policy; - if (!ValidateData(data, payload.secure_hash(), &policy)) { - // The data for this proto is corrupted. Note that the error details - // are logged by ValidateData(). + std::string data_error; + if (!ValidateData(data, payload.secure_hash(), &policy, &data_error)) { + // The data for this proto is corrupted. + LOG(ERROR) << "Discarding policy for component " << ns.component_id + << " due to data validation failure: " << data_error; Delete(ns); continue; } @@ -211,11 +218,10 @@ // |serialized_policy| has already been validated; validate the data now. PolicyMap policy; - if (!ValidateData(data, secure_hash, &policy)) { - // TODO(emaxx): Incorporate the validation error message here and in other - // contextual log messages. - DLOG(ERROR) << "Discarding policy for component " << ns.component_id - << " due to validation failure."; + std::string error; + if (!ValidateData(data, secure_hash, &policy, &error)) { + LOG(ERROR) << "Discarding policy for component " << ns.component_id + << " due to data validation failure: " << error; return false; } @@ -306,20 +312,23 @@ const PolicyNamespace& ns, std::unique_ptr<em::PolicyFetchResponse> proto, em::PolicyData* policy_data, - em::ExternalPolicyData* payload) { + em::ExternalPolicyData* payload, + std::string* error) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (domain_constants_->domain != ns.domain) + if (domain_constants_->domain != ns.domain) { + *error = "Domains do not match."; return false; + } if (ns.component_id.empty()) { - LOG(ERROR) << "Empty component id."; + *error = "Empty component id."; return false; } if (username_.empty() || dm_token_.empty() || device_id_.empty() || public_key_.empty() || public_key_version_ == -1) { - LOG(WARNING) << "Credentials are not loaded yet."; + *error = "Credentials are not loaded yet."; return false; } @@ -344,17 +353,22 @@ validator->ValidatePayload(); validator->ValidateSignature(public_key_); validator->RunValidation(); - if (!validator->success()) + if (!validator->success()) { + *error = base::StrCat( + {"Unsuccessful validation with Status ", + CloudPolicyValidatorBase::StatusToString(validator->status()), "."}); return false; + } if (!validator->policy_data()->has_public_key_version()) { - LOG(ERROR) << "Public key version missing."; + *error = "Public key version missing."; return false; } if (validator->policy_data()->public_key_version() != public_key_version_) { - LOG(ERROR) << "Wrong public key version " - << validator->policy_data()->public_key_version() - << " - expected " << public_key_version_ << "."; + *error = base::StrCat( + {"Wrong public key version ", + base::NumberToString(validator->policy_data()->public_key_version()), + " - expected ", base::NumberToString(public_key_version_), "."}); return false; } @@ -364,15 +378,15 @@ // policy, or that the policy has been removed. if (data->has_download_url() && !data->download_url().empty()) { if (!GURL(data->download_url()).is_valid()) { - LOG(ERROR) << "Invalid URL: " << data->download_url() << " ."; + *error = base::StrCat({"Invalid URL: ", data->download_url(), " ."}); return false; } if (!data->has_secure_hash() || data->secure_hash().empty()) { - LOG(ERROR) << "Secure hash missing."; + *error = "Secure hash missing."; return false; } } else if (data->has_secure_hash()) { - LOG(ERROR) << "URL missing."; + *error = "URL missing."; return false; } @@ -385,26 +399,29 @@ bool ComponentCloudPolicyStore::ValidateData(const std::string& data, const std::string& secure_hash, - PolicyMap* policy) { + PolicyMap* policy, + std::string* error) { if (crypto::SHA256HashString(data) != secure_hash) { - LOG(ERROR) << "The received data doesn't match the expected hash."; + *error = "The received data doesn't match the expected hash."; return false; } - return ParsePolicy(data, policy); + return ParsePolicy(data, policy, error); } bool ComponentCloudPolicyStore::ParsePolicy(const std::string& data, - PolicyMap* policy) { + PolicyMap* policy, + std::string* error) { base::JSONReader::ValueWithError value_with_error = base::JSONReader::ReadAndReturnValueWithError( data, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS); if (!value_with_error.value) { - LOG(ERROR) << "Invalid JSON blob: " << value_with_error.error_message; + *error = + base::StrCat({"Invalid JSON blob: ", value_with_error.error_message}); return false; } base::Value json = std::move(value_with_error.value.value()); if (!json.is_dict()) { - LOG(ERROR) << "The JSON blob is not a dictionary."; + *error = "The JSON blob is not a dictionary."; return false; } @@ -417,15 +434,15 @@ const std::string& policy_name = it.first; base::Value description = std::move(it.second); if (!description.is_dict()) { - LOG(ERROR) << "The JSON blob dictionary value is not a dictionary."; + *error = "The JSON blob dictionary value is not a dictionary."; return false; } absl::optional<base::Value> value = description.ExtractKey(kValue); if (!value.has_value()) { - LOG(ERROR) - << "The JSON blob dictionary value doesn't contain the required " - << kValue << " field."; + *error = base::StrCat( + {"The JSON blob dictionary value doesn't contain the required ", + kValue, " field."}); return false; }
diff --git a/components/policy/core/common/cloud/component_cloud_policy_store.h b/components/policy/core/common/cloud/component_cloud_policy_store.h index 2ab7fd5..f3551d0 100644 --- a/components/policy/core/common/cloud/component_cloud_policy_store.h +++ b/components/policy/core/common/cloud/component_cloud_policy_store.h
@@ -133,7 +133,8 @@ const PolicyNamespace& ns, std::unique_ptr<enterprise_management::PolicyFetchResponse> proto, enterprise_management::PolicyData* policy_data, - enterprise_management::ExternalPolicyData* payload); + enterprise_management::ExternalPolicyData* payload, + std::string* error); private: // Validates the JSON policy serialized in |data|, and verifies its hash @@ -141,11 +142,14 @@ // parsed policies in |policy|. bool ValidateData(const std::string& data, const std::string& secure_hash, - PolicyMap* policy); + PolicyMap* policy, + std::string* error); // Parses the JSON policy in |data| into |policy|, and returns true if the // parse was successful. - bool ParsePolicy(const std::string& data, PolicyMap* policy); + bool ParsePolicy(const std::string& data, + PolicyMap* policy, + std::string* error); Delegate* const delegate_; ResourceCache* const cache_;
diff --git a/components/policy/core/common/cloud/component_cloud_policy_store_unittest.cc b/components/policy/core/common/cloud/component_cloud_policy_store_unittest.cc index c67d0d3..08d88d82 100644 --- a/components/policy/core/common/cloud/component_cloud_policy_store_unittest.cc +++ b/components/policy/core/common/cloud/component_cloud_policy_store_unittest.cc
@@ -146,13 +146,15 @@ } void StoreTestPolicyWithNamespace(ComponentCloudPolicyStore* store, const PolicyNamespace& ns) { + std::string error; EXPECT_TRUE(store->ValidatePolicy(ns, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated()); EXPECT_TRUE(store->Store(ns, CreateSerializedResponse(), CreatePolicyData().get(), TestPolicyHash(), kTestPolicy)); + EXPECT_EQ(std::string(), error); Mock::VerifyAndClearExpectations(&store_delegate_); EXPECT_TRUE(store->policy().Equals(expected_bundle_)); EXPECT_FALSE(LoadCacheExtensionsSubkeys().empty()); @@ -183,12 +185,14 @@ TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicy) { em::PolicyData policy_data; em::ExternalPolicyData payload; + std::string error; EXPECT_TRUE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), - &policy_data, &payload)); + &policy_data, &payload, &error)); EXPECT_EQ(dm_protocol::kChromeExtensionPolicyType, policy_data.policy_type()); EXPECT_EQ(kTestExtension, policy_data.settings_entity_id()); EXPECT_EQ(kTestDownload, payload.download_url()); EXPECT_EQ(TestPolicyHash(), payload.secure_hash()); + EXPECT_EQ(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongTimestamp) { @@ -201,83 +205,106 @@ (base::Time() + base::TimeDelta::FromDays(1)).ToJavaTime(); CHECK_GT(PolicyBuilder::kFakeTimestamp, kPastTimestamp); builder_.policy_data().set_timestamp(kPastTimestamp); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongUser) { builder_.policy_data().set_username("anotheruser@example.com"); builder_.policy_data().set_gaia_id("another-gaia-id"); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongDMToken) { builder_.policy_data().set_request_token("notmytoken"); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongDeviceId) { builder_.policy_data().set_device_id("invalid"); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyBadType) { builder_.policy_data().set_policy_type(dm_protocol::kChromeUserPolicyType); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongNamespace) { + std::string error; EXPECT_FALSE(store_->ValidatePolicy( PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "nosuchid"), CreateResponse(), - nullptr /* policy_data */, nullptr /* payload */)); + nullptr /* policy_data */, nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyNoSignature) { builder_.UnsetSigningKey(); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyBadSignature) { std::unique_ptr<em::PolicyFetchResponse> response = CreateResponse(); response->set_policy_data_signature("invalid"); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, std::move(response), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyEmptyComponentId) { builder_.policy_data().set_settings_entity_id(std::string()); + std::string error; EXPECT_FALSE(store_->ValidatePolicy( PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, std::string()), - CreateResponse(), nullptr /* policy_data */, nullptr /* payload */)); + CreateResponse(), nullptr /* policy_data */, nullptr /* payload */, + &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongPublicKey) { // Test against a policy signed with a wrong key. builder_.SetSigningKey(*PolicyBuilder::CreateTestOtherSigningKey()); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongPublicKeyVersion) { // Test against a policy containing wrong public key version. builder_.policy_data().set_public_key_version( PolicyBuilder::kFakePublicKeyVersion + 1); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyDifferentPublicKey) { @@ -286,40 +313,50 @@ builder_.SetSigningKey(*PolicyBuilder::CreateTestOtherSigningKey()); builder_.policy_data().set_public_key_version( PolicyBuilder::kFakePublicKeyVersion + 1); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyBadDownloadUrl) { builder_.payload().set_download_url("invalidurl"); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyEmptyDownloadUrl) { builder_.payload().clear_download_url(); builder_.payload().clear_secure_hash(); + std::string error; // This is valid; it's how "no policy" is signalled to the client. EXPECT_TRUE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_EQ(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyBadPayload) { builder_.clear_payload(); builder_.policy_data().set_policy_value("broken"); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidateNoCredentials) { store_ = CreateStore(); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidateNoCredentialsUser) { @@ -328,9 +365,11 @@ PolicyBuilder::kFakeToken, PolicyBuilder::kFakeDeviceId, public_key_, PolicyBuilder::kFakePublicKeyVersion); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidateNoCredentialsDMToken) { @@ -339,9 +378,11 @@ PolicyBuilder::kFakeUsername, PolicyBuilder::kFakeGaiaId, std::string() /* dm_token */, PolicyBuilder::kFakeDeviceId, public_key_, PolicyBuilder::kFakePublicKeyVersion); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidateNoCredentialsDeviceId) { @@ -350,9 +391,11 @@ PolicyBuilder::kFakeGaiaId, PolicyBuilder::kFakeToken, std::string() /* device_id */, public_key_, PolicyBuilder::kFakePublicKeyVersion); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidateNoCredentialsPublicKey) { @@ -361,9 +404,11 @@ PolicyBuilder::kFakeUsername, PolicyBuilder::kFakeGaiaId, PolicyBuilder::kFakeToken, PolicyBuilder::kFakeDeviceId, std::string() /* public_key */, PolicyBuilder::kFakePublicKeyVersion); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(kTestPolicyNS, CreateResponse(), nullptr /* policy_data */, - nullptr /* payload */)); + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, ValidateNoCredentialsPublicKeyVersion) { @@ -436,23 +481,35 @@ store_ = CreateStore(dm_protocol::kChromeMachineLevelExtensionCloudPolicyType); + std::string error; EXPECT_FALSE(store_->ValidatePolicy(ns_chrome, CreateResponse(), - nullptr /*policy_data*/, - nullptr /*payload*/)); + nullptr /* policy_data */, + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); EXPECT_FALSE(store_->ValidatePolicy(ns_signin_extension, CreateResponse(), - nullptr, nullptr)); + nullptr /* policy_data */, + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); store_ = CreateStore(dm_protocol::kChromeSigninExtensionPolicyType); - EXPECT_FALSE( - store_->ValidatePolicy(ns_chrome, CreateResponse(), nullptr, nullptr)); - EXPECT_FALSE( - store_->ValidatePolicy(ns_extension, CreateResponse(), nullptr, nullptr)); + EXPECT_FALSE(store_->ValidatePolicy(ns_chrome, CreateResponse(), + nullptr /* policy_data */, + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); + EXPECT_FALSE(store_->ValidatePolicy(ns_extension, CreateResponse(), + nullptr /* policy_data */, + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); store_ = CreateStore(dm_protocol::kChromeExtensionPolicyType); - EXPECT_FALSE( - store_->ValidatePolicy(ns_chrome, CreateResponse(), nullptr, nullptr)); + EXPECT_FALSE(store_->ValidatePolicy(ns_chrome, CreateResponse(), + nullptr /* policy_data */, + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); EXPECT_FALSE(store_->ValidatePolicy(ns_signin_extension, CreateResponse(), - nullptr, nullptr)); + nullptr /* policy_data */, + nullptr /* payload */, &error)); + EXPECT_NE(std::string(), error); } TEST_F(ComponentCloudPolicyStoreTest, StoreAndLoad) {
diff --git a/components/policy/core/common/cloud/component_cloud_policy_updater.cc b/components/policy/core/common/cloud/component_cloud_policy_updater.cc index d9b0d7d..f419296 100644 --- a/components/policy/core/common/cloud/component_cloud_policy_updater.cc +++ b/components/policy/core/common/cloud/component_cloud_policy_updater.cc
@@ -76,8 +76,11 @@ // Validate the policy before doing anything else. auto policy_data = std::make_unique<em::PolicyData>(); em::ExternalPolicyData data; - if (!store_->ValidatePolicy(ns, std::move(response), policy_data.get(), - &data)) { + std::string error; + if (!store_->ValidatePolicy(ns, std::move(response), policy_data.get(), &data, + &error)) { + LOG(ERROR) << "Discarding policy for component " << ns.component_id + << " due to policy validation failure: " << error; return; }
diff --git a/components/policy/core/common/cloud/device_management_service.cc b/components/policy/core/common/cloud/device_management_service.cc index 80f31f8..f26b7e4c78 100644 --- a/components/policy/core/common/cloud/device_management_service.cc +++ b/components/policy/core/common/cloud/device_management_service.cc
@@ -22,6 +22,7 @@ #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "url/gurl.h" namespace em = enterprise_management;
diff --git a/components/policy/core/common/cloud/device_management_service_unittest.cc b/components/policy/core/common/cloud/device_management_service_unittest.cc index 4536ab7..70adb8e 100644 --- a/components/policy/core/common/cloud/device_management_service_unittest.cc +++ b/components/policy/core/common/cloud/device_management_service_unittest.cc
@@ -29,6 +29,7 @@ #include "net/http/http_response_headers.h" #include "net/http/http_util.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "services/network/test/test_url_loader_factory.h" #include "services/network/test/test_utils.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/policy/core/common/cloud/dmserver_job_configurations.cc b/components/policy/core/common/cloud/dmserver_job_configurations.cc index 009d1d09..59ba544 100644 --- a/components/policy/core/common/cloud/dmserver_job_configurations.cc +++ b/components/policy/core/common/cloud/dmserver_job_configurations.cc
@@ -9,6 +9,7 @@ #include "components/policy/core/common/cloud/cloud_policy_constants.h" #include "net/base/url_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" +#include "url/gurl.h" namespace em = enterprise_management;
diff --git a/components/policy/core/common/cloud/dmserver_job_configurations.h b/components/policy/core/common/cloud/dmserver_job_configurations.h index 5518100..36eed2e 100644 --- a/components/policy/core/common/cloud/dmserver_job_configurations.h +++ b/components/policy/core/common/cloud/dmserver_job_configurations.h
@@ -16,6 +16,7 @@ #include "components/policy/policy_export.h" #include "components/policy/proto/cloud_policy.pb.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "url/gurl.h" namespace network { class SharedURLLoaderFactory;
diff --git a/components/policy/core/common/cloud/external_policy_data_fetcher.cc b/components/policy/core/common/cloud/external_policy_data_fetcher.cc index a10da29..34db6c7 100644 --- a/components/policy/core/common/cloud/external_policy_data_fetcher.cc +++ b/components/policy/core/common/cloud/external_policy_data_fetcher.cc
@@ -19,6 +19,7 @@ #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" #include "services/network/public/cpp/simple_url_loader_stream_consumer.h" +#include "services/network/public/mojom/url_response_head.mojom.h" namespace policy {
diff --git a/components/policy/core/common/cloud/reporting_job_configuration_base.cc b/components/policy/core/common/cloud/reporting_job_configuration_base.cc index 1c2ec11..4b97ea3 100644 --- a/components/policy/core/common/cloud/reporting_job_configuration_base.cc +++ b/components/policy/core/common/cloud/reporting_job_configuration_base.cc
@@ -22,7 +22,9 @@ #include "components/version_info/version_info.h" #include "google_apis/google_api_keys.h" #include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "url/gurl.h" namespace policy {
diff --git a/components/policy/core/common/cloud/user_info_fetcher.cc b/components/policy/core/common/cloud/user_info_fetcher.cc index b71afe7..749456c 100644 --- a/components/policy/core/common/cloud/user_info_fetcher.cc +++ b/components/policy/core/common/cloud/user_info_fetcher.cc
@@ -17,6 +17,7 @@ #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "url/gurl.h" namespace {
diff --git a/components/policy/test_support/BUILD.gn b/components/policy/test_support/BUILD.gn index 1d07772..5c660f1d 100644 --- a/components/policy/test_support/BUILD.gn +++ b/components/policy/test_support/BUILD.gn
@@ -64,6 +64,9 @@ deps = [ ":test_support", "//chrome/test:test_support", + "//services/network:test_support", + "//services/network/public/cpp", + "//services/network/public/mojom", "//third_party/abseil-cpp:absl", ] }
diff --git a/components/policy/test_support/DEPS b/components/policy/test_support/DEPS index dee9ca8..931c4dc 100644 --- a/components/policy/test_support/DEPS +++ b/components/policy/test_support/DEPS
@@ -8,6 +8,7 @@ "+crypto", "+net", "+services/network/public/cpp", + "+services/network/public/mojom", "+services/network/test", "+third_party/re2", ]
diff --git a/components/policy/test_support/embedded_policy_test_server_test_base.cc b/components/policy/test_support/embedded_policy_test_server_test_base.cc index 2afa4bb4..597768e9 100644 --- a/components/policy/test_support/embedded_policy_test_server_test_base.cc +++ b/components/policy/test_support/embedded_policy_test_server_test_base.cc
@@ -16,6 +16,7 @@ #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" +#include "services/network/public/mojom/url_response_head.mojom.h" #include "services/network/test/test_shared_url_loader_factory.h" using enterprise_management::DeviceManagementResponse;
diff --git a/components/search_engines/template_url_data_util.cc b/components/search_engines/template_url_data_util.cc index 5bd88c1..8c2255c 100644 --- a/components/search_engines/template_url_data_util.cc +++ b/components/search_engines/template_url_data_util.cc
@@ -102,9 +102,8 @@ const base::ListValue* alternate_urls = nullptr; if (dict.GetList(DefaultSearchManager::kAlternateURLs, &alternate_urls)) { for (const auto& it : alternate_urls->GetList()) { - std::string alternate_url; - if (it.GetAsString(&alternate_url)) - result->alternate_urls.push_back(std::move(alternate_url)); + if (it.is_string()) + result->alternate_urls.push_back(it.GetString()); } } @@ -112,8 +111,8 @@ if (dict.GetList(DefaultSearchManager::kInputEncodings, &encodings)) { for (const auto& it : encodings->GetList()) { std::string encoding; - if (it.GetAsString(&encoding)) - result->input_encodings.push_back(std::move(encoding)); + if (it.is_string()) + result->input_encodings.push_back(it.GetString()); } }
diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp index 3e14630..761095a 100644 --- a/components/security_interstitials_strings.grdp +++ b/components/security_interstitials_strings.grdp
@@ -128,7 +128,7 @@ </if> <if expr="_google_chrome"> <message name="IDS_CLOCK_ERROR_EXPLANATION" desc="Body text under an 'Advanced' button. Context: error shown when the browser can't load a page because the device's clock is wrong. This paragraph explains why a correct clock is necessary."> - To establish a secure connection, your clock needs to be set correctly. This is because the certificates that websites use to identify themselves are only valid for specific periods of time. Since your device's clock is incorrect, Google Chrome cannot verify these certificates. + To establish a secure connection, your clock needs to be set correctly. This is because the certificates that websites use to identify themselves are only valid for specific periods of time. Since your device's clock is incorrect, Chrome cannot verify these certificates. </message> </if> <if expr="not _google_chrome"> @@ -177,10 +177,10 @@ </message> <if expr="_google_chrome"> <message name="IDS_SSL_NONOVERRIDABLE_MORE" desc="Body text for the explanation shown if user clicks on the Details button."> - <ph name="SITE">$1<ex>google.com</ex></ph> normally uses encryption to protect your information. When Google Chrome tried to connect to <ph name="SITE">$1<ex>google.com</ex></ph> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE">$1<ex>google.com</ex></ph>, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Google Chrome stopped the connection before any data was exchanged. + <ph name="SITE">$1<ex>google.com</ex></ph> normally uses encryption to protect your information. When Chrome tried to connect to <ph name="SITE">$1<ex>google.com</ex></ph> this time, the website sent back unusual and incorrect credentials. This may happen when an attacker is trying to pretend to be <ph name="SITE">$1<ex>google.com</ex></ph>, or a Wi-Fi sign-in screen has interrupted the connection. Your information is still secure because Chrome stopped the connection before any data was exchanged. </message> <message name="IDS_SSL_NONOVERRIDABLE_INVALID" desc="A sentence to explain why the user can't proceed."> - You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website sent scrambled credentials that Google Chrome cannot process. Network errors and attacks are usually temporary, so this page will probably work later. + You cannot visit <ph name="SITE">$1<ex>google.com</ex></ph> right now because the website sent scrambled credentials that Chrome cannot process. Network errors and attacks are usually temporary, so this page will probably work later. </message> </if> <if expr="not _google_chrome">
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm index a04ebfc1..2038360c 100644 --- a/components/signin/ios/browser/account_consistency_service.mm +++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -125,15 +125,16 @@ web::PageLoadCompletionStatus load_completion_status) override; // web::WebStatePolicyDecider override. - WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( + void ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) override; + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; // Decides on navigation corresponding to |response| whether the navigation // should continue and updates authentication cookies on Google domains. void ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(PolicyDecision)> callback) override; + web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; void WebStateDestroyed() override; // Loads |url| in the current tab. @@ -164,10 +165,10 @@ web_state->AddObserver(this); } -web::WebStatePolicyDecider::PolicyDecision -AccountConsistencyService::AccountConsistencyHandler::ShouldAllowRequest( +void AccountConsistencyService::AccountConsistencyHandler::ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) { + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { GURL url = net::GURLWithNSURL(request.URL); if (base::FeatureList::IsEnabled(signin::kRestoreGaiaCookiesOnUserAction) && signin::IsUrlEligibleForMirrorCookie(url) && @@ -179,13 +180,13 @@ // necessary. account_consistency_service_->AddChromeConnectedCookies(); } - return PolicyDecision::Allow(); + std::move(callback).Run(PolicyDecision::Allow()); } void AccountConsistencyService::AccountConsistencyHandler::ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(PolicyDecision)> callback) { + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { NSHTTPURLResponse* http_response = base::mac::ObjCCast<NSHTTPURLResponse>(response); if (!http_response) {
diff --git a/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2 b/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2 index 3dfee489..1497feb 100644 --- a/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2 +++ b/components/test/android/browsertests_apk/AndroidManifest.xml.jinja2
@@ -27,6 +27,7 @@ android:theme="@android:style/Theme.Holo.Light.NoActionBar" android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" + android:exported="true" android:process=":test_process"> <intent-filter> <action android:name="android.intent.action.MAIN"/>
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc index e711f9d..9cb35f22 100644 --- a/components/translate/content/browser/content_translate_driver.cc +++ b/components/translate/content/browser/content_translate_driver.cc
@@ -245,7 +245,10 @@ InitiateTranslationIfReload(navigation_handle); - if (navigation_handle->IsInMainFrame()) + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (navigation_handle->IsInPrimaryMainFrame()) finish_navigation_time_ = base::TimeTicks::Now(); // Let the LanguageState clear its state. @@ -263,9 +266,13 @@ google_util::ALLOW_NON_STANDARD_PORTS) || IsAutoHrefTranslateAllOriginsEnabled()); + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. translate_manager_->GetLanguageState()->DidNavigate( - navigation_handle->IsSameDocument(), navigation_handle->IsInMainFrame(), - reload, navigation_handle->GetHrefTranslate(), navigation_from_google); + navigation_handle->IsSameDocument(), + navigation_handle->IsInPrimaryMainFrame(), reload, + navigation_handle->GetHrefTranslate(), navigation_from_google); } bool ContentTranslateDriver::IsAutoHrefTranslateAllOriginsEnabled() const {
diff --git a/components/translate/content/browser/per_frame_content_translate_driver.cc b/components/translate/content/browser/per_frame_content_translate_driver.cc index 29a1cdaa..9aba77ad 100644 --- a/components/translate/content/browser/per_frame_content_translate_driver.cc +++ b/components/translate/content/browser/per_frame_content_translate_driver.cc
@@ -271,7 +271,10 @@ InitiateTranslationIfReload(navigation_handle); - if (navigation_handle->IsInMainFrame()) + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (navigation_handle->IsInPrimaryMainFrame()) finish_navigation_time_ = base::TimeTicks::Now(); // Let the LanguageState clear its state. @@ -289,9 +292,13 @@ google_util::ALLOW_NON_STANDARD_PORTS) || IsAutoHrefTranslateAllOriginsEnabled()); + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. translate_manager()->GetLanguageState()->DidNavigate( - navigation_handle->IsSameDocument(), navigation_handle->IsInMainFrame(), - reload, navigation_handle->GetHrefTranslate(), navigation_from_google); + navigation_handle->IsSameDocument(), + navigation_handle->IsInPrimaryMainFrame(), reload, + navigation_handle->GetHrefTranslate(), navigation_from_google); } void PerFrameContentTranslateDriver::DOMContentLoaded(
diff --git a/components/url_matcher/url_matcher_factory.cc b/components/url_matcher/url_matcher_factory.cc index a996856..aab8cb0e 100644 --- a/components/url_matcher/url_matcher_factory.cc +++ b/components/url_matcher/url_matcher_factory.cc
@@ -188,12 +188,12 @@ const std::string& condition_attribute_name, const base::Value* value, std::string* error) { - std::string str_value; - if (!value->GetAsString(&str_value)) { + if (!value->is_string()) { *error = base::StringPrintf(kAttributeExpectedString, condition_attribute_name.c_str()); return URLMatcherCondition(); } + const std::string& str_value = value->GetString(); if (condition_attribute_name == keys::kHostContainsKey || condition_attribute_name == keys::kHostPrefixKey || condition_attribute_name == keys::kHostSuffixKey ||
diff --git a/components/webapps/browser/banners/app_banner_manager.cc b/components/webapps/browser/banners/app_banner_manager.cc index 146d15b..a1d8b523 100644 --- a/components/webapps/browser/banners/app_banner_manager.cc +++ b/components/webapps/browser/banners/app_banner_manager.cc
@@ -590,7 +590,10 @@ } void AppBannerManager::DidFinishNavigation(content::NavigationHandle* handle) { - if (!handle->IsInMainFrame() || !handle->HasCommitted() || + // TODO(https://crbug.com/1218946): With MPArch there may be multiple main + // frames. This caller was converted automatically to the primary main frame + // to preserve its semantics. Follow up to confirm correctness. + if (!handle->IsInPrimaryMainFrame() || !handle->HasCommitted() || handle->IsSameDocument()) { return; }
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc index 81638b9..1418e10 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc
@@ -1008,6 +1008,8 @@ // but before the IO thread is started. if (base::HangWatcher::IsEnabled()) { hang_watcher_ = new base::HangWatcher(); + unregister_thread_closure_ = base::HangWatcher::RegisterThread( + base::HangWatcher::ThreadType::kUIThread); hang_watcher_->Start(); ANNOTATE_LEAKING_OBJECT_PTR(hang_watcher_); }
diff --git a/content/app/content_main_runner_impl.h b/content/app/content_main_runner_impl.h index 86c624e..5dbc33d9 100644 --- a/content/app/content_main_runner_impl.h +++ b/content/app/content_main_runner_impl.h
@@ -62,6 +62,11 @@ // The hang watcher is leaked to make sure it survives all watched threads. base::HangWatcher* hang_watcher_; + // Unregisters UI thread from hang watching on destruction. + // NOTE: The thread should be unregistered before HangWatcher stops so this + // member must be after |hang_watcher|. + base::ScopedClosureRunner unregister_thread_closure_; + std::unique_ptr<discardable_memory::DiscardableSharedMemoryManager> discardable_shared_memory_manager_; std::unique_ptr<StartupDataImpl> startup_data_;
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc index 711f4d3c..086af31 100644 --- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc +++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -688,6 +688,61 @@ } #endif // !defined(OS_ANDROID) +// Select controls behave differently on Mac/Android, this test doesn't apply. +#if !defined(OS_ANDROID) && !defined(OS_MAC) +IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest, + SelectSizeChangeWithOpenedPopupDoesNotCrash) { + LoadInitialAccessibilityTreeFromHtml(R"HTML( + <!DOCTYPE html> + <html> + <body> + <select aria-label="Select" id="select_node"> + <option>Option 1</option> + <option>Option 2</option> + <option>Option 3</option> + </select> + </body> + </html>)HTML"); + + WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(), + "Select"); + + const BrowserAccessibility* root = GetManager()->GetRoot(); + ASSERT_NE(root, nullptr); + const BrowserAccessibility* body = root->PlatformGetChild(0); + ASSERT_NE(body, nullptr); + + for (size_t attempts = 0; attempts < 10; ++attempts) { + BrowserAccessibility* select = FindNode("Select"); + ASSERT_NE(select, nullptr); + // If there is a popup, expand it and wait for it to appear. + // If it's a list, it will simply click on the list. + { + AccessibilityNotificationWaiter waiter( + shell()->web_contents(), ui::kAXModeComplete, + ax::mojom::Event::kChildrenChanged); + + ui::AXActionData action_data; + action_data.action = ax::mojom::Action::kDoDefault; + select->AccessibilityPerformAction(action_data); + waiter.WaitForNotification(); + } + + // Toggle whether 'size' is '2' or not present (effectively size=1), + // There can't be a popup when the size to 2, because it becomes a list box. + // This means the accessible object for the listbox needs to be cleanly + // removed, and the widget's accessible hierarchy is rebuilt. + ExecuteScript( + "var select = document.getElementById('select_node');" + "if (select.hasAttribute('size')) {" + " select.removeAttribute('size');" + "} else {" + " select.setAttribute('size', '2');" + "}"); + } +} +#endif // !defined(OS_ANDROID) && !defined(OS_MAC) + IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest, PlatformIterator) { LoadInitialAccessibilityTreeFromHtml(R"HTML(
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc index 00956ce..ae2374c 100644 --- a/content/browser/back_forward_cache_browsertest.cc +++ b/content/browser/back_forward_cache_browsertest.cc
@@ -12387,11 +12387,19 @@ ExpectRestored(FROM_HERE); } +// Flaky on Cast: crbug.com/1229182 +#if BUILDFLAG(IS_CHROMECAST) +#define MAYBE_PagesWithCacheControlNoStoreEvictedIfCookieChange \ + DISABLED_PagesWithCacheControlNoStoreEvictedIfCookieChange +#else +#define MAYBE_PagesWithCacheControlNoStoreEvictedIfCookieChange \ + PagesWithCacheControlNoStoreEvictedIfCookieChange +#endif // Test that a page with cache-control:no-store enters bfcache with the flag on, // but gets evicted if cookies change. IN_PROC_BROWSER_TEST_F( BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange, - PagesWithCacheControlNoStoreEvictedIfCookieChange) { + MAYBE_PagesWithCacheControlNoStoreEvictedIfCookieChange) { net::test_server::ControllableHttpResponse response(embedded_test_server(), "/main_document"); net::test_server::ControllableHttpResponse response2(embedded_test_server(),
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 92c4fe2..e0c0c75 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -476,15 +476,6 @@ DCHECK(scoped_execution_fence_) << "ThreadPool must be halted before kicking off content."; g_current_browser_main_loop = this; - - // Register the UI thread for hang watching before it starts running and set - // up a closure to automatically unregister when |this| is destroyed. This - // works since the UI thread running the message loop is the main thread and - // that makes it the same as the current one. - if (base::HangWatcher::IsUIThreadHangWatchingEnabled()) { - unregister_thread_closure_ = base::HangWatcher::RegisterThread( - base::HangWatcher::ThreadType::kUIThread); - } } BrowserMainLoop::~BrowserMainLoop() {
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index 090ca9c6..5d41104a 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h
@@ -327,11 +327,6 @@ // This must get destroyed before other threads that are created in |parts_|. std::unique_ptr<BrowserThreadImpl> main_thread_; - // Unregister UI thread from hang watching on destruction. - // NOTE: Hang watching should stop before the watched thread stops so this - // member must be after |main_thread_|. - base::ScopedClosureRunner unregister_thread_closure_; - // Members initialized in |CreateStartupTasks()| ----------------------------- std::unique_ptr<StartupTaskRunner> startup_task_runner_;
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc index 255c206..8f7ad6a5 100644 --- a/content/browser/devtools/devtools_instrumentation.cc +++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -344,11 +344,16 @@ const GURL& signed_exchange_url) { // Make sure both back-ends yield the same timestamp. auto timestamp = base::TimeTicks::Now(); - DispatchToAgents(frame_tree_node, &protocol::NetworkHandler::RequestSent, - request_id.ToString(), loader_id.ToString(), request, - protocol::Network::Initiator::TypeEnum::SignedExchange, - signed_exchange_url, /*initiator_devtools_request_id=*/"", - timestamp); + network::mojom::URLRequestDevToolsInfo request_info( + request.method, request.url, request.priority, request.referrer_policy, + request.trust_token_params ? request.trust_token_params->Clone() + : nullptr, + request.has_user_gesture); + DispatchToAgents( + frame_tree_node, &protocol::NetworkHandler::RequestSent, + request_id.ToString(), loader_id.ToString(), request.headers, + request_info, protocol::Network::Initiator::TypeEnum::SignedExchange, + signed_exchange_url, /*initiator_devtools_request_id=*/"", timestamp); auto value = std::make_unique<base::trace_event::TracedValue>(); value->SetString("requestId", request_id.ToString());
diff --git a/content/browser/devtools/network_service_devtools_observer.cc b/content/browser/devtools/network_service_devtools_observer.cc index 332b197..e8c2e54 100644 --- a/content/browser/devtools/network_service_devtools_observer.cc +++ b/content/browser/devtools/network_service_devtools_observer.cc
@@ -137,7 +137,8 @@ void NetworkServiceDevToolsObserver::OnCorsPreflightRequest( const base::UnguessableToken& devtools_request_id, - const network::ResourceRequest& request, + const net::HttpRequestHeaders& request_headers, + network::mojom::URLRequestDevToolsInfoPtr request_info, const GURL& initiator_url, const std::string& initiator_devtools_request_id) { auto* host = GetDevToolsAgentHost(); @@ -146,7 +147,7 @@ auto timestamp = base::TimeTicks::Now(); auto id = devtools_request_id.ToString(); DispatchToAgents(host, &protocol::NetworkHandler::RequestSent, id, - /* loader_id=*/"", request, + /* loader_id=*/"", request_headers, *request_info, protocol::Network::Initiator::TypeEnum::Preflight, initiator_url, initiator_devtools_request_id, timestamp); }
diff --git a/content/browser/devtools/network_service_devtools_observer.h b/content/browser/devtools/network_service_devtools_observer.h index be9ebed..1533832 100644 --- a/content/browser/devtools/network_service_devtools_observer.h +++ b/content/browser/devtools/network_service_devtools_observer.h
@@ -57,7 +57,8 @@ network::mojom::ClientSecurityStatePtr client_security_state) override; void OnCorsPreflightRequest( const base::UnguessableToken& devtools_request_id, - const network::ResourceRequest& request, + const net::HttpRequestHeaders& request_headers, + network::mojom::URLRequestDevToolsInfoPtr request_info, const GURL& initiator_url, const std::string& initiator_devtools_request_id) override; void OnCorsPreflightResponse(
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index f5a5887..1d566462 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -1958,7 +1958,8 @@ void NetworkHandler::RequestSent( const std::string& request_id, const std::string& loader_id, - const network::ResourceRequest& request, + const net::HttpRequestHeaders& request_headers, + const network::mojom::URLRequestDevToolsInfo& request_info, const char* initiator_type, const absl::optional<GURL>& initiator_url, const std::string& initiator_devtools_request_id, @@ -1966,7 +1967,7 @@ if (!enabled_) return; std::unique_ptr<DictionaryValue> headers_dict(DictionaryValue::create()); - for (net::HttpRequestHeaders::Iterator it(request.headers); it.GetNext();) + for (net::HttpRequestHeaders::Iterator it(request_headers); it.GetNext();) headers_dict->setString(it.name(), it.value()); std::unique_ptr<Network::Initiator> initiator = Network::Initiator::Create().SetType(initiator_type).Build(); @@ -1976,27 +1977,27 @@ initiator->SetRequestId(initiator_devtools_request_id); std::string url_fragment; std::string url_without_fragment = - ExtractFragment(request.url, &url_fragment); + ExtractFragment(request_info.url, &url_fragment); auto request_object = Network::Request::Create() .SetUrl(url_without_fragment) - .SetMethod(request.method) + .SetMethod(request_info.method) .SetHeaders(Object::fromValue(headers_dict.get(), nullptr)) - .SetInitialPriority(resourcePriority(request.priority)) - .SetReferrerPolicy(referrerPolicy(request.referrer_policy)) + .SetInitialPriority(resourcePriority(request_info.priority)) + .SetReferrerPolicy(referrerPolicy(request_info.referrer_policy)) .Build(); if (!url_fragment.empty()) request_object->SetUrlFragment(url_fragment); - if (request.trust_token_params.has_value()) { + if (request_info.trust_token_params) { request_object->SetTrustTokenParams( - BuildTrustTokenParams(request.trust_token_params.value())); + BuildTrustTokenParams(*request_info.trust_token_params)); } frontend_->RequestWillBeSent( request_id, loader_id, url_without_fragment, std::move(request_object), timestamp.since_origin().InSecondsF(), base::Time::Now().ToDoubleT(), std::move(initiator), std::unique_ptr<Network::Response>(), std::string(Network::ResourceTypeEnum::Other), - Maybe<std::string>() /* frame_id */, request.has_user_gesture); + Maybe<std::string>() /* frame_id */, request_info.has_user_gesture); } namespace {
diff --git a/content/browser/devtools/protocol/network_handler.h b/content/browser/devtools/protocol/network_handler.h index e1945504..6166801 100644 --- a/content/browser/devtools/protocol/network_handler.h +++ b/content/browser/devtools/protocol/network_handler.h
@@ -184,7 +184,8 @@ base::TimeTicks timestamp); void RequestSent(const std::string& request_id, const std::string& loader_id, - const network::ResourceRequest& request, + const net::HttpRequestHeaders& request_headers, + const network::mojom::URLRequestDevToolsInfo& request_info, const char* initiator_type, const absl::optional<GURL>& initiator_url, const std::string& initiator_devtools_request_id,
diff --git a/content/browser/devtools/service_worker_devtools_manager.cc b/content/browser/devtools/service_worker_devtools_manager.cc index 947ec418..6f3ee2d 100644 --- a/content/browser/devtools/service_worker_devtools_manager.cc +++ b/content/browser/devtools/service_worker_devtools_manager.cc
@@ -314,9 +314,15 @@ if (it == live_hosts_.end()) return; auto timestamp = base::TimeTicks::Now(); + network::mojom::URLRequestDevToolsInfo request_info( + request.method, request.url, request.priority, request.referrer_policy, + request.trust_token_params ? request.trust_token_params->Clone() + : nullptr, + request.has_user_gesture); for (auto* network : protocol::NetworkHandler::ForAgentHost(it->second.get())) { - network->RequestSent(request_id, std::string(), request, + network->RequestSent(request_id, std::string(), request.headers, + request_info, protocol::Network::Initiator::TypeEnum::Preload, /*initiator_url=*/absl::nullopt, /*initiator_devtools_request_id=*/"", timestamp);
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc index 12a029d..c2a46356 100644 --- a/content/browser/navigation_browsertest.cc +++ b/content/browser/navigation_browsertest.cc
@@ -43,6 +43,7 @@ #include "content/public/browser/navigation_controller.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_client.h" #include "content/public/common/content_features.h" @@ -4646,19 +4647,60 @@ void VerifyImageSubresourceLoads( const ToRenderFrameHost& target, const std::string& target_document = "document") { - VerifySingleImageSubresourceLoad(target, target_document); + RenderFrameHostImpl* target_frame = + static_cast<RenderFrameHostImpl*>(target.render_frame_host()); + VerifySingleImageSubresourceLoad(target_frame, target_document); // Verify detecting and recovering from a NetworkService crash (e.g. via the // `network_service_disconnect_handler_holder_mojo` field and the // UpdateSubresourceLoaderFactories method of RenderFrameHostImpl). if (!IsInProcessNetworkService() && test_network_service_crashes_) { SimulateNetworkServiceCrash(); - VerifySingleImageSubresourceLoad(target, target_document); + + // In addition to waiting (inside SimulateNetworkServiceCrash above) for + // getting notified about being disconnected from + // network::mojom::NetworkServiceTest, we also want to make sure that the + // relevant RenderFrameHost realizes that the NetworkService has crashed. + // Which RenderFrameHost is relevant varies from test to test, so we + // flush multiple frames and use kDoNothingIfNoNetworkServiceConnection. + FlushNetworkInterfacesInOpenerChain(target_frame); + + // Rerun the test after the NetworkService crash. + VerifySingleImageSubresourceLoad(target_frame, target_document); } } private: - void VerifySingleImageSubresourceLoad(const ToRenderFrameHost& target, + void FlushNetworkInterfacesInOpenerChain(RenderFrameHostImpl* current_frame) { + std::set<WebContents*> visited_contents; + while (true) { + // Check if we've already visited the current frame tree. + DCHECK(current_frame); + WebContents* current_contents = + WebContents::FromRenderFrameHost(current_frame); + DCHECK(current_contents); + if (base::Contains(visited_contents, current_contents)) + break; + visited_contents.insert(current_contents); + + // Flush all the frames in the `current_frame`'s frame tree. + for (RenderFrameHost* frame_to_flush : current_contents->GetAllFrames()) { + constexpr bool kDoNothingIfNoNetworkServiceConnection = true; + frame_to_flush->FlushNetworkAndNavigationInterfacesForTesting( + kDoNothingIfNoNetworkServiceConnection); + } + + // Traverse the `current_frame`'s opener chain. + if (FrameTreeNode* opener_node = + current_frame->frame_tree_node()->opener()) { + current_frame = opener_node->current_frame_host(); + } else { + break; // Break out of the loop if there is no opener. + } + } + } + + void VerifySingleImageSubresourceLoad(RenderFrameHost* target, const std::string& target_document) { // Use a random, GUID-based hostname, to avoid hitting the network cache. GURL image_url = embedded_test_server()->GetURL( @@ -4951,17 +4993,9 @@ // See the doc comment for the // URLLoaderFactoryInInitialEmptyDoc_NewFrameWithoutSrc test case. -// crbug.com/1224893: Test flaky on Mac. -#if defined(OS_MAC) -#define MAYBE_URLLoaderFactoryInInitialEmptyDoc_NewFrameWithAboutBlank \ - DISABLED_URLLoaderFactoryInInitialEmptyDoc_NewFrameWithAboutBlank -#else -#define MAYBE_URLLoaderFactoryInInitialEmptyDoc_NewFrameWithAboutBlank \ - URLLoaderFactoryInInitialEmptyDoc_NewFrameWithAboutBlank -#endif IN_PROC_BROWSER_TEST_F( SubresourceLoadingTest, - MAYBE_URLLoaderFactoryInInitialEmptyDoc_NewFrameWithAboutBlank) { + URLLoaderFactoryInInitialEmptyDoc_NewFrameWithAboutBlank) { GURL opener_url(embedded_test_server()->GetURL("/title1.html")); EXPECT_TRUE(NavigateToURL(shell(), opener_url));
diff --git a/content/browser/notifications/notification_database.cc b/content/browser/notifications/notification_database.cc index a43a64d..b795303 100644 --- a/content/browser/notifications/notification_database.cc +++ b/content/browser/notifications/notification_database.cc
@@ -272,7 +272,7 @@ ReadAllNotificationsCallback callback) const { return ForEachNotificationDataInternal( GURL() /* origin */, blink::mojom::kInvalidServiceWorkerRegistrationId, - std::move(callback)); + absl::nullopt /* is_shown_by_browser */, std::move(callback)); } NotificationDatabase::Status @@ -280,8 +280,9 @@ const GURL& origin, int64_t service_worker_registration_id, ReadAllNotificationsCallback callback) const { - return ForEachNotificationDataInternal(origin, service_worker_registration_id, - std::move(callback)); + return ForEachNotificationDataInternal( + origin, service_worker_registration_id, + absl::nullopt /* is_shown_by_browser */, std::move(callback)); } NotificationDatabase::Status @@ -290,15 +291,17 @@ std::vector<NotificationDatabaseData>* notification_data_vector) const { return ReadAllNotificationDataInternal( origin, blink::mojom::kInvalidServiceWorkerRegistrationId, - notification_data_vector); + absl::nullopt /* is_shown_by_browser */, notification_data_vector); } NotificationDatabase::Status NotificationDatabase::ReadAllNotificationDataForServiceWorkerRegistration( const GURL& origin, int64_t service_worker_registration_id, + absl::optional<bool> is_shown_by_browser, std::vector<NotificationDatabaseData>* notification_data_vector) const { return ReadAllNotificationDataInternal(origin, service_worker_registration_id, + is_shown_by_browser, notification_data_vector); } @@ -380,9 +383,11 @@ NotificationDatabase::DeleteAllNotificationDataForOrigin( const GURL& origin, const std::string& tag, + absl::optional<bool> is_shown_by_browser, std::set<std::string>* deleted_notification_ids) { return DeleteAllNotificationDataInternal( - origin, tag, blink::mojom::kInvalidServiceWorkerRegistrationId, + origin, tag, is_shown_by_browser, + blink::mojom::kInvalidServiceWorkerRegistrationId, deleted_notification_ids); } @@ -391,9 +396,9 @@ const GURL& origin, int64_t service_worker_registration_id, std::set<std::string>* deleted_notification_ids) { - return DeleteAllNotificationDataInternal(origin, "" /* tag */, - service_worker_registration_id, - deleted_notification_ids); + return DeleteAllNotificationDataInternal( + origin, "" /* tag */, absl::nullopt /* is_shown_by_browser */, + service_worker_registration_id, deleted_notification_ids); } NotificationDatabase::Status NotificationDatabase::Destroy() { @@ -418,12 +423,13 @@ NotificationDatabase::ReadAllNotificationDataInternal( const GURL& origin, int64_t service_worker_registration_id, + absl::optional<bool> is_shown_by_browser, std::vector<NotificationDatabaseData>* notification_data_vector) const { DCHECK(sequence_checker_.CalledOnValidSequence()); DCHECK(notification_data_vector); return ForEachNotificationDataInternal( - origin, service_worker_registration_id, + origin, service_worker_registration_id, is_shown_by_browser, base::BindRepeating( [](std::vector<NotificationDatabaseData>* datas, const NotificationDatabaseData& data) { datas->push_back(data); }, @@ -434,6 +440,7 @@ NotificationDatabase::ForEachNotificationDataInternal( const GURL& origin, int64_t service_worker_registration_id, + absl::optional<bool> is_shown_by_browser, ReadAllNotificationsCallback callback) const { DCHECK(sequence_checker_.CalledOnValidSequence()); @@ -460,6 +467,11 @@ continue; } + if (is_shown_by_browser && notification_database_data.is_shown_by_browser != + *is_shown_by_browser) { + continue; + } + callback.Run(notification_database_data); } @@ -470,6 +482,7 @@ NotificationDatabase::DeleteAllNotificationDataInternal( const GURL& origin, const std::string& tag, + absl::optional<bool> is_shown_by_browser, int64_t service_worker_registration_id, std::set<std::string>* deleted_notification_ids) { DCHECK(sequence_checker_.CalledOnValidSequence()); @@ -499,6 +512,11 @@ continue; } + if (is_shown_by_browser && notification_database_data.is_shown_by_browser != + *is_shown_by_browser) { + continue; + } + if (service_worker_registration_id != blink::mojom::kInvalidServiceWorkerRegistrationId && notification_database_data.service_worker_registration_id !=
diff --git a/content/browser/notifications/notification_database.h b/content/browser/notifications/notification_database.h index f1ec475..3c4ad19 100644 --- a/content/browser/notifications/notification_database.h +++ b/content/browser/notifications/notification_database.h
@@ -16,6 +16,7 @@ #include "base/sequence_checker.h" #include "content/common/content_export.h" #include "content/public/browser/platform_notification_context.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class GURL; @@ -138,10 +139,12 @@ // Reads all notification data associated to |service_worker_registration_id| // belonging to |origin| from the database, and appends the data to the - // |notification_data_vector|. Returns the status code. + // |notification_data_vector|. Optionally filtered by |is_shown_by_browser|. + // Returns the status code. Status ReadAllNotificationDataForServiceWorkerRegistration( const GURL& origin, int64_t service_worker_registration_id, + absl::optional<bool> is_shown_by_browser, std::vector<NotificationDatabaseData>* notification_data_vector) const; // Writes the |notification_data| for a new notification belonging to |origin| @@ -166,12 +169,13 @@ const GURL& origin); // Deletes all data associated with |origin| from the database, optionally - // filtered by the |tag|, and appends the deleted notification ids to - // |deleted_notification_ids|. Returns the status code of the deletion - // operation. + // filtered by |tag| and |is_shown_by_browser|, and appends the deleted + // notification ids to |deleted_notification_ids|. Returns the status code of + // the deletion operation. Status DeleteAllNotificationDataForOrigin( const GURL& origin, const std::string& tag, + absl::optional<bool> is_shown_by_browser, std::set<std::string>* deleted_notification_ids); // Deletes all data associated with the |service_worker_registration_id| @@ -205,26 +209,32 @@ Status ReadAllNotificationDataInternal( const GURL& origin, int64_t service_worker_registration_id, + absl::optional<bool> is_shown_by_browser, std::vector<NotificationDatabaseData>* notification_data_vector) const; // Reads all notification data with the given constraints. |origin| may be // empty to read all notification data from all origins. If |origin| is // set, but |service_worker_registration_id| is invalid, then all notification // data for |origin| will be read. If both are set, then all notification data - // for the given |service_worker_registration_id| will be read. + // for the given |service_worker_registration_id| will be read. If + // |is_shown_by_browser| is not absl::nullopt, only notification data with + // matching |is_shown_by_browser| flags will be read. Status ForEachNotificationDataInternal( const GURL& origin, int64_t service_worker_registration_id, + absl::optional<bool> is_shown_by_browser, ReadAllNotificationsCallback callback) const; // Deletes all notification data with the given constraints. |origin| must // always be set - use Destroy() when the goal is to empty the database. If // |service_worker_registration_id| is invalid, all notification data for the - // |origin| will be deleted, optionally filtered by the |tag| when non-empty. - // All deleted notification ids will be written to |deleted_notification_ids|. + // |origin| will be deleted, optionally filtered by |tag| and + // |is_shown_by_browser| when non-empty. All deleted notification ids will be + // written to |deleted_notification_ids|. Status DeleteAllNotificationDataInternal( const GURL& origin, const std::string& tag, + absl::optional<bool> is_shown_by_browser, int64_t service_worker_registration_id, std::set<std::string>* deleted_notification_ids);
diff --git a/content/browser/notifications/notification_database_conversions.cc b/content/browser/notifications/notification_database_conversions.cc index 9681dde7..85e19bc 100644 --- a/content/browser/notifications/notification_database_conversions.cc +++ b/content/browser/notifications/notification_database_conversions.cc
@@ -181,6 +181,8 @@ output->has_triggered = message.has_triggered(); + output->is_shown_by_browser = message.is_shown_by_browser(); + output->notification_resources = absl::nullopt; return true; @@ -306,6 +308,8 @@ message.set_has_triggered(input.has_triggered); + message.set_is_shown_by_browser(input.is_shown_by_browser); + return message.SerializeToString(output); }
diff --git a/content/browser/notifications/notification_database_conversions_unittest.cc b/content/browser/notifications/notification_database_conversions_unittest.cc index 814a70c..d70be51 100644 --- a/content/browser/notifications/notification_database_conversions_unittest.cc +++ b/content/browser/notifications/notification_database_conversions_unittest.cc
@@ -116,6 +116,7 @@ base::TimeDelta::FromMilliseconds(kTimeUntilCloseMillis); database_data.closed_reason = NotificationDatabaseData::ClosedReason::USER; database_data.has_triggered = kHasTriggered; + database_data.is_shown_by_browser = true; std::string serialized_data; // Serialize the data in |notification_data| to the string |serialized_data|. @@ -147,6 +148,7 @@ copied_data.time_until_close_millis); EXPECT_EQ(database_data.closed_reason, copied_data.closed_reason); EXPECT_EQ(database_data.has_triggered, copied_data.has_triggered); + EXPECT_EQ(database_data.is_shown_by_browser, copied_data.is_shown_by_browser); const blink::PlatformNotificationData& copied_notification_data = copied_data.notification_data;
diff --git a/content/browser/notifications/notification_database_data.proto b/content/browser/notifications/notification_database_data.proto index c92cf8d..1fb6421 100644 --- a/content/browser/notifications/notification_database_data.proto +++ b/content/browser/notifications/notification_database_data.proto
@@ -11,7 +11,7 @@ // Stores information about a Web Notification. This message is the protocol // buffer meant to serialize the content::NotificationDatabaseData structure. // -// Next tag: 15 +// Next tag: 16 message NotificationDatabaseDataProto { enum ClosedReason { USER = 0; @@ -87,4 +87,8 @@ // Keeps track if a notification with a |show_trigger_timestamp| has been // displayed already. optional bool has_triggered = 14; + + // Flag for notifications shown by the browser that should not be visible to + // the origin when requesting a list of notifications. + optional bool is_shown_by_browser = 15; }
diff --git a/content/browser/notifications/notification_database_unittest.cc b/content/browser/notifications/notification_database_unittest.cc index cc217f04e..be28509 100644 --- a/content/browser/notifications/notification_database_unittest.cc +++ b/content/browser/notifications/notification_database_unittest.cc
@@ -15,6 +15,7 @@ #include "content/public/browser/notification_database_data.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/notifications/notification_resources.h" #include "third_party/blink/public/common/notifications/platform_notification_data.h" #include "third_party/blink/public/mojom/notifications/notification.mojom.h" @@ -63,6 +64,7 @@ void CreateAndWriteNotification(NotificationDatabase* database, const GURL& origin, const std::string& tag, + bool is_shown_by_browser, int64_t service_worker_registration_id, std::string* notification_id) { DCHECK(notification_id); @@ -73,6 +75,7 @@ database_data.service_worker_registration_id = service_worker_registration_id; database_data.notification_data.tag = tag; + database_data.is_shown_by_browser = is_shown_by_browser; ASSERT_EQ(NotificationDatabase::STATUS_OK, database->WriteNotificationData(origin, database_data)); @@ -87,6 +90,7 @@ for (const auto& notification_data : kExampleNotificationData) { ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( database, GURL(notification_data.origin), notification_data.tag, + false /* is_shown_by_browser */, notification_data.service_worker_registration_id, ¬ification_id)); } } @@ -202,9 +206,9 @@ GURL origin("https://example.com"); std::string notification_id; - ASSERT_NO_FATAL_FAILURE( - CreateAndWriteNotification(database.get(), origin, "" /* tag */, - 0 /* sw_registration_id */, ¬ification_id)); + ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( + database.get(), origin, "" /* tag */, false /* is_shown_by_browser */, + 0 /* sw_registration_id */, ¬ification_id)); database.reset(CreateDatabaseOnFileSystem(database_dir.GetPath())); ASSERT_EQ(NotificationDatabase::STATUS_OK, @@ -431,8 +435,8 @@ // notification id (it is the responsibility of the user to increment this). for (int i = 1; i <= 10; ++i) { ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( - database.get(), origin, "" /* tag */, i /* sw_registration_id */, - ¬ification_id)); + database.get(), origin, "" /* tag */, false /* is_shown_by_browser */, + i /* sw_registration_id */, ¬ification_id)); EXPECT_FALSE(notification_id.empty()); @@ -704,11 +708,63 @@ std::vector<NotificationDatabaseData> notifications; ASSERT_EQ(NotificationDatabase::STATUS_OK, database->ReadAllNotificationDataForServiceWorkerRegistration( - origin, kExampleServiceWorkerRegistrationId, ¬ifications)); + origin, kExampleServiceWorkerRegistrationId, + absl::nullopt /* is_shown_by_browser */, ¬ifications)); EXPECT_EQ(2u, notifications.size()); } +TEST_F(NotificationDatabaseTest, + ReadAllNotificationDataForServiceWorkerRegistrationShownByBrowser) { + std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->Open(true /* create_if_missing */)); + GURL origin("https://example.com:443"); + std::string kTag = "tag"; + + std::string non_browser_notification_id; + ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( + database.get(), origin, kTag, false /* is_shown_by_browser */, + kExampleServiceWorkerRegistrationId, &non_browser_notification_id)); + + std::string browser_notification_id; + ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( + database.get(), origin, kTag, true /* is_shown_by_browser */, + kExampleServiceWorkerRegistrationId, &browser_notification_id)); + + { + // Expect to be able to read notification shown by the browser. + std::vector<NotificationDatabaseData> notifications; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->ReadAllNotificationDataForServiceWorkerRegistration( + origin, kExampleServiceWorkerRegistrationId, + true /* is_shown_by_browser */, ¬ifications)); + ASSERT_EQ(1u, notifications.size()); + EXPECT_EQ(browser_notification_id, notifications[0].notification_id); + } + + { + // Expect to be able to read notification not shown by the browser. + std::vector<NotificationDatabaseData> notifications; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->ReadAllNotificationDataForServiceWorkerRegistration( + origin, kExampleServiceWorkerRegistrationId, + false /* is_shown_by_browser */, ¬ifications)); + ASSERT_EQ(1u, notifications.size()); + EXPECT_EQ(non_browser_notification_id, notifications[0].notification_id); + } + + { + // Expect to be able to read notification not shown by anyone. + std::vector<NotificationDatabaseData> notifications; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->ReadAllNotificationDataForServiceWorkerRegistration( + origin, kExampleServiceWorkerRegistrationId, + absl::nullopt /* is_shown_by_browser */, ¬ifications)); + ASSERT_EQ(2u, notifications.size()); + } +} + TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForOrigin) { std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); ASSERT_EQ(NotificationDatabase::STATUS_OK, @@ -721,7 +777,8 @@ std::set<std::string> deleted_notification_ids; ASSERT_EQ(NotificationDatabase::STATUS_OK, database->DeleteAllNotificationDataForOrigin( - origin, "" /* tag */, &deleted_notification_ids)); + origin, "" /* tag */, absl::nullopt /* is_shown_by_browser */, + &deleted_notification_ids)); EXPECT_EQ(4u, deleted_notification_ids.size()); @@ -761,9 +818,11 @@ ASSERT_GT(notifications_without_tag, 0u); std::set<std::string> deleted_notification_ids; - ASSERT_EQ(NotificationDatabase::STATUS_OK, - database->DeleteAllNotificationDataForOrigin( - origin, "foo" /* tag */, &deleted_notification_ids)); + ASSERT_EQ( + NotificationDatabase::STATUS_OK, + database->DeleteAllNotificationDataForOrigin( + origin, "foo" /* tag */, absl::nullopt /* is_shown_by_browser */, + &deleted_notification_ids)); EXPECT_EQ(notifications_with_tag, deleted_notification_ids.size()); @@ -798,12 +857,89 @@ std::set<std::string> deleted_notification_ids; ASSERT_EQ(NotificationDatabase::STATUS_OK, database->DeleteAllNotificationDataForOrigin( - origin, "" /* tag */, &deleted_notification_ids)); + origin, "" /* tag */, absl::nullopt /* is_shown_by_browser */, + &deleted_notification_ids)); EXPECT_EQ(0u, deleted_notification_ids.size()); } TEST_F(NotificationDatabaseTest, + DeleteAllNotificationDataForOriginShownByBrowser) { + std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->Open(true /* create_if_missing */)); + GURL origin("https://example.com:443"); + std::string kTag = "tag"; + + std::string non_browser_notification_id; + ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( + database.get(), origin, kTag, false /* is_shown_by_browser */, + kExampleServiceWorkerRegistrationId, &non_browser_notification_id)); + + std::string browser_notification_id; + ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( + database.get(), origin, kTag, true /* is_shown_by_browser */, + kExampleServiceWorkerRegistrationId, &browser_notification_id)); + + { + // Expect two notifications in the database for |origin|. + std::vector<NotificationDatabaseData> notifications; + ASSERT_EQ( + NotificationDatabase::STATUS_OK, + database->ReadAllNotificationDataForOrigin(origin, ¬ifications)); + EXPECT_EQ(2u, notifications.size()); + } + + { + // Expect to be able to delete only notifications from the browser. + std::set<std::string> deleted_notification_ids; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->DeleteAllNotificationDataForOrigin( + origin, kTag, true /* is_shown_by_browser */, + &deleted_notification_ids)); + EXPECT_EQ(1u, deleted_notification_ids.size()); + EXPECT_EQ(1u, deleted_notification_ids.count(browser_notification_id)); + } + + ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( + database.get(), origin, kTag, true /* is_shown_by_browser */, + kExampleServiceWorkerRegistrationId, &browser_notification_id)); + + { + // Expect to be able to delete only notifications not from the browser. + std::set<std::string> deleted_notification_ids; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->DeleteAllNotificationDataForOrigin( + origin, kTag, false /* is_shown_by_browser */, + &deleted_notification_ids)); + EXPECT_EQ(1u, deleted_notification_ids.size()); + EXPECT_EQ(1u, deleted_notification_ids.count(non_browser_notification_id)); + } + + ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( + database.get(), origin, kTag, false /* is_shown_by_browser */, + kExampleServiceWorkerRegistrationId, &non_browser_notification_id)); + + { + // Expect to be able to delete notifications from the browser or not. + std::set<std::string> deleted_notification_ids; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->DeleteAllNotificationDataForOrigin( + origin, kTag, absl::nullopt /* is_shown_by_browser */, + &deleted_notification_ids)); + EXPECT_EQ(2u, deleted_notification_ids.size()); + EXPECT_EQ(1u, deleted_notification_ids.count(browser_notification_id)); + EXPECT_EQ(1u, deleted_notification_ids.count(non_browser_notification_id)); + } + + // Expect no remaining notifications. + std::vector<NotificationDatabaseData> notifications; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->ReadAllNotificationDataForOrigin(origin, ¬ifications)); + EXPECT_EQ(0u, notifications.size()); +} + +TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForServiceWorkerRegistration) { std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); ASSERT_EQ(NotificationDatabase::STATUS_OK, @@ -823,7 +959,8 @@ std::vector<NotificationDatabaseData> notifications; ASSERT_EQ(NotificationDatabase::STATUS_OK, database->ReadAllNotificationDataForServiceWorkerRegistration( - origin, kExampleServiceWorkerRegistrationId, ¬ifications)); + origin, kExampleServiceWorkerRegistrationId, + absl::nullopt /* is_shown_by_browser */, ¬ifications)); EXPECT_EQ(0u, notifications.size()); }
diff --git a/content/browser/notifications/notification_id_generator.cc b/content/browser/notifications/notification_id_generator.cc index eebdf0d..fd74788 100644 --- a/content/browser/notifications/notification_id_generator.cc +++ b/content/browser/notifications/notification_id_generator.cc
@@ -18,6 +18,7 @@ const char kNotificationTagSeparator = '#'; const char kPersistentNotificationPrefix = 'p'; const char kNonPersistentNotificationPrefix = 'n'; +const char kNotificationShownByBrowserFlag = 'b'; } // namespace @@ -36,17 +37,23 @@ } // Notification Id is of the following format: -// p#<origin>#[1|0][<developer_tag>|persistent_notification_id] +// p[b]#<origin>#[1|0][<developer_tag>|persistent_notification_id] std::string NotificationIdGenerator::GenerateForPersistentNotification( const GURL& origin, const std::string& tag, + bool is_shown_by_browser, int64_t persistent_notification_id) const { DCHECK(origin.is_valid()); DCHECK_EQ(origin, origin.GetOrigin()); std::stringstream stream; - stream << kPersistentNotificationPrefix << kNotificationTagSeparator; + stream << kPersistentNotificationPrefix; + + if (is_shown_by_browser) + stream << kNotificationShownByBrowserFlag; + + stream << kNotificationTagSeparator; stream << origin; stream << kNotificationTagSeparator; @@ -60,7 +67,7 @@ } // Notification Id is of the following format: -// p#<origin>#<token> +// n#<origin>#<token> std::string NotificationIdGenerator::GenerateForNonPersistentNotification( const url::Origin& origin, const std::string& token) const {
diff --git a/content/browser/notifications/notification_id_generator.h b/content/browser/notifications/notification_id_generator.h index 8ccf902..ab596fb 100644 --- a/content/browser/notifications/notification_id_generator.h +++ b/content/browser/notifications/notification_id_generator.h
@@ -36,6 +36,10 @@ // It is important to note that, for persistent notifications, the generated // notification id can outlive the browser process responsible for creating it. // +// The browser may create notifications on behalf of an origin which will be +// captured as part of the notification id to make sure those ids don't collide +// with ones created via the website. +// // Note that the PlatformNotificationService is expected to handle // distinguishing identical generated ids from different browser contexts. // @@ -56,11 +60,13 @@ const base::StringPiece& notification_id); // Generates an id for a persistent notification given the notification's - // origin, tag and persistent notification id. The persistent notification id - // will have been created by the persistent notification database. + // origin, tag, is_shown_by_browser and persistent notification id. The + // persistent notification id will have been created by the persistent + // notification database. std::string GenerateForPersistentNotification( const GURL& origin, const std::string& tag, + bool is_shown_by_browser, int64_t persistent_notification_id) const; // Generates an id for a non-persistent notification given the notification's
diff --git a/content/browser/notifications/notification_id_generator_unittest.cc b/content/browser/notifications/notification_id_generator_unittest.cc index b803113..84130ca 100644 --- a/content/browser/notifications/notification_id_generator_unittest.cc +++ b/content/browser/notifications/notification_id_generator_unittest.cc
@@ -34,14 +34,18 @@ // in exactly the same notification ids being generated. TEST_F(NotificationIdGeneratorTest, GenerateForPersistent_IsDetermenistic) { EXPECT_EQ(generator_.GenerateForPersistentNotification( - origin_.GetURL(), kExampleTag, kPersistentNotificationId), + origin_.GetURL(), kExampleTag, false /* is_shown_by_browser */, + kPersistentNotificationId), generator_.GenerateForPersistentNotification( - origin_.GetURL(), kExampleTag, kPersistentNotificationId)); + origin_.GetURL(), kExampleTag, false /* is_shown_by_browser */, + kPersistentNotificationId)); EXPECT_EQ(generator_.GenerateForPersistentNotification( - origin_.GetURL(), "" /* tag */, kPersistentNotificationId), + origin_.GetURL(), "" /* tag */, false /* is_shown_by_browser */, + kPersistentNotificationId), generator_.GenerateForPersistentNotification( - origin_.GetURL(), "" /* tag */, kPersistentNotificationId)); + origin_.GetURL(), "" /* tag */, false /* is_shown_by_browser */, + kPersistentNotificationId)); } // The origin of the notification will impact the generated notification id. @@ -49,11 +53,12 @@ url::Origin different_origin( url::Origin::Create(GURL("https://example2.com"))); - EXPECT_NE( - generator_.GenerateForPersistentNotification( - origin_.GetURL(), kExampleTag, kPersistentNotificationId), - generator_.GenerateForPersistentNotification( - different_origin.GetURL(), kExampleTag, kPersistentNotificationId)); + EXPECT_NE(generator_.GenerateForPersistentNotification( + origin_.GetURL(), kExampleTag, false /* is_shown_by_browser */, + kPersistentNotificationId), + generator_.GenerateForPersistentNotification( + different_origin.GetURL(), kExampleTag, + false /* is_shown_by_browser */, kPersistentNotificationId)); } // The tag, when non-empty, will impact the generated notification id. @@ -61,18 +66,22 @@ const std::string& different_tag = std::string(kExampleTag) + "2"; EXPECT_NE(generator_.GenerateForPersistentNotification( - origin_.GetURL(), kExampleTag, kPersistentNotificationId), + origin_.GetURL(), kExampleTag, false /* is_shown_by_browser */, + kPersistentNotificationId), generator_.GenerateForPersistentNotification( - origin_.GetURL(), different_tag, kPersistentNotificationId)); + origin_.GetURL(), different_tag, + false /* is_shown_by_browser */, kPersistentNotificationId)); } // The persistent or non-persistent notification id will impact the generated // notification id when the tag is empty. TEST_F(NotificationIdGeneratorTest, GenerateForPersistent_DifferentIds) { EXPECT_NE(generator_.GenerateForPersistentNotification( - origin_.GetURL(), "" /* tag */, kPersistentNotificationId), + origin_.GetURL(), "" /* tag */, false /* is_shown_by_browser */, + kPersistentNotificationId), generator_.GenerateForPersistentNotification( - origin_.GetURL(), "" /* tag */, kPersistentNotificationId + 1)); + origin_.GetURL(), "" /* tag */, false /* is_shown_by_browser */, + kPersistentNotificationId + 1)); } // Using a numeric tag that could resemble a persistent notification id should @@ -81,9 +90,10 @@ EXPECT_NE( generator_.GenerateForPersistentNotification( origin_.GetURL(), base::NumberToString(kPersistentNotificationId), - kPersistentNotificationId), + false /* is_shown_by_browser */, kPersistentNotificationId), generator_.GenerateForPersistentNotification( - origin_.GetURL(), "" /* tag */, kPersistentNotificationId)); + origin_.GetURL(), "" /* tag */, false /* is_shown_by_browser */, + kPersistentNotificationId)); } // Using port numbers and a tag which, when concatenated, could end up being @@ -93,9 +103,11 @@ GURL origin_8051("https://example.com:8051"); EXPECT_NE(generator_.GenerateForPersistentNotification( - origin_805, "17", kPersistentNotificationId), + origin_805, "17", false /* is_shown_by_browser */, + kPersistentNotificationId), generator_.GenerateForPersistentNotification( - origin_8051, "7", kPersistentNotificationId)); + origin_8051, "7", false /* is_shown_by_browser */, + kPersistentNotificationId)); } // ----------------------------------------------------------------------------- @@ -142,7 +154,8 @@ // identify persistent and non-persistent notification IDs. TEST_F(NotificationIdGeneratorTest, DetectIdFormat) { std::string persistent_id = generator_.GenerateForPersistentNotification( - origin_.GetURL(), "" /* tag */, kPersistentNotificationId); + origin_.GetURL(), "" /* tag */, false /* is_shown_by_browser */, + kPersistentNotificationId); std::string non_persistent_id = generator_.GenerateForNonPersistentNotification(origin_, "token"); @@ -157,5 +170,23 @@ NotificationIdGenerator::IsPersistentNotification(non_persistent_id)); } +TEST_F(NotificationIdGeneratorTest, ShownByBrowser) { + std::string id = generator_.GenerateForPersistentNotification( + origin_.GetURL(), "" /* tag */, true /* is_shown_by_browser */, + kPersistentNotificationId); + + // We should still be able to detect browser notifications as persistent. + EXPECT_TRUE(NotificationIdGenerator::IsPersistentNotification(id)); + EXPECT_FALSE(NotificationIdGenerator::IsNonPersistentNotification(id)); + + // Browser vs non-browser ids should be different. + EXPECT_NE(generator_.GenerateForPersistentNotification( + origin_.GetURL(), kExampleTag, false /* is_shown_by_browser */, + kPersistentNotificationId), + generator_.GenerateForPersistentNotification( + origin_.GetURL(), kExampleTag, true /* is_shown_by_browser */, + kPersistentNotificationId)); +} + } // namespace } // namespace content
diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc index 7cd9f5fd..4e194cb 100644 --- a/content/browser/notifications/platform_notification_context_impl.cc +++ b/content/browser/notifications/platform_notification_context_impl.cc
@@ -378,12 +378,14 @@ InitializeDatabase(base::BindOnce( &PlatformNotificationContextImpl::DoDeleteAllNotificationDataForOrigins, - this, std::move(origins), /* tag= */ std::string(), std::move(callback))); + this, std::move(origins), /* tag= */ std::string(), + /* is_shown_by_browser= */ absl::nullopt, std::move(callback))); } void PlatformNotificationContextImpl::DoDeleteAllNotificationDataForOrigins( std::set<GURL> origins, const std::string& tag, + absl::optional<bool> is_shown_by_browser, DeleteAllResultCallback callback, bool initialized) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); @@ -398,7 +400,7 @@ NotificationDatabase::Status status = NotificationDatabase::STATUS_OK; for (const auto& origin : origins) { status = database_->DeleteAllNotificationDataForOrigin( - origin, tag, &deleted_notification_ids); + origin, tag, is_shown_by_browser, &deleted_notification_ids); if (status != NotificationDatabase::STATUS_OK) break; } @@ -426,13 +428,14 @@ void PlatformNotificationContextImpl::DeleteAllNotificationDataWithTag( const std::string& tag, + absl::optional<bool> is_shown_by_browser, const GURL& origin, DeleteAllResultCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); std::set<GURL> origins = {origin}; InitializeDatabase(base::BindOnce( &PlatformNotificationContextImpl::DoDeleteAllNotificationDataForOrigins, - this, std::move(origins), tag, std::move(callback))); + this, std::move(origins), tag, is_shown_by_browser, std::move(callback))); } void PlatformNotificationContextImpl::ReadNotificationDataAndRecordInteraction( @@ -794,9 +797,12 @@ std::vector<NotificationDatabaseData> notification_datas; + // TODO(crbug.com/1202149): Pass in via an argument whether we want to include + // notifications shown by the browser or not. NotificationDatabase::Status status = database_->ReadAllNotificationDataForServiceWorkerRegistration( - origin, service_worker_registration_id, ¬ification_datas); + origin, service_worker_registration_id, + /* is_shown_by_browser= */ false, ¬ification_datas); UMA_HISTOGRAM_ENUMERATION("Notifications.Database.ReadForServiceWorkerResult", status, NotificationDatabase::STATUS_COUNT); @@ -936,7 +942,7 @@ std::string notification_id = notification_id_generator_.GenerateForPersistentNotification( origin, database_data.notification_data.tag, - persistent_notification_id); + database_data.is_shown_by_browser, persistent_notification_id); // Eagerly delete data for replaced notifications from the database. if (!database_data.notification_data.tag.empty()) { @@ -944,7 +950,7 @@ NotificationDatabase::Status delete_status = database_->DeleteAllNotificationDataForOrigin( origin, database_data.notification_data.tag, - &deleted_notification_ids); + database_data.is_shown_by_browser, &deleted_notification_ids); replaces_existing = deleted_notification_ids.count(notification_id) != 0; @@ -1062,6 +1068,9 @@ } } + // TODO(crbug.com/1202149): Should we verify that websites don't try to close + // notifications shown by the browser (is_shown_by_browser == true)? + NotificationDatabase::Status status = database_->DeleteNotificationData(notification_id, origin);
diff --git a/content/browser/notifications/platform_notification_context_impl.h b/content/browser/notifications/platform_notification_context_impl.h index b195cb84..9ee758d7 100644 --- a/content/browser/notifications/platform_notification_context_impl.h +++ b/content/browser/notifications/platform_notification_context_impl.h
@@ -101,6 +101,7 @@ DeleteResultCallback callback) override; void DeleteAllNotificationDataWithTag( const std::string& tag, + absl::optional<bool> is_shown_by_browser, const GURL& origin, DeleteAllResultCallback callback) override; void DeleteAllNotificationDataForBlockedOrigins( @@ -275,10 +276,12 @@ // database. Optionally filtered by |tag|. Must only be called on the // |task_runner_| thread. |callback| will be invoked on the UI thread when the // operation has completed. - void DoDeleteAllNotificationDataForOrigins(std::set<GURL> origins, - const std::string& tag, - DeleteAllResultCallback callback, - bool initialized); + void DoDeleteAllNotificationDataForOrigins( + std::set<GURL> origins, + const std::string& tag, + absl::optional<bool> is_shown_by_browser, + DeleteAllResultCallback callback, + bool initialized); // Actually writes the notification resources to the database. Must only be // called on the |task_runner_| thread. |callback| will be invoked on the UI
diff --git a/content/browser/notifications/platform_notification_context_unittest.cc b/content/browser/notifications/platform_notification_context_unittest.cc index a4b8dbd..2e37de1 100644 --- a/content/browser/notifications/platform_notification_context_unittest.cc +++ b/content/browser/notifications/platform_notification_context_unittest.cc
@@ -338,6 +338,27 @@ EXPECT_EQ(notification_database_data.origin, read_database_data.origin); } +TEST_F(PlatformNotificationContextTest, ReadNotificationsFromBrowser) { + scoped_refptr<PlatformNotificationContextImpl> context = + CreatePlatformNotificationContext(); + + GURL origin("https://example.com"); + NotificationDatabaseData data; + data.origin = origin; + data.service_worker_registration_id = kFakeServiceWorkerRegistrationId; + + // Write one notification shown not by the browser. + data.is_shown_by_browser = false; + WriteNotificationDataSync(context.get(), origin, data); + // Write one notification shown by the browser. + data.is_shown_by_browser = true; + WriteNotificationDataSync(context.get(), origin, data); + + // Reading via ReadAllNotificationDataForServiceWorkerRegistration should not + // return notifications shown by the browser. + EXPECT_EQ(1u, GetStoredNotificationsSync(context.get(), origin).size()); +} + TEST_F(PlatformNotificationContextTest, WriteReadReplacedNotification) { scoped_refptr<PlatformNotificationContextImpl> context = CreatePlatformNotificationContext(); @@ -1032,7 +1053,11 @@ data.origin = origin; data.service_worker_registration_id = kFakeServiceWorkerRegistrationId; + // Notification shown by the browser will be visible. + data.is_shown_by_browser = true; + WriteNotificationDataSync(context.get(), origin, data); // Regular notification will be visible. + data.is_shown_by_browser = false; WriteNotificationDataSync(context.get(), origin, data); // We will close this notification without removing it from the database. std::string notification_id = @@ -1042,8 +1067,8 @@ base::Time::Now() + base::TimeDelta::FromDays(10); WriteNotificationDataSync(context.get(), origin, data); - // Expect to see two notifications. - ASSERT_EQ(2u, GetDisplayedNotificationsSync(service).size()); + // Expect to see three notifications. + ASSERT_EQ(3u, GetDisplayedNotificationsSync(service).size()); // Close the notification without deleting it. service->ClosePersistentNotification(notification_id); @@ -1053,8 +1078,8 @@ origin, kFakeServiceWorkerRegistrationId, base::BindLambdaForTesting([&](bool success, int count) { EXPECT_TRUE(success); - // Only the first notification should be counted as visible. - EXPECT_EQ(1, count); + // Only the first two notifications should be counted as visible. + EXPECT_EQ(2, count); run_loop.Quit(); })); run_loop.Run(); @@ -1088,7 +1113,7 @@ base::RunLoop run_loop; context->DeleteAllNotificationDataWithTag( - tag, origin, + tag, /*is_shown_by_browser=*/false, origin, base::BindLambdaForTesting([&](bool success, size_t deleted_count) { EXPECT_TRUE(success); EXPECT_EQ(1u, deleted_count); @@ -1107,6 +1132,53 @@ EXPECT_EQ(0u, displayed_notifications.count(notification_id)); } +TEST_F(PlatformNotificationContextTest, DeleteNotificationsWithTagFromBrowser) { + NotificationBrowserClient notification_browser_client(browser_context()); + SetBrowserClientForTesting(¬ification_browser_client); + PlatformNotificationService* service = + notification_browser_client.GetPlatformNotificationService( + browser_context()); + + scoped_refptr<PlatformNotificationContextImpl> context = + CreatePlatformNotificationContext(); + + const GURL origin("https://example.com"); + const std::string tag = "foo"; + + NotificationDatabaseData data; + data.notification_data.tag = tag; + + // Write notifications from and not from the browser to the database. + data.is_shown_by_browser = false; + WriteNotificationDataSync(context.get(), origin, data); + data.is_shown_by_browser = true; + std::string notification_id = + WriteNotificationDataSync(context.get(), origin, data); + + // Expect to see both notifications. + ASSERT_EQ(2u, GetDisplayedNotificationsSync(service).size()); + + base::RunLoop run_loop; + context->DeleteAllNotificationDataWithTag( + tag, /*is_shown_by_browser=*/true, origin, + base::BindLambdaForTesting([&](bool success, size_t deleted_count) { + EXPECT_TRUE(success); + EXPECT_EQ(1u, deleted_count); + run_loop.Quit(); + })); + run_loop.Run(); + + // The notifications close task has a lower priority than the response + // callback, run tasks so we can check visible notifications after close. + base::RunLoop().RunUntilIdle(); + + // Expect the notification shown by the browser to be closed. + std::set<std::string> displayed_notifications = + GetDisplayedNotificationsSync(service); + EXPECT_EQ(1u, displayed_notifications.size()); + EXPECT_EQ(0u, displayed_notifications.count(notification_id)); +} + TEST_F(PlatformNotificationContextTest, GetOldestNotificationTime) { base::HistogramTester histogram_tester; NotificationBrowserClient notification_browser_client(browser_context());
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index eca080ec..4ed776e 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4873,7 +4873,12 @@ delegate_->ViewSource(this); } -void RenderFrameHostImpl::FlushNetworkAndNavigationInterfacesForTesting() { +void RenderFrameHostImpl::FlushNetworkAndNavigationInterfacesForTesting( + bool do_nothing_if_no_network_service_connection) { + if (do_nothing_if_no_network_service_connection && + !network_service_disconnect_handler_holder_) { + return; + } DCHECK(network_service_disconnect_handler_holder_); network_service_disconnect_handler_holder_.FlushForTesting(); // IN-TEST
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index 409e156..787541b 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -377,7 +377,8 @@ const base::flat_set<url::Origin>& isolated_world_origins, bool push_to_renderer_now) override; bool IsSandboxed(network::mojom::WebSandboxFlags flags) override; - void FlushNetworkAndNavigationInterfacesForTesting() override; + void FlushNetworkAndNavigationInterfacesForTesting( + bool do_nothing_if_no_network_service_connection = false) override; std::string GetBackForwardCanStoreNowDebugStringForTesting() override; void PrepareForInnerWebContentsAttach( PrepareForInnerWebContentsAttachCallback callback) override;
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc index 8fec285ae..f9b0a86 100644 --- a/content/browser/renderer_host/render_widget_host_browsertest.cc +++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -904,9 +904,7 @@ FlagGetsSetFromRenderFrameMetadata) { ASSERT_TRUE(ExecJs(shell()->web_contents(), R"( let presenter = null; - navigator.ink.requestPresenter('delegated-ink-trail').then(e => { - presenter = e; - }); + navigator.ink.requestPresenter().then(e => { presenter = e; }); let style = { color: 'green', diameter: 21 }; window.addEventListener('pointermove' , evt => {
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index 0c9c0d3..ea0b3e9 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -7372,9 +7372,7 @@ EXPECT_TRUE(ExecJs(child->current_frame_host(), R"( let presenter = null; - navigator.ink.requestPresenter('delegated-ink-trail').then(e => { - presenter = e; - }); + navigator.ink.requestPresenter().then(e => { presenter = e; }); let style = { color: 'green', diameter: 21 }; window.addEventListener('pointermove' , evt => {
diff --git a/content/public/browser/notification_database_data.h b/content/public/browser/notification_database_data.h index 862f44d..10070eb 100644 --- a/content/public/browser/notification_database_data.h +++ b/content/public/browser/notification_database_data.h
@@ -92,6 +92,10 @@ // Why the notification was closed. ClosedReason closed_reason = ClosedReason::UNKNOWN; + + // Flag for notifications shown by the browser that should not be visible to + // the origin when requesting a list of notifications. + bool is_shown_by_browser = false; }; } // namespace content
diff --git a/content/public/browser/platform_notification_context.h b/content/public/browser/platform_notification_context.h index 08d00da7..3e756f1b 100644 --- a/content/public/browser/platform_notification_context.h +++ b/content/public/browser/platform_notification_context.h
@@ -15,6 +15,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_database_data.h" #include "content/public/browser/notification_resource_data.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class GURL; @@ -147,12 +148,13 @@ bool close_notification, DeleteResultCallback callback) = 0; - // Deletes all data of notifications with |tag| belonging to |origin| from the - // database and closes the notifications. |callback| will be invoked with the - // success status and the number of closed notifications when the operation - // has completed. + // Deletes all data of notifications with |tag|, optionally filtered by + // |is_shown_by_browser|, belonging to |origin| from the database and closes + // the notifications. |callback| will be invoked with the success status and + // the number of closed notifications when the operation has completed. virtual void DeleteAllNotificationDataWithTag( const std::string& tag, + absl::optional<bool> is_shown_by_browser, const GURL& origin, DeleteAllResultCallback callback) = 0;
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h index 485e7fc..f252b923 100644 --- a/content/public/browser/render_frame_host.h +++ b/content/public/browser/render_frame_host.h
@@ -794,7 +794,13 @@ // Calls |FlushForTesting()| on Network Service and FrameNavigationControl // related interfaces to make sure all in-flight mojo messages have been // received by the other end. For test use only. - virtual void FlushNetworkAndNavigationInterfacesForTesting() = 0; + // + // It is usually an error to call this method when the frame doesn't have any + // NetworkService connection. OTOH, tests that can't easily tell when this + // may happen can set `do_nothing_if_no_network_service_connection` to true + // (this should be needed relatively rarely). + virtual void FlushNetworkAndNavigationInterfacesForTesting( + bool do_nothing_if_no_network_service_connection = false) = 0; // Retrieve the back/forward cache CanStoreNow debug string. virtual std::string GetBackForwardCanStoreNowDebugStringForTesting() = 0;
diff --git a/content/public/browser/web_contents_receiver_set.h b/content/public/browser/web_contents_receiver_set.h index 725e64c..f5b7c44a 100644 --- a/content/public/browser/web_contents_receiver_set.h +++ b/content/public/browser/web_contents_receiver_set.h
@@ -18,7 +18,6 @@ #include "mojo/public/cpp/bindings/pending_associated_receiver.h" #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" -class ChromePasswordManagerClient; class EmbeddedSearchClientFactoryImpl; class LiteVideoObserver; class OfflinePageTabHelper; @@ -122,7 +121,6 @@ private: WebContentsFrameReceiverSetPassKey() = default; - friend class ::ChromePasswordManagerClient; friend class ::EmbeddedSearchClientFactoryImpl; friend class ::LiteVideoObserver; friend class ::PluginObserver;
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc index 8f42fc3..537926a 100644 --- a/content/renderer/accessibility/render_accessibility_impl.cc +++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -444,11 +444,6 @@ } } -void RenderAccessibilityImpl::HandleWebAccessibilityEvent( - const ui::AXEvent& event) { - HandleAXEvent(event); -} - void RenderAccessibilityImpl::MarkWebAXObjectDirty( const WebAXObject& obj, bool subtree,
diff --git a/content/renderer/accessibility/render_accessibility_impl.h b/content/renderer/accessibility/render_accessibility_impl.h index 04715d8..765c2a9 100644 --- a/content/renderer/accessibility/render_accessibility_impl.h +++ b/content/renderer/accessibility/render_accessibility_impl.h
@@ -120,14 +120,13 @@ void Reset(int32_t reset_token); // Called when an accessibility notification occurs in Blink. - void HandleWebAccessibilityEvent(const ui::AXEvent& event); + void HandleAXEvent(const ui::AXEvent& event); void MarkWebAXObjectDirty( const blink::WebAXObject& obj, bool subtree, ax::mojom::Action event_from_action = ax::mojom::Action::kNone, std::vector<ui::AXEventIntent> event_intents = {}); - void HandleAXEvent(const ui::AXEvent& event); // Returns the main top-level document for this page, or NULL if there's // no view or frame.
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 21a03f22..c96d327 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -4508,8 +4508,8 @@ if (!IsAccessibilityEnabled()) return; - render_accessibility_manager_->GetRenderAccessibilityImpl() - ->HandleWebAccessibilityEvent(event); + render_accessibility_manager_->GetRenderAccessibilityImpl()->HandleAXEvent( + event); } void RenderFrameImpl::MarkWebAXObjectDirty(
diff --git a/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2 b/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2 index 281f73e..0fb1409 100644 --- a/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2 +++ b/content/shell/android/browsertests_apk/AndroidManifest.xml.jinja2
@@ -27,6 +27,7 @@ android:theme="@android:style/Theme.Holo.Light.NoActionBar" android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" + android:exported="true" android:process=":test_process"> <intent-filter> <action android:name="android.intent.action.MAIN"/>
diff --git a/content/shell/android/shell_apk/AndroidManifest.xml.jinja2 b/content/shell/android/shell_apk/AndroidManifest.xml.jinja2 index 251c702..2722488 100644 --- a/content/shell/android/shell_apk/AndroidManifest.xml.jinja2 +++ b/content/shell/android/shell_apk/AndroidManifest.xml.jinja2
@@ -31,7 +31,8 @@ android:theme="@android:style/Theme.Holo.Light.NoActionBar" android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:windowSoftInputMode="adjustResize" - android:hardwareAccelerated="true"> + android:hardwareAccelerated="true" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/google_apis/google_api_keys.cc b/google_apis/google_api_keys.cc index 17327b9..f63d9dc 100644 --- a/google_apis/google_api_keys.cc +++ b/google_apis/google_api_keys.cc
@@ -74,11 +74,8 @@ #define GOOGLE_CLIENT_SECRET_REMOTING_HOST DUMMY_API_TOKEN #endif -// This is really the API key for non-stable channels on Android. It's -// named after the first feature that used it. -// TODO(jkrcal,rogerta): Rename this to GOOGLE_API_KEY_ANDROID_NON_STABLE. -#if !defined(GOOGLE_API_KEY_PHYSICAL_WEB_TEST) -#define GOOGLE_API_KEY_PHYSICAL_WEB_TEST DUMMY_API_TOKEN +#if !defined(GOOGLE_API_KEY_ANDROID_NON_STABLE) +#define GOOGLE_API_KEY_ANDROID_NON_STABLE DUMMY_API_TOKEN #endif #if !defined(GOOGLE_API_KEY_REMOTING) @@ -132,8 +129,8 @@ // A special non-stable key is at the moment defined only for Android Chrome. #if defined(OS_ANDROID) api_key_non_stable_ = CalculateKeyValue( - GOOGLE_API_KEY_PHYSICAL_WEB_TEST, - STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_PHYSICAL_WEB_TEST), nullptr, + GOOGLE_API_KEY_ANDROID_NON_STABLE, + STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_ANDROID_NON_STABLE), nullptr, std::string(), environment.get(), command_line, gaia_config); #else api_key_non_stable_ = api_key_;
diff --git a/google_apis/google_api_keys.py b/google_apis/google_api_keys.py index 664169b..8ba81c5 100755 --- a/google_apis/google_api_keys.py +++ b/google_apis/google_api_keys.py
@@ -72,9 +72,9 @@ return _GetToken('GOOGLE_API_KEY') -def GetAPIKeyPhysicalWebTest(): - """Returns the API key to test Physical Web service.""" - return _GetToken('GOOGLE_API_KEY_PHYSICAL_WEB_TEST') +def GetAPIKeyAndroidNonStable(): + """Returns the API key for non-stable Android.""" + return _GetToken('GOOGLE_API_KEY_ANDROID_NON_STABLE') def GetClientID(client_name):
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index 1928e03..8ce915d 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn
@@ -344,8 +344,6 @@ "command_buffer/tests/gl_set_aggressively_free_resources_unittest.cc", "command_buffer/tests/gl_shared_resources_unittest.cc", "command_buffer/tests/gl_stream_draw_unittest.cc", - "command_buffer/tests/gl_test_setup_helper.cc", - "command_buffer/tests/gl_test_setup_helper.h", "command_buffer/tests/gl_test_utils.cc", "command_buffer/tests/gl_test_utils.h", "command_buffer/tests/gl_tests_main.cc",
diff --git a/gpu/command_buffer/service/shared_image_backing_egl_image.cc b/gpu/command_buffer/service/shared_image_backing_egl_image.cc index 9efed56..fb5d19d9c 100644 --- a/gpu/command_buffer/service/shared_image_backing_egl_image.cc +++ b/gpu/command_buffer/service/shared_image_backing_egl_image.cc
@@ -180,6 +180,7 @@ GLuint gl_type, SharedImageBatchAccessManager* batch_access_manager, const GpuDriverBugWorkarounds& workarounds, + const SharedImageBackingGLCommon::UnpackStateAttribs& attribs, bool use_passthrough) : ClearTrackingSharedImageBacking(mailbox, format, @@ -193,6 +194,7 @@ gl_format_(gl_format), gl_type_(gl_type), batch_access_manager_(batch_access_manager), + gl_unpack_attribs_(attribs), use_passthrough_(use_passthrough) { DCHECK(batch_access_manager_); created_on_context_ = gl::g_current_gl_context; @@ -457,4 +459,20 @@ source_texture_holder_.reset(); } +void SharedImageBackingEglImage::InitializePixels(GLenum format, + GLenum type, + const uint8_t* data) { + auto texture_holder = + source_texture_holder_ ? source_texture_holder_ : GenEGLImageSibling(); + const GLenum target = texture_holder->texture()->target(); + const unsigned int service_id = texture_holder->texture()->service_id(); + gl::GLApi* api = gl::g_current_gl_context; + SharedImageBackingGLCommon::ScopedRestoreTexture scoped_restore(api, target); + api->glBindTextureFn(target, service_id); + SharedImageBackingGLCommon::ScopedResetAndRestoreUnpackState + scoped_unpack_state(api, gl_unpack_attribs_, true /* uploading_data */); + api->glTexSubImage2DFn(target, 0, 0, 0, size().width(), size().height(), + format, type, data); +} + } // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing_egl_image.h b/gpu/command_buffer/service/shared_image_backing_egl_image.h index c3460e3..550eb759 100644 --- a/gpu/command_buffer/service/shared_image_backing_egl_image.h +++ b/gpu/command_buffer/service/shared_image_backing_egl_image.h
@@ -8,6 +8,7 @@ #include "base/memory/scoped_refptr.h" #include "components/viz/common/resources/resource_format.h" #include "gpu/command_buffer/service/shared_image_backing.h" +#include "gpu/command_buffer/service/shared_image_backing_gl_common.h" #include "ui/gfx/buffer_types.h" #include "ui/gl/gl_bindings.h" @@ -47,6 +48,7 @@ GLuint gl_type, SharedImageBatchAccessManager* batch_access_manager, const GpuDriverBugWorkarounds& workarounds, + const SharedImageBackingGLCommon::UnpackStateAttribs& attribs, bool use_passthrough); ~SharedImageBackingEglImage() override; @@ -55,6 +57,8 @@ bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override; void MarkForDestruction() override; + void InitializePixels(GLenum format, GLenum type, const uint8_t* data); + protected: std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture( SharedImageManager* manager, @@ -115,6 +119,7 @@ GUARDED_BY(lock_); SharedImageBatchAccessManager* batch_access_manager_ = nullptr; + const SharedImageBackingGLCommon::UnpackStateAttribs gl_unpack_attribs_; const bool use_passthrough_; DISALLOW_COPY_AND_ASSIGN(SharedImageBackingEglImage);
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_egl.cc b/gpu/command_buffer/service/shared_image_backing_factory_egl.cc index 5dd5ba1..0734505 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_egl.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_egl.cc
@@ -31,53 +31,11 @@ const GpuDriverBugWorkarounds& workarounds, const GpuFeatureInfo& gpu_feature_info, SharedImageBatchAccessManager* batch_access_manager) - : use_passthrough_(gpu_preferences.use_passthrough_cmd_decoder && - gles2::PassthroughCommandDecoderSupported()), - workarounds_(workarounds) { - batch_access_manager_ = batch_access_manager; - gl::GLApi* api = gl::g_current_gl_context; - api->glGetIntegervFn(GL_MAX_TEXTURE_SIZE, &max_texture_size_); - // When the passthrough command decoder is used, the max_texture_size - // workaround is implemented by ANGLE. Trying to adjust the max size here - // would cause discrepancy between what we think the max size is and what - // ANGLE tells the clients. - if (!use_passthrough_ && workarounds.max_texture_size) { - max_texture_size_ = - std::min(max_texture_size_, workarounds.max_texture_size); - } - // Ensure max_texture_size_ is less than INT_MAX so that gfx::Rect and friends - // can be used to accurately represent all valid sub-rects, with overflow - // cases, clamped to INT_MAX, always invalid. - max_texture_size_ = std::min(max_texture_size_, INT_MAX - 1); - - // TODO(piman): Can we extract the logic out of FeatureInfo? - scoped_refptr<gles2::FeatureInfo> feature_info = - new gles2::FeatureInfo(workarounds, gpu_feature_info); - feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2, - use_passthrough_, gles2::DisallowedFeatures()); - const gles2::Validators* validators = feature_info->validators(); - for (int i = 0; i <= viz::RESOURCE_FORMAT_MAX; ++i) { - auto format = static_cast<viz::ResourceFormat>(i); - FormatInfo& info = format_info_[i]; - if (!viz::GLSupportsFormat(format)) - continue; - const GLuint image_internal_format = viz::GLInternalFormat(format); - const GLenum gl_format = viz::GLDataFormat(format); - const GLenum gl_type = viz::GLDataType(format); - const bool uncompressed_format_valid = - validators->texture_internal_format.IsValid(image_internal_format) && - validators->texture_format.IsValid(gl_format); - const bool compressed_format_valid = - validators->compressed_texture_format.IsValid(image_internal_format); - if ((uncompressed_format_valid || compressed_format_valid) && - validators->pixel_type.IsValid(gl_type)) { - info.enabled = true; - info.is_compressed = compressed_format_valid; - info.gl_format = gl_format; - info.gl_type = gl_type; - } - } -} + : SharedImageBackingFactoryGLCommon(gpu_preferences, + workarounds, + gpu_feature_info, + /*progress_reporter=*/nullptr), + batch_access_manager_(batch_access_manager) {} SharedImageBackingFactoryEGL::~SharedImageBackingFactoryEGL() = default; @@ -93,7 +51,7 @@ uint32_t usage, bool is_thread_safe) { return MakeEglImageBacking(mailbox, format, size, color_space, surface_origin, - alpha_type, usage); + alpha_type, usage, base::span<const uint8_t>()); } std::unique_ptr<SharedImageBacking> @@ -106,8 +64,8 @@ SkAlphaType alpha_type, uint32_t usage, base::span<const uint8_t> pixel_data) { - NOTIMPLEMENTED_LOG_ONCE(); - return nullptr; + return MakeEglImageBacking(mailbox, format, size, color_space, surface_origin, + alpha_type, usage, pixel_data); } std::unique_ptr<SharedImageBacking> @@ -135,9 +93,10 @@ GrContextType gr_context_type, bool* allow_legacy_mailbox, bool is_pixel_used) { - if (is_pixel_used) { + if (is_pixel_used && gr_context_type != GrContextType::kGL) { return false; } + // Doesn't support gmb for now if (gmb_type != gfx::EMPTY_BUFFER) { return false; @@ -163,18 +122,13 @@ const gfx::ColorSpace& color_space, GrSurfaceOrigin surface_origin, SkAlphaType alpha_type, - uint32_t usage) { - const FormatInfo& format_info = format_info_[format]; - if (!format_info.enabled) { - DLOG(ERROR) << "MakeEglImageBacking: invalid format"; - return nullptr; - } - + uint32_t usage, + base::span<const uint8_t> pixel_data) { DCHECK(!(usage & SHARED_IMAGE_USAGE_SCANOUT)); - if (size.width() < 1 || size.height() < 1 || - size.width() > max_texture_size_ || size.height() > max_texture_size_) { - DLOG(ERROR) << "MakeEglImageBacking: Invalid size"; + const FormatInfo& format_info = format_info_[format]; + GLenum target = GL_TEXTURE_2D; + if (!CanCreateSharedImage(size, pixel_data, format_info, target)) { return nullptr; } @@ -185,10 +139,16 @@ return nullptr; } - return std::make_unique<SharedImageBackingEglImage>( + auto egl_backing = std::make_unique<SharedImageBackingEglImage>( mailbox, format, size, color_space, surface_origin, alpha_type, usage, estimated_size, format_info.gl_format, format_info.gl_type, - batch_access_manager_, workarounds_, use_passthrough_); + batch_access_manager_, workarounds_, attribs_, use_passthrough_); + + if (!pixel_data.empty()) { + egl_backing->InitializePixels(format_info.adjusted_format, + format_info.gl_type, pixel_data.data()); + } + return egl_backing; } } // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_egl.h b/gpu/command_buffer/service/shared_image_backing_factory_egl.h index 6e24953e..9778944 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_egl.h +++ b/gpu/command_buffer/service/shared_image_backing_factory_egl.h
@@ -9,6 +9,7 @@ #include "components/viz/common/resources/resource_format.h" #include "gpu/command_buffer/service/shared_image_backing_factory.h" +#include "gpu/command_buffer/service/shared_image_backing_factory_gl_common.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/gpu_gles2_export.h" #include "ui/gfx/buffer_types.h" @@ -30,7 +31,7 @@ // Implementation of SharedImageBackingFactory that produces EGL backed // SharedImages. class GPU_GLES2_EXPORT SharedImageBackingFactoryEGL - : public SharedImageBackingFactory { + : public SharedImageBackingFactoryGLCommon { public: SharedImageBackingFactoryEGL( const GpuPreferences& gpu_preferences, @@ -87,26 +88,8 @@ const gfx::ColorSpace& color_space, GrSurfaceOrigin surface_origin, SkAlphaType alpha_type, - uint32_t usage); - - struct FormatInfo { - // Whether this format is supported. - bool enabled = false; - - // Whether the texture is a compressed type. - bool is_compressed = false; - - GLenum gl_format = 0; - GLenum gl_type = 0; - }; - - // Whether we're using the passthrough command decoder and should generate - // passthrough textures. - const bool use_passthrough_; - - FormatInfo format_info_[viz::RESOURCE_FORMAT_MAX + 1]; - int32_t max_texture_size_ = 0; - GpuDriverBugWorkarounds workarounds_; + uint32_t usage, + base::span<const uint8_t> pixel_data); SharedImageBatchAccessManager* batch_access_manager_ = nullptr; };
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_egl_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_egl_unittest.cc index e5de993..67c0d48 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_egl_unittest.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_egl_unittest.cc
@@ -144,7 +144,8 @@ SharedImageManager* shared_image_manager, MemoryTypeTracker* memory_type_tracker, SharedImageRepresentationFactory* shared_image_representation_factory, - SharedContextState* context_state); + SharedContextState* context_state, + bool upload_initial_data); ~CreateAndValidateSharedImageRepresentations(); gfx::Size size() { return size_; } @@ -165,7 +166,17 @@ backing_factory_.get(), get_format(), true /* is_thread_safe */, &mailbox_manager_, shared_image_manager_.get(), memory_type_tracker_.get(), shared_image_representation_factory_.get(), - context_state_.get()); + context_state_.get(), /*upload_initial_data=*/false); +} + +// Intent of this test is to create at thread safe backing with initial pixel +// data and test if all representations are working. +TEST_P(SharedImageBackingFactoryEGLThreadSafeTest, BasicInitialData) { + CreateAndValidateSharedImageRepresentations shared_image( + backing_factory_.get(), get_format(), true /* is_thread_safe */, + &mailbox_manager_, shared_image_manager_.get(), + memory_type_tracker_.get(), shared_image_representation_factory_.get(), + context_state_.get(), /*upload_initial_data=*/true); } // Intent of this test is to use the shared image mailbox system by 2 different @@ -178,7 +189,7 @@ backing_factory_.get(), get_format(), true /* is_thread_safe */, &mailbox_manager_, shared_image_manager_.get(), memory_type_tracker_.get(), shared_image_representation_factory_.get(), - context_state_.get()); + context_state_.get(), /*upload_initial_data=*/false); auto mailbox = shared_image.mailbox(); auto size = shared_image.size(); @@ -252,7 +263,8 @@ SharedImageManager* shared_image_manager, MemoryTypeTracker* memory_type_tracker, SharedImageRepresentationFactory* shared_image_representation_factory, - SharedContextState* context_state) + SharedContextState* context_state, + bool upload_initial_data) : mailbox_manager_(mailbox_manager), size_(256, 256) { // Make the context current. DCHECK(context_state); @@ -269,9 +281,17 @@ uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_RASTER; if (!is_thread_safe) usage |= SHARED_IMAGE_USAGE_DISPLAY; - backing_ = backing_factory->CreateSharedImage( - mailbox_, format, surface_handle, size_, color_space, surface_origin, - alpha_type, usage, is_thread_safe); + if (upload_initial_data) { + std::vector<uint8_t> initial_data( + viz::ResourceSizes::CheckedSizeInBytes<unsigned int>(size_, format)); + backing_ = backing_factory->CreateSharedImage( + mailbox_, format, size_, color_space, surface_origin, alpha_type, usage, + initial_data); + } else { + backing_ = backing_factory->CreateSharedImage( + mailbox_, format, surface_handle, size_, color_space, surface_origin, + alpha_type, usage, is_thread_safe); + } // As long as either |chromium_image_ar30| or |chromium_image_ab30| is // enabled, we can create a non-scanout SharedImage with format
diff --git a/gpu/command_buffer/tests/gl_test_setup_helper.cc b/gpu/command_buffer/tests/gl_test_setup_helper.cc deleted file mode 100644 index 78b5b03b..0000000 --- a/gpu/command_buffer/tests/gl_test_setup_helper.cc +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gpu/command_buffer/tests/gl_test_setup_helper.h" - -#include "components/viz/test/test_gpu_service_holder.h" -#include "gpu/command_buffer/client/gles2_lib.h" -#include "gpu/command_buffer/tests/gl_test_utils.h" -#include "ui/gl/init/gl_factory.h" - -namespace gpu { - -GLTestSetupHelper::GLTestSetupHelper() { - viz::TestGpuServiceHolder::DoNotResetOnTestExit(); - testing::TestEventListeners& listeners = - testing::UnitTest::GetInstance()->listeners(); - listeners.Append(this); -} - -GLTestSetupHelper::~GLTestSetupHelper() { - testing::TestEventListeners& listeners = - testing::UnitTest::GetInstance()->listeners(); - CHECK_EQ(this, listeners.Release(this)); -} - -void GLTestSetupHelper::OnTestStart(const testing::TestInfo& test_info) { - gpu::GLTestHelper::InitializeGLDefault(); - ::gles2::Initialize(); -} - -void GLTestSetupHelper::OnTestEnd(const testing::TestInfo& test_info) { - // Explicitly tear down the gpu-service (if active) before shutting down GL. - // Otherwise the gpu-service tries to access GL during tear-down and causes - // crashes. - viz::TestGpuServiceHolder::ResetInstance(); - gl::init::ShutdownGL(/*due_to_fallback=*/false); -} - -} // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_test_setup_helper.h b/gpu/command_buffer/tests/gl_test_setup_helper.h deleted file mode 100644 index 402c03a..0000000 --- a/gpu/command_buffer/tests/gl_test_setup_helper.h +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GPU_COMMAND_BUFFER_TESTS_GL_TEST_SETUP_HELPER_H_ -#define GPU_COMMAND_BUFFER_TESTS_GL_TEST_SETUP_HELPER_H_ - -#include "testing/gtest/include/gtest/gtest.h" - -namespace gpu { - -// Helper class to automatically set-up and initialize GL environment before -// every test, and tear down the environment after every test. This should -// normally be used from base::TestSuite instances, so that it takes care of the -// set-up/tear-down between every test, and each test does not have to do this -// explicitly. -class GLTestSetupHelper : public testing::EmptyTestEventListener { - public: - GLTestSetupHelper(); - ~GLTestSetupHelper(); - - // testing::EmptyTestEventListener: - void OnTestStart(const testing::TestInfo& test_info) override; - void OnTestEnd(const testing::TestInfo& test_info) override; -}; - -} // namespace gpu -#endif // GPU_COMMAND_BUFFER_TESTS_GL_TEST_SETUP_HELPER_H_
diff --git a/gpu/command_buffer/tests/gl_tests_main.cc b/gpu/command_buffer/tests/gl_tests_main.cc index 86ac4559..cb0166c 100644 --- a/gpu/command_buffer/tests/gl_tests_main.cc +++ b/gpu/command_buffer/tests/gl_tests_main.cc
@@ -11,7 +11,7 @@ #include "base/test/task_environment.h" #include "base/test/test_suite.h" #include "build/build_config.h" -#include "gpu/command_buffer/tests/gl_test_setup_helper.h" +#include "gpu/command_buffer/client/gles2_lib.h" #include "gpu/command_buffer/tests/gl_test_utils.h" #include "mojo/core/embedder/embedder.h" #include "testing/gmock/include/gmock/gmock.h" @@ -49,12 +49,13 @@ ui::OzonePlatform::InitializeForGPU(params); } #endif - gl_setup_ = std::make_unique<gpu::GLTestSetupHelper>(); + gpu::GLTestHelper::InitializeGLDefault(); + + ::gles2::Initialize(); } private: std::unique_ptr<base::test::TaskEnvironment> task_environment_; - std::unique_ptr<gpu::GLTestSetupHelper> gl_setup_; }; } // namespace
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index de26e6f..b5ae040 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg
@@ -29622,6 +29622,98 @@ } } builders { + name: "android-cronet-x86-dbg-10-tests" + swarming_host: "chromium-swarm.appspot.com" + swarming_tags: "vpython:native-python-wrapper" + dimensions: "builderless:1" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-18.04" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:0" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/master" + cmd: "luciexe" + } + properties: + '{' + ' "$build/goma": {' + ' "enable_ats": true,' + ' "rpc_extra_params": "?prod",' + ' "server_host": "goma.chromium.org",' + ' "use_luci_auth": true' + ' },' + ' "$kitchen": {' + ' "devshell": true,' + ' "git_auth": true' + ' },' + ' "$recipe_engine/isolated": {' + ' "server": "https://isolateserver.appspot.com"' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "chromium.android.fyi",' + ' "recipe": "chromium"' + '}' + execution_timeout_secs: 10800 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { + key: "chromium.resultdb.result_sink.gtests_local" + value: 100 + } + experiments { + key: "chromium.resultdb.result_sink.junit_tests" + value: 100 + } + experiments { + key: "luci.use_realms" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "luci-resultdb" + dataset: "chromium" + table: "ci_test_results" + test_results {} + } + bq_exports { + project: "luci-resultdb" + dataset: "chromium" + table: "gpu_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+" + } + } + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "blink_web_tests_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://[^/]*blink_web_tests/.+" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "android-cronet-x86-rel" swarming_host: "chromium-swarm.appspot.com" swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg index eaceaf3c..9240459 100644 --- a/infra/config/generated/luci-milo.cfg +++ b/infra/config/generated/luci-milo.cfg
@@ -3478,6 +3478,11 @@ short_name: "P" } builders { + name: "buildbucket/luci.chromium.ci/android-cronet-x86-dbg-10-tests" + category: "cronet|test" + short_name: "10" + } + builders { name: "buildbucket/luci.chromium.ci/android-11-x86-fyi-rel" category: "emulator|11|x86" short_name: "rel"
diff --git a/infra/config/generated/luci-notify.cfg b/infra/config/generated/luci-notify.cfg index 7087c0a..843c889 100644 --- a/infra/config/generated/luci-notify.cfg +++ b/infra/config/generated/luci-notify.cfg
@@ -2423,6 +2423,18 @@ } builders { bucket: "ci" + name: "android-cronet-x86-dbg-10-tests" + } +} +notifiers { + notifications { + on_change: true + email { + recipients: "cronet-sheriff@grotations.appspotmail.com" + } + } + builders { + bucket: "ci" name: "android-cronet-x86-rel" repository: "https://chromium.googlesource.com/chromium/src" }
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg index c91958c0..0ead81a 100644 --- a/infra/config/generated/luci-scheduler.cfg +++ b/infra/config/generated/luci-scheduler.cfg
@@ -4600,6 +4600,20 @@ } } job { + id: "android-cronet-x86-dbg-10-tests" + realm: "ci" + acls { + role: TRIGGERER + granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + } + acl_sets: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "android-cronet-x86-dbg-10-tests" + } +} +job { id: "android-cronet-x86-rel" realm: "ci" acl_sets: "ci"
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star index 7326544..1690ad0 100644 --- a/infra/config/subprojects/chromium/ci.star +++ b/infra/config/subprojects/chromium/ci.star
@@ -854,6 +854,16 @@ notifies = ["cronet"], ) +ci.android_fyi_builder( + name = "android-cronet-x86-dbg-10-tests", + console_view_entry = consoles.console_view_entry( + category = "cronet|test", + short_name = "10", + ), + notifies = ["cronet"], + triggered_by = ["android-cronet-x86-dbg"], +) + ci.android_builder( name = "android-cronet-x86-rel", console_view_entry = consoles.console_view_entry(
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd index 2b67cc7..805d7cb 100644 --- a/ios/chrome/app/strings/ios_google_chrome_strings.grd +++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -169,7 +169,7 @@ Copied to Chrome </message> <message name="IDS_IOS_BANDWIDTH_MANAGEMENT_DESCRIPTION_LEARN_MORE" desc="Description text bandwidth management panel in settings with explicit Learn More link [iOS only]"> - Google Chrome has features that help you manage your internet data and how quickly you're able to load webpages. + Chrome has features that help you manage your internet data and how quickly you're able to load webpages. <ph name="BEGIN_LINK">BEGIN_LINK</ph>Learn more<ph name="END_LINK">END_LINK</ph> </message> <message name="IDS_IOS_BOTTOM_TOOLBAR_IPH_PROMOTION_VOICE_OVER" desc="Text to be read by VoiceOver when the Bottom Toolbar Tip is presented to the user, explaining that the bottom toolbar can be used to reach some controls. Read by Text-to-Speech. [iOS only]">
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn index bfe76c0..019aa4f 100644 --- a/ios/chrome/browser/BUILD.gn +++ b/ios/chrome/browser/BUILD.gn
@@ -183,6 +183,8 @@ "application_context_impl.mm", "ios_chrome_main_parts.h", "ios_chrome_main_parts.mm", + "ios_thread_profiler.cc", + "ios_thread_profiler.h", ] deps = [ ":browser", @@ -201,6 +203,7 @@ "//components/language/core/browser", "//components/metrics", "//components/metrics:child_call_stack_profile_builder", + "//components/metrics/public/mojom:call_stack_mojo_bindings", "//components/metrics_services_manager", "//components/net_log", "//components/network_time", @@ -242,6 +245,7 @@ "//ios/public/provider/chrome/browser", "//ios/web", "//ios/web/public/init", + "//mojo/public/cpp/bindings", "//net", "//rlz/buildflags", "//services/network:network_service",
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h index 56fc265..1b0e1713 100644 --- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h +++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.h
@@ -46,9 +46,10 @@ bool link_transition); // web::WebStatePolicyDecider implementation - web::WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( + void ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) override; + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; private: friend class web::WebStateUserData<AppLauncherTabHelper>;
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm index 986abdc7..1b29d92 100644 --- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm +++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper.mm
@@ -161,15 +161,16 @@ } } -web::WebStatePolicyDecider::PolicyDecision -AppLauncherTabHelper::ShouldAllowRequest( +void AppLauncherTabHelper::ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) { + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { GURL request_url = net::GURLWithNSURL(request.URL); if (!IsAppUrl(request_url)) { // This URL can be handled by the WebState and doesn't require App launcher // handling. - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Allow()); } if (IsURLBlocklistEnabled()) { @@ -179,15 +180,17 @@ web_state()->GetBrowserState()); if (blocklistService->GetURLBlocklistState(request_url) == policy::URLBlocklist::URLBlocklistState::URL_IN_BLOCKLIST) { - return web::WebStatePolicyDecider::PolicyDecision::CancelAndDisplayError( - policy_url_blocking_util::CreateBlockedUrlError()); + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::CancelAndDisplayError( + policy_url_blocking_util::CreateBlockedUrlError())); } } // Disallow navigations to tel: URLs from cross-origin frames. if (request_url.SchemeIs(url::kTelScheme) && request_info.target_frame_is_cross_origin) { - return web::WebStatePolicyDecider::PolicyDecision::Cancel(); + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Cancel()); } ExternalURLRequestStatus request_status = @@ -205,11 +208,15 @@ UMA_HISTOGRAM_ENUMERATION("WebController.ExternalURLRequestBlocking", request_status, ExternalURLRequestStatus::kCount); // Request is blocked. - if (request_status == ExternalURLRequestStatus::kSubFrameRequestBlocked) - return web::WebStatePolicyDecider::PolicyDecision::Cancel(); + if (request_status == ExternalURLRequestStatus::kSubFrameRequestBlocked) { + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Cancel()); + } - if (!IsValidAppUrl(request_url)) - return web::WebStatePolicyDecider::PolicyDecision::Cancel(); + if (!IsValidAppUrl(request_url)) { + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Cancel()); + } // If this is a Universal 2nd Factor (U2F) call, the origin needs to be // checked to make sure it's secure and then update the |request_url| with @@ -222,8 +229,10 @@ U2FTabHelper* u2f_helper = U2FTabHelper::FromWebState(web_state_); request_url = u2f_helper->GetXCallbackUrl(request_url, origin); // If the URL was rejected by the U2F handler, |request_url| will be empty. - if (!request_url.is_valid()) - return web::WebStatePolicyDecider::PolicyDecision::Cancel(); + if (!request_url.is_valid()) { + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Cancel()); + } } GURL last_committed_url = web_state_->GetLastCommittedURL(); @@ -252,7 +261,7 @@ // tab. RequestToLaunchApp(request_url, last_committed_url, is_link_transition); } - return web::WebStatePolicyDecider::PolicyDecision::Cancel(); + std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Cancel()); } WEB_STATE_USER_DATA_KEY_IMPL(AppLauncherTabHelper)
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm index a52cd4c..fb622d53c 100644 --- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm +++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
@@ -126,9 +126,19 @@ web::WebStatePolicyDecider::RequestInfo request_info( transition_type, target_frame_is_main, target_frame_is_cross_origin, has_user_gesture); - return tab_helper_ - ->ShouldAllowRequest([NSURLRequest requestWithURL:url], request_info) - .ShouldAllowNavigation(); + __block bool callback_called = false; + __block web::WebStatePolicyDecider::PolicyDecision policy_decision = + web::WebStatePolicyDecider::PolicyDecision::Allow(); + auto callback = + base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) { + policy_decision = decision; + callback_called = true; + }); + tab_helper_->ShouldAllowRequest([NSURLRequest requestWithURL:url], + request_info, std::move(callback)); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(callback_called); + return policy_decision.ShouldAllowNavigation(); } // Initialize reading list model and its required tab helpers. @@ -175,10 +185,19 @@ transition_type, /*target_frame_is_main=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/true); - EXPECT_TRUE(tab_helper_ - ->ShouldAllowRequest([NSURLRequest requestWithURL:url], - request_info) - .ShouldCancelNavigation()); + __block bool callback_called = false; + __block web::WebStatePolicyDecider::PolicyDecision policy_decision = + web::WebStatePolicyDecider::PolicyDecision::Allow(); + auto callback = + base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) { + policy_decision = decision; + callback_called = true; + }); + tab_helper_->ShouldAllowRequest([NSURLRequest requestWithURL:url], + request_info, std::move(callback)); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(callback_called); + EXPECT_TRUE(policy_decision.ShouldCancelNavigation()); const ReadingListEntry* entry = model->GetEntryByURL(pending_url); return entry->IsRead() == expected_read_status;
diff --git a/ios/chrome/browser/ios_chrome_main_parts.h b/ios/chrome/browser/ios_chrome_main_parts.h index 0f951c1e..9eff4a71 100644 --- a/ios/chrome/browser/ios_chrome_main_parts.h +++ b/ios/chrome/browser/ios_chrome_main_parts.h
@@ -17,6 +17,7 @@ class ApplicationContextImpl; class HeapProfilerController; class PrefService; +class IOSThreadProfiler; class IOSChromeMainParts : public web::WebMainParts { public: @@ -55,6 +56,10 @@ IOSChromeFieldTrials ios_field_trials_; + // A profiler that periodically samples stack traces. Used to understand + // thread and process startup and normal behavior. + std::unique_ptr<IOSThreadProfiler> sampling_profiler_; + #if BUILDFLAG(USE_ALLOCATOR_SHIM) // Manages heap (memory) profiling. Requires the allocator shim to be enabled. std::unique_ptr<HeapProfilerController> heap_profiler_controller_;
diff --git a/ios/chrome/browser/ios_chrome_main_parts.mm b/ios/chrome/browser/ios_chrome_main_parts.mm index d1223f41..bd2df07 100644 --- a/ios/chrome/browser/ios_chrome_main_parts.mm +++ b/ios/chrome/browser/ios_chrome_main_parts.mm
@@ -48,6 +48,7 @@ #import "ios/chrome/browser/first_run/first_run.h" #include "ios/chrome/browser/flags/about_flags.h" #include "ios/chrome/browser/install_time_util.h" +#include "ios/chrome/browser/ios_thread_profiler.h" #include "ios/chrome/browser/metrics/ios_chrome_metrics_service_accessor.h" #include "ios/chrome/browser/metrics/ios_expired_histograms_array.h" #include "ios/chrome/browser/open_from_clipboard/create_clipboard_recent_content.h" @@ -55,6 +56,7 @@ #include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/safe_browsing/safe_browsing_service.h" #include "ios/chrome/browser/translate/translate_service_ios.h" +#include "ios/chrome/common/channel_info.h" #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #include "ios/web/public/thread/web_task_traits.h" #include "ios/web/public/thread/web_thread.h" @@ -140,6 +142,15 @@ } void IOSChromeMainParts::PreCreateThreads() { + // Create and start the stack sampling profiler if CANARY or DEV. The warning + // below doesn't apply. + if (::GetChannel() == version_info::Channel::CANARY || + ::GetChannel() == version_info::Channel::DEV) { + sampling_profiler_ = IOSThreadProfiler::CreateAndStartOnMainThread(); + IOSThreadProfiler::SetMainThreadTaskRunner( + base::ThreadTaskRunnerHandle::Get()); + } + // IMPORTANT // Calls in this function should not post tasks or create threads as // components used to handle those tasks are not yet available. This work @@ -187,6 +198,10 @@ // initialization is handled in PreMainMessageLoopRun since it posts tasks. SetupFieldTrials(); + // Set metrics upload for stack/heap profiles. + IOSThreadProfiler::SetBrowserProcessReceiverCallback(base::BindRepeating( + &metrics::CallStackProfileMetricsProvider::ReceiveProfile)); + // Sync the crashpad field tral state to NSUserDefaults. Called immediately // after setting up field trials. crash_helper::SyncCrashpadEnabledOnNextRun(); @@ -204,9 +219,6 @@ // Start heap profiling as early as possible so it can start recording // memory allocations. Requires the allocator shim to be enabled. heap_profiler_controller_ = std::make_unique<HeapProfilerController>(); - metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback( - base::BindRepeating( - &metrics::CallStackProfileMetricsProvider::ReceiveProfile)); heap_profiler_controller_->Start(); } }
diff --git a/ios/chrome/browser/ios_thread_profiler.cc b/ios/chrome/browser/ios_thread_profiler.cc new file mode 100644 index 0000000..178997a2 --- /dev/null +++ b/ios/chrome/browser/ios_thread_profiler.cc
@@ -0,0 +1,293 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Adapted from chrome/common/profiler/thread_profiler.cc + +#include "ios/chrome/browser/ios_thread_profiler.h" + +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/memory/ptr_util.h" +#include "base/message_loop/work_id_provider.h" +#include "base/process/process.h" +#include "base/profiler/profiler_buildflags.h" +#include "base/profiler/sample_metadata.h" +#include "base/profiler/sampling_profiler_thread_token.h" +#include "base/rand_util.h" +#include "base/threading/platform_thread.h" +#include "base/threading/sequence_local_storage_slot.h" +#include "base/threading/thread_task_runner_handle.h" +#include "build/build_config.h" +#include "components/metrics/call_stack_profile_builder.h" +#include "components/metrics/call_stack_profile_metrics_provider.h" + +using CallStackProfileBuilder = metrics::CallStackProfileBuilder; +using CallStackProfileParams = metrics::CallStackProfileParams; +using StackSamplingProfiler = base::StackSamplingProfiler; + +namespace { + +// Pointer to the main thread instance, if any. Stored as a global because it's +// created very early in chrome/app - and is thus otherwise inaccessible from +// chrome_dll, by the time we need to register the main thread task runner. +IOSThreadProfiler* g_main_thread_instance = nullptr; + +// Run continuous profiling 2% of the time. +constexpr double kFractionOfExecutionTimeToSample = 0.02; + +bool IsCurrentProcessBackgrounded() { + return base::Process::Current().IsProcessBackgrounded(); +} + +base::StackSamplingProfiler::UnwindersFactory CreateCoreUnwindersFactory() { + return base::StackSamplingProfiler::UnwindersFactory(); +} + +const base::RepeatingClosure GetApplyPerSampleMetadataCallback( + CallStackProfileParams::Process process) { + if (process != CallStackProfileParams::RENDERER_PROCESS) + return base::RepeatingClosure(); + static const base::SampleMetadata process_backgrounded("ProcessBackgrounded"); + return base::BindRepeating( + [](base::SampleMetadata process_backgrounded) { + process_backgrounded.Set(IsCurrentProcessBackgrounded()); + }, + process_backgrounded); +} + +} // namespace + +// The scheduler works by splitting execution time into repeated periods such +// that the time to take one collection represents +// |fraction_of_execution_time_to_sample| of the period, and the time not spent +// sampling represents 1 - |fraction_of_execution_time_to_sample| of the period. +// The collection start time is chosen randomly within each period such that the +// entire collection is contained within the period. +// +// The kFractionOfExecutionTimeToSample and SamplingParams settings at the top +// of the file specify fraction = 0.02 and sampling period = 1 sample / .1s +// sampling interval * 300 samples = 30s. The period length works out to +// 30s/0.02 = 1500s = 25m. So every 25 minutes a random 30 second continuous +// interval will be picked to sample. +PeriodicSamplingScheduler::PeriodicSamplingScheduler( + base::TimeDelta sampling_duration, + double fraction_of_execution_time_to_sample, + base::TimeTicks start_time) + : period_duration_(sampling_duration / + fraction_of_execution_time_to_sample), + sampling_duration_(sampling_duration), + period_start_time_(start_time) { + DCHECK(sampling_duration_ <= period_duration_); +} + +PeriodicSamplingScheduler::~PeriodicSamplingScheduler() = default; + +base::TimeDelta PeriodicSamplingScheduler::GetTimeToNextCollection() { + const base::TimeTicks now = Now(); + // Avoid scheduling in the past in the presence of discontinuous jumps in + // the current TimeTicks. + period_start_time_ = std::max(period_start_time_, now); + + const base::TimeDelta sampling_offset = + (period_duration_ - sampling_duration_) * RandDouble(); + const base::TimeTicks next_collection_time = + period_start_time_ + sampling_offset; + period_start_time_ += period_duration_; + return next_collection_time - now; +} + +double PeriodicSamplingScheduler::RandDouble() const { + return base::RandDouble(); +} + +base::TimeTicks PeriodicSamplingScheduler::Now() const { + return base::TimeTicks::Now(); +} + +// Records the current unique id for the work item being executed in the target +// thread's message loop. +class IOSThreadProfiler::WorkIdRecorder : public metrics::WorkIdRecorder { + public: + explicit WorkIdRecorder(base::WorkIdProvider* work_id_provider) + : work_id_provider_(work_id_provider) {} + + // Invoked on the profiler thread while the target thread is suspended. + unsigned int RecordWorkId() const override { + return work_id_provider_->GetWorkId(); + } + + WorkIdRecorder(const WorkIdRecorder&) = delete; + WorkIdRecorder& operator=(const WorkIdRecorder&) = delete; + + private: + base::WorkIdProvider* const work_id_provider_; +}; + +IOSThreadProfiler::~IOSThreadProfiler() { + if (g_main_thread_instance == this) + g_main_thread_instance = nullptr; +} + +// static +std::unique_ptr<IOSThreadProfiler> +IOSThreadProfiler::CreateAndStartOnMainThread() { + DCHECK(!g_main_thread_instance); + auto instance = base::WrapUnique( + new IOSThreadProfiler(CallStackProfileParams::MAIN_THREAD)); + if (!g_main_thread_instance) + g_main_thread_instance = instance.get(); + return instance; +} + +// static +void IOSThreadProfiler::SetMainThreadTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + DCHECK(g_main_thread_instance); + g_main_thread_instance->SetMainThreadTaskRunnerImpl(task_runner); +} + +// static +void IOSThreadProfiler::StartOnChildThread( + CallStackProfileParams::Thread thread) { + // The profiler object is stored in a SequenceLocalStorageSlot on child + // threads to give it the same lifetime as the threads. + static base::SequenceLocalStorageSlot<std::unique_ptr<IOSThreadProfiler>> + child_thread_profiler_sequence_local_storage; + child_thread_profiler_sequence_local_storage.emplace( + new IOSThreadProfiler(thread, base::ThreadTaskRunnerHandle::Get())); +} + +// static +void IOSThreadProfiler::SetBrowserProcessReceiverCallback( + const base::RepeatingCallback<void(base::TimeTicks, + metrics::SampledProfile)>& callback) { + CallStackProfileBuilder::SetBrowserProcessReceiverCallback(callback); +} + +// static +void IOSThreadProfiler::SetCollectorForChildProcess( + mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> collector) { + CallStackProfileBuilder::SetParentProfileCollectorForChildProcess( + std::move(collector)); +} + +// static +base::StackSamplingProfiler::SamplingParams +IOSThreadProfiler::GetSamplingParams() { + base::StackSamplingProfiler::SamplingParams params; + params.initial_delay = base::TimeDelta::FromMilliseconds(0); + const base::TimeDelta duration = base::TimeDelta::FromSeconds(30); + params.sampling_interval = base::TimeDelta::FromMilliseconds(100); + params.samples_per_profile = duration / params.sampling_interval; + + return params; +} + +// IOSThreadProfiler implementation synopsis: +// +// On creation, the profiler creates and starts the startup +// StackSamplingProfiler, and configures the PeriodicSamplingScheduler such that +// it starts scheduling from the time the startup profiling will be complete. +// When a message loop is available (either in the constructor, or via +// SetMainThreadTaskRunner) a task is posted to start the first periodic +// collection at the initial scheduled collection time. +// +// When the periodic collection task executes, it creates and starts a new +// periodic profiler and configures it to call OnPeriodicCollectionCompleted as +// its completion callback. OnPeriodicCollectionCompleted is called on the +// profiler thread and schedules a task on the original thread to schedule +// another periodic collection. When the task runs, it posts a new task to start +// another periodic collection at the next scheduled collection time. +// +// The process in previous paragraph continues until the IOSThreadProfiler is +// destroyed prior to thread exit. +IOSThreadProfiler::IOSThreadProfiler( + CallStackProfileParams::Thread thread, + scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner) + : process_(CallStackProfileParams::BROWSER_PROCESS), + thread_(thread), + owning_thread_task_runner_(owning_thread_task_runner), + work_id_recorder_(std::make_unique<WorkIdRecorder>( + base::WorkIdProvider::GetForCurrentThread())) { + const base::StackSamplingProfiler::SamplingParams sampling_params = + IOSThreadProfiler::GetSamplingParams(); + + startup_profiler_ = std::make_unique<StackSamplingProfiler>( + base::GetSamplingProfilerCurrentThreadToken(), sampling_params, + std::make_unique<CallStackProfileBuilder>( + CallStackProfileParams(process_, thread, + CallStackProfileParams::PROCESS_STARTUP), + work_id_recorder_.get()), + CreateCoreUnwindersFactory(), + GetApplyPerSampleMetadataCallback(process_)); + + startup_profiler_->Start(); + + // Estimated time at which the startup profiling will be completed. It's OK if + // this doesn't exactly coincide with the end of the startup profiling, since + // there's no harm in having a brief overlap of startup and periodic + // profiling. + base::TimeTicks startup_profiling_completion_time = + base::TimeTicks::Now() + + sampling_params.samples_per_profile * sampling_params.sampling_interval; + + periodic_sampling_scheduler_ = std::make_unique<PeriodicSamplingScheduler>( + sampling_params.samples_per_profile * sampling_params.sampling_interval, + kFractionOfExecutionTimeToSample, startup_profiling_completion_time); + + if (owning_thread_task_runner_) + ScheduleNextPeriodicCollection(); +} + +// static +void IOSThreadProfiler::OnPeriodicCollectionCompleted( + scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner, + base::WeakPtr<IOSThreadProfiler> thread_profiler) { + owning_thread_task_runner->PostTask( + FROM_HERE, + base::BindOnce(&IOSThreadProfiler::ScheduleNextPeriodicCollection, + thread_profiler)); +} + +void IOSThreadProfiler::SetMainThreadTaskRunnerImpl( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // This should only be called if the task runner wasn't provided in the + // constructor. + DCHECK(!owning_thread_task_runner_); + owning_thread_task_runner_ = task_runner; + ScheduleNextPeriodicCollection(); +} + +void IOSThreadProfiler::ScheduleNextPeriodicCollection() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + owning_thread_task_runner_->PostDelayedTask( + FROM_HERE, + base::BindOnce(&IOSThreadProfiler::StartPeriodicSamplingCollection, + weak_factory_.GetWeakPtr()), + periodic_sampling_scheduler_->GetTimeToNextCollection()); +} + +void IOSThreadProfiler::StartPeriodicSamplingCollection() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // NB: Destroys the previous profiler as side effect. + periodic_profiler_ = std::make_unique<StackSamplingProfiler>( + base::GetSamplingProfilerCurrentThreadToken(), + IOSThreadProfiler::GetSamplingParams(), + std::make_unique<CallStackProfileBuilder>( + CallStackProfileParams(process_, thread_, + CallStackProfileParams::PERIODIC_COLLECTION), + work_id_recorder_.get(), + base::BindOnce(&IOSThreadProfiler::OnPeriodicCollectionCompleted, + owning_thread_task_runner_, + weak_factory_.GetWeakPtr())), + CreateCoreUnwindersFactory(), + GetApplyPerSampleMetadataCallback(process_)); + + periodic_profiler_->Start(); +}
diff --git a/ios/chrome/browser/ios_thread_profiler.h b/ios/chrome/browser/ios_thread_profiler.h new file mode 100644 index 0000000..8aa7d47 --- /dev/null +++ b/ios/chrome/browser/ios_thread_profiler.h
@@ -0,0 +1,156 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Adapted from chrome/common/profiler/thread_profiler.h + +// TODO(crbug.com/1229530): remove this once //chrome/common/profiler is moved +// to components/profiler. + +#ifndef IOS_CHROME_BROWSER_IOS_THREAD_PROFILER_H_ +#define IOS_CHROME_BROWSER_IOS_THREAD_PROFILER_H_ + +#include <memory> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/profiler/stack_sampling_profiler.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread.h" +#include "base/threading/thread_checker.h" +#include "base/time/time.h" +#include "components/metrics/call_stack_profile_params.h" +#include "components/metrics/public/mojom/call_stack_profile_collector.mojom.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "third_party/metrics_proto/sampled_profile.pb.h" + +// PeriodicSamplingScheduler repeatedly schedules periodic sampling of the +// thread through calls to GetTimeToNextCollection(). This class is exposed +// to allow testing. +class PeriodicSamplingScheduler { + public: + PeriodicSamplingScheduler(base::TimeDelta sampling_duration, + double fraction_of_execution_time_to_sample, + base::TimeTicks start_time); + virtual ~PeriodicSamplingScheduler(); + + PeriodicSamplingScheduler(const PeriodicSamplingScheduler&) = delete; + PeriodicSamplingScheduler& operator=(const PeriodicSamplingScheduler&) = + delete; + + // Returns the amount of time between now and the next collection. + base::TimeDelta GetTimeToNextCollection(); + + protected: + // Virtual to provide seams for test use. + virtual double RandDouble() const; + virtual base::TimeTicks Now() const; + + private: + const base::TimeDelta period_duration_; + const base::TimeDelta sampling_duration_; + base::TimeTicks period_start_time_; +}; + +// IOSThreadProfiler performs startup and periodic profiling of Chrome +// threads. +class IOSThreadProfiler { + public: + ~IOSThreadProfiler(); + IOSThreadProfiler(const IOSThreadProfiler&) = delete; + IOSThreadProfiler& operator=(const IOSThreadProfiler&) = delete; + + // Creates a profiler for a main thread and immediately starts it. This + // function should only be used when profiling the main thread of a + // process. The returned profiler must be destroyed prior to thread exit to + // stop the profiling. + // + // SetMainThreadTaskRunner() should be called after the message loop has been + // started on the thread. It is the caller's responsibility to ensure that + // the instance returned by this function is still alive when the static API + // SetMainThreadTaskRunner() is used. The latter is static to support Chrome's + // set up where the IOSThreadProfiler is created in chrome/app which cannot be + // easily accessed from chrome_browser_main.cc which sets the task runner. + static std::unique_ptr<IOSThreadProfiler> CreateAndStartOnMainThread(); + + // Sets the task runner when profiling on the main thread. This occurs in a + // separate call from CreateAndStartOnMainThread so that startup profiling can + // occur prior to message loop start. The task runner is associated with the + // instance returned by CreateAndStartOnMainThread(), which must be alive when + // this is called. + static void SetMainThreadTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + + // Get the stack sampling params to use. + static base::StackSamplingProfiler::SamplingParams GetSamplingParams(); + + // Creates a profiler for a child thread and immediately starts it. This + // should be called from a task posted on the child thread immediately after + // thread start. The thread will be profiled until exit. + static void StartOnChildThread( + metrics::CallStackProfileParams::Thread thread); + + // Sets the callback to use for reporting browser process profiles. This + // indirection is required to avoid a dependency on unnecessary metrics code + // in child processes. + static void SetBrowserProcessReceiverCallback( + const base::RepeatingCallback<void(base::TimeTicks, + metrics::SampledProfile)>& callback); + + // This function must be called within child processes to supply the Service + // Manager's connector, to bind the interface through which a profile is sent + // back to the browser process. + // + // Note that the metrics::CallStackProfileCollector interface also must be + // exposed to the child process, and metrics::mojom::CallStackProfileCollector + // declared in chrome_content_browser_manifest_overlay.json, for the binding + // to succeed. + static void SetCollectorForChildProcess( + mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> collector); + + private: + class WorkIdRecorder; + + // Creates the profiler. The task runner will be supplied for child threads + // but not for main threads. + IOSThreadProfiler( + metrics::CallStackProfileParams::Thread thread, + scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner = + scoped_refptr<base::SingleThreadTaskRunner>()); + + // Posts a task on |owning_thread_task_runner| to start the next periodic + // sampling collection on the completion of the previous collection. + static void OnPeriodicCollectionCompleted( + scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner, + base::WeakPtr<IOSThreadProfiler> thread_profiler); + + // Sets the task runner when profiling on the main thread. This occurs in a + // separate call from CreateAndStartOnMainThread so that startup profiling can + // occur prior to message loop start. + void SetMainThreadTaskRunnerImpl( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + + // Posts a delayed task to start the next periodic sampling collection. + void ScheduleNextPeriodicCollection(); + + // Creates a new periodic profiler and initiates a collection with it. + void StartPeriodicSamplingCollection(); + + const metrics::CallStackProfileParams::Process process_; + const metrics::CallStackProfileParams::Thread thread_; + + scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner_; + + std::unique_ptr<WorkIdRecorder> work_id_recorder_; + + std::unique_ptr<base::StackSamplingProfiler> startup_profiler_; + + std::unique_ptr<base::StackSamplingProfiler> periodic_profiler_; + std::unique_ptr<PeriodicSamplingScheduler> periodic_sampling_scheduler_; + + THREAD_CHECKER(thread_checker_); + base::WeakPtrFactory<IOSThreadProfiler> weak_factory_{this}; +}; + +#endif // IOS_CHROME_BROWSER_IOS_THREAD_PROFILER_H_
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h index 5ac01b5..894c23a 100644 --- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h +++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
@@ -44,9 +44,10 @@ static bool CanHandleUrl(const GURL& url); // web::WebStatePolicyDecider implementation - web::WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( + void ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) override; + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; private: friend class web::WebStateUserData<ITunesUrlsHandlerTabHelper>;
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm index f7ffb32..edb0282 100644 --- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm +++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
@@ -111,24 +111,27 @@ return path_components[media_type_index] == kITunesAppPathIdentifier; } -web::WebStatePolicyDecider::PolicyDecision -ITunesUrlsHandlerTabHelper::ShouldAllowRequest( +void ITunesUrlsHandlerTabHelper::ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) { + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { // Don't Handle URLS in Off The record mode as this will open StoreKit with // Users' iTunes account. Also don't Handle navigations in iframe because they // may be spam, and they will be handled by other policy deciders. if (web_state()->GetBrowserState()->IsOffTheRecord() || !request_info.target_frame_is_main) { - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Allow()); } GURL request_url = net::GURLWithNSURL(request.URL); - if (!CanHandleUrl(request_url)) - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + if (!CanHandleUrl(request_url)) { + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Allow()); + } HandleITunesUrl(request_url); - return web::WebStatePolicyDecider::PolicyDecision::Cancel(); + std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Cancel()); } // private
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm index 603204a1..9396c460 100644 --- a/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm +++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
@@ -46,10 +46,19 @@ ui::PageTransition::PAGE_TRANSITION_LINK, main_frame, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - web::WebStatePolicyDecider::PolicyDecision request_policy = - web_state_.ShouldAllowRequest( - [NSURLRequest requestWithURL:[NSURL URLWithString:url_string]], - request_info); + __block bool callback_called = false; + __block web::WebStatePolicyDecider::PolicyDecision request_policy = + web::WebStatePolicyDecider::PolicyDecision::Allow(); + auto callback = + base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) { + request_policy = decision; + callback_called = true; + }); + web_state_.ShouldAllowRequest( + [NSURLRequest requestWithURL:[NSURL URLWithString:url_string]], + request_info, std::move(callback)); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(callback_called); return request_policy.ShouldCancelNavigation() && (fake_launcher_.launchedProductID != nil || fake_launcher_.launchedProductParams != nil);
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h index 1fee183..cadd8d6 100644 --- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h +++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h
@@ -31,8 +31,10 @@ public: ~WellKnownChangePasswordTabHelper() override; // web::WebStatePolicyDecider: - PolicyDecision ShouldAllowRequest(NSURLRequest* request, - const RequestInfo& request_info) override; + void ShouldAllowRequest( + NSURLRequest* request, + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; void ShouldAllowResponse( NSURLResponse* response, bool for_main_frame,
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm index 45026342..ed6badc 100644 --- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm +++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm
@@ -48,10 +48,10 @@ } } -web::WebStatePolicyDecider::PolicyDecision -WellKnownChangePasswordTabHelper::ShouldAllowRequest( +void WellKnownChangePasswordTabHelper::ShouldAllowRequest( NSURLRequest* request, - const RequestInfo& request_info) { + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { GURL request_url = net::GURLWithNSURL(request.URL); // The custom behaviour is only used if the .well-known/change-password // request if the request is the main frame opened in a new tab. @@ -76,7 +76,7 @@ } } - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Allow()); } void WellKnownChangePasswordTabHelper::ShouldAllowResponse(
diff --git a/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.h b/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.h index 2c39a063..8767854 100644 --- a/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.h +++ b/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.h
@@ -17,9 +17,10 @@ ~PolicyUrlBlockingTabHelper() override; // web::WebStatePolicyDecider - web::WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( + void ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) override; + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; private: friend class web::WebStateUserData<PolicyUrlBlockingTabHelper>;
diff --git a/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.mm b/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.mm index 59e936e9..ff0b2f7b 100644 --- a/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.mm +++ b/ios/chrome/browser/policy_url_blocking/policy_url_blocking_tab_helper.mm
@@ -18,22 +18,22 @@ PolicyUrlBlockingTabHelper::PolicyUrlBlockingTabHelper(web::WebState* web_state) : web::WebStatePolicyDecider(web_state) {} -web::WebStatePolicyDecider::PolicyDecision -PolicyUrlBlockingTabHelper::ShouldAllowRequest( +void PolicyUrlBlockingTabHelper::ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) { - + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { GURL gurl = net::GURLWithNSURL(request.URL); PolicyBlocklistService* blocklistService = PolicyBlocklistServiceFactory::GetForBrowserState( web_state()->GetBrowserState()); if (blocklistService->GetURLBlocklistState(gurl) == policy::URLBlocklist::URLBlocklistState::URL_IN_BLOCKLIST) { - return web::WebStatePolicyDecider::PolicyDecision::CancelAndDisplayError( - policy_url_blocking_util::CreateBlockedUrlError()); + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::CancelAndDisplayError( + policy_url_blocking_util::CreateBlockedUrlError())); } - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Allow()); } WEB_STATE_USER_DATA_KEY_IMPL(PolicyUrlBlockingTabHelper)
diff --git a/ios/chrome/browser/prerender/preload_controller.mm b/ios/chrome/browser/prerender/preload_controller.mm index 14b14ddf..2e60d5e 100644 --- a/ios/chrome/browser/prerender/preload_controller.mm +++ b/ios/chrome/browser/prerender/preload_controller.mm
@@ -566,18 +566,20 @@ } #pragma mark - CRWWebStatePolicyDecider -- (WebStatePolicyDecider::PolicyDecision) - shouldAllowRequest:(NSURLRequest*)request - requestInfo:(const WebStatePolicyDecider::RequestInfo&)info { +- (void)shouldAllowRequest:(NSURLRequest*)request + requestInfo: + (const WebStatePolicyDecider::RequestInfo&)requestInfo + decisionHandler:(PolicyDecisionHandler)decisionHandler { GURL requestURL = net::GURLWithNSURL(request.URL); // Don't allow preloading for requests that are handled by opening another // application or by presenting a native UI. if (AppLauncherTabHelper::IsAppUrl(requestURL) || ITunesUrlsHandlerTabHelper::CanHandleUrl(requestURL)) { [self schedulePrerenderCancel]; - return WebStatePolicyDecider::PolicyDecision::Cancel(); + decisionHandler(WebStatePolicyDecider::PolicyDecision::Cancel()); + return; } - return WebStatePolicyDecider::PolicyDecision::Allow(); + decisionHandler(WebStatePolicyDecider::PolicyDecision::Allow()); } #pragma mark - ManageAccountsDelegate
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h index f07bf08..a8773f85 100644 --- a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h +++ b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h
@@ -98,9 +98,10 @@ }; // web::WebStatePolicyDecider implementation - web::WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( + void ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) override; + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; void ShouldAllowResponse( NSURLResponse* response, bool for_main_frame,
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm index 55f09f9..ce5fb8b 100644 --- a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm +++ b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm
@@ -132,16 +132,18 @@ #pragma mark web::WebStatePolicyDecider -web::WebStatePolicyDecider::PolicyDecision -SafeBrowsingTabHelper::PolicyDecider::ShouldAllowRequest( +void SafeBrowsingTabHelper::PolicyDecider::ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) { + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { // Allow navigations for URLs that cannot be checked by the service. GURL request_url = GetCanonicalizedUrl(net::GURLWithNSURL(request.URL)); SafeBrowsingService* safe_browsing_service = GetApplicationContext()->GetSafeBrowsingService(); - if (!safe_browsing_service->CanCheckUrl(request_url)) - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + if (!safe_browsing_service->CanCheckUrl(request_url)) { + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Allow()); + } // Track all pending URL queries. bool is_main_frame = request_info.target_frame_is_main; @@ -170,7 +172,8 @@ // error decision once error pages for cancelled requests are supported. // For now, only cancelled response errors are displayed properly. pending_main_frame_query_->decision = CreateSafeBrowsingErrorDecision(); - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Allow()); } // Error pages for unsafe subframes are triggered by associating an @@ -190,7 +193,8 @@ // error decision once error pages for cancelled requests are supported. // For now, only cancelled response errors are displayed properly. pending_main_frame_query_->decision = CreateSafeBrowsingErrorDecision(); - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Allow()); } } @@ -201,7 +205,8 @@ web_state()->GetNavigationManager()->GetLastCommittedItem()) { main_frame_item_id = item->GetUniqueID(); } else { - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + return std::move(callback).Run( + web::WebStatePolicyDecider::PolicyDecision::Allow()); } } @@ -211,22 +216,20 @@ // Allow all requests to continue. If a safe browsing error is detected, the // navigation will be cancelled for using the response policy decision. - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Allow()); } void SafeBrowsingTabHelper::PolicyDecider::ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(web::WebStatePolicyDecider::PolicyDecision)> - callback) { + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { // Allow navigations for URLs that cannot be checked by the service. SafeBrowsingService* safe_browsing_service = GetApplicationContext()->GetSafeBrowsingService(); GURL response_url = GetCanonicalizedUrl(net::GURLWithNSURL(response.URL)); if (!safe_browsing_service->CanCheckUrl(response_url)) { - std::move(callback).Run( + return std::move(callback).Run( web::WebStatePolicyDecider::PolicyDecision::Allow()); - return; } if (for_main_frame) {
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm index a3e27ba5..5af00e4 100644 --- a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm +++ b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm
@@ -72,8 +72,19 @@ web::WebStatePolicyDecider::RequestInfo request_info( transition, for_main_frame, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - return web_state_.ShouldAllowRequest( - [NSURLRequest requestWithURL:net::NSURLWithGURL(url)], request_info); + __block bool callback_called = false; + __block web::WebStatePolicyDecider::PolicyDecision policy_decision = + web::WebStatePolicyDecider::PolicyDecision::Allow(); + auto callback = + base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) { + policy_decision = decision; + callback_called = true; + }); + web_state_.ShouldAllowRequest( + [NSURLRequest requestWithURL:net::NSURLWithGURL(url)], request_info, + std::move(callback)); + EXPECT_TRUE(callback_called); + return policy_decision; } // Helper function that calls into WebState::ShouldAllowResponse with the
diff --git a/ios/chrome/browser/sessions/scene_util_test_support.h b/ios/chrome/browser/sessions/scene_util_test_support.h index a6a6a68..ac777f0 100644 --- a/ios/chrome/browser/sessions/scene_util_test_support.h +++ b/ios/chrome/browser/sessions/scene_util_test_support.h
@@ -5,7 +5,7 @@ #ifndef IOS_CHROME_BROWSER_SESSIONS_SCENE_UTIL_TEST_SUPPORT_H_ #define IOS_CHROME_BROWSER_SESSIONS_SCENE_UTIL_TEST_SUPPORT_H_ -#import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> // Returns a fake UIScene with |identifier| as session persistent identifier // when running on iOS 13+ or nil otherwise. The fake object implements just
diff --git a/ios/chrome/browser/sessions/scene_util_test_support.mm b/ios/chrome/browser/sessions/scene_util_test_support.mm index a35d795..e8d3538 100644 --- a/ios/chrome/browser/sessions/scene_util_test_support.mm +++ b/ios/chrome/browser/sessions/scene_util_test_support.mm
@@ -39,6 +39,8 @@ @property(nonatomic, strong, readonly) FakeSceneSession* session; +@property(nonatomic, strong, readonly) NSArray<UIWindow*>* windows; + @end @implementation FakeScene { @@ -56,6 +58,10 @@ return _session; } +- (NSArray<UIWindow*>*)windows { + return nil; +} + @end id FakeSceneWithIdentifier(NSString* identifier) {
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm index f4541ce..5827848 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm +++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
@@ -15,7 +15,6 @@ #import "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller_delegate.h" #import "ios/chrome/browser/ui/authentication/views/identity_button_control.h" #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" -#import "ios/chrome/browser/ui/util/label_link_controller.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #include "ios/chrome/common/string_util.h" #import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h" @@ -67,8 +66,6 @@ // Constraint for the maximum height of the header view (also used to hide the // the header view if needed). @property(nonatomic, strong) NSLayoutConstraint* headerViewMaxHeightConstraint; -// Settings link controller. -@property(nonatomic, strong) LabelLinkController* settingsLinkController; // Text description that may show link to advanced Sync settings. @property(nonatomic, strong) UITextView* syncSettingsTextView;
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn index 0a316e64..ff4675e 100644 --- a/ios/chrome/browser/ui/browser_view/BUILD.gn +++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -244,6 +244,7 @@ "//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/download", "//ios/chrome/browser/favicon", + "//ios/chrome/browser/history", "//ios/chrome/browser/main:test_support", "//ios/chrome/browser/search_engines", "//ios/chrome/browser/sessions",
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm index e6f552b..4b54da6a 100644 --- a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
@@ -5,9 +5,15 @@ #import "ios/chrome/browser/ui/browser_view/browser_coordinator.h" #include "base/files/file_util.h" +#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #include "ios/chrome/browser/download/download_directory_util.h" #import "ios/chrome/browser/download/external_app_util.h" +#include "ios/chrome/browser/favicon/favicon_service_factory.h" +#include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h" +#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h" +#include "ios/chrome/browser/history/history_service_factory.h" #include "ios/chrome/browser/main/test_browser.h" +#include "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/ui/commands/activity_service_commands.h" #import "ios/chrome/browser/ui/commands/browser_coordinator_commands.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h" @@ -41,8 +47,24 @@ protected: BrowserCoordinatorTest() : base_view_controller_([[UIViewController alloc] init]), - browser_(std::make_unique<TestBrowser>()), scene_state_([[SceneState alloc] initWithAppState:nil]) { + TestChromeBrowserState::Builder test_cbs_builder; + test_cbs_builder.AddTestingFactory( + ios::TemplateURLServiceFactory::GetInstance(), + ios::TemplateURLServiceFactory::GetDefaultFactory()); + test_cbs_builder.AddTestingFactory( + IOSChromeFaviconLoaderFactory::GetInstance(), + IOSChromeFaviconLoaderFactory::GetDefaultFactory()); + test_cbs_builder.AddTestingFactory( + IOSChromeLargeIconServiceFactory::GetInstance(), + IOSChromeLargeIconServiceFactory::GetDefaultFactory()); + test_cbs_builder.AddTestingFactory( + ios::FaviconServiceFactory::GetInstance(), + ios::FaviconServiceFactory::GetDefaultFactory()); + + chrome_browser_state_ = test_cbs_builder.Build(); + CHECK(chrome_browser_state_->CreateHistoryService()); + browser_ = std::make_unique<TestBrowser>(chrome_browser_state_.get()); UrlLoadingNotifierBrowserAgent::CreateForBrowser(browser_.get()); SceneStateBrowserAgent::CreateForBrowser(browser_.get(), scene_state_); WebNavigationBrowserAgent::CreateForBrowser(browser_.get()); @@ -64,6 +86,7 @@ web::WebTaskEnvironment task_environment_; UIViewController* base_view_controller_; + std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; std::unique_ptr<TestBrowser> browser_; SceneState* scene_state_; };
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm b/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm index ff03d3c..fe3cda9 100644 --- a/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm
@@ -19,6 +19,7 @@ #import "ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.h" #import "ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.h" #import "ios/chrome/browser/ui/infobars/infobar_constants.h" +#import "ios/chrome/browser/ui/infobars/infobar_feature.h" #import "ios/chrome/browser/ui/infobars/infobar_positioner.h" #import "ios/chrome/browser/ui/infobars/test/test_infobar_password_delegate.h" #import "ios/chrome/browser/ui/infobars/test_infobar_delegate.h" @@ -60,6 +61,7 @@ @end // Test fixture for testing InfobarContainerCoordinatorTest. +// TODO(crbug.com/927064): Remove once Overlays is turned on by default. class InfobarContainerCoordinatorTest : public PlatformTest { protected: InfobarContainerCoordinatorTest() @@ -223,6 +225,9 @@ // InfobarBanner is presented. TEST_F(InfobarContainerCoordinatorTest, InfobarBannerPresentationStatePresented) { + if (IsInfobarOverlayUIEnabled()) { + return; + } EXPECT_NE(infobar_container_coordinator_.infobarBannerState, InfobarBannerPresentationState::Presented); AddInfobar(/*high_priority_presentation=*/false); @@ -238,6 +243,9 @@ // Tests that the InfobarBanner is automatically dismissed after // kInfobarBannerPresentationDurationInSeconds seconds. TEST_F(InfobarContainerCoordinatorTest, TestAutomaticInfobarBannerDismissal) { + if (IsInfobarOverlayUIEnabled()) { + return; + } EXPECT_NE(infobar_container_coordinator_.infobarBannerState, InfobarBannerPresentationState::Presented); @@ -263,6 +271,9 @@ // Tests that the InfobarBanner is correctly dismissed after calling // dismissInfobarBannerAnimated. TEST_F(InfobarContainerCoordinatorTest, TestInfobarBannerDismissal) { + if (IsInfobarOverlayUIEnabled()) { + return; + } EXPECT_FALSE(infobar_container_coordinator_.infobarBannerState == InfobarBannerPresentationState::Presented); @@ -290,6 +301,9 @@ // Tests that the InfobarBanner is dismissed when changing Webstates. TEST_F(InfobarContainerCoordinatorTest, TestInfobarBannerDismissAtWebStateChange) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); AddSecondWebstate(); @@ -316,6 +330,9 @@ // different Webstate. TEST_F(InfobarContainerCoordinatorTest, TestInfobarBannerNotPresentAfterWebStateChange) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); AddSecondWebstate(); @@ -351,6 +368,9 @@ // Tests infobarBannerState is NotPresented once an InfobarBanner has been // dismissed directly by its base VC. TEST_F(InfobarContainerCoordinatorTest, TestInfobarBannerDismissalByBaseVC) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( base::test::ios::kWaitForUIElementTimeout, ^bool { @@ -373,6 +393,9 @@ // Tests that the Infobar is dismissed before its presentation is completed. TEST_F(InfobarContainerCoordinatorTest, TestInfobarBannerDismissalMidPresentation) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); // Call dismiss without calling WaitUntilConditionOrTimeout before. [base_view_controller_ dismissViewControllerAnimated:NO completion:nil]; @@ -390,6 +413,9 @@ // presentation is completed. TEST_F(InfobarContainerCoordinatorTest, TestInfobarBannerDismissedClosingWebstate) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); // Close the Webstate without calling WaitUntilConditionOrTimeout. browser_->GetWebStateList()->CloseWebStateAt(0, 0); @@ -404,6 +430,9 @@ // Tests that the Infobar is dismissed when both the VC and Webstate are closed. TEST_F(InfobarContainerCoordinatorTest, TestDismissingAndClosingWebstate) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( base::test::ios::kWaitForUIElementTimeout, ^bool { @@ -429,6 +458,9 @@ // and there's more than one webstate. TEST_F(InfobarContainerCoordinatorTest, TestDismissingAndClosingWebstateSecondWebstate) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); AddSecondWebstate(); EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( @@ -454,6 +486,9 @@ // Tests that the ChildCoordinators are deleted once the Webstate is closed. TEST_F(InfobarContainerCoordinatorTest, TestInfobarChildCoordinatorCountWebstate) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( @@ -511,6 +546,9 @@ // Tests that the ChildCoordinators are deleted once they stop. TEST_F(InfobarContainerCoordinatorTest, TestInfobarChildCoordinatorCountStop) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( @@ -567,6 +605,9 @@ // Tests that that a second Infobar (added right after the first one) is // displayed after the first one has been dismissed. TEST_F(InfobarContainerCoordinatorTest, TestInfobarQueueAndDisplay) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); AddSecondInfobar(/*high_priority_presentation=*/false); ASSERT_EQ(NSUInteger(2), @@ -605,6 +646,9 @@ // added after a high priority one will appear first. TEST_F(InfobarContainerCoordinatorTest, TestInfobarQueueAndDisplayWhenAppeared) { + if (IsInfobarOverlayUIEnabled()) { + return; + } [scoped_key_window_.Get() setRootViewController:nil]; AddInfobar(/*high_priority_presentation=*/true); AddSecondInfobar(/*high_priority_presentation=*/false); @@ -647,6 +691,9 @@ // Tests that that a second Infobar (added right after the first one) is // not displayed if its destroyed before presentation. TEST_F(InfobarContainerCoordinatorTest, TestInfobarQueueStoppedNoDisplay) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddInfobar(/*high_priority_presentation=*/false); AddSecondInfobar(/*high_priority_presentation=*/false); ASSERT_EQ(NSUInteger(2), @@ -678,6 +725,9 @@ // Tests that a High Priority Presentation Infobar added after a non High // Priority Presentation Infobar is presented first. TEST_F(InfobarContainerCoordinatorTest, TestInfobarQueuePriority) { + if (IsInfobarOverlayUIEnabled()) { + return; + } [scoped_key_window_.Get() setRootViewController:nil]; AddInfobar(/*high_priority_presentation=*/false); AddSecondInfobar(/*high_priority_presentation=*/true); @@ -720,6 +770,9 @@ // Tests that a High Priority Presentation Infobar added after a High // Priority Presentation Infobar is presented first. TEST_F(InfobarContainerCoordinatorTest, TestInfobarQueueHighPriority) { + if (IsInfobarOverlayUIEnabled()) { + return; + } [scoped_key_window_.Get() setRootViewController:nil]; AddInfobar(/*high_priority_presentation=*/true); AddSecondInfobar(/*high_priority_presentation=*/true); @@ -761,6 +814,9 @@ // Tests that a Confirm Infobar is stopped after it has been dismissed. TEST_F(InfobarContainerCoordinatorTest, TestConfirmInfobarStoppedOnDismissal) { + if (IsInfobarOverlayUIEnabled()) { + return; + } AddConfirmInfobar(/*high_priority_presentation=*/false); ASSERT_EQ(NSUInteger(1), infobar_container_coordinator_.childCoordinators.count);
diff --git a/ios/chrome/browser/ui/infobars/infobar_feature.mm b/ios/chrome/browser/ui/infobars/infobar_feature.mm index 8667bbc..abc3a6a 100644 --- a/ios/chrome/browser/ui/infobars/infobar_feature.mm +++ b/ios/chrome/browser/ui/infobars/infobar_feature.mm
@@ -9,7 +9,7 @@ #endif const base::Feature kInfobarOverlayUI{"InfobarOverlayUI", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; bool IsInfobarOverlayUIEnabled() { return base::FeatureList::IsEnabled(kInfobarOverlayUI);
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn index 52b78ae..6853f581 100644 --- a/ios/chrome/browser/ui/main/BUILD.gn +++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -304,8 +304,11 @@ "//ios/chrome/app/startup", "//ios/chrome/browser/bookmarks", "//ios/chrome/browser/browser_state:test_support", + "//ios/chrome/browser/favicon", + "//ios/chrome/browser/history", "//ios/chrome/browser/main", "//ios/chrome/browser/main:test_support", + "//ios/chrome/browser/search_engines", "//ios/chrome/browser/sessions:restoration_agent", "//ios/chrome/browser/sessions:scene_util_test_support", "//ios/chrome/browser/sessions:test_support",
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm b/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm index 14ae57e1..18acc17 100644 --- a/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm +++ b/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm
@@ -7,9 +7,14 @@ #import <UIKit/UIKit.h> #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#include "ios/chrome/browser/favicon/favicon_service_factory.h" +#include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h" +#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h" +#include "ios/chrome/browser/history/history_service_factory.h" #import "ios/chrome/browser/main/browser_list.h" #import "ios/chrome/browser/main/browser_list_factory.h" #import "ios/chrome/browser/main/test_browser_list_observer.h" +#include "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/sessions/scene_util_test_support.h" #include "ios/chrome/browser/sessions/session_restoration_browser_agent.h" #import "ios/chrome/browser/sessions/test_session_service.h" @@ -59,8 +64,21 @@ test_cbs_builder.AddTestingFactory( SendTabToSelfSyncServiceFactory::GetInstance(), SendTabToSelfSyncServiceFactory::GetDefaultFactory()); + test_cbs_builder.AddTestingFactory( + ios::TemplateURLServiceFactory::GetInstance(), + ios::TemplateURLServiceFactory::GetDefaultFactory()); + test_cbs_builder.AddTestingFactory( + IOSChromeFaviconLoaderFactory::GetInstance(), + IOSChromeFaviconLoaderFactory::GetDefaultFactory()); + test_cbs_builder.AddTestingFactory( + IOSChromeLargeIconServiceFactory::GetInstance(), + IOSChromeLargeIconServiceFactory::GetDefaultFactory()); + test_cbs_builder.AddTestingFactory( + ios::FaviconServiceFactory::GetInstance(), + ios::FaviconServiceFactory::GetDefaultFactory()); chrome_browser_state_ = test_cbs_builder.Build(); + CHECK(chrome_browser_state_->CreateHistoryService()); session_service_block_ = ^SessionServiceIOS*(id self) { return test_session_service_;
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 d8902fa..73f5ece 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -1000,7 +1000,8 @@ @"popup_menu_translate", kToolsMenuTranslateId); if (self.engagementTracker && self.engagementTracker->ShouldTriggerHelpUI( - feature_engagement::kIPHBadgedTranslateManualTriggerFeature)) { + feature_engagement::kIPHBadgedTranslateManualTriggerFeature) && + self.isTranslateEnabled) { self.translateItem.badgeText = l10n_util::GetNSStringWithFixup( IDS_IOS_TOOLS_MENU_CELL_NEW_FEATURE_BADGE); }
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm index c1740ae..6a7eb41 100644 --- a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm +++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
@@ -15,13 +15,13 @@ #include "ios/chrome/browser/chrome_url_constants.h" #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" #import "ios/chrome/browser/ui/commands/application_commands.h" -#import "ios/chrome/browser/ui/util/label_link_controller.h" #include "ios/chrome/browser/ui/util/rtl_geometry.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" #import "ios/chrome/common/ui/util/pointer_interaction_util.h" #include "ios/web/public/browser_state.h" #include "ios/web/public/navigation/navigation_manager.h" +#import "net/base/mac/url_conversions.h" #include "ui/base/device_form_factor.h" #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" @@ -55,7 +55,7 @@ NSString* const kMessageTextViewBulletRTLFormat = @"\u202E%@\u202C"; } // namespace -@interface SadTabView () { +@interface SadTabView () <UITextViewDelegate> { UITextView* _messageTextView; MDCFlatButton* _actionButton; } @@ -69,10 +69,7 @@ // Displays the Sad Tab title. @property(nonatomic, readonly, strong) UILabel* titleLabel; // Displays the Sad Tab footer message (including a link to more help). -@property(nonatomic, readonly, strong) UILabel* footerLabel; -// Provides Link functionality to the footerLabel. -@property(nonatomic, readonly, strong) - LabelLinkController* footerLabelLinkController; +@property(nonatomic, readonly, strong) UITextView* footerLabel; // The bounds of |containerView|, with a height updated to CGFLOAT_MAX to allow // text to be laid out using as many lines as necessary. @property(nonatomic, readonly) CGRect containerBounds; @@ -106,11 +103,6 @@ // Returns the string to be used for the main action button. - (nonnull NSString*)buttonText; -// Attaches a link controller to |label|, finding the |linkString| -// within the |label| text to use as the link. -- (void)attachLinkControllerToLabel:(nonnull UILabel*)label - forLinkText:(nonnull NSString*)linkText; - // The action selector for |_actionButton|. - (void)handleActionButtonTapped; @@ -123,14 +115,10 @@ @implementation SadTabView -@synthesize offTheRecord = _offTheRecord; @synthesize imageView = _imageView; @synthesize containerView = _containerView; @synthesize titleLabel = _titleLabel; @synthesize footerLabel = _footerLabel; -@synthesize footerLabelLinkController = _footerLabelLinkController; -@synthesize mode = _mode; -@synthesize delegate = _delegate; - (instancetype)initWithMode:(SadTabViewMode)mode offTheRecord:(BOOL)offTheRecord { @@ -292,26 +280,6 @@ return label; } -- (void)attachLinkControllerToLabel:(nonnull UILabel*)label - forLinkText:(nonnull NSString*)linkText { - __weak __typeof(self) weakSelf = self; - _footerLabelLinkController = [[LabelLinkController alloc] - initWithLabel:label - action:^(const GURL& URL) { - [weakSelf.delegate sadTabView:weakSelf - showSuggestionsPageWithURL:URL]; - }]; - - _footerLabelLinkController.linkFont = - [[MDCTypography fontLoader] boldFontOfSize:kFooterLabelFontSize]; - _footerLabelLinkController.linkUnderlineStyle = NSUnderlineStyleSingle; - NSRange linkRange = [label.text rangeOfString:linkText]; - DCHECK(linkRange.location != NSNotFound); - DCHECK(linkRange.length > 0); - [_footerLabelLinkController addLinkWithRange:linkRange - url:GURL(kCrashReasonURL)]; -} - #pragma mark Accessors - (UIView*)containerView { @@ -347,18 +315,34 @@ return _titleLabel; } -- (UILabel*)footerLabel { +- (UITextView*)footerLabel { if (!_footerLabel) { - _footerLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - [_footerLabel setBackgroundColor:self.backgroundColor]; - [_footerLabel setNumberOfLines:0]; - [_footerLabel setFont:[[MDCTypography fontLoader] - regularFontOfSize:kFooterLabelFontSize]]; - [_footerLabel setTextColor:[UIColor colorNamed:kTextSecondaryColor]]; + _footerLabel = [[UITextView alloc] initWithFrame:CGRectZero]; + _footerLabel.backgroundColor = self.backgroundColor; + _footerLabel.delegate = self; - [_footerLabel setText:[self footerLabelText]]; - [self attachLinkControllerToLabel:_footerLabel - forLinkText:[self footerLinkText]]; + // Set base text styling for footer. + NSDictionary<NSAttributedStringKey, id>* footerAttributes = @{ + NSFontAttributeName : + [[MDCTypography fontLoader] regularFontOfSize:kFooterLabelFontSize], + NSForegroundColorAttributeName : [UIColor colorNamed:kTextSecondaryColor], + }; + NSMutableAttributedString* footerText = + [[NSMutableAttributedString alloc] initWithString:[self footerLabelText] + attributes:footerAttributes]; + + // Add link to footer. + NSURL* linkURL = net::NSURLWithGURL(GURL(kCrashReasonURL)); + NSDictionary<NSAttributedStringKey, id>* linkAttributes = @{ + NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor], + NSLinkAttributeName : linkURL, + }; + NSRange linkRange = [footerText.string rangeOfString:[self footerLinkText]]; + DCHECK(linkRange.location != NSNotFound); + DCHECK(linkRange.length > 0); + [footerText addAttributes:linkAttributes range:linkRange]; + + _footerLabel.attributedText = footerText; } return _footerLabel; } @@ -527,6 +511,21 @@ return [UIColor colorNamed:kBackgroundColor]; } +#pragma mark - UITextViewDelegate + +- (BOOL)textView:(UITextView*)textView + shouldInteractWithURL:(NSURL*)URL + inRange:(NSRange)characterRange + interaction:(UITextItemInteraction)interaction { + DCHECK(self.footerLabel == textView); + DCHECK(URL); + + [self.delegate sadTabView:self + showSuggestionsPageWithURL:net::GURLWithNSURL(URL)]; + // Returns NO as the app is handling the opening of the URL. + return NO; +} + @end #pragma mark -
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm index 0e0b7f8..df681421 100644 --- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm +++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm
@@ -27,9 +27,10 @@ NavigationBlockerDecider(web::WebState* web_state) : web::WebStatePolicyDecider(web_state) {} - PolicyDecision ShouldAllowRequest(NSURLRequest* request, - const RequestInfo& request_info) override { - return PolicyDecision::Cancel(); + void ShouldAllowRequest(NSURLRequest* request, + const RequestInfo& request_info, + PolicyDecisionCallback callback) override { + std::move(callback).Run(PolicyDecision::Cancel()); } WEB_STATE_USER_DATA_KEY_DECL();
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm index 0c1fc629..43b60a0 100644 --- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm +++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
@@ -143,6 +143,9 @@ // Removes the |curtain_| if there was an active swipe, and resets // |inSwipe_| value. - (void)dismissCurtain; +// Cleans up Browser, WebStateList, and WebState references in the instance of a +// BrowserDestroyed BrowserObserver call. +- (void)browserDestroyed; @end // A browser observer that nullifies SideSwipeController's pointer to browser @@ -153,7 +156,7 @@ : side_swipe_controller_(controller) {} void BrowserDestroyed(Browser* browser) override { - side_swipe_controller_.browser = nullptr; + [side_swipe_controller_ browserDestroyed]; } private: @@ -207,6 +210,14 @@ _webStateObserverBridge.reset(); } +- (void)browserDestroyed { + self.webStateList->RemoveObserver(_webStateListObserver.get()); + _scopedWebStateObservation.reset(); + _webStateObserverBridge.reset(); + self.browser->RemoveObserver(_browserRemover.get()); + self.browser = nullptr; +} + - (void)addHorizontalGesturesToView:(UIView*)view { _swipeGestureRecognizer = [[SideSwipeGestureRecognizer alloc] initWithTarget:self
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h index 5c51938..12b1988 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h
@@ -31,7 +31,7 @@ // TableViewCell that displays a text label that might contain a link. @interface TableViewTextLinkCell : TableViewCell // The text to display. -@property(nonatomic, readonly, strong) UILabel* textLabel; +@property(nonatomic, readonly, strong) UITextView* textView; // Delegate for the TableViewTextLinkCell. Is notified when a link is // tapped. @property(nonatomic, weak) id<TableViewTextLinkCellDelegate> delegate;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm index a40fc7d7..5c61a584 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm
@@ -8,11 +8,11 @@ #include "base/mac/foundation_util.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" -#import "ios/chrome/browser/ui/util/label_link_controller.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/common/string_util.h" #import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" +#import "net/base/mac/url_conversions.h" #include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -38,7 +38,7 @@ [super configureCell:tableCell withStyler:styler]; TableViewTextLinkCell* cell = base::mac::ObjCCastStrict<TableViewTextLinkCell>(tableCell); - cell.textLabel.text = self.text; + cell.textView.text = self.text; cell.selectionStyle = UITableViewCellSelectionStyleNone; if (!self.linkURL.is_empty()) [cell setLinkURL:self.linkURL]; @@ -48,49 +48,41 @@ #pragma mark - TableViewTextLinkCell -@interface TableViewTextLinkCell () -// Array that holds all LabelLinkController for this Cell. -@property(nonatomic, strong) - NSMutableArray<LabelLinkController*>* labelLinkControllers; - +@interface TableViewTextLinkCell () <UITextViewDelegate> @end @implementation TableViewTextLinkCell -@synthesize delegate = _delegate; -@synthesize textLabel = _textLabel; - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // Text Label, set font sizes using dynamic type. - _textLabel = [[UILabel alloc] init]; - _textLabel.translatesAutoresizingMaskIntoConstraints = NO; - _textLabel.numberOfLines = 0; - _textLabel.lineBreakMode = NSLineBreakByWordWrapping; - _textLabel.font = + _textView = [[UITextView alloc] init]; + _textView.scrollEnabled = NO; + _textView.editable = NO; + _textView.delegate = self; + _textView.translatesAutoresizingMaskIntoConstraints = NO; + _textView.font = [UIFont preferredFontForTextStyle:kTableViewSublabelFontStyle]; - _textLabel.textColor = UIColor.cr_secondaryLabelColor; + _textView.textColor = UIColor.cr_secondaryLabelColor; // Add subviews to View Hierarchy. - [self.contentView addSubview:_textLabel]; - - // Create labelLinkController array. - self.labelLinkControllers = [NSMutableArray array]; + [self.contentView addSubview:_textView]; // Set and activate constraints. [NSLayoutConstraint activateConstraints:@[ // Title Label Constraints. - [_textLabel.leadingAnchor + [_textView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:kTableViewHorizontalSpacing], - [_textLabel.topAnchor + [_textView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:kTableViewLabelVerticalTopSpacing], - [_textLabel.bottomAnchor + [_textView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:0], - [_textLabel.trailingAnchor + [_textView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-kTableViewHorizontalSpacing] ]]; @@ -99,48 +91,50 @@ } - (void)setLinkURL:(const GURL&)URL { - LabelLinkController* labelLinkController = - [self labelLinkControllerForURL:URL]; - - // Remove link delimiter from text and get ranges for links. Must be parsed - // before being added to the controller because modifying the label text - // clears all added links. if (URL.is_valid()) { - // TODO(crbug.com/1184151): Move to use AttributedStringFromStringWithLink. - const StringWithTag parsedString = ParseStringWithLink(self.textLabel.text); - DCHECK(parsedString.range != NSMakeRange(NSNotFound, 0)); - self.textLabel.text = parsedString.string; - [labelLinkController addLinkWithRange:parsedString.range url:URL]; + UITextView* textView = self.textView; + DCHECK(textView.text.length > 0); + // Attribute form of the font/color given to the text view on init. + NSDictionary<NSAttributedStringKey, id>* textAttributes = + [textView.attributedText attributesAtIndex:0 effectiveRange:nullptr]; + textView.attributedText = AttributedStringFromStringWithLink( + textView.text, textAttributes, [self linkAttributesForURL:URL]); } - [self.labelLinkControllers addObject:labelLinkController]; } - (void)setLinkURL:(const GURL&)URL forRange:(NSRange)range { - LabelLinkController* labelLinkController = - [self labelLinkControllerForURL:URL]; if (URL.is_valid()) { - [labelLinkController addLinkWithRange:range url:URL]; + NSMutableAttributedString* text = [[NSMutableAttributedString alloc] + initWithAttributedString:self.textView.attributedText]; + [text addAttributes:[self linkAttributesForURL:URL] range:range]; + self.textView.attributedText = text; } - [self.labelLinkControllers addObject:labelLinkController]; +} + +- (NSDictionary<NSAttributedStringKey, id>*)linkAttributesForURL: + (const GURL&)URL { + NSURL* linkURL = net::NSURLWithGURL(URL); + return @{ + NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor], + NSLinkAttributeName : linkURL, + }; } - (void)prepareForReuse { [super prepareForReuse]; - self.labelLinkControllers = [NSMutableArray array]; self.delegate = nil; } -// Returns a configured labelLinkController. -- (LabelLinkController*)labelLinkControllerForURL:(const GURL&)URL { - __weak TableViewTextLinkCell* weakSelf = self; - LabelLinkController* labelLinkController = [[LabelLinkController alloc] - initWithLabel:self.textLabel - action:^(const GURL& URL) { - [[weakSelf delegate] tableViewTextLinkCell:weakSelf - didRequestOpenURL:URL]; - }]; - [labelLinkController setLinkColor:[UIColor colorNamed:kBlueColor]]; - return labelLinkController; +- (BOOL)textView:(UITextView*)textView + shouldInteractWithURL:(NSURL*)URL + inRange:(NSRange)characterRange + interaction:(UITextItemInteraction)interaction { + DCHECK(self.textView == textView); + DCHECK(URL); + [self.delegate tableViewTextLinkCell:self + didRequestOpenURL:net::GURLWithNSURL(URL)]; + // Returns NO as the app is handling the opening of the URL. + return NO; } @end
diff --git a/ios/chrome/browser/web/invalid_url_tab_helper.h b/ios/chrome/browser/web/invalid_url_tab_helper.h index 4e70a8d..8f4e822 100644 --- a/ios/chrome/browser/web/invalid_url_tab_helper.h +++ b/ios/chrome/browser/web/invalid_url_tab_helper.h
@@ -23,8 +23,10 @@ private: explicit InvalidUrlTabHelper(web::WebState* web_state); - PolicyDecision ShouldAllowRequest(NSURLRequest* request, - const RequestInfo& request_info) override; + void ShouldAllowRequest( + NSURLRequest* request, + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; friend class web::WebStateUserData<InvalidUrlTabHelper>; WEB_STATE_USER_DATA_KEY_DECL();
diff --git a/ios/chrome/browser/web/invalid_url_tab_helper.mm b/ios/chrome/browser/web/invalid_url_tab_helper.mm index 17daad5..2d2d6c9 100644 --- a/ios/chrome/browser/web/invalid_url_tab_helper.mm +++ b/ios/chrome/browser/web/invalid_url_tab_helper.mm
@@ -47,11 +47,12 @@ : web::WebStatePolicyDecider(web_state) {} InvalidUrlTabHelper::~InvalidUrlTabHelper() = default; -web::WebStatePolicyDecider::PolicyDecision -InvalidUrlTabHelper::ShouldAllowRequest(NSURLRequest* request, - const RequestInfo& request_info) { +void InvalidUrlTabHelper::ShouldAllowRequest( + NSURLRequest* request, + const web::WebStatePolicyDecider::RequestInfo& request_info, + web::WebStatePolicyDecider::PolicyDecisionCallback callback) { if (IsUrlRequestValid(request)) { - return PolicyDecision::Allow(); + return std::move(callback).Run(PolicyDecision::Allow()); } // URL is invalid. Show error for certain browser-initiated navigations (f.e. @@ -64,12 +65,12 @@ if (PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) || PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_GENERATED) || PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_AUTO_BOOKMARK)) { - return PolicyDecision::CancelAndDisplayError([NSError - errorWithDomain:net::kNSErrorDomain - code:net::ERR_INVALID_URL - userInfo:nil]); + return std::move(callback).Run(PolicyDecision::CancelAndDisplayError( + [NSError errorWithDomain:net::kNSErrorDomain + code:net::ERR_INVALID_URL + userInfo:nil])); } - return PolicyDecision::Cancel(); + std::move(callback).Run(PolicyDecision::Cancel()); } WEB_STATE_USER_DATA_KEY_IMPL(InvalidUrlTabHelper)
diff --git a/ios/chrome/browser/web/invalid_url_tab_helper_unittest.mm b/ios/chrome/browser/web/invalid_url_tab_helper_unittest.mm index 62fa19c1..6b5b15e 100644 --- a/ios/chrome/browser/web/invalid_url_tab_helper_unittest.mm +++ b/ios/chrome/browser/web/invalid_url_tab_helper_unittest.mm
@@ -35,7 +35,17 @@ /*target_frame_is_main=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - return web_state_.ShouldAllowRequest(request, info); + __block bool callback_called = false; + __block web::WebStatePolicyDecider::PolicyDecision policy_decision = + web::WebStatePolicyDecider::PolicyDecision::Allow(); + auto callback = + base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) { + policy_decision = decision; + callback_called = true; + }); + web_state_.ShouldAllowRequest(request, info, std::move(callback)); + EXPECT_TRUE(callback_called); + return policy_decision; } web::FakeWebState web_state_;
diff --git a/ios/chrome/browser/web/lookalike_url_app_interface.mm b/ios/chrome/browser/web/lookalike_url_app_interface.mm index 1c1e8b1..aef313b4 100644 --- a/ios/chrome/browser/web/lookalike_url_app_interface.mm +++ b/ios/chrome/browser/web/lookalike_url_app_interface.mm
@@ -69,7 +69,7 @@ std::move(callback).Run(CreateLookalikeErrorDecision()); return; } - return std::move(callback).Run( + std::move(callback).Run( web::WebStatePolicyDecider::PolicyDecision::Allow()); }
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 index 8176183..4f9c7dd 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -e14a4ef87866965768ad2aa6c0d605f8095098a4 \ No newline at end of file +eedbae1a1d4677d2610f4d66eb91f300cc466c59 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 index 1864406..a7c55c7e 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -2316846bc43dec35168165237123a6969991b729 \ No newline at end of file +e11efb1cda1d31f9eeac918e803db5afb7e6240a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 index dd59036..559cd38 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -13d147316769c843f7de634fbe6d182ba311165f \ No newline at end of file +c38026e4bbb988fb7ca740cb56f854b451f46ac2 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 index b4e014d9..a358194 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -c95674414d97bdf912fec57839af96b596847cec \ No newline at end of file +b079631189cd8c5eef580a7ccd7eb73e0bbdecc6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 index 701af136..d14b420 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -9856096d2f82a8a87d6bc144de61229cd9a62f46 \ No newline at end of file +91438d3e75a79781a524b7ca2cd25c9f9b177166 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 index 1f38b50e..7f49648 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -41c5e70fd097f04c3f44391dc01d8d5bdbc69998 \ No newline at end of file +84baf1882e3e5e7882b6728a962b3912cbbc0ece \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 index 6be32ab..b0c786e 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -0a9c74478dc4bd2b6e7c080a46c440c16dec1805 \ No newline at end of file +77e5fddf9778f035a81dafccedc5b11c056061fa \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 index 6ae78e5..ff0b376 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -86034b1d2aa0d1b11e926075794bb393bb7420b1 \ No newline at end of file +f1feb214cd26bb2c08615fba5d629bacd1549941 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 index eb3bc375..d5094b90 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@ -0482972ed0a37f56ea6be9dfb8e9bc0653e1b7b7 \ No newline at end of file +6bba66b873465ee6bd796571bb0724eda879bb1e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 index c2a0736..16776a6bb 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@ -86055b37639e9ef1c954578a484a44487a3b78a1 \ No newline at end of file +54654f90c2caf38430c68b77fbea4a49192d443c \ No newline at end of file
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm index f492074b..3cf3ef9f 100644 --- a/ios/web/navigation/crw_wk_navigation_handler.mm +++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -406,122 +406,51 @@ requestURL.SchemeIs(url::kAboutScheme) || requestURL.SchemeIs(url::kBlobScheme); - if (policyDecision.ShouldAllowNavigation()) { - BOOL userInteractedWithRequestMainFrame = - self.userInteractionState->HasUserTappedRecently(webView) && - net::GURLWithNSURL(action.request.mainDocumentURL) == - self.userInteractionState->LastUserInteraction()->main_document_url; - BOOL isCrossOriginTargetFrame = NO; - if (action.sourceFrame && action.targetFrame && - action.sourceFrame != action.targetFrame) { - url::Origin sourceOrigin = - url::Origin::Create(web::GURLOriginWithWKSecurityOrigin( - action.sourceFrame.securityOrigin)); - url::Origin targetOrigin = - url::Origin::Create(web::GURLOriginWithWKSecurityOrigin( - action.targetFrame.securityOrigin)); - isCrossOriginTargetFrame = !sourceOrigin.IsSameOriginWith(targetOrigin); - } - web::WebStatePolicyDecider::RequestInfo requestInfo( - transition, isMainFrameNavigationAction, isCrossOriginTargetFrame, - userInteractedWithRequestMainFrame); - - policyDecision = - self.webStateImpl->ShouldAllowRequest(action.request, requestInfo); - - // The WebState may have been closed in the ShouldAllowRequest callback. - if (self.beingDestroyed) { - decisionHandler(WKNavigationActionPolicyCancel); - return; - } - } - - if (!webControllerCanShow) { - policyDecision = web::WebStatePolicyDecider::PolicyDecision::Cancel(); - } - - if (policyDecision.ShouldAllowNavigation()) { - if ([[action.request HTTPMethod] isEqualToString:@"POST"]) { - // Display the confirmation dialog if a form repost is detected. - if (action.navigationType == WKNavigationTypeFormResubmitted) { - self.webStateImpl->ShowRepostFormWarningDialog( - base::BindOnce(^(bool shouldContinue) { - if (self.beingDestroyed) { - decisionHandler(WKNavigationActionPolicyCancel); - } else if (shouldContinue) { - decisionHandler(WKNavigationActionPolicyAllow); - } else { - decisionHandler(WKNavigationActionPolicyCancel); - if (action.targetFrame.mainFrame) { - [self.pendingNavigationInfo setCancelled:YES]; - } - } - })); - return; - } - - web::NavigationItemImpl* item = - self.navigationManagerImpl->GetCurrentItemImpl(); - // TODO(crbug.com/570699): Remove this check once it's no longer possible - // to have no current entries. - if (item) - [self cachePOSTDataForRequest:action.request inNavigationItem:item]; - } - } else { - if (action.targetFrame.mainFrame) { - if (!self.beingDestroyed && policyDecision.ShouldDisplayError()) { - DCHECK(policyDecision.GetDisplayError()); - - // Navigation was blocked by |ShouldProvisionallyFailRequest|. Cancel - // load of page. - decisionHandler(WKNavigationActionPolicyCancel); - - // Handling presentation of policy decision error is dependent on - // |web::features::kUseJSForErrorPage| feature. - if (!base::FeatureList::IsEnabled(web::features::kUseJSForErrorPage)) { + __weak CRWWKNavigationHandler* weakSelf = self; + auto callback = base::BindOnce( + ^(web::WebStatePolicyDecider::PolicyDecision policyDecision) { + __strong CRWWKNavigationHandler* strongSelf = weakSelf; + // The WebState may have been closed in the ShouldAllowRequest callback. + if (!strongSelf || strongSelf.beingDestroyed) { + decisionHandler(WKNavigationActionPolicyCancel); return; } - [self displayError:policyDecision.GetDisplayError() - forCancelledNavigationToURL:action.request.URL - inWebView:webView - withTransition:transition]; - return; - } + if (!webControllerCanShow) { + policyDecision = web::WebStatePolicyDecider::PolicyDecision::Cancel(); + } - [self.pendingNavigationInfo setCancelled:YES]; - if (self.navigationManagerImpl->GetPendingItemIndex() == -1) { - // Discard the new pending item to ensure that the current URL is not - // different from what is displayed on the view. There is no need to - // reset pending item index for a different pending back-forward - // navigation. - self.navigationManagerImpl->DiscardNonCommittedItems(); - } + [strongSelf answerDecisionHandler:decisionHandler + forNavigationAction:action + withPolicyDecision:policyDecision + webView:webView + forceBlockUniversalLinks:forceBlockUniversalLinks]; + }); - web::NavigationContextImpl* context = - [self contextForPendingMainFrameNavigationWithURL:requestURL]; - if (context) { - // Destroy associated pending item, because this will be the last - // WKWebView callback for this navigation context. - context->ReleaseItem(); - } - - if (!self.beingDestroyed && - [self shouldClosePageOnNativeApplicationLoad]) { - self.webStateImpl->CloseWebState(); - decisionHandler(WKNavigationActionPolicyCancel); - return; - } - } - } - - if (policyDecision.ShouldCancelNavigation()) { - decisionHandler(WKNavigationActionPolicyCancel); + if (!policyDecision.ShouldAllowNavigation()) { + std::move(callback).Run(policyDecision); return; } - BOOL isOffTheRecord = self.webStateImpl->GetBrowserState()->IsOffTheRecord(); - decisionHandler(web::GetAllowNavigationActionPolicy( - isOffTheRecord || forceBlockUniversalLinks)); + + BOOL userInteractedWithRequestMainFrame = + self.userInteractionState->HasUserTappedRecently(webView) && + net::GURLWithNSURL(action.request.mainDocumentURL) == + self.userInteractionState->LastUserInteraction()->main_document_url; + BOOL isCrossOriginTargetFrame = NO; + if (action.sourceFrame && action.targetFrame && + action.sourceFrame != action.targetFrame) { + url::Origin sourceOrigin = url::Origin::Create( + web::GURLOriginWithWKSecurityOrigin(action.sourceFrame.securityOrigin)); + url::Origin targetOrigin = url::Origin::Create( + web::GURLOriginWithWKSecurityOrigin(action.targetFrame.securityOrigin)); + isCrossOriginTargetFrame = !sourceOrigin.IsSameOriginWith(targetOrigin); + } + web::WebStatePolicyDecider::RequestInfo requestInfo( + transition, isMainFrameNavigationAction, isCrossOriginTargetFrame, + userInteractedWithRequestMainFrame); + + self.webStateImpl->ShouldAllowRequest(action.request, requestInfo, + std::move(callback)); } - (void)webView:(WKWebView*)webView @@ -1644,6 +1573,105 @@ [self.navigationStates removeNavigation:navigation]; } +// This method should be called on deciding policy for navigation action. It +// Answers the |decisionHandler| with a final decision caculated with passed +// |policyDecision|. The passed |policyDecision| should be determined by some +// conditions and policy deciders +- (void)answerDecisionHandler: + (void (^)(WKNavigationActionPolicy))decisionHandler + forNavigationAction:(WKNavigationAction*)action + withPolicyDecision: + (web::WebStatePolicyDecider::PolicyDecision)policyDecision + webView:(WKWebView*)webView + forceBlockUniversalLinks:(BOOL)forceBlockUniversalLinks { + if (policyDecision.ShouldAllowNavigation()) { + if ([[action.request HTTPMethod] isEqualToString:@"POST"]) { + // Display the confirmation dialog if a form repost is detected. + if (action.navigationType == WKNavigationTypeFormResubmitted) { + self.webStateImpl->ShowRepostFormWarningDialog( + base::BindOnce(^(bool shouldContinue) { + if (self.beingDestroyed) { + decisionHandler(WKNavigationActionPolicyCancel); + } else if (shouldContinue) { + decisionHandler(WKNavigationActionPolicyAllow); + } else { + decisionHandler(WKNavigationActionPolicyCancel); + if (action.targetFrame.mainFrame) { + [self.pendingNavigationInfo setCancelled:YES]; + } + } + })); + return; + } + + web::NavigationItemImpl* item = + self.navigationManagerImpl->GetCurrentItemImpl(); + // TODO(crbug.com/570699): Remove this check once it's no longer + // possible to have no current entries. + if (item) + [self cachePOSTDataForRequest:action.request inNavigationItem:item]; + } + } else { + if (action.targetFrame.mainFrame) { + if (!self.beingDestroyed && policyDecision.ShouldDisplayError()) { + DCHECK(policyDecision.GetDisplayError()); + + // Navigation was blocked by |ShouldProvisionallyFailRequest|. Cancel + // load of page. + decisionHandler(WKNavigationActionPolicyCancel); + + // Handling presentation of policy decision error is dependent on + // |web::features::kUseJSForErrorPage| feature. + if (!base::FeatureList::IsEnabled(web::features::kUseJSForErrorPage)) { + return; + } + + ui::PageTransition transition = + [self pageTransitionFromNavigationType:action.navigationType]; + + [self displayError:policyDecision.GetDisplayError() + forCancelledNavigationToURL:action.request.URL + inWebView:webView + withTransition:transition]; + return; + } + + [self.pendingNavigationInfo setCancelled:YES]; + if (self.navigationManagerImpl->GetPendingItemIndex() == -1) { + // Discard the new pending item to ensure that the current URL is not + // different from what is displayed on the view. There is no need to + // reset pending item index for a different pending back-forward + // navigation. + self.navigationManagerImpl->DiscardNonCommittedItems(); + } + + web::NavigationContextImpl* context = [self + contextForPendingMainFrameNavigationWithURL:net::GURLWithNSURL( + action.request.URL)]; + if (context) { + // Destroy associated pending item, because this will be the last + // WKWebView callback for this navigation context. + context->ReleaseItem(); + } + + if (!self.beingDestroyed && + [self shouldClosePageOnNativeApplicationLoad]) { + self.webStateImpl->CloseWebState(); + decisionHandler(WKNavigationActionPolicyCancel); + return; + } + } + } + + if (policyDecision.ShouldCancelNavigation()) { + decisionHandler(WKNavigationActionPolicyCancel); + return; + } + BOOL isOffTheRecord = self.webStateImpl->GetBrowserState()->IsOffTheRecord(); + decisionHandler(web::GetAllowNavigationActionPolicy( + isOffTheRecord || forceBlockUniversalLinks)); +} + #pragma mark - Auth Challenge // Used in webView:didReceiveAuthenticationChallenge:completionHandler: to
diff --git a/ios/web/public/navigation/web_state_policy_decider.h b/ios/web/public/navigation/web_state_policy_decider.h index 3501166..1125318 100644 --- a/ios/web/public/navigation/web_state_policy_decider.h +++ b/ios/web/public/navigation/web_state_policy_decider.h
@@ -106,18 +106,13 @@ virtual ~WebStatePolicyDecider(); // Asks the decider whether the navigation corresponding to |request| should - // be allowed to continue. The first policy decider returning a PolicyDecision - // where ShouldCancelNavigation() is true will be the PolicyDecision used for - // the navigation. This means that a policy decider may not be called and have - // its expected decision performed for a given navigation. As such, the - // highest priority policy deciders should be added first to ensure those - // decisions are prioritized. - // Called before WebStateObserver::DidStartNavigation. - // Defaults to PolicyDecision::Allow() if not overridden. - // Never called in the following cases: + // be allowed to continue. Defaults to PolicyDecision::Allow() if not + // overridden. Called before WebStateObserver::DidStartNavigation. Calls + // |callback| with the decision. Never called in the following cases: // - same-document back-forward and state change navigations - virtual PolicyDecision ShouldAllowRequest(NSURLRequest* request, - const RequestInfo& request_info); + virtual void ShouldAllowRequest(NSURLRequest* request, + const RequestInfo& request_info, + PolicyDecisionCallback callback); // Asks the decider whether the navigation corresponding to |response| should // be allowed to display an error page if an error occurs. Defaults to
diff --git a/ios/web/public/navigation/web_state_policy_decider_bridge.h b/ios/web/public/navigation/web_state_policy_decider_bridge.h index 97fa402e..9e8276c1 100644 --- a/ios/web/public/navigation/web_state_policy_decider_bridge.h +++ b/ios/web/public/navigation/web_state_policy_decider_bridge.h
@@ -9,27 +9,28 @@ #import "ios/web/public/navigation/web_state_policy_decider.h" +typedef void (^PolicyDecisionHandler)( + web::WebStatePolicyDecider::PolicyDecision); + // Objective-C interface for web::WebStatePolicyDecider. @protocol CRWWebStatePolicyDecider <NSObject> @optional // Invoked by |WebStatePolicyDeciderBridge::ShouldAllowRequest|. -- (web::WebStatePolicyDecider::PolicyDecision) - shouldAllowRequest:(NSURLRequest*)request - requestInfo: - (const web::WebStatePolicyDecider::RequestInfo&)requestInfo; +- (void)shouldAllowRequest:(NSURLRequest*)request + requestInfo: + (const web::WebStatePolicyDecider::RequestInfo&)requestInfo + decisionHandler:(PolicyDecisionHandler)decisionHandler; // Invoked by |WebStatePolicyDeciderBridge::ShouldAllowRequest|. - (bool)shouldAllowErrorPageToBeDisplayed:(NSURLResponse*)response forMainFrame:(BOOL)forMainFrame; // Invoked by |WebStatePolicyDeciderBridge::ShouldAllowResponse|. -- (void) - decidePolicyForNavigationResponse:(NSURLResponse*)response - forMainFrame:(BOOL)forMainFrame - completionHandler: - (void (^)(web::WebStatePolicyDecider::PolicyDecision)) - completionHandler; +- (void)decidePolicyForNavigationResponse:(NSURLResponse*)response + forMainFrame:(BOOL)forMainFrame + decisionHandler: + (PolicyDecisionHandler)decisionHandler; @end namespace web { @@ -43,13 +44,13 @@ ~WebStatePolicyDeciderBridge() override; // web::WebStatePolicyDecider methods. - PolicyDecision ShouldAllowRequest(NSURLRequest* request, - const RequestInfo& request_info) override; + void ShouldAllowRequest(NSURLRequest* request, + const RequestInfo& request_info, + PolicyDecisionCallback callback) override; - void ShouldAllowResponse( - NSURLResponse* response, - bool for_main_frame, - base::OnceCallback<void(PolicyDecision)> callback) override; + void ShouldAllowResponse(NSURLResponse* response, + bool for_main_frame, + PolicyDecisionCallback callback) override; bool ShouldAllowErrorPageToBeDisplayed(NSURLResponse* response, bool for_main_frame) override;
diff --git a/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.mm b/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.mm index 2a8d9597..ad568b3 100644 --- a/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.mm +++ b/ios/web/public/test/fakes/crw_fake_web_state_policy_decider.mm
@@ -41,27 +41,25 @@ #pragma mark CRWWebStatePolicyDecider methods - -- (web::WebStatePolicyDecider::PolicyDecision) - shouldAllowRequest:(NSURLRequest*)request - requestInfo: - (const web::WebStatePolicyDecider::RequestInfo&)requestInfo { +- (void)shouldAllowRequest:(NSURLRequest*)request + requestInfo: + (const web::WebStatePolicyDecider::RequestInfo&)requestInfo + decisionHandler:(PolicyDecisionHandler)decisionHandler { _shouldAllowRequestInfo = std::make_unique<web::FakeShouldAllowRequestInfo>(); _shouldAllowRequestInfo->request = request; _shouldAllowRequestInfo->request_info = requestInfo; - return web::WebStatePolicyDecider::PolicyDecision::Allow(); + decisionHandler(web::WebStatePolicyDecider::PolicyDecision::Allow()); } -- (void) - decidePolicyForNavigationResponse:(NSURLResponse*)response - forMainFrame:(BOOL)forMainFrame - completionHandler: - (void (^)(web::WebStatePolicyDecider::PolicyDecision)) - completionHandler { +- (void)decidePolicyForNavigationResponse:(NSURLResponse*)response + forMainFrame:(BOOL)forMainFrame + decisionHandler: + (PolicyDecisionHandler)decisionHandler { _decidePolicyForNavigationResponseInfo = std::make_unique<web::FakeDecidePolicyForNavigationResponseInfo>(); _decidePolicyForNavigationResponseInfo->response = response; _decidePolicyForNavigationResponseInfo->for_main_frame = forMainFrame; - completionHandler(web::WebStatePolicyDecider::PolicyDecision::Allow()); + decisionHandler(web::WebStatePolicyDecider::PolicyDecision::Allow()); } @end
diff --git a/ios/web/public/test/fakes/fake_web_state.h b/ios/web/public/test/fakes/fake_web_state.h index 41fad446..47bd077e 100644 --- a/ios/web/public/test/fakes/fake_web_state.h +++ b/ios/web/public/test/fakes/fake_web_state.h
@@ -118,18 +118,20 @@ void SetCanTakeSnapshot(bool can_take_snapshot); // Getters for test data. - // Uses |policy_deciders| to return whether the navigation corresponding to - // |request| should be allowed. Defaults to PolicyDecision::Allow(). - WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( + // Uses |policy_deciders| to determine whether the navigation corresponding to + // |request| should be allowed. Calls |callback| with the decision. Defaults + // to PolicyDecision::Allow(). + void ShouldAllowRequest( NSURLRequest* request, - const WebStatePolicyDecider::RequestInfo& request_info); + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback callback); // Uses |policy_deciders| to determine whether the navigation corresponding to // |response| should be allowed. Calls |callback| with the decision. Defaults // to PolicyDecision::Allow(). void ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(WebStatePolicyDecider::PolicyDecision)> callback); + WebStatePolicyDecider::PolicyDecisionCallback callback); std::u16string GetLastExecutedJavascript() const; // Returns a copy of the last added callback, if one has been added. absl::optional<ScriptCommandCallback> GetLastAddedCallback() const;
diff --git a/ios/web/public/test/fakes/fake_web_state.mm b/ios/web/public/test/fakes/fake_web_state.mm index a91c36e..17e5435 100644 --- a/ios/web/public/test/fakes/fake_web_state.mm +++ b/ios/web/public/test/fakes/fake_web_state.mm
@@ -354,23 +354,34 @@ } } -WebStatePolicyDecider::PolicyDecision FakeWebState::ShouldAllowRequest( +void FakeWebState::ShouldAllowRequest( NSURLRequest* request, - const WebStatePolicyDecider::RequestInfo& request_info) { + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback callback) { + auto request_state_tracker = + std::make_unique<PolicyDecisionStateTracker>(std::move(callback)); + PolicyDecisionStateTracker* request_state_tracker_ptr = + request_state_tracker.get(); + auto policy_decider_callback = base::BindRepeating( + &PolicyDecisionStateTracker::OnSinglePolicyDecisionReceived, + base::Owned(std::move(request_state_tracker))); + int num_decisions_requested = 0; for (auto& policy_decider : policy_deciders_) { - WebStatePolicyDecider::PolicyDecision result = - policy_decider.ShouldAllowRequest(request, request_info); - if (result.ShouldCancelNavigation()) { - return result; - } + policy_decider.ShouldAllowRequest(request, request_info, + policy_decider_callback); + num_decisions_requested++; + if (request_state_tracker_ptr->DeterminedFinalResult()) + break; } - return WebStatePolicyDecider::PolicyDecision::Allow(); + + request_state_tracker_ptr->FinishedRequestingDecisions( + num_decisions_requested); } void FakeWebState::ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(WebStatePolicyDecider::PolicyDecision)> callback) { + WebStatePolicyDecider::PolicyDecisionCallback callback) { auto response_state_tracker = std::make_unique<PolicyDecisionStateTracker>(std::move(callback)); PolicyDecisionStateTracker* response_state_tracker_ptr =
diff --git a/ios/web/public/test/fakes/fake_web_state_policy_decider.h b/ios/web/public/test/fakes/fake_web_state_policy_decider.h index 8cded2d..4df20d1 100644 --- a/ios/web/public/test/fakes/fake_web_state_policy_decider.h +++ b/ios/web/public/test/fakes/fake_web_state_policy_decider.h
@@ -24,15 +24,14 @@ WebStatePolicyDecider::PolicyDecision should_allow_request); // WebStatePolicyDecider overrides - // Returns the value set with |SetShouldAllowRequest|. Defaults to true. - WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( - NSURLRequest* request, - const RequestInfo& request_info) override; // Always calls |callback| with PolicyDecision::Allow(). - void ShouldAllowResponse( - NSURLResponse* response, - bool for_main_frame, - base::OnceCallback<void(PolicyDecision)> callback) override; + void ShouldAllowRequest(NSURLRequest* request, + const RequestInfo& request_info, + PolicyDecisionCallback callback) override; + // Always calls |callback| with PolicyDecision::Allow(). + void ShouldAllowResponse(NSURLResponse* response, + bool for_main_frame, + PolicyDecisionCallback callback) override; void WebStateDestroyed() override {} private:
diff --git a/ios/web/public/test/fakes/fake_web_state_policy_decider.mm b/ios/web/public/test/fakes/fake_web_state_policy_decider.mm index e3cbb2e..3df6b75 100644 --- a/ios/web/public/test/fakes/fake_web_state_policy_decider.mm +++ b/ios/web/public/test/fakes/fake_web_state_policy_decider.mm
@@ -18,16 +18,17 @@ should_allow_request_ = should_allow_request; } -WebStatePolicyDecider::PolicyDecision -FakeWebStatePolicyDecider::ShouldAllowRequest(NSURLRequest* request, - const RequestInfo& request_info) { - return should_allow_request_; +void FakeWebStatePolicyDecider::ShouldAllowRequest( + NSURLRequest* request, + const RequestInfo& request_info, + PolicyDecisionCallback callback) { + std::move(callback).Run(should_allow_request_); } void FakeWebStatePolicyDecider::ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(PolicyDecision)> callback) { + PolicyDecisionCallback callback) { std::move(callback).Run(PolicyDecision::Allow()); }
diff --git a/ios/web/web_state/error_page_inttest.mm b/ios/web/web_state/error_page_inttest.mm index 112f818..ed646613 100644 --- a/ios/web/web_state/error_page_inttest.mm +++ b/ios/web/web_state/error_page_inttest.mm
@@ -92,13 +92,14 @@ const std::string& allowed_page_text() const { return allowed_query_; } // WebStatePolicyDecider overrides - PolicyDecision ShouldAllowRequest(NSURLRequest* request, - const RequestInfo& request_info) override { + void ShouldAllowRequest(NSURLRequest* request, + const RequestInfo& request_info, + PolicyDecisionCallback callback) override { PolicyDecision decision = PolicyDecision::Allow(); GURL URL = net::GURLWithNSURL(request.URL); if (URL.path() != path_ || URL.query() == blocked_request_query_) decision = PolicyDecision::CancelAndDisplayError(CreateEmbedderError()); - return decision; + std::move(callback).Run(decision); } void ShouldAllowResponse(NSURLResponse* response, bool for_main_frame,
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 6b8e6f1..ff8ae41b 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -981,16 +981,15 @@ ~TestWebStatePolicyDecider() override = default; // WebStatePolicyDecider overrides - PolicyDecision ShouldAllowRequest( - NSURLRequest* request, - const RequestInfo& request_info) override { + void ShouldAllowRequest(NSURLRequest* request, + const RequestInfo& request_info, + PolicyDecisionCallback callback) override { test_fixture->DestroyWebState(); - return PolicyDecision::Allow(); + std::move(callback).Run(PolicyDecision::Allow()); } - void ShouldAllowResponse( - NSURLResponse* response, - bool for_main_frame, - base::OnceCallback<void(PolicyDecision)> callback) override { + void ShouldAllowResponse(NSURLResponse* response, + bool for_main_frame, + PolicyDecisionCallback callback) override { std::move(callback).Run(PolicyDecision::Allow()); } void WebStateDestroyed() override {}
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h index 5803d09..8ce1478 100644 --- a/ios/web/web_state/web_state_impl.h +++ b/ios/web/web_state/web_state_impl.h
@@ -135,12 +135,18 @@ // that is the point where MIME type is set from HTTP headers. void SetContentsMimeType(const std::string& mime_type); - // Returns whether the navigation corresponding to |request| should be allowed - // to continue by asking its policy deciders. Defaults to - // PolicyDecision::Allow(). - WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( + // Decides whether the navigation corresponding to |request| should be + // allowed to continue by asking its policy deciders, and calls |callback| + // with the decision. Defaults to PolicyDecision::Allow(). If at least one + // policy decider's decision is PolicyDecision::Cancel(), the final result is + // PolicyDecision::Cancel(). Otherwise, if at least one policy decider's + // decision is PolicyDecision::CancelAndDisplayError(), the final result is + // PolicyDecision::CancelAndDisplayError(), with the error corresponding to + // the first PolicyDecision::CancelAndDisplayError() result that was received. + void ShouldAllowRequest( NSURLRequest* request, - const WebStatePolicyDecider::RequestInfo& request_info); + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback callback); // Decides whether the navigation corresponding to |response| should // be allowed to display an error page if an error occurs, by asking its @@ -160,7 +166,7 @@ void ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(WebStatePolicyDecider::PolicyDecision)> callback); + WebStatePolicyDecider::PolicyDecisionCallback callback); // Determines whether the given link with |link_url| should show a preview on // force touch.
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm index 9270381..08edda6 100644 --- a/ios/web/web_state/web_state_impl.mm +++ b/ios/web/web_state/web_state_impl.mm
@@ -465,17 +465,28 @@ mime_type_ = mime_type; } -WebStatePolicyDecider::PolicyDecision WebStateImpl::ShouldAllowRequest( +void WebStateImpl::ShouldAllowRequest( NSURLRequest* request, - const WebStatePolicyDecider::RequestInfo& request_info) { + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback callback) { + auto request_state_tracker = + std::make_unique<PolicyDecisionStateTracker>(std::move(callback)); + PolicyDecisionStateTracker* request_state_tracker_ptr = + request_state_tracker.get(); + auto policy_decider_callback = base::BindRepeating( + &PolicyDecisionStateTracker::OnSinglePolicyDecisionReceived, + base::Owned(std::move(request_state_tracker))); + int num_decisions_requested = 0; for (auto& policy_decider : policy_deciders_) { - WebStatePolicyDecider::PolicyDecision result = - policy_decider.ShouldAllowRequest(request, request_info); - if (result.ShouldCancelNavigation()) { - return result; - } + policy_decider.ShouldAllowRequest(request, request_info, + policy_decider_callback); + num_decisions_requested++; + if (request_state_tracker_ptr->DeterminedFinalResult()) + break; } - return WebStatePolicyDecider::PolicyDecision::Allow(); + + request_state_tracker_ptr->FinishedRequestingDecisions( + num_decisions_requested); } bool WebStateImpl::ShouldAllowErrorPageToBeDisplayed(NSURLResponse* response, @@ -492,7 +503,7 @@ void WebStateImpl::ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(WebStatePolicyDecider::PolicyDecision)> callback) { + WebStatePolicyDecider::PolicyDecisionCallback callback) { auto response_state_tracker = std::make_unique<PolicyDecisionStateTracker>(std::move(callback)); PolicyDecisionStateTracker* response_state_tracker_ptr =
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm index 45f1a336..1da78d7 100644 --- a/ios/web/web_state/web_state_impl_unittest.mm +++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -118,19 +118,17 @@ : WebStatePolicyDecider(web_state) {} virtual ~MockWebStatePolicyDecider() {} - MOCK_METHOD2(ShouldAllowRequest, - WebStatePolicyDecider::PolicyDecision( - NSURLRequest* request, - const WebStatePolicyDecider::RequestInfo& request_info)); + MOCK_METHOD3(ShouldAllowRequest, + void(NSURLRequest* request, + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback callback)); MOCK_METHOD2(ShouldAllowErrorPageToBeDisplayed, bool(NSURLResponse* response, bool for_main_frame)); - MOCK_METHOD3( - ShouldAllowResponse, - void(NSURLResponse* response, - bool for_main_frame, - base::OnceCallback<void(WebStatePolicyDecider::PolicyDecision)> - callback)); + MOCK_METHOD3(ShouldAllowResponse, + void(NSURLResponse* response, + bool for_main_frame, + WebStatePolicyDecider::PolicyDecisionCallback callback)); MOCK_METHOD0(WebStateDestroyed, void()); }; @@ -620,17 +618,28 @@ /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(decider, ShouldAllowRequest( - request, RequestInfoMatch(request_info_main_frame))) + EXPECT_CALL( + decider, + ShouldAllowRequest(request, RequestInfoMatch(request_info_main_frame), _)) .Times(1) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); - EXPECT_CALL(decider2, ShouldAllowRequest( - request, RequestInfoMatch(request_info_main_frame))) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL( + decider2, + ShouldAllowRequest(request, RequestInfoMatch(request_info_main_frame), _)) .Times(1) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); WebStatePolicyDecider::PolicyDecision policy_decision = - web_state_->ShouldAllowRequest(request, request_info_main_frame); + WebStatePolicyDecider::PolicyDecision::Cancel(); + auto callback = base::BindRepeating( + [](WebStatePolicyDecider::PolicyDecision* policy_decision, + WebStatePolicyDecider::PolicyDecision result) { + *policy_decision = result; + }, + base::Unretained(&policy_decision)); + web_state_->ShouldAllowRequest(request, request_info_main_frame, callback); EXPECT_TRUE(policy_decision.ShouldAllowNavigation()); EXPECT_FALSE(policy_decision.ShouldCancelNavigation()); @@ -640,16 +649,17 @@ /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); EXPECT_CALL(decider, ShouldAllowRequest( - request, RequestInfoMatch(request_info_iframe))) + request, RequestInfoMatch(request_info_iframe), _)) .Times(1) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(decider2, ShouldAllowRequest( - request, RequestInfoMatch(request_info_iframe))) + request, RequestInfoMatch(request_info_iframe), _)) .Times(1) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); - policy_decision = - web_state_->ShouldAllowRequest(request, request_info_iframe); + web_state_->ShouldAllowRequest(request, request_info_iframe, callback); EXPECT_TRUE(policy_decision.ShouldAllowNavigation()); EXPECT_FALSE(policy_decision.ShouldCancelNavigation()); @@ -658,23 +668,22 @@ { bool decider_called = false; bool decider2_called = false; - EXPECT_CALL( - decider, - ShouldAllowRequest(request, RequestInfoMatch(request_info_main_frame))) + EXPECT_CALL(decider, + ShouldAllowRequest( + request, RequestInfoMatch(request_info_main_frame), _)) .Times(AtMost(1)) - .WillOnce( - DoAll(Assign(&decider_called, true), - Return(WebStatePolicyDecider::PolicyDecision::Cancel()))); - EXPECT_CALL( - decider2, - ShouldAllowRequest(request, RequestInfoMatch(request_info_main_frame))) + .WillOnce(DoAll(Assign(&decider_called, true), + RunOnceCallback<2>( + WebStatePolicyDecider::PolicyDecision::Cancel()))); + EXPECT_CALL(decider2, + ShouldAllowRequest( + request, RequestInfoMatch(request_info_main_frame), _)) .Times(AtMost(1)) - .WillOnce( - DoAll(Assign(&decider2_called, true), - Return(WebStatePolicyDecider::PolicyDecision::Cancel()))); + .WillOnce(DoAll(Assign(&decider2_called, true), + RunOnceCallback<2>( + WebStatePolicyDecider::PolicyDecision::Cancel()))); - WebStatePolicyDecider::PolicyDecision policy_decision = - web_state_->ShouldAllowRequest(request, request_info_main_frame); + web_state_->ShouldAllowRequest(request, request_info_main_frame, callback); EXPECT_FALSE(policy_decision.ShouldAllowNavigation()); EXPECT_TRUE(policy_decision.ShouldCancelNavigation()); EXPECT_FALSE(decider_called && decider2_called); @@ -690,13 +699,6 @@ .WillOnce( RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); - policy_decision = WebStatePolicyDecider::PolicyDecision::Cancel(); - auto callback = base::BindRepeating( - [](WebStatePolicyDecider::PolicyDecision* policy_decision, - WebStatePolicyDecider::PolicyDecision result) { - *policy_decision = result; - }, - base::Unretained(&policy_decision)); web_state_->ShouldAllowResponse(response, true, callback); EXPECT_TRUE(policy_decision.ShouldAllowNavigation()); EXPECT_FALSE(policy_decision.ShouldCancelNavigation());
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm index 81b4dff..2e4ce38 100644 --- a/ios/web/web_state/web_state_observer_inttest.mm +++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -66,6 +66,7 @@ using base::test::RunOnceCallback; using wk_navigation_util::CreateRedirectUrl; +using ::testing::WithArgs; const char kExpectedMimeType[] = "text/html"; @@ -94,7 +95,10 @@ dispatch_async(dispatch_get_main_queue(), ^{ web_state->Stop(); }); - return WebStatePolicyDecider::PolicyDecision::Allow(); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(arg0), + WebStatePolicyDecider::PolicyDecision::Allow())); } // Verifies correctness of WebState's title. @@ -770,16 +774,21 @@ class PolicyDeciderMock : public WebStatePolicyDecider { public: PolicyDeciderMock(WebState* web_state) : WebStatePolicyDecider(web_state) {} - MOCK_METHOD2(ShouldAllowRequest, - WebStatePolicyDecider::PolicyDecision( - NSURLRequest*, - const WebStatePolicyDecider::RequestInfo& request_info)); - MOCK_METHOD3( - ShouldAllowResponse, - void(NSURLResponse*, - bool for_main_frame, - base::OnceCallback<void(WebStatePolicyDecider::PolicyDecision)> - callback)); + + void ShouldAllowRequest( + NSURLRequest* request, + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback callback) override { + MockShouldAllowRequest(request, request_info, callback); + } + MOCK_METHOD3(MockShouldAllowRequest, + void(NSURLRequest*, + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback& callback)); + MOCK_METHOD3(ShouldAllowResponse, + void(NSURLResponse*, + bool for_main_frame, + WebStatePolicyDecider::PolicyDecisionCallback callback)); }; } // namespace @@ -866,10 +875,11 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) .InSequence(callbacks_sequence) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .InSequence(callbacks_sequence) .WillOnce(VerifyPageStartedContext( @@ -917,9 +927,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -961,9 +972,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStopLoading(web_state())); EXPECT_CALL(observer_, DidStartLoading(web_state())); @@ -982,9 +994,10 @@ PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS)); // Load |second_url|. - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartLoading(web_state())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( @@ -1029,9 +1042,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1064,9 +1078,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1122,9 +1137,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1144,7 +1160,7 @@ // Navigate to an invalid URL using JavaScript. // There should be no calls to WebStatePolicyDecider, since the navigation // should get cancelled before that is reached. - EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).Times(0); + EXPECT_CALL(*decider_, MockShouldAllowRequest(_, _, _)).Times(0); ExecuteJavaScript(@"window.location.pathname = '/%00%50'"); } @@ -1165,9 +1181,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, @@ -1202,9 +1219,10 @@ ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); // WKWebView.URL changes from |url| nil and then to rewritten URL, while // WKWebView.loading changes from true to false and then back to true. @@ -1243,9 +1261,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1292,9 +1311,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1340,9 +1360,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStopLoading(web_state())); test::LoadUrl(web_state(), url); @@ -1362,9 +1383,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -1384,9 +1406,10 @@ /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(reload_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(reload_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce( VerifyReloadStartedContext(web_state(), url, &context, &nav_id)); @@ -1416,9 +1439,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -1437,9 +1461,11 @@ ui::PageTransition::PAGE_TRANSITION_RELOAD, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, ShouldAllowRequest( - _, RequestInfoMatch(expected_reload_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest( + _, RequestInfoMatch(expected_reload_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_RELOAD, @@ -1470,9 +1496,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1497,10 +1524,11 @@ /*has_user_gesture=*/false); EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL( - *decider_, - ShouldAllowRequest(_, RequestInfoMatch(hash_url_expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest( + _, RequestInfoMatch(hash_url_expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())); EXPECT_CALL(observer_, DidStopLoading(web_state())); @@ -1563,9 +1591,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1588,9 +1617,11 @@ ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, ShouldAllowRequest( - _, RequestInfoMatch(expected_hash_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest( + _, RequestInfoMatch(expected_hash_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) @@ -1622,9 +1653,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1687,9 +1719,10 @@ ui::PageTransition::PAGE_TRANSITION_GENERATED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPostStartedContext( web_state(), url, /*has_user_gesture=*/true, &context, &nav_id, @@ -1725,9 +1758,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -1748,8 +1782,9 @@ /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(form_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + MockShouldAllowRequest(_, RequestInfoMatch(form_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartLoading(web_state())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPostStartedContext( @@ -1782,9 +1817,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -1803,8 +1839,9 @@ /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(form_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + MockShouldAllowRequest(_, RequestInfoMatch(form_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartLoading(web_state())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) @@ -1828,9 +1865,10 @@ ui::PageTransition::PAGE_TRANSITION_RELOAD, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(form_reload_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(form_reload_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPostStartedContext( @@ -1868,9 +1906,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -1889,8 +1928,9 @@ /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(form_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + MockShouldAllowRequest(_, RequestInfoMatch(form_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartLoading(web_state())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) @@ -1915,8 +1955,9 @@ EXPECT_CALL(observer_, DidStartLoading(web_state())); EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())).Times(2); EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(back_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + MockShouldAllowRequest(_, RequestInfoMatch(back_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _)); @@ -1938,9 +1979,10 @@ int32_t nav_id = 0; EXPECT_CALL(observer_, DidStartLoading(web_state())); EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())).Times(2); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(forward_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(forward_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPostStartedContext(web_state(), action, @@ -1984,9 +2026,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -1997,30 +2040,35 @@ ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL( - *decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_redirect_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest( + _, RequestInfoMatch(expected_redirect_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidRedirectNavigation(web_state(), _)); - EXPECT_CALL( - *decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_redirect_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest( + _, RequestInfoMatch(expected_redirect_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidRedirectNavigation(web_state(), _)); - EXPECT_CALL( - *decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_redirect_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest( + _, RequestInfoMatch(expected_redirect_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidRedirectNavigation(web_state(), _)); - EXPECT_CALL( - *decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_redirect_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest( + _, RequestInfoMatch(expected_redirect_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidRedirectNavigation(web_state(), _)); - EXPECT_CALL( - *decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_redirect_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest( + _, RequestInfoMatch(expected_redirect_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidRedirectNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) @@ -2048,9 +2096,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -2079,9 +2128,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -2130,8 +2180,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, ShouldAllowRequest(_, RequestInfoMatch(request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, + MockShouldAllowRequest(_, RequestInfoMatch(request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -2165,9 +2217,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Cancel())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Cancel())); EXPECT_CALL(observer_, DidStopLoading(web_state())); test::LoadUrl(web_state(), test_server_->GetURL("/echo")); ASSERT_TRUE(test::WaitForPageToFinishLoading(web_state())); @@ -2191,9 +2244,9 @@ NSError* error = [NSError errorWithDomain:net::kNSErrorDomain code:net::ERR_BLOCKED_BY_ADMINISTRATOR userInfo:nil]; - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return( + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce(RunOnceCallback<2>( WebStatePolicyDecider::PolicyDecision::CancelAndDisplayError(error))); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); @@ -2227,9 +2280,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -2270,9 +2324,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -2303,9 +2358,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -2339,9 +2395,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); test::LoadUrl(web_state(), test_server_->GetURL("/hung")); web_state()->Stop(); ASSERT_TRUE(test::WaitForPageToFinishLoading(web_state())); @@ -2369,9 +2426,9 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(ReturnAllowRequestAndStopNavigation(web_state())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce(WithArgs<2>(ReturnAllowRequestAndStopNavigation(web_state()))); EXPECT_CALL(observer_, DidStopLoading(web_state())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyAbortedNavigationStartedContext( @@ -2402,9 +2459,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -2459,9 +2517,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -2473,9 +2532,10 @@ ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT, /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(iframe_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(iframe_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/false, _)) .WillOnce( RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); @@ -2491,9 +2551,10 @@ ui::PageTransition::PAGE_TRANSITION_LINK, /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/true); - EXPECT_CALL(*decider_, ShouldAllowRequest( - _, RequestInfoMatch(link_clicked_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(link_clicked_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/false, _)) .WillOnce( RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); @@ -2519,9 +2580,10 @@ /*has_user_gesture=*/true); EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())) .Times(2); // called once each for canGoBack and canGoForward - EXPECT_CALL(*decider_, ShouldAllowRequest( - _, RequestInfoMatch(forward_back_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(forward_back_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStopLoading(web_state())); @@ -2539,9 +2601,10 @@ ASSERT_FALSE(web_state()->GetNavigationManager()->CanGoBack()); // Trigger same-document load in iframe. - EXPECT_CALL(*decider_, ShouldAllowRequest( - _, RequestInfoMatch(link_clicked_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(link_clicked_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); // ShouldAllowResponse() is not called for same-document navigation. EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())) .Times(2); // called once each for canGoBack and canGoForward @@ -2567,9 +2630,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -2581,9 +2645,10 @@ ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT, /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(iframe_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(iframe_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/false, _)) .WillOnce( RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); @@ -2602,9 +2667,10 @@ ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT, /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(iframe_request_info2))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(iframe_request_info2), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/false, _)) .WillOnce( RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); @@ -2622,9 +2688,10 @@ ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT, /*target_main_frame=*/false, /*target_frame_is_cross_origin=*/true, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(iframe_request_info3))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(iframe_request_info3), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/false, _)) .WillOnce( RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); @@ -2641,8 +2708,9 @@ // Perform first navigation. const GURL first_url = test_server_->GetURL("/echoall"); EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest(_, _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -2656,8 +2724,9 @@ // Perform second navigation. const GURL hash_url = test_server_->GetURL("/echoall#1"); EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest(_, _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())); EXPECT_CALL(observer_, DidStopLoading(web_state())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); @@ -2691,8 +2760,9 @@ // New page load destroys forward navigation entries. const GURL url = test_server_->GetURL("/echo"); EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest(_, _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( @@ -2731,8 +2801,9 @@ EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest(_, _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true, _)) .WillOnce( RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); @@ -2747,8 +2818,9 @@ // Client-side redirect to restore_session.html?targetUrl=url1. EXPECT_CALL(*decider_, - ShouldAllowRequest(URLMatch(CreateRedirectUrl(url1)), _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + MockShouldAllowRequest(URLMatch(CreateRedirectUrl(url1)), _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartLoading(web_state())); @@ -2760,8 +2832,9 @@ EXPECT_CALL(observer_, DidStopLoading(web_state())); // Client-side redirect to |url1|. - EXPECT_CALL(*decider_, ShouldAllowRequest(URLMatch(url1), _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest(URLMatch(url1), _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartLoading(web_state())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); @@ -2793,8 +2866,9 @@ // Load restore_session.html?targetUrl=url0. EXPECT_CALL(*decider_, - ShouldAllowRequest(URLMatch(CreateRedirectUrl(url0)), _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + MockShouldAllowRequest(URLMatch(CreateRedirectUrl(url0)), _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(*decider_, ShouldAllowResponse(URLMatch(CreateRedirectUrl(url0)), /*for_main_frame=*/true, _)) .WillOnce( @@ -2803,8 +2877,9 @@ EXPECT_CALL(observer_, DidStopLoading(web_state())); // Client-side redirect to |url0|. - EXPECT_CALL(*decider_, ShouldAllowRequest(URLMatch(url0), _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest(URLMatch(url0), _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartLoading(web_state())); @@ -2882,9 +2957,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyPageStartedContext( web_state(), url, ui::PageTransition::PAGE_TRANSITION_TYPED, &context, @@ -2914,9 +2990,10 @@ ui::PageTransition::PAGE_TRANSITION_TYPED, /*target_main_frame=*/true, /*target_frame_is_cross_origin=*/false, /*has_user_gesture=*/false); - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(expected_request_info))) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest( + _, RequestInfoMatch(expected_request_info), _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); NavigationContext* context = nullptr; int32_t nav_id = 0; EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) @@ -2939,8 +3016,9 @@ GURL data_url("https://www.chromium.test"); EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)) - .WillOnce(Return(WebStatePolicyDecider::PolicyDecision::Allow())); + EXPECT_CALL(*decider_, MockShouldAllowRequest(_, _, _)) + .WillOnce( + RunOnceCallback<2>(WebStatePolicyDecider::PolicyDecision::Allow())); // ShouldAllowResponse is not called on loadData navigation. EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifyDataStartedContext(
diff --git a/ios/web/web_state/web_state_policy_decider.mm b/ios/web/web_state/web_state_policy_decider.mm index 00dca39..c33216e 100644 --- a/ios/web/web_state/web_state_policy_decider.mm +++ b/ios/web/web_state/web_state_policy_decider.mm
@@ -64,10 +64,11 @@ } } -WebStatePolicyDecider::PolicyDecision WebStatePolicyDecider::ShouldAllowRequest( +void WebStatePolicyDecider::ShouldAllowRequest( NSURLRequest* request, - const WebStatePolicyDecider::RequestInfo& request_info) { - return WebStatePolicyDecider::PolicyDecision::Allow(); + const RequestInfo& request_info, + PolicyDecisionCallback callback) { + std::move(callback).Run(PolicyDecision::Allow()); } bool WebStatePolicyDecider::ShouldAllowErrorPageToBeDisplayed( @@ -79,7 +80,7 @@ void WebStatePolicyDecider::ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(PolicyDecision)> callback) { + PolicyDecisionCallback callback) { std::move(callback).Run(PolicyDecision::Allow()); }
diff --git a/ios/web/web_state/web_state_policy_decider_bridge.mm b/ios/web/web_state/web_state_policy_decider_bridge.mm index b420ceb..fbf3adf 100644 --- a/ios/web/web_state/web_state_policy_decider_bridge.mm +++ b/ios/web/web_state/web_state_policy_decider_bridge.mm
@@ -17,15 +17,21 @@ WebStatePolicyDeciderBridge::~WebStatePolicyDeciderBridge() = default; -WebStatePolicyDecider::PolicyDecision -WebStatePolicyDeciderBridge::ShouldAllowRequest( +void WebStatePolicyDeciderBridge::ShouldAllowRequest( NSURLRequest* request, - const WebStatePolicyDecider::RequestInfo& request_info) { - if ([decider_ - respondsToSelector:@selector(shouldAllowRequest:requestInfo:)]) { - return [decider_ shouldAllowRequest:request requestInfo:request_info]; + const RequestInfo& request_info, + PolicyDecisionCallback callback) { + if ([decider_ respondsToSelector:@selector + (shouldAllowRequest:requestInfo:decisionHandler:)]) { + __block PolicyDecisionCallback block_callback = std::move(callback); + [decider_ shouldAllowRequest:request + requestInfo:request_info + decisionHandler:^(PolicyDecision result) { + std::move(block_callback).Run(result); + }]; + return; } - return WebStatePolicyDecider::PolicyDecision::Allow(); + std::move(callback).Run(PolicyDecision::Allow()); } bool WebStatePolicyDeciderBridge::ShouldAllowErrorPageToBeDisplayed( @@ -42,17 +48,16 @@ void WebStatePolicyDeciderBridge::ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(PolicyDecision)> callback) { + PolicyDecisionCallback callback) { if ([decider_ respondsToSelector:@selector (decidePolicyForNavigationResponse: - forMainFrame:completionHandler:)]) { - __block base::OnceCallback<void(PolicyDecision)> block_callback = - std::move(callback); + forMainFrame:decisionHandler:)]) { + __block PolicyDecisionCallback block_callback = std::move(callback); [decider_ decidePolicyForNavigationResponse:response forMainFrame:for_main_frame - completionHandler:^(PolicyDecision result) { - std::move(block_callback).Run(result); - }]; + decisionHandler:^(PolicyDecision result) { + std::move(block_callback).Run(result); + }]; return; } std::move(callback).Run(PolicyDecision::Allow());
diff --git a/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm b/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm index 54a71602..c11705d 100644 --- a/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm +++ b/ios/web/web_state/web_state_policy_decider_bridge_unittest.mm
@@ -40,7 +40,7 @@ WebStatePolicyDecider::RequestInfo request_info( transition_type, target_frame_is_main, target_frame_is_cross_origin, has_user_gesture); - decider_bridge_.ShouldAllowRequest(request, request_info); + decider_bridge_.ShouldAllowRequest(request, request_info, base::DoNothing()); FakeShouldAllowRequestInfo* should_allow_request_info = [decider_ shouldAllowRequestInfo]; ASSERT_TRUE(should_allow_request_info);
diff --git a/ios/web_view/internal/web_view_web_state_policy_decider.h b/ios/web_view/internal/web_view_web_state_policy_decider.h index eeebaadf..43c478b 100644 --- a/ios/web_view/internal/web_view_web_state_policy_decider.h +++ b/ios/web_view/internal/web_view_web_state_policy_decider.h
@@ -25,14 +25,14 @@ WebViewWebStatePolicyDecider(web::WebState* web_state, CWVWebView* web_view); // web::WebStatePolicyDecider overrides: - web::WebStatePolicyDecider::PolicyDecision ShouldAllowRequest( + void ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) override; + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback callback) override; void ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(WebStatePolicyDecider::PolicyDecision)> callback) - override; + WebStatePolicyDecider::PolicyDecisionCallback callback) override; private: // Delegates to |delegate| property of this web view.
diff --git a/ios/web_view/internal/web_view_web_state_policy_decider.mm b/ios/web_view/internal/web_view_web_state_policy_decider.mm index 4072ca4..37722d44 100644 --- a/ios/web_view/internal/web_view_web_state_policy_decider.mm +++ b/ios/web_view/internal/web_view_web_state_policy_decider.mm
@@ -19,10 +19,10 @@ CWVWebView* web_view) : web::WebStatePolicyDecider(web_state), web_view_(web_view) {} -web::WebStatePolicyDecider::PolicyDecision -WebViewWebStatePolicyDecider::ShouldAllowRequest( +void WebViewWebStatePolicyDecider::ShouldAllowRequest( NSURLRequest* request, - const web::WebStatePolicyDecider::RequestInfo& request_info) { + const WebStatePolicyDecider::RequestInfo& request_info, + WebStatePolicyDecider::PolicyDecisionCallback callback) { id<CWVNavigationDelegate> delegate = web_view_.navigationDelegate; if ([delegate respondsToSelector:@selector (webView:shouldStartLoadWithRequest:navigationType:)]) { @@ -36,16 +36,18 @@ shouldStartLoadWithRequest:request navigationType:navigation_type]; if (!allow) { - return WebStatePolicyDecider::PolicyDecision::Cancel(); + return std::move(callback).Run( + web::WebStatePolicyDecider::WebStatePolicyDecider::PolicyDecision:: + Cancel()); } } - return WebStatePolicyDecider::PolicyDecision::Allow(); + std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Allow()); } void WebViewWebStatePolicyDecider::ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, - base::OnceCallback<void(WebStatePolicyDecider::PolicyDecision)> callback) { + WebStatePolicyDecider::PolicyDecisionCallback callback) { id<CWVNavigationDelegate> delegate = web_view_.navigationDelegate; if ([delegate respondsToSelector:@selector (webView:shouldContinueLoadWithResponse:forMainFrame:)]) { @@ -53,8 +55,8 @@ shouldContinueLoadWithResponse:response forMainFrame:for_main_frame]; if (!allow) { - std::move(callback).Run(WebStatePolicyDecider::PolicyDecision::Cancel()); - return; + return std::move(callback).Run( + WebStatePolicyDecider::PolicyDecision::Cancel()); }; } std::move(callback).Run(WebStatePolicyDecider::PolicyDecision::Allow());
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc index 1d910d62..258f241 100644 --- a/media/gpu/vaapi/vaapi_wrapper.cc +++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -553,45 +553,76 @@ return success; } -bool VADisplayState::InitializeVaDisplay_Locked() { +#if defined(USE_X11) + +absl::optional<VADisplay> GetVADisplayStateX11(const base::ScopedFD& drm_fd) { + bool use_drm_as_fallback = false; switch (gl::GetGLImplementation()) { case gl::kGLImplementationEGLGLES2: - va_display_ = vaGetDisplayDRM(drm_fd_.get()); - break; - case gl::kGLImplementationDesktopGL: -#if defined(USE_X11) - if (!features::IsUsingOzonePlatform()) { - va_display_ = vaGetDisplay(x11::Connection::Get()->GetXlibDisplay()); - if (!vaDisplayIsValid(va_display_)) - va_display_ = vaGetDisplayDRM(drm_fd_.get()); - } -#endif // USE_X11 - break; - case gl::kGLImplementationEGLANGLE: -#if defined(USE_X11) - if (!features::IsUsingOzonePlatform()) - va_display_ = vaGetDisplay(x11::Connection::Get()->GetXlibDisplay()); -#endif // USE_X11 - break; - // Cannot infer platform from GL, try all available displays + return vaGetDisplayDRM(drm_fd.get()); + case gl::kGLImplementationNone: -#if defined(USE_X11) + use_drm_as_fallback = true; + FALLTHROUGH; + + case gl::kGLImplementationDesktopGL: { if (!features::IsUsingOzonePlatform()) { - va_display_ = vaGetDisplay(x11::Connection::Get()->GetXlibDisplay()); - if (vaDisplayIsValid(va_display_)) - break; + VADisplay display = + vaGetDisplay(x11::Connection::Get()->GetXlibDisplay()); + if (vaDisplayIsValid(display)) + return display; + return vaGetDisplayDRM(drm_fd.get()); } -#endif // USE_X11 - va_display_ = vaGetDisplayDRM(drm_fd_.get()); break; + } + + case gl::kGLImplementationEGLANGLE: { + if (!features::IsUsingOzonePlatform()) + return vaGetDisplay(x11::Connection::Get()->GetXlibDisplay()); + break; + } default: LOG(WARNING) << "VAAPI video acceleration not available for " << gl::GetGLImplementationGLName( gl::GetGLImplementationParts()); - return false; + return absl::nullopt; } + if (use_drm_as_fallback) + return vaGetDisplayDRM(drm_fd.get()); + return absl::nullopt; +} + +#else + +absl::optional<VADisplay> GetVADisplayState(const base::ScopedFD& drm_fd) { + switch (gl::GetGLImplementation()) { + case gl::kGLImplementationEGLGLES2: + case gl::kGLImplementationNone: + return vaGetDisplayDRM(drm_fd.get()); + default: + LOG(WARNING) << "VAAPI video acceleration not available for " + << gl::GetGLImplementationGLName( + gl::GetGLImplementationParts()); + return absl::nullopt; + } +} + +#endif // defined(USE_X11) + +bool VADisplayState::InitializeVaDisplay_Locked() { + absl::optional<VADisplay> display = +#if defined(USE_X11) + GetVADisplayStateX11(drm_fd_); +#else + GetVADisplayState(drm_fd_); +#endif + + if (!display) + return false; + + va_display_ = *display; if (!vaDisplayIsValid(va_display_)) { LOG(ERROR) << "Could not get a valid VA display"; return false;
diff --git a/net/android/unittest_support/AndroidManifest.xml b/net/android/unittest_support/AndroidManifest.xml index 4cbc0b9..06a61cb 100644 --- a/net/android/unittest_support/AndroidManifest.xml +++ b/net/android/unittest_support/AndroidManifest.xml
@@ -31,6 +31,7 @@ <activity android:name=".NativeUnitTestActivity" android:label="NativeTest" android:configChanges="orientation|keyboardHidden" + android:exported="true" android:process=":test_process"> <intent-filter> <action android:name="android.intent.action.MAIN" />
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc index e9b9de5..83865d3 100644 --- a/services/network/cors/preflight_controller.cc +++ b/services/network/cors/preflight_controller.cc
@@ -233,8 +233,16 @@ if (devtools_observer_) { DCHECK(devtools_request_id_); + auto request_info = network::mojom::URLRequestDevToolsInfo::New( + preflight_request->method, preflight_request->url, + preflight_request->priority, preflight_request->referrer_policy, + preflight_request->trust_token_params + ? preflight_request->trust_token_params->Clone() + : nullptr, + request.has_user_gesture); devtools_observer_->OnCorsPreflightRequest( - *devtools_request_id_, *preflight_request, original_request_.url, + *devtools_request_id_, preflight_request->headers, + std::move(request_info), original_request_.url, original_request_.devtools_request_id.value_or("")); } loader_ =
diff --git a/services/network/cors/preflight_controller_unittest.cc b/services/network/cors/preflight_controller_unittest.cc index 06df120e..f633a47 100644 --- a/services/network/cors/preflight_controller_unittest.cc +++ b/services/network/cors/preflight_controller_unittest.cc
@@ -270,8 +270,8 @@ bool on_raw_request_called() const { return on_raw_request_called_; } bool on_raw_response_called() const { return on_raw_response_called_; } - const absl::optional<network::ResourceRequest>& preflight_request() const { - return preflight_request_; + const network::mojom::URLRequestDevToolsInfoPtr& preflight_request() const { + return preflight_request_info_; } const network::mojom::URLResponseHeadPtr& preflight_response() const { return preflight_response_; @@ -303,10 +303,11 @@ } void OnCorsPreflightRequest( const base::UnguessableToken& devtool_request_id, - const network::ResourceRequest& request, + const net::HttpRequestHeaders& request_headers, + network::mojom::URLRequestDevToolsInfoPtr request_info, const GURL& initiator_url, const std::string& initiator_devtools_request_id) override { - preflight_request_ = request; + preflight_request_info_ = std::move(request_info); initiator_devtools_request_id_ = initiator_devtools_request_id; } void OnCorsPreflightResponse( @@ -363,7 +364,7 @@ base::OnceClosure wait_for_completed_; bool on_raw_request_called_ = false; bool on_raw_response_called_ = false; - absl::optional<network::ResourceRequest> preflight_request_; + network::mojom::URLRequestDevToolsInfoPtr preflight_request_info_; network::mojom::URLResponseHeadPtr preflight_response_; absl::optional<network::URLLoaderCompletionStatus> preflight_status_; std::string initiator_devtools_request_id_; @@ -697,7 +698,7 @@ devtools_observer()->WaitUntilRequestCompleted(); EXPECT_TRUE(devtools_observer()->on_raw_request_called()); EXPECT_TRUE(devtools_observer()->on_raw_response_called()); - ASSERT_TRUE(devtools_observer()->preflight_request().has_value()); + ASSERT_TRUE(devtools_observer()->preflight_request()); EXPECT_EQ(request.url, devtools_observer()->preflight_request()->url); EXPECT_EQ("OPTIONS", devtools_observer()->preflight_request()->method); ASSERT_TRUE(devtools_observer()->preflight_response());
diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom index 31161f3..72bab00 100644 --- a/services/network/public/mojom/url_request.mojom +++ b/services/network/public/mojom/url_request.mojom
@@ -506,6 +506,17 @@ DataElementChunkedDataPipe chunked_data_pipe; }; +// A struct with information about a URLRequest that is reported to DevTools. +// See URLRequest definition for a description of the fields. +struct URLRequestDevToolsInfo { + string method; + url.mojom.Url url; + RequestPriority priority; + URLRequestReferrerPolicy referrer_policy; + TrustTokenParams? trust_token_params; + bool has_user_gesture; +}; + // Interface for devtools receiving information about individual request // state. interface DevToolsObserver { @@ -545,7 +556,8 @@ // |devtool_request_id| is available on the original request. OnCorsPreflightRequest( mojo_base.mojom.UnguessableToken devtool_request_id, - URLRequest request, + HttpRequestHeaders request_headers, + URLRequestDevToolsInfo request_info, url.mojom.Url initiator_url, string initiator_devtool_request_id);
diff --git a/services/network/test/mock_devtools_observer.cc b/services/network/test/mock_devtools_observer.cc index 169f21c6..93bc6af 100644 --- a/services/network/test/mock_devtools_observer.cc +++ b/services/network/test/mock_devtools_observer.cc
@@ -73,7 +73,8 @@ void MockDevToolsObserver::OnCorsPreflightRequest( const base::UnguessableToken& devtool_request_id, - const network::ResourceRequest& request, + const net::HttpRequestHeaders& request_headers, + network::mojom::URLRequestDevToolsInfoPtr request_info, const GURL& initiator_url, const std::string& initiator_devtool_request_id) {}
diff --git a/services/network/test/mock_devtools_observer.h b/services/network/test/mock_devtools_observer.h index ca48f36..55857e9 100644 --- a/services/network/test/mock_devtools_observer.h +++ b/services/network/test/mock_devtools_observer.h
@@ -50,7 +50,8 @@ void OnCorsPreflightRequest( const base::UnguessableToken& devtool_request_id, - const network::ResourceRequest& request, + const net::HttpRequestHeaders& request_headers, + network::mojom::URLRequestDevToolsInfoPtr request_info, const GURL& initiator_url, const std::string& initiator_devtool_request_id) override;
diff --git a/services/network/throttling/throttling_network_interceptor.h b/services/network/throttling/throttling_network_interceptor.h index 09c7d6e..19a5050 100644 --- a/services/network/throttling/throttling_network_interceptor.h +++ b/services/network/throttling/throttling_network_interceptor.h
@@ -38,15 +38,48 @@ // Applies network emulation configuration. void UpdateConditions(std::unique_ptr<NetworkConditions> conditions); - // Throttles with |is_upload == true| always succeed, even in offline mode. + // This function implements throttling logic. It is meant to be called after + // the interaction with a real network to delay invocation of a client + // callback. + // * 'result' holds the result of a real network operation from + // net/base/net_error_list.h. + // * 'bytes' is the amount of data transferred over the network. It is used + // to calculate the delay. + // * 'send_end' is the time when the the real network operation was finished. + // * 'start' is true if this is invoked for starting HTTP transaction (as + // opposed to other operations such as reading ressponse or uploading + // data). + // * 'is_upload' is true if this is invoked for sending data over the network + // (as opposed to reading data from the network). NetworkConditions could + // specify different speed for upload and download and this parameter is + // used to pick the right speed. + // * 'callback' is what needs to be invoked later, if extra delay is + // introduced to emulate a slow network. + // + // This function returns net::ERR_IO_PENDING if the delay is introduced and + // 'callack' will be invoked after this delay. + // When no throttling is needed, this function simply returns 'result' and + // ignores the rest of the arguments including 'callback'. + // The same happens if 'result' corresponds to an error (i.e. is negative + // meaning that the real network operation has failed). + // When emulating offline network, the function returns + // net::ERR_INTERNET_DISCONNECTED and also ignores the arguments including + // 'callback'. + // Note, however, that if 'is_upload' is true the function will + // return 'result' insead of net::ERR_INTERNET_DISCONNECTED. (But why?) int StartThrottle(int result, int64_t bytes, base::TimeTicks send_end, bool start, bool is_upload, const ThrottleCallback& callback); + + // Cancels throttling, previously started with the given 'callback'. + // This is useful to call if the client is being destructed or otherwise is + // no longer interested in throttling. void StopThrottle(const ThrottleCallback& callback); + // Whether offline network is emulated. bool IsOffline(); private:
diff --git a/testing/android/native_test/java/AndroidManifest.xml.jinja2 b/testing/android/native_test/java/AndroidManifest.xml.jinja2 index c4ab893a..2ffecbb3 100644 --- a/testing/android/native_test/java/AndroidManifest.xml.jinja2 +++ b/testing/android/native_test/java/AndroidManifest.xml.jinja2
@@ -36,7 +36,8 @@ <activity android:name=".NativeUnitTestNativeActivity" android:label="NativeTest" android:configChanges="orientation|keyboardHidden" - android:process=":test_process"> + android:process=":test_process" + android:exported="true"> {% if is_component_build == 'true' %} <meta-data android:name="android.app.lib_name" android:value="{{ native_library_name }}.cr" />
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 77ac33c..86be2fc9 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -24251,6 +24251,424 @@ } ] }, + "android-cronet-x86-dbg-10-tests": { + "gtest_tests": [ + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android29.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cronet_sample_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "named_caches": [ + { + "name": "avd_generic_android29", + "path": ".android" + }, + { + "name": "system_images_android_29_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "avd_generic_android29" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cronet_sample_test_apk", + "test_id_prefix": "ninja://components/cronet/android:cronet_sample_test_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android29.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cronet_smoketests_missing_native_library_instrumentation_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "named_caches": [ + { + "name": "avd_generic_android29", + "path": ".android" + }, + { + "name": "system_images_android_29_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "avd_generic_android29" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cronet_smoketests_missing_native_library_instrumentation_apk", + "test_id_prefix": "ninja://components/cronet/android:cronet_smoketests_missing_native_library_instrumentation_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android29.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cronet_smoketests_platform_only_instrumentation_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "named_caches": [ + { + "name": "avd_generic_android29", + "path": ".android" + }, + { + "name": "system_images_android_29_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "avd_generic_android29" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cronet_smoketests_platform_only_instrumentation_apk", + "test_id_prefix": "ninja://components/cronet/android:cronet_smoketests_platform_only_instrumentation_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android29.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cronet_test_instrumentation_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "named_caches": [ + { + "name": "avd_generic_android29", + "path": ".android" + }, + { + "name": "system_images_android_29_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "avd_generic_android29" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cronet_test_instrumentation_apk", + "test_id_prefix": "ninja://components/cronet/android:cronet_test_instrumentation_apk/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android29.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cronet_tests_android" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "named_caches": [ + { + "name": "avd_generic_android29", + "path": ".android" + }, + { + "name": "system_images_android_29_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "avd_generic_android29" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cronet_tests_android", + "test_id_prefix": "ninja://components/cronet/android:cronet_tests_android/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android29.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "cronet_unittests_android" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "named_caches": [ + { + "name": "avd_generic_android29", + "path": ".android" + }, + { + "name": "system_images_android_29_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "avd_generic_android29" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cronet_unittests_android", + "test_id_prefix": "ninja://components/cronet/android:cronet_unittests_android/" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices", + "--avd-config=../../tools/android/avd/proto/generic_android29.textpb" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "net_unittests" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "resultdb": { + "enable": true + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "named_caches": [ + { + "name": "avd_generic_android29", + "path": ".android" + }, + { + "name": "system_images_android_29_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "optional_dimensions": { + "60": [ + { + "caches": "avd_generic_android29" + } + ] + }, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 4 + }, + "test": "net_unittests", + "test_id_prefix": "ninja://net:net_unittests/" + } + ] + }, "android-cronet-x86-rel": { "additional_compile_targets": [ "cronet_package",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index c222e680..7423a0d 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -795,6 +795,16 @@ 'isolated_scripts': 'cronet_dbg_isolated_scripts', }, }, + 'android-cronet-x86-dbg-10-tests': { + 'mixins': [ + 'enable_resultdb', + '10-x86-emulator', + ], + 'test_suites': { + 'gtest_tests': 'cronet_gtests', + }, + 'os_type': 'android', + }, 'android-cronet-x86-rel': { 'additional_compile_targets': [ 'cronet_package',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 8de92a5..e1a77535 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -4161,21 +4161,6 @@ ] } ], - "IOSPasswordReuseDetection": [ - { - "platforms": [ - "ios" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "PasswordReuseDetectionEnabled" - ] - } - ] - } - ], "IOSReduceSessionSize": [ { "platforms": [
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni index 0a5bc95..19a5ab7 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -1212,8 +1212,6 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_presentation_connection_close_reason.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_presentation_connection_state.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_presentation_connection_state.h", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_presenter_type.cc", - "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_presenter_type.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_type.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_type.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_purchase_state.cc", @@ -1833,6 +1831,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_image_track_list.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ink.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ink.h", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ink_presenter_param.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_ink_presenter_param.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_input_device_info.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_input_device_info.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_install_event.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni index 6b462f1a..57338f1 100644 --- a/third_party/blink/renderer/bindings/idl_in_modules.gni +++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -191,6 +191,7 @@ "//third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.idl", "//third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.idl", "//third_party/blink/renderer/modules/delegated_ink/ink.idl", + "//third_party/blink/renderer/modules/delegated_ink/ink_presenter_param.idl", "//third_party/blink/renderer/modules/delegated_ink/ink_trail_style.idl", "//third_party/blink/renderer/modules/delegated_ink/navigator_ink.idl", "//third_party/blink/renderer/modules/device_orientation/device_motion_event.idl",
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc index cfe26b72..c9d144c 100644 --- a/third_party/blink/renderer/core/frame/dom_window.cc +++ b/third_party/blink/renderer/core/frame/dom_window.cc
@@ -248,8 +248,6 @@ if (accessing_window_url.IsNull()) return String(); - // FIXME: This message, and other console messages, have extra newlines. - // Should remove them. const SecurityOrigin* active_origin = accessing_window->GetSecurityOrigin(); const SecurityOrigin* target_origin = GetFrame()->GetSecurityContext()->GetSecurityOrigin(); @@ -309,7 +307,7 @@ return message + " The frame requesting access has a protocol of \"" + active_url.Protocol() + "\", the frame being accessed has a protocol of \"" + - target_url.Protocol() + "\". Protocols must match.\n"; + target_url.Protocol() + "\". Protocols must match."; // 'document.domain' errors. if (target_origin->DomainWasSetInDOM() && active_origin->DomainWasSetInDOM())
diff --git a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h index cca785c..e233b2a 100644 --- a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h +++ b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
@@ -76,6 +76,8 @@ inline bool IsManagedByLayoutNG(const LayoutObject& object) { if (!object.IsLayoutNGMixin()) return false; + if (object.IsOutOfFlowPositioned()) + return true; const auto* containing_block = object.ContainingBlock(); if (UNLIKELY(!containing_block)) return false;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc index 2e37347f..7e7e7ea 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -798,7 +798,7 @@ void AXObjectCacheImpl::Invalidate(Document& document, AXID ax_id) { if (GetInvalidatedIds(document).insert(ax_id).is_new_entry) - ScheduleVisualUpdate(); + ScheduleVisualUpdate(document); } AXID AXObjectCacheImpl::GetAXID(Node* node) { @@ -1573,7 +1573,7 @@ // These events are fired during DocumentLifecycle::kInAccessibility, // ensure there is a document lifecycle update scheduled. - ScheduleVisualUpdate(); + ScheduleVisualUpdate(*tree_update_document); } void AXObjectCacheImpl::DeferTreeUpdateInternal(base::OnceClosure callback, @@ -1618,7 +1618,7 @@ // These events are fired during DocumentLifecycle::kInAccessibility, // ensure there is a document lifecycle update scheduled. - ScheduleVisualUpdate(); + ScheduleVisualUpdate(tree_update_document); } void AXObjectCacheImpl::DeferTreeUpdate( @@ -2076,8 +2076,14 @@ << "Unclean document at lifecycle " << document->Lifecycle().ToString(); #endif // DCHECK_IS_ON() - if (obj) + if (obj) { obj->ChildrenChangedWithCleanLayout(); + // TODO(accessibility) Only needed for <select> size changes. + // This can turn into a DCHECK if the shadow DOM is used for <select> + // elements instead of AXMenuList* and AXListBox* classes. + if (obj->IsDetached()) + return; + } if (optional_node) relation_cache_->UpdateRelatedTree(optional_node, obj); @@ -2347,6 +2353,7 @@ DCHECK_EQ(node, obj->GetNode()); DCHECK_EQ(GetWithoutInvalidation(node), obj); } + DCHECK_EQ(obj->GetDocument(), document); } } #endif @@ -2440,28 +2447,29 @@ // These events are fired during DocumentLifecycle::kInAccessibility, // ensure there is a visual update scheduled. - ScheduleVisualUpdate(); + ScheduleVisualUpdate(document); } -void AXObjectCacheImpl::ScheduleVisualUpdate() { +void AXObjectCacheImpl::ScheduleVisualUpdate(Document& document) { // Scheduling visual updates before the document is finished loading can - // interfere with event ordering. - if (!GetDocument().IsLoadCompleted()) + // interfere with event ordering. In any case, at least one visual update will + // occur between now and when the document load is complete. + if (!document.IsLoadCompleted()) return; // If there was a document change that doesn't trigger a lifecycle update on // its own, (e.g. because it doesn't make layout dirty), make sure we run // lifecycle phases to update the computed accessibility tree. - LocalFrameView* frame_view = GetDocument().View(); - Page* page = GetDocument().GetPage(); + LocalFrameView* frame_view = document.View(); + Page* page = document.GetPage(); if (!frame_view || !page) return; if (!frame_view->CanThrottleRendering() && - (!GetDocument().GetPage()->Animator().IsServicingAnimations() || - GetDocument().Lifecycle().GetState() >= + (!document.GetPage()->Animator().IsServicingAnimations() || + document.Lifecycle().GetState() >= DocumentLifecycle::kInAccessibility)) { - page->Animator().ScheduleVisualUpdate(GetDocument().GetFrame()); + page->Animator().ScheduleVisualUpdate(document.GetFrame()); } } @@ -3184,10 +3192,9 @@ ax::mojom::blink::EventFrom event_from, ax::mojom::blink::Action event_from_action, const BlinkAXEventIntentsSet& event_intents) { - if (!document_ || !document_->View() || - !document_->View()->GetFrame().GetPage()) { + obj = GetSerializationTarget(obj); + if (!obj) return; - } WebLocalFrameImpl* web_frame = WebLocalFrameImpl::FromFrame(document_->AXObjectCacheOwner().GetFrame()); @@ -3209,11 +3216,9 @@ void AXObjectCacheImpl::MarkAXObjectDirtyWithCleanLayoutHelper(AXObject* obj, bool subtree) { - if (!obj || obj->IsDetached() || !obj->GetDocument() || - !obj->GetDocument()->View() || - !obj->GetDocument()->View()->GetFrame().GetPage()) { + obj = GetSerializationTarget(obj); + if (!obj) return; - } WebLocalFrameImpl* webframe = WebLocalFrameImpl::FromFrame( obj->GetDocument()->AXObjectCacheOwner().GetFrame()); @@ -3258,6 +3263,40 @@ MarkAXObjectDirtyWithCleanLayout(Get(element)); } +AXObject* AXObjectCacheImpl::GetSerializationTarget(AXObject* obj) { + if (!obj || obj->IsDetached() || !obj->GetDocument() || + !obj->GetDocument()->View() || + !obj->GetDocument()->View()->GetFrame().GetPage()) { + return nullptr; + } + + // Ensure still in tree. + if (obj->IsMissingParent()) { + // TODO(accessibility) Only needed because of <select> size changes. + // This should become a DCHECK(!obj->IsMissingParent()) once the shadow DOM + // is used for <select> elements instead of AXMenuList* and AXListBox* + // classes. + if (!RestoreParentOrPrune(obj)) + return nullptr; + } + + // Return included in tree object. + if (obj->LastKnownIsIncludedInTreeValue()) + return obj; + + return obj->ParentObjectIncludedInTree(); +} + +AXObject* AXObjectCacheImpl::RestoreParentOrPrune(AXObject* child) { + AXObject* parent = child->ComputeParent(); + if (parent) + child->SetParent(parent); + else // If no parent is possible, the child is no longer part of the tree. + Remove(child); + + return parent; +} + void AXObjectCacheImpl::HandleFocusedUIElementChanged( Element* old_focused_element, Element* new_focused_element) {
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 dbf5fc8..ed1d1f820 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
@@ -233,6 +233,10 @@ void MarkAXObjectDirtyWithCleanLayout(AXObject*); void MarkAXSubtreeDirtyWithCleanLayout(AXObject*); + // Set the parent of |child|. If no parent is possible, this means the child + // can no longer be in the AXTree, so remove the child. + AXObject* RestoreParentOrPrune(AXObject* child); + // When an object is created or its id changes, this must be called so that // the relation cache is updated. void MaybeNewRelationTarget(Node& node, AXObject* obj); @@ -439,6 +443,13 @@ void MarkElementDirty(const Node*); void MarkElementDirtyWithCleanLayout(const Node*); + // Given an object to mark dirty or fire an event on, return an object + // included in the tree that can be used with the serializer, or null if there + // is no relevant object to use. Objects that are not included in the tree, + // and have no ancestor object included in the tree, are pruned from the tree, + // in which case there is nothing to be serialized. + AXObject* GetSerializationTarget(AXObject* obj); + // Helper that clears children up to the first included ancestor and returns // the ancestor if a children changed notification should be fired on it. AXObject* InvalidateChildren(AXObject* obj); @@ -575,7 +586,7 @@ // setting enabled, or where there is no active ancestral aria-modal dialog. AXObject* AncestorAriaModalDialog(Node* node); - void ScheduleVisualUpdate(); + void ScheduleVisualUpdate(Document& document); void FireTreeUpdatedEventImmediately( Document& document, ax::mojom::blink::EventFrom event_from,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc index 201b178..4c2148a 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -192,8 +192,10 @@ // Don't do this if it's also in the newly owned ids, as it's about to // get a new parent, and we want to avoid accidentally pruning it. if (!newly_owned_ids.Contains(removed_child_id)) { - if (AXObject* real_parent = RestoreParentOrPrune(removed_child)) + if (AXObject* real_parent = + object_cache_->RestoreParentOrPrune(removed_child)) { ChildrenChanged(real_parent); + } // Now that the child is not owned, it's "included in tree" state must // be recomputed because while owned children are always included in the // tree, unowned children may not be included. @@ -253,7 +255,7 @@ validated_owned_children_result.push_back(child); } else if (child) { // Invalid owns relation: repair the parent that was set above. - RestoreParentOrPrune(child); + object_cache_->RestoreParentOrPrune(child); } } @@ -336,7 +338,7 @@ owned_children.push_back(child); } else if (child) { // Invalid owns relation: repair the parent that was set above. - RestoreParentOrPrune(child); + object_cache_->RestoreParentOrPrune(child); } } } @@ -434,16 +436,6 @@ } } -AXObject* AXRelationCache::RestoreParentOrPrune(AXObject* child) { - AXObject* parent = child->ComputeParent(); - if (parent) - child->SetParent(parent); - else // If no parent is possible, the child is no longer part of the tree. - object_cache_->Remove(child); - - return parent; -} - void AXRelationCache::UpdateRelatedTree(Node* node, AXObject* obj) { HeapVector<Member<AXObject>> related_sources; #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h index 5d00269..c319b31 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h +++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
@@ -114,11 +114,6 @@ void MapOwnedChildren(const AXObject* owner, const Vector<AXID>&); void GetReverseRelated(Node*, HeapVector<Member<AXObject>>& sources); - // Set the parent of |child| to its natural parent, without any aria-owns. - // If no natural parent is possible, this means the child can no longer be in - // the AXTree, so remove the child. - AXObject* RestoreParentOrPrune(AXObject* child); - // Updates |aria_owner_to_children_mapping_| after calling UpdateAriaOwns for // either the content attribute or the attr associated elements. void UpdateAriaOwnerToChildrenMappingWithCleanLayout(
diff --git a/third_party/blink/renderer/modules/credentialmanager/password_credential.cc b/third_party/blink/renderer/modules/credentialmanager/password_credential.cc index 3f1a860b..d4521ac 100644 --- a/third_party/blink/renderer/modules/credentialmanager/password_credential.cc +++ b/third_party/blink/renderer/modules/credentialmanager/password_credential.cc
@@ -67,7 +67,7 @@ V8FormDataEntryValue* value = form_data->get(submittable_element->GetName()); - if (!value->IsUSVString()) + if (!value || !value->IsUSVString()) continue; const String& usv_string_value = value->GetAsUSVString();
diff --git a/third_party/blink/renderer/modules/delegated_ink/ink.cc b/third_party/blink/renderer/modules/delegated_ink/ink.cc index bca13e38..bf7b099 100644 --- a/third_party/blink/renderer/modules/delegated_ink/ink.cc +++ b/third_party/blink/renderer/modules/delegated_ink/ink.cc
@@ -5,7 +5,7 @@ #include "third_party/blink/renderer/modules/delegated_ink/ink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" -#include "third_party/blink/renderer/bindings/modules/v8/v8_presenter_type.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_ink_presenter_param.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/navigator.h" #include "third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.h" @@ -28,11 +28,9 @@ Ink::Ink(Navigator& navigator) : Supplement<Navigator>(navigator) {} ScriptPromise Ink::requestPresenter(ScriptState* state, - const V8PresenterType& type, - Element* presentation_area, + InkPresenterParam* presenter_param, ExceptionState& exception_state) { DCHECK(RuntimeEnabledFeatures::DelegatedInkTrailsEnabled()); - DCHECK_EQ(type.AsEnum(), V8PresenterType::Enum::kDelegatedInkTrail); if (!state->ContextIsValid()) { exception_state.ThrowException( @@ -44,7 +42,8 @@ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(state); ScriptPromise promise = resolver->Promise(); resolver->Resolve(MakeGarbageCollected<DelegatedInkTrailPresenter>( - presentation_area, GetSupplementable()->DomWindow()->GetFrame())); + presenter_param->presentationArea(), + GetSupplementable()->DomWindow()->GetFrame())); return promise; }
diff --git a/third_party/blink/renderer/modules/delegated_ink/ink.h b/third_party/blink/renderer/modules/delegated_ink/ink.h index 7d6bf39..bdca0b6 100644 --- a/third_party/blink/renderer/modules/delegated_ink/ink.h +++ b/third_party/blink/renderer/modules/delegated_ink/ink.h
@@ -10,12 +10,11 @@ namespace blink { -class Element; class ExceptionState; +class InkPresenterParam; class Navigator; class ScriptPromise; class ScriptState; -class V8PresenterType; class Ink : public ScriptWrappable, public Supplement<Navigator> { DEFINE_WRAPPERTYPEINFO(); @@ -26,8 +25,7 @@ explicit Ink(Navigator&); ScriptPromise requestPresenter(ScriptState* state, - const V8PresenterType& type, - Element* presentation_area, + InkPresenterParam* presenter_param, ExceptionState& exception_state); void Trace(blink::Visitor*) const override;
diff --git a/third_party/blink/renderer/modules/delegated_ink/ink.idl b/third_party/blink/renderer/modules/delegated_ink/ink.idl index 03ee065..d85a93b 100644 --- a/third_party/blink/renderer/modules/delegated_ink/ink.idl +++ b/third_party/blink/renderer/modules/delegated_ink/ink.idl
@@ -4,13 +4,9 @@ // https://github.com/WICG/ink-enhancement -enum PresenterType { - "delegated-ink-trail" -}; - [ RuntimeEnabled=DelegatedInkTrails, Exposed=Window ] interface Ink { - [CallWith=ScriptState, RaisesException] Promise<DelegatedInkTrailPresenter> requestPresenter(PresenterType type, optional Element? presentationArea = null); + [CallWith=ScriptState, RaisesException] Promise<DelegatedInkTrailPresenter> requestPresenter(optional InkPresenterParam param = {}); };
diff --git a/third_party/blink/renderer/modules/delegated_ink/ink_presenter_param.idl b/third_party/blink/renderer/modules/delegated_ink/ink_presenter_param.idl new file mode 100644 index 0000000..9d923122 --- /dev/null +++ b/third_party/blink/renderer/modules/delegated_ink/ink_presenter_param.idl
@@ -0,0 +1,9 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/ink-enhancement/ + +dictionary InkPresenterParam { + Element? presentationArea = null; +}; \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc index 293a05c..5537ffb 100644 --- a/third_party/blink/renderer/modules/exported/web_ax_object.cc +++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -938,6 +938,11 @@ if (IsDetached()) return false; + DCHECK_GE(private_->GetDocument()->Lifecycle().GetState(), + DocumentLifecycle::kLayoutClean) + << "Document lifecycle must be at LayoutClean or later, was " + << private_->GetDocument()->Lifecycle().GetState(); + return private_->AccessibilityIsIncludedInTree(); }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index b6296083..81986aab 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2681,8 +2681,6 @@ crbug.com/626703 external/wpt/webrtc-extensions/transfer-datachannel-service-worker.https.html [ Timeout ] crbug.com/626703 external/wpt/webrtc-extensions/transfer-datachannel.html [ Timeout ] crbug.com/626703 [ Mac11.0 ] virtual/no-auto-wpt-origin-isolation/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/1-iframe/parent-no-child-yeswithparams-subdomain.sub.https.html [ Failure Timeout ] -crbug.com/626703 [ Mac11.0 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Failure Timeout ] -crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Failure Timeout ] crbug.com/626703 [ Mac11.0 ] virtual/no-auto-wpt-origin-isolation/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-yes-subdomainport.sub.https.html [ Failure Timeout ] crbug.com/626703 [ Mac11.0 ] virtual/no-auto-wpt-origin-isolation/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/popups/opener-no-openee-yes-same.sub.https.html [ Failure Timeout ] crbug.com/626703 [ Mac11.0 ] virtual/no-auto-wpt-origin-isolation/external/wpt/html/browsers/origin/origin-keyed-agent-clusters/2-iframes/parent-yes-child1-yes-subdomain-child2-no-port.sub.https.html [ Failure Timeout ] @@ -5933,6 +5931,11 @@ crbug.com/v8/10556 external/wpt/wasm/jsapi/instance/constructor-caching.any.html [ Failure Pass ] crbug.com/v8/10556 external/wpt/wasm/jsapi/instance/constructor-caching.any.worker.html [ Failure Pass ] +# Temporarily disabled to land the new wasm exception handling JS API +crbug.com/v8/11992 external/wpt/wasm/jsapi/exception/* [ Skip ] +crbug.com/v8/11992 external/wpt/wasm/jsapi/tag/* [ Skip ] +crbug.com/v8/11992 http/tests/origin_trials/webexposed/wasm-exceptions-origin-trial-enabled.html [ Skip ] + # Disabled for landing DevTools change crbug.com/1011811 http/tests/devtools/network/network-xhr-data-received-async-response-type-blob.js [ Failure Pass ] crbug.com/1011811 http/tests/devtools/network/download.js [ Failure Pass ] @@ -6330,9 +6333,6 @@ # Wpt importer sheriff 2021-01-05 crbug.com/1163175 external/wpt/css/css-pseudo/first-letter-punctuation-and-space.html [ Failure ] -# COOP flaky test (timeout) -crbug.com/1161244 external/wpt/html/cross-origin-opener-policy/popup-coop-by-sw-from-coop.https.html [ Pass Timeout ] - # Sheriff 2020-12-22 crbug.com/1161301 [ Mac10.15 ] external/wpt/webxr/xrSession_requestReferenceSpace_features.https.html [ Pass Timeout ] crbug.com/1161301 [ Mac10.14 ] external/wpt/webxr/xrSession_requestReferenceSpace_features.https.html [ Failure Pass Timeout ] @@ -7303,7 +7303,6 @@ crbug.com/1220114 [ Linux ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-simulcast.https.html [ Failure Pass Timeout ] crbug.com/1228788 [ Linux ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-audio.https.html [ Failure Pass ] crbug.com/1228772 [ Linux ] external/wpt/webrtc/simulcast/h264.https.html [ Crash Failure Pass ] -crbug.com/1228772 [ Linux ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Failure Pass ] crbug.com/1228959 [ Linux ] virtual/scroll-unification/fast/scroll-snap/snaps-after-wheel-scrolling-single-tick.html [ Failure Pass ] # PlzServiceWorker failing tests @@ -7343,8 +7342,6 @@ crbug.com/1229212 inspector-protocol/heap-profiler/heap-samples-in-snapshot.js [ Failure ] # Sheriff 2021-07-15 -crbug.com/1229439 [ Mac10.14 ] virtual/dark-color-scheme/media/audio-focus-ring.html [ Failure Pass ] -crbug.com/1229439 [ Mac10.14 ] media/audio-repaint.html [ Failure Pass ] crbug.com/1229666 external/wpt/html/semantics/forms/form-submission-0/urlencoded2.window.html [ Pass Timeout ] crbug.com/1229666 virtual/synchronous_html_parser/external/wpt/html/semantics/forms/form-submission-0/urlencoded2.window.html [ Pass Timeout ] crbug.com/1093027 http/tests/credentialmanager/credentialscontainer-create-with-virtual-authenticator.html [ Pass Failure Crash Timeout ] @@ -7360,3 +7357,8 @@ crbug.com/1229802 fast/events/pointerevents/multi-touch-events.html [ Pass Failure ] crbug.com/835943 http/tests/appcache/non-html.xhtml [ Crash Failure Pass Timeout ] crbug.com/1181886 external/wpt/pointerevents/pointerevent_movementxy.html?* [ Failure Pass Timeout ] +crbug.com/1161244 external/wpt/html/cross-origin-opener-policy/popup-coop-by-sw-from-coop.https.html?* [ Pass Timeout ] + +# Sheriff 2021-07-16 +crbug.com/1229973 external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Pass Failure Timeout ] +crbug.com/1229973 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https.html [ Pass Failure Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-dynamic-auto-overflow.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-dynamic-auto-overflow.html new file mode 100644 index 0000000..142af95 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-dynamic-auto-overflow.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1225548"> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="position: fixed; background: red; max-height: 150px; overflow-y: auto;"> + <div id="target" style="width: 100px; background: green;"></div> +</div> +<script> +document.body.offsetTop; +const target = document.getElementById('target'); +target.style.height = '200px'; +document.body.offsetTop; +target.style.height = '100px'; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-bad-color.tentative.html b/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-bad-color.tentative.html index 24e54c5..54c28efb 100644 --- a/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-bad-color.tentative.html +++ b/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-bad-color.tentative.html
@@ -8,7 +8,7 @@ <canvas id="canvas"></canvas> <script> promise_test(async (t) => { - const presenter = await navigator.ink.requestPresenter('delegated-ink-trail', canvas); + const presenter = await navigator.ink.requestPresenter({presentationArea: canvas}); const style = { color: "bad-color", diameter: 6 }; canvas.addEventListener("pointermove", evt => {
diff --git a/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-diameter-less-than-or-equal-to-0.tentative.html b/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-diameter-less-than-or-equal-to-0.tentative.html index 8a283e7..bf26ab1 100644 --- a/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-diameter-less-than-or-equal-to-0.tentative.html +++ b/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-diameter-less-than-or-equal-to-0.tentative.html
@@ -9,7 +9,7 @@ <script> function RunTest(d, move) { promise_test(async (t) => { - const presenter = await navigator.ink.requestPresenter('delegated-ink-trail', canvas); + const presenter = await navigator.ink.requestPresenter({presentationArea: canvas}); const style = { color: "green", diameter: d }; canvas.addEventListener("pointermove", evt => {
diff --git a/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-untrusted-event.tentative.window.js b/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-untrusted-event.tentative.window.js index de4a2b43..0b83dd2 100644 --- a/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-untrusted-event.tentative.window.js +++ b/third_party/blink/web_tests/external/wpt/delegated-ink/exception-thrown-untrusted-event.tentative.window.js
@@ -1,4 +1,4 @@ -let presenter = navigator.ink.requestPresenter('delegated-ink-trail'); +let presenter = navigator.ink.requestPresenter(); let style = { color: "red", diameter: 3 }; let evt = new PointerEvent("pointerdown", {clientX: 10, clientY: 10}); presenter.then( function(p) {
diff --git a/third_party/blink/web_tests/external/wpt/delegated-ink/requestPresenter-returns-valid-promise.tentative.window.js b/third_party/blink/web_tests/external/wpt/delegated-ink/requestPresenter-returns-valid-promise.tentative.window.js index 0a54115ee..6cbc69d 100644 --- a/third_party/blink/web_tests/external/wpt/delegated-ink/requestPresenter-returns-valid-promise.tentative.window.js +++ b/third_party/blink/web_tests/external/wpt/delegated-ink/requestPresenter-returns-valid-promise.tentative.window.js
@@ -3,9 +3,21 @@ }, "navigator needs to support ink to run this test."); promise_test(t => { - return promise_rejects_js(t, TypeError, navigator.ink.requestPresenter('bad-type')); -}, "Receive rejected promise for a bad type."); + return promise_rejects_js(t, TypeError, navigator.ink.requestPresenter('invalid-param')); +}, "Receive rejected promise for an invalid param."); promise_test(() => { - return navigator.ink.requestPresenter('delegated-ink-trail'); -}, "Received fulfilled promise for a good type."); \ No newline at end of file + return navigator.ink.requestPresenter(); +}, "Received fulfilled promise for no param"); + +promise_test(() => { + return navigator.ink.requestPresenter(null); +}, "Received fulfilled promise for null param"); + +promise_test(() => { + return navigator.ink.requestPresenter({}); +}, "Received fulfilled promise for empty dictionary param"); + +promise_test(() => { + return navigator.ink.requestPresenter({presentationArea: null}); +}, "Received fulfilled promise for dictionary param with valid element."); \ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/element-set-sanitized-html.https.tentative.html b/third_party/blink/web_tests/external/wpt/sanitizer-api/element-set-sanitized-html.https.tentative.html similarity index 100% rename from third_party/blink/web_tests/wpt_internal/sanitizer-api/element-set-sanitized-html.https.tentative.html rename to third_party/blink/web_tests/external/wpt/sanitizer-api/element-set-sanitized-html.https.tentative.html
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-query-config.https.tenative.html b/third_party/blink/web_tests/external/wpt/sanitizer-api/sanitizer-query-config.https.tenative.html similarity index 100% rename from third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-query-config.https.tenative.html rename to third_party/blink/web_tests/external/wpt/sanitizer-api/sanitizer-query-config.https.tenative.html
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeFor.https.tentative.html b/third_party/blink/web_tests/external/wpt/sanitizer-api/sanitizer-sanitizeFor.https.tentative.html similarity index 100% rename from third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-sanitizeFor.https.tentative.html rename to third_party/blink/web_tests/external/wpt/sanitizer-api/sanitizer-sanitizeFor.https.tentative.html
diff --git a/third_party/blink/web_tests/external/wpt/sanitizer-api/support/testcases.sub.js b/third_party/blink/web_tests/external/wpt/sanitizer-api/support/testcases.sub.js index 4b49c49..c840fb32 100644 --- a/third_party/blink/web_tests/external/wpt/sanitizer-api/support/testcases.sub.js +++ b/third_party/blink/web_tests/external/wpt/sanitizer-api/support/testcases.sub.js
@@ -41,4 +41,27 @@ {config_input: {allowAttributes: {"id": ["*"]}}, value: "<p id='test' onclick='a= 123'>Click.</p>", result: "<p id=\"test\">Click.</p>", message: "allowAttributes list {\"id\": [\"*\"]} with id attribute and onclick scripts"}, {config_input: {allowAttributes: {"*": ["a"]}}, value: "<a id='a' style='color: black'>Click.</a><div style='color: white'>div</div>", result: "<a id=\"a\" style=\"color: black\">Click.</a><div>div</div>", message: "allowAttributes list {\"*\": [\"a\"]} with style attribute"}, {config_input: {dropAttributes: {"style": ["*"]}, allowAttributes: {"style": ["*"]}}, value: "<p style='color: black'>Click.</p>", result: "<p>Click.</p>", message: "allowAttributes list has no influence to dropAttributes"}, + {config_input: {allowElements: ["template", "div"]}, value: "<template><script>test</script><div>hello</div></template>", result: "<template><div>hello</div></template>", message: "Template element"}, + {config_input: {}, value: "<a href='javascript:evil.com'>Click.</a>", result: "<a>Click.</a>", message: "HTMLAnchorElement with javascript protocal"}, + {config_input: {}, value: "<a href=' javascript:evil.com'>Click.</a>", result: "<a>Click.</a>", message: "HTMLAnchorElement with javascript protocal start with space"}, + {config_input: {}, value: "<a href='http:evil.com'>Click.</a>", result: "<a href=\"http:evil.com\">Click.</a>", message: "HTMLAnchorElement"}, + {config_input: {}, value: "<area href='javascript:evil.com'>Click.</area>", result: "<area>Click.", message: "HTMLAreaElement with javascript protocal"}, + {config_input: {}, value: "<area href=' javascript:evil.com'>Click.</area>", result: "<area>Click.", message: "HTMLAreaElement with javascript protocal start with space"}, + {config_input: {}, value: "<area href='http:evil.com'>Click.</area>", result: "<area href=\"http:evil.com\">Click.", message: "HTMLAreaElement"}, + {config_input: {}, value: "<form action='javascript:evil.com'>Click.</form>", result: "<form>Click.</form>", message: "HTMLFormElement with javascript action"}, + {config_input: {}, value: "<form action=' javascript:evil.com'>Click.</form>", result: "<form>Click.</form>", message: "HTMLFormElement with javascript action start with space"}, + {config_input: {}, value: "<form action='http:evil.com'>Click.</form>", result: "<form action=\"http:evil.com\">Click.</form>", message: "HTMLFormElement"}, + {config_input: {}, value: "<input formaction='javascript:evil.com'>Click.</input>", result: "<input>Click.", message: "HTMLInputElement with javascript formaction"}, + {config_input: {}, value: "<input formaction=' javascript:evil.com'>Click.</input>", result: "<input>Click.", message: "HTMLInputElement with javascript formaction start with space"}, + {config_input: {}, value: "<input formaction='http:evil.com'>Click.</input>", result: "<input formaction=\"http:evil.com\">Click.", message: "HTMLInputElement"}, + {config_input: {}, value: "<button formaction='javascript:evil.com'>Click.</button>", result: "<button>Click.</button>", message: "HTMLButtonElement with javascript formaction"}, + {config_input: {}, value: "<button formaction=' javascript:evil.com'>Click.</button>", result: "<button>Click.</button>", message: "HTMLButtonElement with javascript formaction start with space"}, + {config_input: {}, value: "<button formaction='http:evil.com'>Click.</button>", result: "<button formaction=\"http:evil.com\">Click.</button>", message: "HTMLButtonElement"}, + {config_input: {}, value: "<p>Some text</p></body><!-- 1 --></html><!-- 2 --><p>Some more text</p>", result: "<p>Some text</p><p>Some more text</p>", message: "malformed HTML"}, + {config_input: {}, value: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>", result: "<p>Some text</p><p>Some more text</p>", message: "HTML with comments; comments not allowed"}, + {config_input: {allowComments: true}, value: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>", result: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>", message: "HTML with comments; allowComments"}, + {config_input: {allowComments: false}, value: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>", result: "<p>Some text</p><p>Some more text</p>", message: "HTML with comments; !allowComments"}, + {config_input: {}, value: "<p>comment<!-- hello -->in<!-- </p> -->text</p>", result: "<p>commentintext</p>", message: "HTML with comments deeper in the tree"}, + {config_input: {allowComments: true}, value: "<p>comment<!-- hello -->in<!-- </p> -->text</p>", result: "<p>comment<!-- hello -->in<!-- </p> -->text</p>", message: "HTML with comments deeper in the tree, allowComments"}, + {config_input: {allowComments: false}, value: "<p>comment<!-- hello -->in<!-- </p> -->text</p>", result: "<p>commentintext</p>", message: "HTML with comments deeper in the tree, !allowComments"}, ];
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt index 010886b..a0bf1d2 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 75 tests; 70 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 75 tests; 71 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS getStats succeeds PASS Validating stats PASS RTCRtpStreamStats's ssrc @@ -9,7 +9,7 @@ PASS RTCReceivedRtpStreamStats's packetsReceived PASS RTCReceivedRtpStreamStats's packetsLost PASS RTCReceivedRtpStreamStats's jitter -FAIL RTCReceivedRtpStreamStats's packetsDiscarded assert_true: Is packetsDiscarded present expected true got false +PASS RTCReceivedRtpStreamStats's packetsDiscarded PASS RTCReceivedRtpStreamStats's framesDropped FAIL RTCInboundRtpStreamStats's receiverId assert_true: Is receiverId present expected true got false PASS RTCInboundRtpStreamStats's remoteId
diff --git a/third_party/blink/web_tests/http/tests/security/document-all-expected.txt b/third_party/blink/web_tests/http/tests/security/document-all-expected.txt index 95b1e02..afa53cf0 100644 --- a/third_party/blink/web_tests/http/tests/security/document-all-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/document-all-expected.txt
@@ -1,3 +1,2 @@ CONSOLE ERROR: line 11: Uncaught SecurityError: Blocked a frame with origin "null" from accessing a frame with origin "http://localhost:8080". The frame requesting access has a protocol of "data", the frame being accessed has a protocol of "http". Protocols must match. -
diff --git a/third_party/blink/web_tests/http/tests/security/window-named-proto-expected.txt b/third_party/blink/web_tests/http/tests/security/window-named-proto-expected.txt index 387f6dc..4d15b18 100644 --- a/third_party/blink/web_tests/http/tests/security/window-named-proto-expected.txt +++ b/third_party/blink/web_tests/http/tests/security/window-named-proto-expected.txt
@@ -1,3 +1,2 @@ CONSOLE ERROR: line 9: Uncaught SecurityError: Blocked a frame with origin "null" from accessing a frame with origin "http://localhost:8080". The frame requesting access has a protocol of "data", the frame being accessed has a protocol of "http". Protocols must match. -
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png index 4c440d524..9219f13 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.14/media/audio-repaint-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png index 86c678bf..af71867 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/media/audio-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt index 010886b..a0bf1d2 100644 --- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-mandatory-getStats.https-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 75 tests; 70 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 75 tests; 71 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS getStats succeeds PASS Validating stats PASS RTCRtpStreamStats's ssrc @@ -9,7 +9,7 @@ PASS RTCReceivedRtpStreamStats's packetsReceived PASS RTCReceivedRtpStreamStats's packetsLost PASS RTCReceivedRtpStreamStats's jitter -FAIL RTCReceivedRtpStreamStats's packetsDiscarded assert_true: Is packetsDiscarded present expected true got false +PASS RTCReceivedRtpStreamStats's packetsDiscarded PASS RTCReceivedRtpStreamStats's framesDropped FAIL RTCInboundRtpStreamStats's receiverId assert_true: Is receiverId present expected true got false PASS RTCInboundRtpStreamStats's remoteId
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/support/testcases.sub.js b/third_party/blink/web_tests/wpt_internal/sanitizer-api/support/testcases.sub.js index e084d75..33344a5 100644 --- a/third_party/blink/web_tests/wpt_internal/sanitizer-api/support/testcases.sub.js +++ b/third_party/blink/web_tests/wpt_internal/sanitizer-api/support/testcases.sub.js
@@ -1,30 +1,4 @@ const testcases = [ - {config_input: {}, value: "<plaintext><p>text</p>", result: "<p>text</p>", message: "plaintext"}, - {config_input: {}, value: "<xmp>TEXT</xmp>", result: "TEXT", message: "xmp"}, - {config_input: {allowElements: ["template", "div"]}, value: "<template><script>test</script><div>hello</div></template>", result: "<template><div>hello</div></template>", message: "Template element"}, - {config_input: {}, value: "<a href='javascript:evil.com'>Click.</a>", result: "<a>Click.</a>", message: "HTMLAnchorElement with javascript protocal"}, - {config_input: {}, value: "<a href=' javascript:evil.com'>Click.</a>", result: "<a>Click.</a>", message: "HTMLAnchorElement with javascript protocal start with space"}, - {config_input: {}, value: "<a href='http:evil.com'>Click.</a>", result: "<a href=\"http:evil.com\">Click.</a>", message: "HTMLAnchorElement"}, - {config_input: {}, value: "<area href='javascript:evil.com'>Click.</area>", result: "<area>Click.", message: "HTMLAreaElement with javascript protocal"}, - {config_input: {}, value: "<area href=' javascript:evil.com'>Click.</area>", result: "<area>Click.", message: "HTMLAreaElement with javascript protocal start with space"}, - {config_input: {}, value: "<area href='http:evil.com'>Click.</area>", result: "<area href=\"http:evil.com\">Click.", message: "HTMLAreaElement"}, - {config_input: {}, value: "<form action='javascript:evil.com'>Click.</form>", result: "<form>Click.</form>", message: "HTMLFormElement with javascript action"}, - {config_input: {}, value: "<form action=' javascript:evil.com'>Click.</form>", result: "<form>Click.</form>", message: "HTMLFormElement with javascript action start with space"}, - {config_input: {}, value: "<form action='http:evil.com'>Click.</form>", result: "<form action=\"http:evil.com\">Click.</form>", message: "HTMLFormElement"}, - {config_input: {}, value: "<input formaction='javascript:evil.com'>Click.</input>", result: "<input>Click.", message: "HTMLInputElement with javascript formaction"}, - {config_input: {}, value: "<input formaction=' javascript:evil.com'>Click.</input>", result: "<input>Click.", message: "HTMLInputElement with javascript formaction start with space"}, - {config_input: {}, value: "<input formaction='http:evil.com'>Click.</input>", result: "<input formaction=\"http:evil.com\">Click.", message: "HTMLInputElement"}, - {config_input: {}, value: "<button formaction='javascript:evil.com'>Click.</button>", result: "<button>Click.</button>", message: "HTMLButtonElement with javascript formaction"}, - {config_input: {}, value: "<button formaction=' javascript:evil.com'>Click.</button>", result: "<button>Click.</button>", message: "HTMLButtonElement with javascript formaction start with space"}, - {config_input: {}, value: "<button formaction='http:evil.com'>Click.</button>", result: "<button formaction=\"http:evil.com\">Click.</button>", message: "HTMLButtonElement"}, - {config_input: {}, value: "<p>Some text</p></body><!-- 1 --></html><!-- 2 --><p>Some more text</p>", result: "<p>Some text</p><p>Some more text</p>", message: "malformed HTML"}, - {config_input: {}, value: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>", result: "<p>Some text</p><p>Some more text</p>", message: "HTML with comments; comments not allowed"}, - {config_input: {allowComments: true}, value: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>", result: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>", message: "HTML with comments; allowComments"}, - {config_input: {allowComments: false}, value: "<p>Some text</p><!-- 1 --><!-- 2 --><p>Some more text</p>", result: "<p>Some text</p><p>Some more text</p>", message: "HTML with comments; !allowComments"}, - {config_input: {}, value: "<p>comment<!-- hello -->in<!-- </p> -->text</p>", result: "<p>commentintext</p>", message: "HTML with comments deeper in the tree"}, - {config_input: {allowComments: true}, value: "<p>comment<!-- hello -->in<!-- </p> -->text</p>", result: "<p>comment<!-- hello -->in<!-- </p> -->text</p>", message: "HTML with comments deeper in the tree, allowComments"}, - {config_input: {allowComments: false}, value: "<p>comment<!-- hello -->in<!-- </p> -->text</p>", result: "<p>commentintext</p>", message: "HTML with comments deeper in the tree, !allowComments"}, - // Test cases from issue WICG/sanitizer-api#84 { config_input: {"allowElements":["svg","use"], "allowAttributes":{"xlink:href":["use"]}}, @@ -50,3 +24,4 @@ message: "Regression test for WICG/sanitizer-api#86." }, ]; +
diff --git a/tools/android/audio_focus_grabber/java/AndroidManifest.xml b/tools/android/audio_focus_grabber/java/AndroidManifest.xml index 8255ea4..f02c19e3 100644 --- a/tools/android/audio_focus_grabber/java/AndroidManifest.xml +++ b/tools/android/audio_focus_grabber/java/AndroidManifest.xml
@@ -13,7 +13,8 @@ <activity android:name="org.chromium.tools.audio_focus_grabber.AudioFocusGrabberActivity" - android:label="@string/app_name" > + android:label="@string/app_name" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
diff --git a/tools/android/customtabs_benchmark/java/AndroidManifest.xml b/tools/android/customtabs_benchmark/java/AndroidManifest.xml index 72e8087..cdff15c 100644 --- a/tools/android/customtabs_benchmark/java/AndroidManifest.xml +++ b/tools/android/customtabs_benchmark/java/AndroidManifest.xml
@@ -12,7 +12,8 @@ <application android:label="CustomTabsBenchmark"> <activity android:name="org.chromium.customtabs.test.MainActivity" - android:label="CustomTabsBenchmark"> + android:label="CustomTabsBenchmark" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
diff --git a/tools/android/dependency_analysis/git_utils.py b/tools/android/dependency_analysis/git_utils.py index 0acd56b7..7fa22f2 100644 --- a/tools/android/dependency_analysis/git_utils.py +++ b/tools/android/dependency_analysis/git_utils.py
@@ -35,7 +35,7 @@ """ description: str = _get_last_commit_with_format('%b') # Will capture from - # '[lines...]Cr-Commit-Position: refs/heads/master@{#123456}' the string + # '[lines...]Cr-Commit-Position: refs/heads/main@{#123456}' the string # '123456'. CR_POSITION_REGEX = r'Cr-Commit-Position: .*{#([0-9]+)}' match: re.Match = re.search(CR_POSITION_REGEX, description)
diff --git a/tools/android/memconsumer/java/AndroidManifest.xml b/tools/android/memconsumer/java/AndroidManifest.xml index c7f12e42..ec01797 100644 --- a/tools/android/memconsumer/java/AndroidManifest.xml +++ b/tools/android/memconsumer/java/AndroidManifest.xml
@@ -11,7 +11,7 @@ <application android:label="MemConsumer"> - <activity android:name=".MemConsumer" android:icon="@drawable/icon" android:launchMode="singleTop"> + <activity android:name=".MemConsumer" android:icon="@drawable/icon" android:launchMode="singleTop" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index feab9ec6..c660165 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -74877,6 +74877,9 @@ <int value="13" label="Abort: password update pending"/> <int value="14" label="Abort: user declined new profile for this account"/> <int value="15" label="Abort: signin interception disabled by policy"/> + <int value="16" label="Intercept: forced enterprise interception"/> + <int value="17" label="Intercept: forced enterprise profile switch"/> + <int value="18" label="Abort: tab closed"/> </enum> <enum name="SigninInterceptResult"> @@ -81582,6 +81585,13 @@ <int value="3" label="Digital assetlinks verification failure"/> </enum> +<enum name="TrustSafetySentimentFeatureArea"> + <int value="0" label="Ineligible"/> + <int value="1" label="Privacy Settings"/> + <int value="2" label="Trusted Surface"/> + <int value="3" label="Transactions"/> +</enum> + <enum name="TrustTokenRequestHelperFactoryOutcome"> <int value="0" label="Successfully created an issuance helper"/> <int value="1" label="Successfully created a redemption helper"/>
diff --git a/tools/metrics/histograms/histograms_xml/content/OWNERS b/tools/metrics/histograms/histograms_xml/content/OWNERS index 953c57a..a4b22e9 100644 --- a/tools/metrics/histograms/histograms_xml/content/OWNERS +++ b/tools/metrics/histograms/histograms_xml/content/OWNERS
@@ -3,3 +3,4 @@ # Prefer sending CLs to the owners listed below. # Use chromium-metrics-reviews@google.com as a backup. dewittj@chromium.org +harrisonsean@chromium.org
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index a68486d..f3ba977 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -6114,6 +6114,27 @@ <summary>Records the source that requested showing the feedback app.</summary> </histogram> +<histogram name="Feedback.TrustSafetySentiment.SurveyRequested" + enum="TrustSafetySentimentFeatureArea" expires_after="M98"> + <owner>sauski@google.com</owner> + <owner>chrome-hats-eng@google.com</owner> + <summary> + Records the associated feature area when the Trust and Safety Sentiment + service requests a survey be shown from the HaTS service. + </summary> +</histogram> + +<histogram name="Feedback.TrustSafetySentiment.TriggerOccured" + enum="TrustSafetySentimentFeatureArea" expires_after="M98"> + <owner>sauski@google.com</owner> + <owner>chrome-hats-eng@google.com</owner> + <summary> + Records the associated feature area when the Trust and Safety sentiment + service detects that the user has performed a trigger action. This is + recorded after the associated probability check. + </summary> +</histogram> + <histogram name="FirstRun.IOSFirebaseConfigured" enum="FirebaseConfiguredState" expires_after="M89"> <owner>ghendel@chromium.org</owner>
diff --git a/tools/metrics/structured/codegen.py b/tools/metrics/structured/codegen.py index 61b1d45..a926ab3 100644 --- a/tools/metrics/structured/codegen.py +++ b/tools/metrics/structured/codegen.py
@@ -83,6 +83,15 @@ self.id_type = 'kProjectId' elif project.id == 'none': self.id_type = 'kUnidentified' + else: + raise ValueError('Invalid id type.') + + if project.scope == 'profile': + self.id_scope = 'kPerProfile' + elif project.scope == 'device': + self.id_scope = 'kPerDevice' + else: + raise ValueError('Invalid id scope.') class EventInfo:
diff --git a/tools/metrics/structured/model.py b/tools/metrics/structured/model.py index 1b32dcb..f95e760 100644 --- a/tools/metrics/structured/model.py +++ b/tools/metrics/structured/model.py
@@ -55,6 +55,7 @@ <project name="MyProject"> <owner>owner@chromium.org</owner> <id>none</id> + <scope>profile</scope> <summary> My project. </summary> <event name="MyEvent"> @@ -73,6 +74,7 @@ NAME_REGEX = r'^[A-Za-z0-9_.]+$' TYPE_REGEX = r'^(hmac-string|int)$' ID_REGEX = r'^(none|per-project|uma)$' + SCOPE_REGEX = r'^(profile|device)$' def __init__(self, xml_string): elem = ET.fromstring(xml_string) @@ -103,6 +105,7 @@ <project name="MyProject"> <owner>owner@chromium.org</owner> <id>none</id> + <scope>project</scope> <summary> My project. </summary> <event name="MyEvent"> @@ -118,11 +121,12 @@ def __init__(self, elem): util.check_attributes(elem, {'name'}) - util.check_children(elem, {'id', 'summary', 'owner', 'event'}) + util.check_children(elem, {'id', 'scope', 'summary', 'owner', 'event'}) util.check_child_names_unique(elem, 'event') self.name = util.get_attr(elem, 'name', Model.NAME_REGEX) self.id = util.get_text_child(elem, 'id', Model.ID_REGEX) + self.scope = util.get_text_child(elem, 'scope', Model.SCOPE_REGEX) self.summary = util.get_text_child(elem, 'summary') self.owners = util.get_text_children(elem, 'owner', Model.OWNER_REGEX) @@ -138,6 +142,7 @@ <project name="{name}"> {owners} <id>{id}</id> + <scope>{scope}</scope> <summary> {summary} </summary> @@ -147,6 +152,7 @@ return result.format(name=self.name, owners=owners, id=self.id, + scope=self.scope, summary=summary, events=events)
diff --git a/tools/metrics/structured/structured.xml b/tools/metrics/structured/structured.xml index 806a958..bb092d20 100644 --- a/tools/metrics/structured/structured.xml +++ b/tools/metrics/structured/structured.xml
@@ -4,6 +4,7 @@ <owner>charleszhao@chromium.org</owner> <owner>tby@chromium.org</owner> <id>per-project</id> + <scope>profile</scope> <summary> Project for recording CrOSActions. </summary> @@ -192,6 +193,7 @@ <project name="LauncherUsage"> <owner>tby@chromium.org</owner> <id>per-project</id> + <scope>profile</scope> <summary> See event summary. </summary> @@ -254,7 +256,8 @@ <project name="TestProjectOne"> <owner>tby@chromium.org</owner> - <id>none</id> + <id>per-project</id> + <scope>profile</scope> <summary> Project for unit testing, do not use. </summary> @@ -278,7 +281,8 @@ <project name="TestProjectTwo"> <owner>tby@chromium.org</owner> - <id>none</id> + <id>per-project</id> + <scope>profile</scope> <summary> Project for unit testing, do not use. </summary> @@ -309,6 +313,7 @@ <project name="TestProjectThree"> <owner>tby@chromium.org</owner> <id>uma</id> + <scope>profile</scope> <summary> Project for unit testing, do not use. </summary> @@ -325,4 +330,24 @@ </event> </project> +<project name="TestProjectFour"> + <owner>tby@chromium.org</owner> + <id>per-project</id> + <scope>device</scope> + <summary> + Project for unit testing, do not use. + </summary> + + <event name="TestEventFive"> + <summary> + Event for unit testing, do not use. + </summary> + <metric name="TestMetricFive" type="hmac-string"> + <summary> + An per-device keyed hashed value. + </summary> + </metric> + </event> +</project> + </structured-metrics> \ No newline at end of file
diff --git a/tools/metrics/structured/templates.py b/tools/metrics/structured/templates.py index 285e817..5a82935d 100644 --- a/tools/metrics/structured/templates.py +++ b/tools/metrics/structured/templates.py
@@ -46,6 +46,7 @@ static constexpr uint64_t kEventNameHash = UINT64_C({event.name_hash}); static constexpr uint64_t kProjectNameHash = UINT64_C({project.name_hash}); static constexpr IdType kIdType = IdType::{project.id_type}; + static constexpr IdScope kIdScope = IdScope::{project.id_scope}; {metric_code}\ }}; @@ -85,7 +86,7 @@ IMPL_EVENT_TEMPLATE = """\ {event.name}::{event.name}() : ::metrics::structured::EventBase(kEventNameHash, kProjectNameHash, - kIdType) {{}} + kIdType, kIdScope) {{}} {event.name}::~{event.name}() = default; {metric_code}\ """
diff --git a/tools/perf/BUILD.gn b/tools/perf/BUILD.gn index 7f8fc6a..344de9f 100644 --- a/tools/perf/BUILD.gn +++ b/tools/perf/BUILD.gn
@@ -2,15 +2,15 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -if (!is_android) { - group("perf") { - testonly = true - data_deps = [ - ":perf_without_chrome", - "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", - ] - } -} else { +group("perf") { + testonly = true + data_deps = [ + ":perf_without_chrome", + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", + ] +} + +if (is_android) { template("perf_android_template") { forward_variables_from(invoker, [ "telemetry_target_suffix" ]) group(target_name) {
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn index 6fdf9ba..902b24d 100644 --- a/tools/perf/chrome_telemetry_build/BUILD.gn +++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -36,7 +36,25 @@ ] data = [] - if (!is_fuchsia && !is_android) { + if (is_android) { + # TODO(crbug.com/1213269): Remove these APK dependencies and fully switch to + # the separate Android targets below once all Android uses of the old target + # have been cleaned up. + data_deps += [ + ":telemetry_weblayer_apks", + "//android_webview:system_webview_apk", + "//android_webview/test:webview_instrumentation_apk", + "//android_webview/tools/system_webview_shell:system_webview_shell_apk", + "//chrome/android:chrome_public_apk", + "//chrome/android:monochrome_public_apk", + "//chrome/android:monochrome_public_bundle", + "//chrome/android/webapk/shell_apk:maps_go_webapk", + ] + + if (enable_chrome_android_internal) { + data_deps += [ "//clank:telemetry_clank_test" ] + } + } else if (!is_fuchsia) { data_deps += [ "//chrome" ] }
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn index 06b53cf..9521351 100644 --- a/tools/perf/contrib/vr_benchmarks/BUILD.gn +++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -50,15 +50,15 @@ } } -if (!is_android) { - group("vr_perf_tests") { - testonly = true - data_deps = [ - ":vr_perf_tests_base", - "//tools/perf:perf", - ] - } -} else { +group("vr_perf_tests") { + testonly = true + data_deps = [ + ":vr_perf_tests_base", + "//tools/perf:perf", + ] +} + +if (is_android) { template("vr_perf_tests_android_template") { forward_variables_from(invoker, [ "telemetry_target_suffix" ]) group(target_name) {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index fe994150..d836e22b 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -217,6 +217,7 @@ crbug.com/1211795 [ mac ] rendering.desktop/skelebuddies_wasm_2020_fast_call [ Skip ] crbug.com/1226854 [ mac ] rendering.desktop/text_scrollbar_* [ Skip ] crbug.com/1229671 [ win ] rendering.desktop/espn_2018 [ Skip ] +crbug.com/1230060 [ win-laptop ] rendering.desktop/yahoo_news_2018 [ Skip ] # Benchmark: rendering.mobile crbug.com/785485 [ android-webview ] rendering.mobile/kevs_3d [ Skip ]
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc index 60fe423..e68b57bf 100644 --- a/ui/aura/client/aura_constants.cc +++ b/ui/aura/client/aura_constants.cc
@@ -36,6 +36,9 @@ // Alphabetical sort. DEFINE_UI_CLASS_PROPERTY_KEY(bool, + kAccessibilityFocusFallsbackToWidgetKey, + true) +DEFINE_UI_CLASS_PROPERTY_KEY(bool, kAccessibilityTouchExplorationPassThrough, false) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kActivateOnPointerKey, true)
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h index e939c70..dad4482 100644 --- a/ui/aura/client/aura_constants.h +++ b/ui/aura/client/aura_constants.h
@@ -38,6 +38,11 @@ // Alphabetical sort. +// A property key to store whether accessibility focus falls back to widget or +// not. +AURA_EXPORT extern const WindowProperty<bool>* const + kAccessibilityFocusFallsbackToWidgetKey; + // A property key to store whether accessibility touch exploration gets handled // by the window and all touches pass through directly. AURA_EXPORT extern const WindowProperty<bool>* const
diff --git a/ui/views/accessibility/ax_aura_obj_cache.cc b/ui/views/accessibility/ax_aura_obj_cache.cc index 10242f58..8ab62ea2 100644 --- a/ui/views/accessibility/ax_aura_obj_cache.cc +++ b/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -200,8 +200,7 @@ View* AXAuraObjCache::GetFocusedView() { Widget* focused_widget = focused_widget_for_testing_; - aura::Window* focused_window = - focused_widget ? focused_widget->GetNativeWindow() : nullptr; + aura::Window* focused_window = nullptr; if (!focused_widget) { // Uses the a11y override window for focus if it exists, otherwise gets the // last focused window. @@ -243,26 +242,20 @@ if (focused_view) return focused_view; - // No view has focus, but a child tree might have focus. - if (focused_window) { + if (focused_window && + focused_window->GetProperty( + aura::client::kAccessibilityFocusFallsbackToWidgetKey)) { + // If focused widget has non client view, falls back to first child view of + // its client view. We don't expect that non client view gets keyboard + // focus. auto* non_client = focused_widget->non_client_view(); auto* client = non_client ? non_client->client_view() : nullptr; - if (client && !client->children().empty()) { - const ViewAccessibility& host_accessibility = - client->children().front()->GetViewAccessibility(); - ui::AXNodeData host_data; - host_accessibility.GetAccessibleNodeData(&host_data); - if (host_accessibility.GetChildTreeID() != ui::AXTreeIDUnknown() || - !host_data - .GetStringAttribute( - ax::mojom::StringAttribute::kChildTreeNodeAppId) - .empty()) { - return client->children().front(); - } - } + return (client && !client->children().empty()) + ? client->children().front() + : focused_widget->GetRootView(); } - return focused_widget->GetRootView(); + return nullptr; } void AXAuraObjCache::OnWindowFocused(aura::Window* gained_focus,
diff --git a/ui/views/accessibility/ax_aura_obj_cache_unittest.cc b/ui/views/accessibility/ax_aura_obj_cache_unittest.cc index cd9ebff..e0dd3f62 100644 --- a/ui/views/accessibility/ax_aura_obj_cache_unittest.cc +++ b/ui/views/accessibility/ax_aura_obj_cache_unittest.cc
@@ -208,14 +208,12 @@ // Note that AXAuraObjCache::GetFocusedView has some logic to force focus on // the first child of the client view when one cannot be found from the - // FocusManager if it has a child tree id. + // FocusManager. auto* client = widget->non_client_view()->client_view(); ASSERT_NE(nullptr, client); auto* client_child = client->children().front(); ASSERT_NE(nullptr, client_child); client_child->GetViewAccessibility().OverrideRole(ax::mojom::Role::kDialog); - client_child->GetViewAccessibility().OverrideChildTreeID( - ui::AXTreeID::CreateNewAXTreeID()); View* parent = new View(); widget->GetRootView()->AddChildView(parent);
diff --git a/weblayer/shell/android/browsertests_apk/AndroidManifest.xml b/weblayer/shell/android/browsertests_apk/AndroidManifest.xml index a325ade..786bb1c 100644 --- a/weblayer/shell/android/browsertests_apk/AndroidManifest.xml +++ b/weblayer/shell/android/browsertests_apk/AndroidManifest.xml
@@ -27,6 +27,7 @@ android:theme="@android:style/Theme.Holo.Light.NoActionBar" android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:windowSoftInputMode="adjustPan|stateUnspecified" + android:exported="true" android:process=":test_process"> <intent-filter> <action android:name="android.intent.action.MAIN"/>
diff --git a/weblayer/shell/android/shell_apk/AndroidManifest.xml b/weblayer/shell/android/shell_apk/AndroidManifest.xml index aad3d83..b7a5d8a9 100644 --- a/weblayer/shell/android/shell_apk/AndroidManifest.xml +++ b/weblayer/shell/android/shell_apk/AndroidManifest.xml
@@ -15,7 +15,8 @@ <activity android:name="WebLayerShellActivity" android:launchMode="singleTask" android:theme="@style/ShellTheme" - android:windowSoftInputMode="adjustResize"> + android:windowSoftInputMode="adjustResize" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> @@ -31,7 +32,8 @@ </activity> <activity android:name="InstrumentationActivity" android:theme="@style/Theme.AppCompat.DayNight" - android:windowSoftInputMode="adjustResize"> + android:windowSoftInputMode="adjustResize" + android:exported="true"> <!-- Add these intent filters so tests can resolve these intents. --> <intent-filter> <action android:name="android.provider.MediaStore.RECORD_SOUND" />